From 90df6628d22c0112e527b07c93c6ba74e87cebe2 Mon Sep 17 00:00:00 2001 From: ksfi Date: Fri, 6 Oct 2023 15:55:24 +0200 Subject: [PATCH] first commit --- .melli.py.swp | Bin 0 -> 28672 bytes .test_melli.py.swp | Bin 0 -> 28672 bytes melli.py | 121 +- myenv/bin/Activate.ps1 | 241 + myenv/bin/activate | 66 + myenv/bin/activate.csh | 25 + myenv/bin/activate.fish | 64 + myenv/bin/black | 8 + myenv/bin/black-primer | 8 + myenv/bin/blackd | 8 + myenv/bin/dotenv | 8 + myenv/bin/easy_install | 8 + myenv/bin/easy_install-3.9 | 8 + myenv/bin/epylint | 8 + myenv/bin/future-fstrings-show | 8 + myenv/bin/get_objgraph | 54 + myenv/bin/httpx | 8 + myenv/bin/isort | 8 + myenv/bin/isort-identify-imports | 8 + myenv/bin/pip | 8 + myenv/bin/pip3 | 8 + myenv/bin/pip3.9 | 8 + myenv/bin/py.test | 8 + myenv/bin/pylint | 8 + myenv/bin/pyreverse | 8 + myenv/bin/pyrsa-decrypt | 8 + myenv/bin/pyrsa-encrypt | 8 + myenv/bin/pyrsa-keygen | 8 + myenv/bin/pyrsa-priv2pub | 8 + myenv/bin/pyrsa-sign | 8 + myenv/bin/pyrsa-verify | 8 + myenv/bin/pytest | 8 + myenv/bin/python | 1 + myenv/bin/python3 | 1 + myenv/bin/python3.9 | 1 + myenv/bin/symilar | 8 + myenv/bin/undill | 22 + myenv/bin/uvicorn | 8 + myenv/bin/watchgod | 8 + .../lib/python3.9/site-packages/CHANGELOG.md | 235 + myenv/lib/python3.9/site-packages/LICENSE | 13 + .../PyYAML-6.0.dist-info/INSTALLER | 1 + .../PyYAML-6.0.dist-info/LICENSE | 20 + .../PyYAML-6.0.dist-info/METADATA | 46 + .../site-packages/PyYAML-6.0.dist-info/RECORD | 25 + .../site-packages/PyYAML-6.0.dist-info/WHEEL | 5 + .../PyYAML-6.0.dist-info/top_level.txt | 2 + myenv/lib/python3.9/site-packages/README.md | 43 + .../python3.9/site-packages/_black_version.py | 1 + .../_cffi_backend.cpython-39-darwin.so | Bin 0 -> 202424 bytes .../site-packages/_pytest/__init__.py | 8 + .../site-packages/_pytest/_argcomplete.py | 117 + .../site-packages/_pytest/_code/__init__.py | 22 + .../site-packages/_pytest/_code/code.py | 1259 + .../site-packages/_pytest/_code/source.py | 212 + .../site-packages/_pytest/_io/__init__.py | 8 + .../site-packages/_pytest/_io/saferepr.py | 129 + .../_pytest/_io/terminalwriter.py | 210 + .../site-packages/_pytest/_io/wcwidth.py | 55 + .../site-packages/_pytest/_version.py | 5 + .../_pytest/assertion/__init__.py | 179 + .../_pytest/assertion/rewrite.py | 1125 + .../_pytest/assertion/truncate.py | 100 + .../site-packages/_pytest/assertion/util.py | 477 + .../site-packages/_pytest/cacheprovider.py | 575 + .../site-packages/_pytest/capture.py | 967 + .../python3.9/site-packages/_pytest/compat.py | 400 + .../site-packages/_pytest/config/__init__.py | 1606 + .../_pytest/config/argparsing.py | 522 + .../_pytest/config/exceptions.py | 11 + .../site-packages/_pytest/config/findpaths.py | 211 + .../site-packages/_pytest/debugging.py | 388 + .../site-packages/_pytest/deprecated.py | 87 + .../site-packages/_pytest/doctest.py | 724 + .../site-packages/_pytest/faulthandler.py | 116 + .../site-packages/_pytest/fixtures.py | 1680 + .../site-packages/_pytest/freeze_support.py | 45 + .../site-packages/_pytest/helpconfig.py | 261 + .../site-packages/_pytest/hookspec.py | 891 + .../site-packages/_pytest/junitxml.py | 700 + .../site-packages/_pytest/logging.py | 821 + .../python3.9/site-packages/_pytest/main.py | 876 + .../site-packages/_pytest/mark/__init__.py | 282 + .../site-packages/_pytest/mark/expression.py | 221 + .../site-packages/_pytest/mark/structures.py | 559 + .../site-packages/_pytest/monkeypatch.py | 379 + .../python3.9/site-packages/_pytest/nodes.py | 591 + .../python3.9/site-packages/_pytest/nose.py | 39 + .../site-packages/_pytest/outcomes.py | 227 + .../site-packages/_pytest/pastebin.py | 110 + .../site-packages/_pytest/pathlib.py | 654 + .../python3.9/site-packages/_pytest/py.typed | 0 .../site-packages/_pytest/pytester.py | 1922 + .../_pytest/pytester_assertions.py | 66 + .../python3.9/site-packages/_pytest/python.py | 1689 + .../site-packages/_pytest/python_api.py | 786 + .../site-packages/_pytest/recwarn.py | 296 + .../site-packages/_pytest/reports.py | 572 + .../python3.9/site-packages/_pytest/runner.py | 462 + .../site-packages/_pytest/setuponly.py | 94 + .../site-packages/_pytest/setupplan.py | 40 + .../site-packages/_pytest/skipping.py | 324 + .../site-packages/_pytest/stepwise.py | 119 + .../python3.9/site-packages/_pytest/store.py | 125 + .../site-packages/_pytest/terminal.py | 1405 + .../site-packages/_pytest/threadexception.py | 90 + .../python3.9/site-packages/_pytest/timing.py | 12 + .../python3.9/site-packages/_pytest/tmpdir.py | 254 + .../site-packages/_pytest/unittest.py | 405 + .../_pytest/unraisableexception.py | 93 + .../site-packages/_pytest/warning_types.py | 132 + .../site-packages/_pytest/warnings.py | 139 + .../python3.9/site-packages/_yaml/__init__.py | 33 + .../site-packages/aaaaa_future_fstrings.pth | 2 + .../anyio-3.6.1.dist-info/INSTALLER | 1 + .../anyio-3.6.1.dist-info/LICENSE | 20 + .../anyio-3.6.1.dist-info/METADATA | 102 + .../anyio-3.6.1.dist-info/RECORD | 45 + .../site-packages/anyio-3.6.1.dist-info/WHEEL | 5 + .../anyio-3.6.1.dist-info/entry_points.txt | 2 + .../anyio-3.6.1.dist-info/top_level.txt | 1 + .../python3.9/site-packages/anyio/__init__.py | 167 + .../site-packages/anyio/_backends/__init__.py | 0 .../site-packages/anyio/_backends/_asyncio.py | 2181 + .../site-packages/anyio/_backends/_trio.py | 988 + .../site-packages/anyio/_core/__init__.py | 0 .../site-packages/anyio/_core/_compat.py | 218 + .../site-packages/anyio/_core/_eventloop.py | 155 + .../site-packages/anyio/_core/_exceptions.py | 93 + .../site-packages/anyio/_core/_fileio.py | 607 + .../site-packages/anyio/_core/_resources.py | 16 + .../site-packages/anyio/_core/_signals.py | 24 + .../site-packages/anyio/_core/_sockets.py | 587 + .../site-packages/anyio/_core/_streams.py | 45 + .../anyio/_core/_subprocesses.py | 136 + .../anyio/_core/_synchronization.py | 595 + .../site-packages/anyio/_core/_tasks.py | 178 + .../site-packages/anyio/_core/_testing.py | 80 + .../site-packages/anyio/_core/_typedattr.py | 81 + .../site-packages/anyio/abc/__init__.py | 88 + .../site-packages/anyio/abc/_resources.py | 29 + .../site-packages/anyio/abc/_sockets.py | 183 + .../site-packages/anyio/abc/_streams.py | 198 + .../site-packages/anyio/abc/_subprocesses.py | 78 + .../site-packages/anyio/abc/_tasks.py | 104 + .../site-packages/anyio/abc/_testing.py | 68 + .../site-packages/anyio/from_thread.py | 502 + .../python3.9/site-packages/anyio/lowlevel.py | 170 + .../python3.9/site-packages/anyio/py.typed | 0 .../site-packages/anyio/pytest_plugin.py | 144 + .../site-packages/anyio/streams/__init__.py | 0 .../site-packages/anyio/streams/buffered.py | 116 + .../site-packages/anyio/streams/file.py | 145 + .../site-packages/anyio/streams/memory.py | 275 + .../site-packages/anyio/streams/stapled.py | 138 + .../site-packages/anyio/streams/text.py | 141 + .../site-packages/anyio/streams/tls.py | 317 + .../site-packages/anyio/to_process.py | 247 + .../site-packages/anyio/to_thread.py | 65 + .../asgiref-3.5.2.dist-info/INSTALLER | 1 + .../asgiref-3.5.2.dist-info/LICENSE | 27 + .../asgiref-3.5.2.dist-info/METADATA | 245 + .../asgiref-3.5.2.dist-info/RECORD | 17 + .../asgiref-3.5.2.dist-info/WHEEL | 5 + .../asgiref-3.5.2.dist-info/top_level.txt | 1 + .../site-packages/asgiref/__init__.py | 1 + .../site-packages/asgiref/compatibility.py | 47 + .../asgiref/current_thread_executor.py | 81 + .../python3.9/site-packages/asgiref/local.py | 120 + .../python3.9/site-packages/asgiref/py.typed | 0 .../python3.9/site-packages/asgiref/server.py | 157 + .../python3.9/site-packages/asgiref/sync.py | 532 + .../site-packages/asgiref/testing.py | 97 + .../site-packages/asgiref/timeout.py | 112 + .../python3.9/site-packages/asgiref/typing.py | 242 + .../python3.9/site-packages/asgiref/wsgi.py | 162 + .../astroid-2.11.7.dist-info/CONTRIBUTORS.txt | 175 + .../astroid-2.11.7.dist-info/INSTALLER | 1 + .../astroid-2.11.7.dist-info/LICENSE | 508 + .../astroid-2.11.7.dist-info/METADATA | 129 + .../astroid-2.11.7.dist-info/RECORD | 101 + .../astroid-2.11.7.dist-info/WHEEL | 5 + .../astroid-2.11.7.dist-info/top_level.txt | 1 + .../site-packages/astroid/__init__.py | 200 + .../site-packages/astroid/__pkginfo__.py | 6 + .../python3.9/site-packages/astroid/_ast.py | 130 + .../site-packages/astroid/arguments.py | 306 + .../site-packages/astroid/astroid_manager.py | 15 + .../python3.9/site-packages/astroid/bases.py | 577 + .../site-packages/astroid/brain/__init__.py | 0 .../astroid/brain/brain_argparse.py | 41 + .../astroid/brain/brain_attrs.py | 84 + .../astroid/brain/brain_boto3.py | 30 + .../astroid/brain/brain_builtin_inference.py | 922 + .../astroid/brain/brain_collections.py | 123 + .../astroid/brain/brain_crypt.py | 28 + .../astroid/brain/brain_ctypes.py | 82 + .../astroid/brain/brain_curses.py | 183 + .../astroid/brain/brain_dataclasses.py | 467 + .../astroid/brain/brain_dateutil.py | 26 + .../astroid/brain/brain_fstrings.py | 48 + .../astroid/brain/brain_functools.py | 159 + .../site-packages/astroid/brain/brain_gi.py | 250 + .../astroid/brain/brain_hashlib.py | 58 + .../site-packages/astroid/brain/brain_http.py | 211 + .../astroid/brain/brain_hypothesis.py | 55 + .../site-packages/astroid/brain/brain_io.py | 41 + .../astroid/brain/brain_mechanize.py | 83 + .../astroid/brain/brain_multiprocessing.py | 106 + .../astroid/brain/brain_namedtuple_enum.py | 574 + .../site-packages/astroid/brain/brain_nose.py | 79 + .../brain/brain_numpy_core_fromnumeric.py | 22 + .../brain/brain_numpy_core_function_base.py | 29 + .../brain/brain_numpy_core_multiarray.py | 95 + .../astroid/brain/brain_numpy_core_numeric.py | 46 + .../brain/brain_numpy_core_numerictypes.py | 263 + .../astroid/brain/brain_numpy_core_umath.py | 154 + .../astroid/brain/brain_numpy_ma.py | 28 + .../astroid/brain/brain_numpy_ndarray.py | 159 + .../brain/brain_numpy_random_mtrand.py | 71 + .../astroid/brain/brain_numpy_utils.py | 85 + .../astroid/brain/brain_pkg_resources.py | 70 + .../astroid/brain/brain_pytest.py | 83 + .../site-packages/astroid/brain/brain_qt.py | 82 + .../astroid/brain/brain_random.py | 87 + .../site-packages/astroid/brain/brain_re.py | 90 + .../astroid/brain/brain_responses.py | 79 + .../astroid/brain/brain_scipy_signal.py | 88 + .../astroid/brain/brain_signal.py | 119 + .../site-packages/astroid/brain/brain_six.py | 239 + .../astroid/brain/brain_sqlalchemy.py | 39 + .../site-packages/astroid/brain/brain_ssl.py | 71 + .../astroid/brain/brain_subprocess.py | 131 + .../astroid/brain/brain_threading.py | 31 + .../site-packages/astroid/brain/brain_type.py | 69 + .../astroid/brain/brain_typing.py | 433 + .../astroid/brain/brain_unittest.py | 31 + .../site-packages/astroid/brain/brain_uuid.py | 18 + .../site-packages/astroid/brain/helpers.py | 17 + .../site-packages/astroid/builder.py | 464 + .../python3.9/site-packages/astroid/const.py | 32 + .../site-packages/astroid/context.py | 201 + .../site-packages/astroid/decorators.py | 273 + .../site-packages/astroid/exceptions.py | 292 + .../astroid/filter_statements.py | 239 + .../site-packages/astroid/helpers.py | 304 + .../site-packages/astroid/inference.py | 1081 + .../site-packages/astroid/inference_tip.py | 89 + .../astroid/interpreter/__init__.py | 0 .../astroid/interpreter/_import/__init__.py | 0 .../astroid/interpreter/_import/spec.py | 378 + .../astroid/interpreter/_import/util.py | 16 + .../astroid/interpreter/dunder_lookup.py | 66 + .../astroid/interpreter/objectmodel.py | 856 + .../site-packages/astroid/manager.py | 353 + .../python3.9/site-packages/astroid/mixins.py | 163 + .../site-packages/astroid/modutils.py | 626 + .../site-packages/astroid/node_classes.py | 97 + .../site-packages/astroid/nodes/__init__.py | 299 + .../site-packages/astroid/nodes/as_string.py | 650 + .../site-packages/astroid/nodes/const.py | 27 + .../astroid/nodes/node_classes.py | 5443 + .../site-packages/astroid/nodes/node_ng.py | 814 + .../astroid/nodes/scoped_nodes/__init__.py | 43 + .../astroid/nodes/scoped_nodes/mixin.py | 171 + .../nodes/scoped_nodes/scoped_nodes.py | 3122 + .../astroid/nodes/scoped_nodes/utils.py | 36 + .../site-packages/astroid/nodes/utils.py | 14 + .../site-packages/astroid/objects.py | 329 + .../site-packages/astroid/protocols.py | 894 + .../site-packages/astroid/raw_building.py | 508 + .../site-packages/astroid/rebuilder.py | 2119 + .../site-packages/astroid/scoped_nodes.py | 33 + .../site-packages/astroid/test_utils.py | 76 + .../site-packages/astroid/transforms.py | 88 + .../python3.9/site-packages/astroid/typing.py | 27 + .../python3.9/site-packages/astroid/util.py | 147 + .../python3.9/site-packages/attr/__init__.py | 80 + .../python3.9/site-packages/attr/__init__.pyi | 484 + .../lib/python3.9/site-packages/attr/_cmp.py | 154 + .../lib/python3.9/site-packages/attr/_cmp.pyi | 13 + .../python3.9/site-packages/attr/_compat.py | 261 + .../python3.9/site-packages/attr/_config.py | 33 + .../python3.9/site-packages/attr/_funcs.py | 422 + .../lib/python3.9/site-packages/attr/_make.py | 3173 + .../python3.9/site-packages/attr/_next_gen.py | 216 + .../site-packages/attr/_version_info.py | 87 + .../site-packages/attr/_version_info.pyi | 9 + .../site-packages/attr/converters.py | 155 + .../site-packages/attr/converters.pyi | 13 + .../site-packages/attr/exceptions.py | 94 + .../site-packages/attr/exceptions.pyi | 17 + .../python3.9/site-packages/attr/filters.py | 54 + .../python3.9/site-packages/attr/filters.pyi | 6 + .../lib/python3.9/site-packages/attr/py.typed | 0 .../python3.9/site-packages/attr/setters.py | 79 + .../python3.9/site-packages/attr/setters.pyi | 19 + .../site-packages/attr/validators.py | 561 + .../site-packages/attr/validators.pyi | 78 + .../attrs-21.4.0.dist-info/AUTHORS.rst | 11 + .../attrs-21.4.0.dist-info/INSTALLER | 1 + .../attrs-21.4.0.dist-info/LICENSE | 21 + .../attrs-21.4.0.dist-info/METADATA | 232 + .../attrs-21.4.0.dist-info/RECORD | 37 + .../attrs-21.4.0.dist-info/WHEEL | 6 + .../attrs-21.4.0.dist-info/top_level.txt | 2 + .../python3.9/site-packages/attrs/__init__.py | 70 + .../site-packages/attrs/__init__.pyi | 63 + .../site-packages/attrs/converters.py | 3 + .../site-packages/attrs/exceptions.py | 3 + .../python3.9/site-packages/attrs/filters.py | 3 + .../python3.9/site-packages/attrs/py.typed | 0 .../python3.9/site-packages/attrs/setters.py | 3 + .../site-packages/attrs/validators.py | 3 + .../bcrypt-3.2.2.dist-info/INSTALLER | 1 + .../bcrypt-3.2.2.dist-info/LICENSE | 201 + .../bcrypt-3.2.2.dist-info/METADATA | 272 + .../bcrypt-3.2.2.dist-info/RECORD | 11 + .../bcrypt-3.2.2.dist-info/WHEEL | 5 + .../bcrypt-3.2.2.dist-info/top_level.txt | 2 + .../site-packages/bcrypt/__about__.py | 41 + .../site-packages/bcrypt/__init__.py | 171 + .../site-packages/bcrypt/_bcrypt.abi3.so | Bin 0 -> 156671 bytes .../site-packages/bcrypt/_bcrypt.pyi | 4 + .../python3.9/site-packages/bcrypt/py.typed | 0 .../black-21.12b0.dist-info/AUTHORS.md | 185 + .../black-21.12b0.dist-info/INSTALLER | 1 + .../black-21.12b0.dist-info/LICENSE | 21 + .../black-21.12b0.dist-info/METADATA | 1112 + .../black-21.12b0.dist-info/RECORD | 54 + .../black-21.12b0.dist-info/WHEEL | 5 + .../black-21.12b0.dist-info/entry_points.txt | 5 + .../black-21.12b0.dist-info/top_level.txt | 5 + .../python3.9/site-packages/black/__init__.py | 1377 + .../python3.9/site-packages/black/__main__.py | 3 + .../python3.9/site-packages/black/brackets.py | 334 + .../python3.9/site-packages/black/cache.py | 83 + .../python3.9/site-packages/black/comments.py | 277 + .../site-packages/black/concurrency.py | 57 + .../python3.9/site-packages/black/const.py | 4 + .../python3.9/site-packages/black/debug.py | 48 + .../python3.9/site-packages/black/files.py | 261 + .../black/handle_ipynb_magics.py | 465 + .../python3.9/site-packages/black/linegen.py | 1025 + .../python3.9/site-packages/black/lines.py | 754 + .../lib/python3.9/site-packages/black/mode.py | 160 + .../python3.9/site-packages/black/nodes.py | 856 + .../python3.9/site-packages/black/numerics.py | 65 + .../python3.9/site-packages/black/output.py | 105 + .../python3.9/site-packages/black/parsing.py | 285 + .../python3.9/site-packages/black/py.typed | 0 .../python3.9/site-packages/black/report.py | 104 + .../python3.9/site-packages/black/rusty.py | 28 + .../python3.9/site-packages/black/strings.py | 234 + .../python3.9/site-packages/black/trans.py | 2064 + .../site-packages/black_primer/__init__.py | 0 .../site-packages/black_primer/cli.py | 195 + .../site-packages/black_primer/lib.py | 423 + .../site-packages/black_primer/primer.json | 188 + .../site-packages/blackd/__init__.py | 201 + .../site-packages/blackd/middlewares.py | 34 + .../site-packages/blib2to3/Grammar.txt | 251 + .../site-packages/blib2to3/PatternGrammar.txt | 28 + .../site-packages/blib2to3/__init__.py | 1 + .../site-packages/blib2to3/pgen2/__init__.py | 4 + .../site-packages/blib2to3/pgen2/conv.py | 256 + .../site-packages/blib2to3/pgen2/driver.py | 327 + .../site-packages/blib2to3/pgen2/grammar.py | 225 + .../site-packages/blib2to3/pgen2/literals.py | 68 + .../site-packages/blib2to3/pgen2/parse.py | 346 + .../site-packages/blib2to3/pgen2/pgen.py | 433 + .../site-packages/blib2to3/pgen2/token.py | 94 + .../site-packages/blib2to3/pgen2/tokenize.py | 688 + .../site-packages/blib2to3/pygram.py | 212 + .../site-packages/blib2to3/pytree.py | 980 + .../certifi-2022.6.15.dist-info/INSTALLER | 1 + .../certifi-2022.6.15.dist-info/LICENSE | 21 + .../certifi-2022.6.15.dist-info/METADATA | 81 + .../certifi-2022.6.15.dist-info/RECORD | 11 + .../certifi-2022.6.15.dist-info/WHEEL | 5 + .../certifi-2022.6.15.dist-info/top_level.txt | 1 + .../site-packages/certifi/__init__.py | 4 + .../site-packages/certifi/__main__.py | 12 + .../site-packages/certifi/cacert.pem | 4685 + .../python3.9/site-packages/certifi/core.py | 68 + .../python3.9/site-packages/certifi/py.typed | 0 .../cffi-1.15.1.dist-info/INSTALLER | 1 + .../cffi-1.15.1.dist-info/LICENSE | 26 + .../cffi-1.15.1.dist-info/METADATA | 34 + .../cffi-1.15.1.dist-info/RECORD | 28 + .../site-packages/cffi-1.15.1.dist-info/WHEEL | 5 + .../cffi-1.15.1.dist-info/entry_points.txt | 2 + .../cffi-1.15.1.dist-info/top_level.txt | 2 + .../python3.9/site-packages/cffi/__init__.py | 14 + .../site-packages/cffi/_cffi_errors.h | 149 + .../site-packages/cffi/_cffi_include.h | 385 + .../python3.9/site-packages/cffi/_embedding.h | 528 + myenv/lib/python3.9/site-packages/cffi/api.py | 965 + .../site-packages/cffi/backend_ctypes.py | 1121 + .../site-packages/cffi/cffi_opcode.py | 187 + .../site-packages/cffi/commontypes.py | 80 + .../python3.9/site-packages/cffi/cparser.py | 1006 + .../lib/python3.9/site-packages/cffi/error.py | 31 + .../site-packages/cffi/ffiplatform.py | 127 + .../lib/python3.9/site-packages/cffi/lock.py | 30 + .../lib/python3.9/site-packages/cffi/model.py | 617 + .../site-packages/cffi/parse_c_type.h | 181 + .../python3.9/site-packages/cffi/pkgconfig.py | 121 + .../site-packages/cffi/recompiler.py | 1581 + .../site-packages/cffi/setuptools_ext.py | 219 + .../site-packages/cffi/vengine_cpy.py | 1076 + .../site-packages/cffi/vengine_gen.py | 675 + .../python3.9/site-packages/cffi/verifier.py | 307 + .../click-8.1.3.dist-info/INSTALLER | 1 + .../click-8.1.3.dist-info/LICENSE.rst | 28 + .../click-8.1.3.dist-info/METADATA | 111 + .../click-8.1.3.dist-info/RECORD | 23 + .../site-packages/click-8.1.3.dist-info/WHEEL | 5 + .../click-8.1.3.dist-info/top_level.txt | 1 + .../python3.9/site-packages/click/__init__.py | 73 + .../python3.9/site-packages/click/_compat.py | 626 + .../site-packages/click/_termui_impl.py | 717 + .../site-packages/click/_textwrap.py | 49 + .../site-packages/click/_winconsole.py | 279 + .../lib/python3.9/site-packages/click/core.py | 2998 + .../site-packages/click/decorators.py | 497 + .../site-packages/click/exceptions.py | 287 + .../site-packages/click/formatting.py | 301 + .../python3.9/site-packages/click/globals.py | 68 + .../python3.9/site-packages/click/parser.py | 529 + .../python3.9/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 580 + .../python3.9/site-packages/click/termui.py | 787 + .../python3.9/site-packages/click/testing.py | 479 + .../python3.9/site-packages/click/types.py | 1073 + .../python3.9/site-packages/click/utils.py | 580 + .../colorama-0.4.5.dist-info/INSTALLER | 1 + .../colorama-0.4.5.dist-info/LICENSE.txt | 27 + .../colorama-0.4.5.dist-info/METADATA | 411 + .../colorama-0.4.5.dist-info/RECORD | 12 + .../colorama-0.4.5.dist-info/WHEEL | 6 + .../colorama-0.4.5.dist-info/top_level.txt | 1 + .../site-packages/colorama/__init__.py | 6 + .../python3.9/site-packages/colorama/ansi.py | 102 + .../site-packages/colorama/ansitowin32.py | 266 + .../site-packages/colorama/initialise.py | 80 + .../python3.9/site-packages/colorama/win32.py | 152 + .../site-packages/colorama/winterm.py | 169 + .../cryptography-37.0.4.dist-info/INSTALLER | 1 + .../cryptography-37.0.4.dist-info/LICENSE | 6 + .../LICENSE.APACHE | 202 + .../cryptography-37.0.4.dist-info/LICENSE.BSD | 27 + .../cryptography-37.0.4.dist-info/LICENSE.PSF | 41 + .../cryptography-37.0.4.dist-info/METADATA | 138 + .../cryptography-37.0.4.dist-info/RECORD | 99 + .../cryptography-37.0.4.dist-info/WHEEL | 5 + .../top_level.txt | 2 + .../site-packages/cryptography/__about__.py | 15 + .../site-packages/cryptography/__init__.py | 29 + .../site-packages/cryptography/exceptions.py | 68 + .../site-packages/cryptography/fernet.py | 212 + .../cryptography/hazmat/__init__.py | 10 + .../site-packages/cryptography/hazmat/_oid.py | 345 + .../cryptography/hazmat/backends/__init__.py | 10 + .../hazmat/backends/openssl/__init__.py | 9 + .../hazmat/backends/openssl/aead.py | 251 + .../hazmat/backends/openssl/backend.py | 2537 + .../hazmat/backends/openssl/ciphers.py | 282 + .../hazmat/backends/openssl/cmac.py | 87 + .../hazmat/backends/openssl/decode_asn1.py | 31 + .../hazmat/backends/openssl/dh.py | 318 + .../hazmat/backends/openssl/dsa.py | 239 + .../hazmat/backends/openssl/ec.py | 315 + .../hazmat/backends/openssl/ed25519.py | 155 + .../hazmat/backends/openssl/ed448.py | 156 + .../hazmat/backends/openssl/encode_asn1.py | 18 + .../hazmat/backends/openssl/hashes.py | 87 + .../hazmat/backends/openssl/hmac.py | 85 + .../hazmat/backends/openssl/poly1305.py | 68 + .../hazmat/backends/openssl/rsa.py | 567 + .../hazmat/backends/openssl/utils.py | 52 + .../hazmat/backends/openssl/x25519.py | 132 + .../hazmat/backends/openssl/x448.py | 117 + .../hazmat/backends/openssl/x509.py | 45 + .../cryptography/hazmat/bindings/__init__.py | 3 + .../hazmat/bindings/_openssl.abi3.so | Bin 0 -> 6023128 bytes .../hazmat/bindings/_rust.abi3.so | Bin 0 -> 2004592 bytes .../hazmat/bindings/_rust/__init__.pyi | 2 + .../hazmat/bindings/_rust/asn1.pyi | 12 + .../hazmat/bindings/_rust/ocsp.pyi | 22 + .../hazmat/bindings/_rust/x509.pyi | 36 + .../hazmat/bindings/openssl/__init__.py | 3 + .../hazmat/bindings/openssl/_conditional.py | 367 + .../hazmat/bindings/openssl/binding.py | 230 + .../hazmat/primitives/__init__.py | 3 + .../hazmat/primitives/_asymmetric.py | 17 + .../hazmat/primitives/_cipheralgorithm.py | 40 + .../hazmat/primitives/_serialization.py | 55 + .../hazmat/primitives/asymmetric/__init__.py | 3 + .../hazmat/primitives/asymmetric/dh.py | 250 + .../hazmat/primitives/asymmetric/dsa.py | 288 + .../hazmat/primitives/asymmetric/ec.py | 523 + .../hazmat/primitives/asymmetric/ed25519.py | 92 + .../hazmat/primitives/asymmetric/ed448.py | 87 + .../hazmat/primitives/asymmetric/padding.py | 101 + .../hazmat/primitives/asymmetric/rsa.py | 425 + .../hazmat/primitives/asymmetric/types.py | 69 + .../hazmat/primitives/asymmetric/utils.py | 24 + .../hazmat/primitives/asymmetric/x25519.py | 81 + .../hazmat/primitives/asymmetric/x448.py | 81 + .../hazmat/primitives/ciphers/__init__.py | 27 + .../hazmat/primitives/ciphers/aead.py | 361 + .../hazmat/primitives/ciphers/algorithms.py | 207 + .../hazmat/primitives/ciphers/base.py | 269 + .../hazmat/primitives/ciphers/modes.py | 263 + .../cryptography/hazmat/primitives/cmac.py | 66 + .../hazmat/primitives/constant_time.py | 13 + .../cryptography/hazmat/primitives/hashes.py | 259 + .../cryptography/hazmat/primitives/hmac.py | 72 + .../hazmat/primitives/kdf/__init__.py | 22 + .../hazmat/primitives/kdf/concatkdf.py | 130 + .../hazmat/primitives/kdf/hkdf.py | 103 + .../hazmat/primitives/kdf/kbkdf.py | 258 + .../hazmat/primitives/kdf/pbkdf2.py | 65 + .../hazmat/primitives/kdf/scrypt.py | 74 + .../hazmat/primitives/kdf/x963kdf.py | 65 + .../cryptography/hazmat/primitives/keywrap.py | 176 + .../cryptography/hazmat/primitives/padding.py | 224 + .../hazmat/primitives/poly1305.py | 60 + .../primitives/serialization/__init__.py | 45 + .../hazmat/primitives/serialization/base.py | 64 + .../hazmat/primitives/serialization/pkcs12.py | 219 + .../hazmat/primitives/serialization/pkcs7.py | 180 + .../hazmat/primitives/serialization/ssh.py | 757 + .../hazmat/primitives/twofactor/__init__.py | 7 + .../hazmat/primitives/twofactor/hotp.py | 92 + .../hazmat/primitives/twofactor/totp.py | 48 + .../site-packages/cryptography/py.typed | 0 .../site-packages/cryptography/utils.py | 180 + .../cryptography/x509/__init__.py | 249 + .../site-packages/cryptography/x509/base.py | 1090 + .../x509/certificate_transparency.py | 48 + .../cryptography/x509/extensions.py | 2103 + .../cryptography/x509/general_name.py | 284 + .../site-packages/cryptography/x509/name.py | 445 + .../site-packages/cryptography/x509/ocsp.py | 551 + .../site-packages/cryptography/x509/oid.py | 32 + .../dill-0.3.5.1.dist-info/INSTALLER | 1 + .../dill-0.3.5.1.dist-info/LICENSE | 35 + .../dill-0.3.5.1.dist-info/METADATA | 269 + .../dill-0.3.5.1.dist-info/RECORD | 44 + .../dill-0.3.5.1.dist-info/WHEEL | 6 + .../dill-0.3.5.1.dist-info/top_level.txt | 1 + .../python3.9/site-packages/dill/__diff.py | 240 + .../python3.9/site-packages/dill/__init__.py | 389 + .../lib/python3.9/site-packages/dill/_dill.py | 2107 + .../python3.9/site-packages/dill/_objects.py | 558 + .../python3.9/site-packages/dill/_shims.py | 266 + .../python3.9/site-packages/dill/detect.py | 327 + .../python3.9/site-packages/dill/objtypes.py | 24 + .../python3.9/site-packages/dill/pointers.py | 122 + .../python3.9/site-packages/dill/settings.py | 28 + .../python3.9/site-packages/dill/source.py | 1023 + .../lib/python3.9/site-packages/dill/temp.py | 263 + .../site-packages/dill/tests/__init__.py | 23 + .../site-packages/dill/tests/__main__.py | 30 + .../site-packages/dill/tests/test_check.py | 63 + .../site-packages/dill/tests/test_classdef.py | 265 + .../site-packages/dill/tests/test_detect.py | 159 + .../dill/tests/test_dictviews.py | 35 + .../site-packages/dill/tests/test_diff.py | 110 + .../dill/tests/test_extendpickle.py | 56 + .../site-packages/dill/tests/test_fglobals.py | 55 + .../site-packages/dill/tests/test_file.py | 502 + .../dill/tests/test_functions.py | 106 + .../site-packages/dill/tests/test_functors.py | 39 + .../site-packages/dill/tests/test_mixins.py | 121 + .../site-packages/dill/tests/test_module.py | 85 + .../dill/tests/test_moduledict.py | 54 + .../site-packages/dill/tests/test_nested.py | 135 + .../site-packages/dill/tests/test_objects.py | 62 + .../dill/tests/test_properties.py | 62 + .../dill/tests/test_recursive.py | 179 + .../dill/tests/test_restricted.py | 27 + .../site-packages/dill/tests/test_selected.py | 99 + .../site-packages/dill/tests/test_session.py | 243 + .../site-packages/dill/tests/test_source.py | 163 + .../site-packages/dill/tests/test_temp.py | 103 + .../site-packages/dill/tests/test_weakref.py | 89 + .../site-packages/dotenv/__init__.py | 49 + .../lib/python3.9/site-packages/dotenv/cli.py | 164 + .../python3.9/site-packages/dotenv/ipython.py | 39 + .../python3.9/site-packages/dotenv/main.py | 373 + .../python3.9/site-packages/dotenv/parser.py | 182 + .../python3.9/site-packages/dotenv/py.typed | 1 + .../site-packages/dotenv/variables.py | 88 + .../python3.9/site-packages/dotenv/version.py | 1 + .../python3.9/site-packages/easy_install.py | 5 + .../ecdsa-0.18.0.dist-info/INSTALLER | 1 + .../ecdsa-0.18.0.dist-info/LICENSE | 24 + .../ecdsa-0.18.0.dist-info/METADATA | 675 + .../ecdsa-0.18.0.dist-info/RECORD | 35 + .../ecdsa-0.18.0.dist-info/WHEEL | 6 + .../ecdsa-0.18.0.dist-info/top_level.txt | 1 + .../python3.9/site-packages/ecdsa/__init__.py | 90 + .../python3.9/site-packages/ecdsa/_compat.py | 153 + .../python3.9/site-packages/ecdsa/_rwlock.py | 86 + .../python3.9/site-packages/ecdsa/_sha3.py | 181 + .../python3.9/site-packages/ecdsa/_version.py | 21 + .../python3.9/site-packages/ecdsa/curves.py | 513 + .../lib/python3.9/site-packages/ecdsa/der.py | 409 + .../lib/python3.9/site-packages/ecdsa/ecdh.py | 336 + .../python3.9/site-packages/ecdsa/ecdsa.py | 859 + .../python3.9/site-packages/ecdsa/eddsa.py | 252 + .../site-packages/ecdsa/ellipticcurve.py | 1584 + .../python3.9/site-packages/ecdsa/errors.py | 4 + .../lib/python3.9/site-packages/ecdsa/keys.py | 1612 + .../site-packages/ecdsa/numbertheory.py | 825 + .../python3.9/site-packages/ecdsa/rfc6979.py | 113 + .../site-packages/ecdsa/test_curves.py | 361 + .../python3.9/site-packages/ecdsa/test_der.py | 476 + .../site-packages/ecdsa/test_ecdh.py | 441 + .../site-packages/ecdsa/test_ecdsa.py | 661 + .../site-packages/ecdsa/test_eddsa.py | 1079 + .../site-packages/ecdsa/test_ellipticcurve.py | 199 + .../site-packages/ecdsa/test_jacobi.py | 657 + .../site-packages/ecdsa/test_keys.py | 959 + .../ecdsa/test_malformed_sigs.py | 370 + .../site-packages/ecdsa/test_numbertheory.py | 433 + .../site-packages/ecdsa/test_pyecdsa.py | 2267 + .../site-packages/ecdsa/test_rw_lock.py | 180 + .../site-packages/ecdsa/test_sha3.py | 111 + .../lib/python3.9/site-packages/ecdsa/util.py | 433 + .../fastapi-0.70.1.dist-info/INSTALLER | 1 + .../fastapi-0.70.1.dist-info/LICENSE | 21 + .../fastapi-0.70.1.dist-info/METADATA | 545 + .../fastapi-0.70.1.dist-info/RECORD | 47 + .../fastapi-0.70.1.dist-info/WHEEL | 4 + .../site-packages/fastapi/__init__.py | 24 + .../site-packages/fastapi/applications.py | 768 + .../site-packages/fastapi/background.py | 1 + .../site-packages/fastapi/concurrency.py | 32 + .../site-packages/fastapi/datastructures.py | 52 + .../fastapi/dependencies/__init__.py | 0 .../fastapi/dependencies/models.py | 58 + .../fastapi/dependencies/utils.py | 769 + .../site-packages/fastapi/encoders.py | 153 + .../fastapi/exception_handlers.py | 25 + .../site-packages/fastapi/exceptions.py | 37 + .../python3.9/site-packages/fastapi/logger.py | 3 + .../fastapi/middleware/__init__.py | 1 + .../site-packages/fastapi/middleware/cors.py | 1 + .../site-packages/fastapi/middleware/gzip.py | 1 + .../fastapi/middleware/httpsredirect.py | 3 + .../fastapi/middleware/trustedhost.py | 3 + .../site-packages/fastapi/middleware/wsgi.py | 1 + .../site-packages/fastapi/openapi/__init__.py | 0 .../fastapi/openapi/constants.py | 3 + .../site-packages/fastapi/openapi/docs.py | 177 + .../site-packages/fastapi/openapi/models.py | 406 + .../site-packages/fastapi/openapi/utils.py | 410 + .../site-packages/fastapi/param_functions.py | 282 + .../python3.9/site-packages/fastapi/params.py | 370 + .../python3.9/site-packages/fastapi/py.typed | 0 .../site-packages/fastapi/requests.py | 2 + .../site-packages/fastapi/responses.py | 34 + .../site-packages/fastapi/routing.py | 1150 + .../fastapi/security/__init__.py | 15 + .../site-packages/fastapi/security/api_key.py | 92 + .../site-packages/fastapi/security/base.py | 6 + .../site-packages/fastapi/security/http.py | 165 + .../site-packages/fastapi/security/oauth2.py | 220 + .../fastapi/security/open_id_connect_url.py | 34 + .../site-packages/fastapi/security/utils.py | 8 + .../site-packages/fastapi/staticfiles.py | 1 + .../site-packages/fastapi/templating.py | 1 + .../site-packages/fastapi/testclient.py | 1 + .../python3.9/site-packages/fastapi/types.py | 3 + .../python3.9/site-packages/fastapi/utils.py | 156 + .../site-packages/fastapi/websockets.py | 2 + .../future_fstrings-1.2.0.dist-info/INSTALLER | 1 + .../future_fstrings-1.2.0.dist-info/LICENSE | 19 + .../future_fstrings-1.2.0.dist-info/METADATA | 110 + .../future_fstrings-1.2.0.dist-info/RECORD | 10 + .../future_fstrings-1.2.0.dist-info/WHEEL | 6 + .../entry_points.txt | 3 + .../top_level.txt | 1 + .../site-packages/future_fstrings.py | 297 + .../h11-0.12.0.dist-info/INSTALLER | 1 + .../h11-0.12.0.dist-info/LICENSE.txt | 22 + .../h11-0.12.0.dist-info/METADATA | 194 + .../site-packages/h11-0.12.0.dist-info/RECORD | 29 + .../site-packages/h11-0.12.0.dist-info/WHEEL | 5 + .../h11-0.12.0.dist-info/top_level.txt | 1 + .../python3.9/site-packages/h11/__init__.py | 21 + .../lib/python3.9/site-packages/h11/_abnf.py | 129 + .../site-packages/h11/_connection.py | 585 + .../python3.9/site-packages/h11/_events.py | 302 + .../python3.9/site-packages/h11/_headers.py | 242 + .../python3.9/site-packages/h11/_readers.py | 222 + .../site-packages/h11/_receivebuffer.py | 152 + .../lib/python3.9/site-packages/h11/_state.py | 307 + .../lib/python3.9/site-packages/h11/_util.py | 122 + .../python3.9/site-packages/h11/_version.py | 16 + .../python3.9/site-packages/h11/_writers.py | 123 + .../site-packages/h11/tests/__init__.py | 0 .../site-packages/h11/tests/data/test-file | 1 + .../site-packages/h11/tests/helpers.py | 77 + .../h11/tests/test_against_stdlib_http.py | 111 + .../h11/tests/test_connection.py | 1078 + .../site-packages/h11/tests/test_events.py | 179 + .../site-packages/h11/tests/test_headers.py | 151 + .../site-packages/h11/tests/test_helpers.py | 23 + .../site-packages/h11/tests/test_io.py | 544 + .../h11/tests/test_receivebuffer.py | 134 + .../site-packages/h11/tests/test_state.py | 250 + .../site-packages/h11/tests/test_util.py | 99 + .../httpcore-0.15.0.dist-info/INSTALLER | 1 + .../httpcore-0.15.0.dist-info/LICENSE.md | 27 + .../httpcore-0.15.0.dist-info/METADATA | 489 + .../httpcore-0.15.0.dist-info/RECORD | 38 + .../httpcore-0.15.0.dist-info/WHEEL | 5 + .../httpcore-0.15.0.dist-info/top_level.txt | 4 + .../site-packages/httpcore/__init__.py | 91 + .../python3.9/site-packages/httpcore/_api.py | 92 + .../site-packages/httpcore/_async/__init__.py | 39 + .../httpcore/_async/connection.py | 208 + .../httpcore/_async/connection_pool.py | 354 + .../site-packages/httpcore/_async/http11.py | 306 + .../site-packages/httpcore/_async/http2.py | 475 + .../httpcore/_async/http_proxy.py | 337 + .../httpcore/_async/interfaces.py | 133 + .../httpcore/_async/socks_proxy.py | 336 + .../site-packages/httpcore/_exceptions.py | 79 + .../site-packages/httpcore/_models.py | 474 + .../python3.9/site-packages/httpcore/_ssl.py | 9 + .../site-packages/httpcore/_sync/__init__.py | 39 + .../httpcore/_sync/connection.py | 208 + .../httpcore/_sync/connection_pool.py | 354 + .../site-packages/httpcore/_sync/http11.py | 306 + .../site-packages/httpcore/_sync/http2.py | 475 + .../httpcore/_sync/http_proxy.py | 337 + .../httpcore/_sync/interfaces.py | 133 + .../httpcore/_sync/socks_proxy.py | 336 + .../httpcore/_synchronization.py | 89 + .../site-packages/httpcore/_trace.py | 54 + .../site-packages/httpcore/_utils.py | 36 + .../httpcore/backends/__init__.py | 0 .../httpcore/backends/asyncio.py | 130 + .../site-packages/httpcore/backends/auto.py | 41 + .../site-packages/httpcore/backends/base.py | 89 + .../site-packages/httpcore/backends/mock.py | 115 + .../site-packages/httpcore/backends/sync.py | 99 + .../site-packages/httpcore/backends/trio.py | 142 + .../python3.9/site-packages/httpcore/py.typed | 0 .../httptools-0.3.0.dist-info/INSTALLER | 1 + .../httptools-0.3.0.dist-info/LICENSE | 21 + .../httptools-0.3.0.dist-info/METADATA | 135 + .../httptools-0.3.0.dist-info/RECORD | 14 + .../httptools-0.3.0.dist-info/WHEEL | 5 + .../httptools-0.3.0.dist-info/top_level.txt | 1 + .../site-packages/httptools/__init__.py | 6 + .../site-packages/httptools/_version.py | 13 + .../httptools/parser/__init__.py | 5 + .../site-packages/httptools/parser/errors.py | 30 + .../site-packages/httptools/parser/parser.c | 10319 + .../parser/parser.cpython-39-darwin.so | Bin 0 -> 148944 bytes .../httptools/parser/url_parser.c | 5935 + .../parser/url_parser.cpython-39-darwin.so | Bin 0 -> 89080 bytes .../httpx-0.23.0.dist-info/INSTALLER | 1 + .../httpx-0.23.0.dist-info/LICENSE.md | 12 + .../httpx-0.23.0.dist-info/METADATA | 1145 + .../httpx-0.23.0.dist-info/RECORD | 32 + .../httpx-0.23.0.dist-info/WHEEL | 5 + .../httpx-0.23.0.dist-info/entry_points.txt | 3 + .../httpx-0.23.0.dist-info/top_level.txt | 2 + .../python3.9/site-packages/httpx/__init__.py | 137 + .../site-packages/httpx/__version__.py | 3 + .../lib/python3.9/site-packages/httpx/_api.py | 445 + .../python3.9/site-packages/httpx/_auth.py | 304 + .../python3.9/site-packages/httpx/_client.py | 2000 + .../python3.9/site-packages/httpx/_compat.py | 40 + .../python3.9/site-packages/httpx/_config.py | 363 + .../python3.9/site-packages/httpx/_content.py | 238 + .../site-packages/httpx/_decoders.py | 333 + .../site-packages/httpx/_exceptions.py | 343 + .../python3.9/site-packages/httpx/_main.py | 497 + .../python3.9/site-packages/httpx/_models.py | 1196 + .../site-packages/httpx/_multipart.py | 236 + .../site-packages/httpx/_status_codes.py | 158 + .../httpx/_transports/__init__.py | 0 .../site-packages/httpx/_transports/asgi.py | 163 + .../site-packages/httpx/_transports/base.py | 82 + .../httpx/_transports/default.py | 365 + .../site-packages/httpx/_transports/mock.py | 34 + .../site-packages/httpx/_transports/wsgi.py | 134 + .../python3.9/site-packages/httpx/_types.py | 151 + .../python3.9/site-packages/httpx/_urls.py | 779 + .../python3.9/site-packages/httpx/_utils.py | 522 + .../python3.9/site-packages/httpx/py.typed | 0 .../idna-3.3.dist-info/INSTALLER | 1 + .../idna-3.3.dist-info/LICENSE.md | 29 + .../site-packages/idna-3.3.dist-info/METADATA | 236 + .../site-packages/idna-3.3.dist-info/RECORD | 15 + .../site-packages/idna-3.3.dist-info/WHEEL | 5 + .../idna-3.3.dist-info/top_level.txt | 1 + .../python3.9/site-packages/idna/__init__.py | 44 + .../lib/python3.9/site-packages/idna/codec.py | 112 + .../python3.9/site-packages/idna/compat.py | 13 + .../lib/python3.9/site-packages/idna/core.py | 397 + .../python3.9/site-packages/idna/idnadata.py | 2137 + .../python3.9/site-packages/idna/intranges.py | 54 + .../site-packages/idna/package_data.py | 2 + .../lib/python3.9/site-packages/idna/py.typed | 0 .../python3.9/site-packages/idna/uts46data.py | 8512 + .../iniconfig-1.1.1.dist-info/INSTALLER | 1 + .../iniconfig-1.1.1.dist-info/LICENSE | 19 + .../iniconfig-1.1.1.dist-info/METADATA | 78 + .../iniconfig-1.1.1.dist-info/RECORD | 9 + .../iniconfig-1.1.1.dist-info/WHEEL | 6 + .../iniconfig-1.1.1.dist-info/top_level.txt | 1 + .../site-packages/iniconfig/__init__.py | 165 + .../site-packages/iniconfig/__init__.pyi | 31 + .../site-packages/iniconfig/py.typed | 0 .../isort-5.10.1.dist-info/INSTALLER | 1 + .../isort-5.10.1.dist-info/LICENSE | 21 + .../isort-5.10.1.dist-info/METADATA | 397 + .../isort-5.10.1.dist-info/RECORD | 56 + .../isort-5.10.1.dist-info/WHEEL | 4 + .../isort-5.10.1.dist-info/entry_points.txt | 10 + .../python3.9/site-packages/isort/__init__.py | 38 + .../python3.9/site-packages/isort/__main__.py | 3 + .../site-packages/isort/_future/__init__.py | 12 + .../isort/_future/_dataclasses.py | 1209 + .../isort/_vendored/tomli/LICENSE | 21 + .../isort/_vendored/tomli/__init__.py | 6 + .../isort/_vendored/tomli/_parser.py | 650 + .../isort/_vendored/tomli/_re.py | 100 + .../isort/_vendored/tomli/py.typed | 1 + .../python3.9/site-packages/isort/_version.py | 1 + .../lib/python3.9/site-packages/isort/api.py | 651 + .../python3.9/site-packages/isort/comments.py | 32 + .../lib/python3.9/site-packages/isort/core.py | 476 + .../isort/deprecated/__init__.py | 0 .../site-packages/isort/deprecated/finders.py | 415 + .../site-packages/isort/exceptions.py | 197 + .../python3.9/site-packages/isort/files.py | 41 + .../python3.9/site-packages/isort/format.py | 156 + .../python3.9/site-packages/isort/hooks.py | 86 + .../python3.9/site-packages/isort/identify.py | 206 + myenv/lib/python3.9/site-packages/isort/io.py | 73 + .../python3.9/site-packages/isort/literal.py | 113 + .../lib/python3.9/site-packages/isort/logo.py | 19 + .../lib/python3.9/site-packages/isort/main.py | 1285 + .../python3.9/site-packages/isort/output.py | 655 + .../python3.9/site-packages/isort/parse.py | 590 + .../python3.9/site-packages/isort/place.py | 145 + .../python3.9/site-packages/isort/profiles.py | 86 + .../python3.9/site-packages/isort/py.typed | 0 .../site-packages/isort/pylama_isort.py | 45 + .../python3.9/site-packages/isort/sections.py | 9 + .../python3.9/site-packages/isort/settings.py | 925 + .../isort/setuptools_commands.py | 61 + .../python3.9/site-packages/isort/sorting.py | 130 + .../site-packages/isort/stdlibs/__init__.py | 2 + .../site-packages/isort/stdlibs/all.py | 3 + .../site-packages/isort/stdlibs/py2.py | 3 + .../site-packages/isort/stdlibs/py27.py | 301 + .../site-packages/isort/stdlibs/py3.py | 3 + .../site-packages/isort/stdlibs/py310.py | 221 + .../site-packages/isort/stdlibs/py35.py | 223 + .../site-packages/isort/stdlibs/py36.py | 224 + .../site-packages/isort/stdlibs/py37.py | 225 + .../site-packages/isort/stdlibs/py38.py | 224 + .../site-packages/isort/stdlibs/py39.py | 224 + .../python3.9/site-packages/isort/utils.py | 72 + .../lib/python3.9/site-packages/isort/wrap.py | 139 + .../site-packages/isort/wrap_modes.py | 376 + .../python3.9/site-packages/jose/__init__.py | 10 + .../site-packages/jose/backends/__init__.py | 32 + .../site-packages/jose/backends/_asn1.py | 83 + .../site-packages/jose/backends/base.py | 89 + .../jose/backends/cryptography_backend.py | 605 + .../jose/backends/ecdsa_backend.py | 150 + .../site-packages/jose/backends/native.py | 76 + .../jose/backends/rsa_backend.py | 284 + .../python3.9/site-packages/jose/constants.py | 98 + .../site-packages/jose/exceptions.py | 59 + myenv/lib/python3.9/site-packages/jose/jwe.py | 607 + myenv/lib/python3.9/site-packages/jose/jwk.py | 79 + myenv/lib/python3.9/site-packages/jose/jws.py | 266 + myenv/lib/python3.9/site-packages/jose/jwt.py | 496 + .../lib/python3.9/site-packages/jose/utils.py | 108 + .../AUTHORS.rst | 10 + .../INSTALLER | 1 + .../lazy_object_proxy-1.7.1.dist-info/LICENSE | 21 + .../METADATA | 219 + .../lazy_object_proxy-1.7.1.dist-info/RECORD | 15 + .../lazy_object_proxy-1.7.1.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../lazy_object_proxy/__init__.py | 23 + .../lazy_object_proxy/_version.py | 5 + .../cext.cpython-39-darwin.so | Bin 0 -> 65584 bytes .../site-packages/lazy_object_proxy/compat.py | 14 + .../site-packages/lazy_object_proxy/simple.py | 278 + .../site-packages/lazy_object_proxy/slots.py | 452 + .../site-packages/lazy_object_proxy/utils.py | 25 + .../lazy_object_proxy/utils_py3.py | 44 + .../mccabe-0.7.0.dist-info/INSTALLER | 1 + .../mccabe-0.7.0.dist-info/LICENSE | 25 + .../mccabe-0.7.0.dist-info/METADATA | 199 + .../mccabe-0.7.0.dist-info/RECORD | 8 + .../mccabe-0.7.0.dist-info/WHEEL | 6 + .../mccabe-0.7.0.dist-info/entry_points.txt | 3 + .../mccabe-0.7.0.dist-info/top_level.txt | 1 + myenv/lib/python3.9/site-packages/mccabe.py | 346 + .../site-packages/multipart/__init__.py | 19 + .../site-packages/multipart/_version.py | 1 + .../site-packages/multipart/decoders.py | 171 + .../site-packages/multipart/exceptions.py | 58 + .../site-packages/multipart/multipart.py | 1911 + .../site-packages/multipart/tests/__init__.py | 0 .../site-packages/multipart/tests/compat.py | 138 + .../multipart/tests/test_multipart.py | 1306 + .../mypy_extensions-0.4.3.dist-info/INSTALLER | 1 + .../mypy_extensions-0.4.3.dist-info/LICENSE | 27 + .../mypy_extensions-0.4.3.dist-info/METADATA | 31 + .../mypy_extensions-0.4.3.dist-info/RECORD | 7 + .../mypy_extensions-0.4.3.dist-info/WHEEL | 6 + .../top_level.txt | 1 + .../site-packages/mypy_extensions.py | 166 + .../networkx-2.8.5.dist-info/INSTALLER | 1 + .../networkx-2.8.5.dist-info/LICENSE.txt | 37 + .../networkx-2.8.5.dist-info/METADATA | 131 + .../networkx-2.8.5.dist-info/RECORD | 644 + .../networkx-2.8.5.dist-info/WHEEL | 5 + .../networkx-2.8.5.dist-info/top_level.txt | 1 + .../site-packages/networkx/__init__.py | 90 + .../networkx/algorithms/__init__.py | 129 + .../algorithms/approximation/__init__.py | 24 + .../algorithms/approximation/clique.py | 233 + .../approximation/clustering_coefficient.py | 64 + .../algorithms/approximation/connectivity.py | 401 + .../approximation/distance_measures.py | 140 + .../approximation/dominating_set.py | 123 + .../algorithms/approximation/kcomponents.py | 368 + .../algorithms/approximation/matching.py | 42 + .../algorithms/approximation/maxcut.py | 111 + .../algorithms/approximation/ramsey.py | 51 + .../algorithms/approximation/steinertree.py | 104 + .../approximation/tests/__init__.py | 0 .../tests/test_approx_clust_coeff.py | 41 + .../approximation/tests/test_clique.py | 113 + .../approximation/tests/test_connectivity.py | 199 + .../tests/test_distance_measures.py | 60 + .../tests/test_dominating_set.py | 67 + .../approximation/tests/test_kcomponents.py | 301 + .../approximation/tests/test_matching.py | 8 + .../approximation/tests/test_maxcut.py | 82 + .../approximation/tests/test_ramsey.py | 31 + .../approximation/tests/test_steinertree.py | 83 + .../tests/test_traveling_salesman.py | 963 + .../approximation/tests/test_treewidth.py | 274 + .../approximation/tests/test_vertex_cover.py | 68 + .../approximation/traveling_salesman.py | 1434 + .../algorithms/approximation/treewidth.py | 249 + .../algorithms/approximation/vertex_cover.py | 80 + .../algorithms/assortativity/__init__.py | 5 + .../algorithms/assortativity/connectivity.py | 139 + .../algorithms/assortativity/correlation.py | 298 + .../algorithms/assortativity/mixing.py | 298 + .../assortativity/neighbor_degree.py | 159 + .../algorithms/assortativity/pairs.py | 114 + .../assortativity/tests/__init__.py | 0 .../assortativity/tests/base_test.py | 85 + .../assortativity/tests/test_connectivity.py | 145 + .../assortativity/tests/test_correlation.py | 114 + .../assortativity/tests/test_mixing.py | 182 + .../tests/test_neighbor_degree.py | 104 + .../assortativity/tests/test_pairs.py | 87 + .../networkx/algorithms/asteroidal.py | 167 + .../networkx/algorithms/bipartite/__init__.py | 86 + .../networkx/algorithms/bipartite/basic.py | 315 + .../algorithms/bipartite/centrality.py | 266 + .../networkx/algorithms/bipartite/cluster.py | 277 + .../networkx/algorithms/bipartite/covering.py | 55 + .../networkx/algorithms/bipartite/edgelist.py | 357 + .../algorithms/bipartite/generators.py | 595 + .../networkx/algorithms/bipartite/matching.py | 579 + .../networkx/algorithms/bipartite/matrix.py | 174 + .../algorithms/bipartite/projection.py | 538 + .../algorithms/bipartite/redundancy.py | 111 + .../networkx/algorithms/bipartite/spectral.py | 68 + .../algorithms/bipartite/tests/__init__.py | 0 .../algorithms/bipartite/tests/test_basic.py | 125 + .../bipartite/tests/test_centrality.py | 176 + .../bipartite/tests/test_cluster.py | 84 + .../bipartite/tests/test_covering.py | 33 + .../bipartite/tests/test_edgelist.py | 192 + .../bipartite/tests/test_generators.py | 400 + .../bipartite/tests/test_matching.py | 326 + .../algorithms/bipartite/tests/test_matrix.py | 79 + .../bipartite/tests/test_project.py | 398 + .../bipartite/tests/test_redundancy.py | 31 + .../tests/test_spectral_bipartivity.py | 81 + .../networkx/algorithms/boundary.py | 135 + .../networkx/algorithms/bridges.py | 199 + .../algorithms/centrality/__init__.py | 19 + .../algorithms/centrality/betweenness.py | 436 + .../centrality/betweenness_subset.py | 282 + .../algorithms/centrality/closeness.py | 279 + .../centrality/current_flow_betweenness.py | 340 + .../current_flow_betweenness_subset.py | 224 + .../centrality/current_flow_closeness.py | 96 + .../algorithms/centrality/degree_alg.py | 127 + .../algorithms/centrality/dispersion.py | 97 + .../algorithms/centrality/eigenvector.py | 229 + .../algorithms/centrality/flow_matrix.py | 131 + .../networkx/algorithms/centrality/group.py | 779 + .../algorithms/centrality/harmonic.py | 79 + .../networkx/algorithms/centrality/katz.py | 333 + .../networkx/algorithms/centrality/load.py | 197 + .../algorithms/centrality/percolation.py | 124 + .../algorithms/centrality/reaching.py | 204 + .../algorithms/centrality/second_order.py | 133 + .../algorithms/centrality/subgraph_alg.py | 338 + .../algorithms/centrality/tests/__init__.py | 0 .../tests/test_betweenness_centrality.py | 780 + .../test_betweenness_centrality_subset.py | 227 + .../tests/test_closeness_centrality.py | 306 + ...est_current_flow_betweenness_centrality.py | 177 + ...rent_flow_betweenness_centrality_subset.py | 147 + .../tests/test_current_flow_closeness.py | 37 + .../tests/test_degree_centrality.py | 145 + .../centrality/tests/test_dispersion.py | 66 + .../tests/test_eigenvector_centrality.py | 168 + .../algorithms/centrality/tests/test_group.py | 278 + .../tests/test_harmonic_centrality.py | 115 + .../centrality/tests/test_katz_centrality.py | 345 + .../centrality/tests/test_load_centrality.py | 337 + .../tests/test_percolation_centrality.py | 82 + .../centrality/tests/test_reaching.py | 109 + .../tests/test_second_order_centrality.py | 67 + .../centrality/tests/test_subgraph.py | 110 + .../centrality/tests/test_trophic.py | 302 + .../centrality/tests/test_voterank.py | 61 + .../networkx/algorithms/centrality/trophic.py | 159 + .../algorithms/centrality/voterank_alg.py | 92 + .../networkx/algorithms/chains.py | 167 + .../networkx/algorithms/chordal.py | 476 + .../networkx/algorithms/clique.py | 776 + .../networkx/algorithms/cluster.py | 568 + .../networkx/algorithms/coloring/__init__.py | 4 + .../algorithms/coloring/equitable_coloring.py | 515 + .../algorithms/coloring/greedy_coloring.py | 550 + .../algorithms/coloring/tests/__init__.py | 0 .../coloring/tests/test_coloring.py | 793 + .../algorithms/communicability_alg.py | 161 + .../networkx/algorithms/community/__init__.py | 26 + .../algorithms/community/asyn_fluid.py | 147 + .../algorithms/community/centrality.py | 170 + .../algorithms/community/community_utils.py | 27 + .../networkx/algorithms/community/kclique.py | 79 + .../algorithms/community/kernighan_lin.py | 137 + .../algorithms/community/label_propagation.py | 209 + .../networkx/algorithms/community/louvain.py | 350 + .../networkx/algorithms/community/lukes.py | 227 + .../algorithms/community/modularity_max.py | 474 + .../networkx/algorithms/community/quality.py | 443 + .../algorithms/community/tests/__init__.py | 0 .../community/tests/test_asyn_fluid.py | 128 + .../community/tests/test_centrality.py | 85 + .../community/tests/test_kclique.py | 92 + .../community/tests/test_kernighan_lin.py | 91 + .../community/tests/test_label_propagation.py | 163 + .../community/tests/test_louvain.py | 181 + .../algorithms/community/tests/test_lukes.py | 154 + .../community/tests/test_modularity_max.py | 333 + .../community/tests/test_quality.py | 147 + .../algorithms/community/tests/test_utils.py | 29 + .../algorithms/components/__init__.py | 6 + .../algorithms/components/attracting.py | 111 + .../algorithms/components/biconnected.py | 382 + .../algorithms/components/connected.py | 200 + .../algorithms/components/semiconnected.py | 64 + .../components/strongly_connected.py | 414 + .../algorithms/components/tests/__init__.py | 0 .../components/tests/test_attracting.py | 70 + .../components/tests/test_biconnected.py | 248 + .../components/tests/test_connected.py | 113 + .../components/tests/test_semiconnected.py | 55 + .../tests/test_strongly_connected.py | 205 + .../components/tests/test_weakly_connected.py | 90 + .../algorithms/components/weakly_connected.py | 184 + .../algorithms/connectivity/__init__.py | 11 + .../algorithms/connectivity/connectivity.py | 818 + .../networkx/algorithms/connectivity/cuts.py | 599 + .../algorithms/connectivity/disjoint_paths.py | 394 + .../connectivity/edge_augmentation.py | 1256 + .../connectivity/edge_kcomponents.py | 581 + .../algorithms/connectivity/kcomponents.py | 224 + .../algorithms/connectivity/kcutsets.py | 231 + .../algorithms/connectivity/stoerwagner.py | 149 + .../algorithms/connectivity/tests/__init__.py | 0 .../connectivity/tests/test_connectivity.py | 421 + .../connectivity/tests/test_cuts.py | 309 + .../connectivity/tests/test_disjoint_paths.py | 249 + .../tests/test_edge_augmentation.py | 497 + .../tests/test_edge_kcomponents.py | 488 + .../connectivity/tests/test_kcomponents.py | 296 + .../connectivity/tests/test_kcutsets.py | 267 + .../connectivity/tests/test_stoer_wagner.py | 102 + .../networkx/algorithms/connectivity/utils.py | 85 + .../site-packages/networkx/algorithms/core.py | 544 + .../networkx/algorithms/covering.py | 140 + .../site-packages/networkx/algorithms/cuts.py | 392 + .../networkx/algorithms/cycles.py | 617 + .../networkx/algorithms/d_separation.py | 142 + .../site-packages/networkx/algorithms/dag.py | 1136 + .../networkx/algorithms/distance_measures.py | 707 + .../networkx/algorithms/distance_regular.py | 231 + .../networkx/algorithms/dominance.py | 133 + .../networkx/algorithms/dominating.py | 92 + .../algorithms/efficiency_measures.py | 147 + .../networkx/algorithms/euler.py | 452 + .../networkx/algorithms/flow/__init__.py | 11 + .../algorithms/flow/boykovkolmogorov.py | 367 + .../algorithms/flow/capacityscaling.py | 404 + .../networkx/algorithms/flow/dinitz_alg.py | 211 + .../networkx/algorithms/flow/edmondskarp.py | 239 + .../networkx/algorithms/flow/gomory_hu.py | 176 + .../networkx/algorithms/flow/maxflow.py | 611 + .../networkx/algorithms/flow/mincost.py | 331 + .../algorithms/flow/networksimplex.py | 664 + .../networkx/algorithms/flow/preflowpush.py | 423 + .../algorithms/flow/shortestaugmentingpath.py | 298 + .../algorithms/flow/tests/__init__.py | 0 .../algorithms/flow/tests/gl1.gpickle.bz2 | Bin 0 -> 44623 bytes .../algorithms/flow/tests/gw1.gpickle.bz2 | Bin 0 -> 42248 bytes .../flow/tests/netgen-2.gpickle.bz2 | Bin 0 -> 18972 bytes .../algorithms/flow/tests/test_gomory_hu.py | 128 + .../algorithms/flow/tests/test_maxflow.py | 551 + .../flow/tests/test_maxflow_large_graph.py | 149 + .../algorithms/flow/tests/test_mincost.py | 469 + .../flow/tests/test_networksimplex.py | 379 + .../algorithms/flow/tests/wlm3.gpickle.bz2 | Bin 0 -> 88132 bytes .../networkx/algorithms/flow/utils.py | 181 + .../networkx/algorithms/graph_hashing.py | 304 + .../networkx/algorithms/graphical.py | 405 + .../networkx/algorithms/hierarchy.py | 47 + .../networkx/algorithms/hybrid.py | 193 + .../networkx/algorithms/isolate.py | 103 + .../algorithms/isomorphism/__init__.py | 6 + .../networkx/algorithms/isomorphism/ismags.py | 1170 + .../algorithms/isomorphism/isomorph.py | 233 + .../algorithms/isomorphism/isomorphvf2.py | 1061 + .../algorithms/isomorphism/matchhelpers.py | 355 + .../isomorphism/temporalisomorphvf2.py | 308 + .../algorithms/isomorphism/tests/__init__.py | 0 .../isomorphism/tests/iso_r01_s80.A99 | Bin 0 -> 1442 bytes .../isomorphism/tests/iso_r01_s80.B99 | Bin 0 -> 1442 bytes .../isomorphism/tests/si2_b06_m200.A99 | Bin 0 -> 310 bytes .../isomorphism/tests/si2_b06_m200.B99 | Bin 0 -> 1602 bytes .../isomorphism/tests/test_ismags.py | 327 + .../isomorphism/tests/test_isomorphism.py | 40 + .../isomorphism/tests/test_isomorphvf2.py | 403 + .../isomorphism/tests/test_match_helpers.py | 64 + .../tests/test_temporalisomorphvf2.py | 211 + .../tests/test_tree_isomorphism.py | 289 + .../isomorphism/tests/test_vf2userfunc.py | 201 + .../isomorphism/tree_isomorphism.py | 279 + .../algorithms/isomorphism/vf2userfunc.py | 197 + .../algorithms/link_analysis/__init__.py | 2 + .../algorithms/link_analysis/hits_alg.py | 399 + .../algorithms/link_analysis/pagerank_alg.py | 508 + .../link_analysis/tests/__init__.py | 0 .../link_analysis/tests/test_hits.py | 89 + .../link_analysis/tests/test_pagerank.py | 220 + .../networkx/algorithms/link_prediction.py | 596 + .../algorithms/lowest_common_ancestors.py | 365 + .../networkx/algorithms/matching.py | 1123 + .../networkx/algorithms/minors/__init__.py | 27 + .../networkx/algorithms/minors/contraction.py | 600 + .../minors/tests/test_contraction.py | 422 + .../site-packages/networkx/algorithms/mis.py | 76 + .../networkx/algorithms/moral.py | 57 + .../node_classification/__init__.py | 52 + .../algorithms/node_classification/hmn.py | 88 + .../algorithms/node_classification/lgc.py | 89 + .../algorithms/node_classification/utils.py | 34 + .../networkx/algorithms/non_randomness.py | 95 + .../networkx/algorithms/operators/__init__.py | 4 + .../networkx/algorithms/operators/all.py | 253 + .../networkx/algorithms/operators/binary.py | 424 + .../networkx/algorithms/operators/product.py | 461 + .../algorithms/operators/tests/__init__.py | 0 .../algorithms/operators/tests/test_all.py | 300 + .../algorithms/operators/tests/test_binary.py | 448 + .../operators/tests/test_product.py | 427 + .../algorithms/operators/tests/test_unary.py | 55 + .../networkx/algorithms/operators/unary.py | 74 + .../networkx/algorithms/planar_drawing.py | 464 + .../networkx/algorithms/planarity.py | 1174 + .../networkx/algorithms/polynomials.py | 290 + .../networkx/algorithms/reciprocity.py | 94 + .../networkx/algorithms/regular.py | 190 + .../networkx/algorithms/richclub.py | 120 + .../algorithms/shortest_paths/__init__.py | 5 + .../algorithms/shortest_paths/astar.py | 199 + .../algorithms/shortest_paths/dense.py | 233 + .../algorithms/shortest_paths/generic.py | 568 + .../shortest_paths/tests/__init__.py | 0 .../shortest_paths/tests/test_astar.py | 177 + .../shortest_paths/tests/test_dense.py | 212 + .../shortest_paths/tests/test_dense_numpy.py | 89 + .../shortest_paths/tests/test_generic.py | 377 + .../shortest_paths/tests/test_unweighted.py | 116 + .../shortest_paths/tests/test_weighted.py | 924 + .../algorithms/shortest_paths/unweighted.py | 530 + .../algorithms/shortest_paths/weighted.py | 2464 + .../networkx/algorithms/similarity.py | 1731 + .../networkx/algorithms/simple_paths.py | 955 + .../networkx/algorithms/smallworld.py | 385 + .../networkx/algorithms/smetric.py | 38 + .../networkx/algorithms/sparsifiers.py | 294 + .../networkx/algorithms/structuralholes.py | 278 + .../networkx/algorithms/summarization.py | 556 + .../site-packages/networkx/algorithms/swap.py | 269 + .../networkx/algorithms/tests/__init__.py | 0 .../algorithms/tests/test_asteroidal.py | 24 + .../algorithms/tests/test_boundary.py | 154 + .../networkx/algorithms/tests/test_bridges.py | 87 + .../networkx/algorithms/tests/test_chains.py | 131 + .../networkx/algorithms/tests/test_chordal.py | 129 + .../networkx/algorithms/tests/test_clique.py | 316 + .../networkx/algorithms/tests/test_cluster.py | 543 + .../algorithms/tests/test_communicability.py | 81 + .../networkx/algorithms/tests/test_core.py | 171 + .../algorithms/tests/test_covering.py | 74 + .../networkx/algorithms/tests/test_cuts.py | 172 + .../networkx/algorithms/tests/test_cycles.py | 347 + .../algorithms/tests/test_d_separation.py | 158 + .../networkx/algorithms/tests/test_dag.py | 710 + .../tests/test_distance_measures.py | 261 + .../algorithms/tests/test_distance_regular.py | 66 + .../algorithms/tests/test_dominance.py | 285 + .../algorithms/tests/test_dominating.py | 46 + .../algorithms/tests/test_efficiency.py | 58 + .../networkx/algorithms/tests/test_euler.py | 275 + .../algorithms/tests/test_graph_hashing.py | 657 + .../algorithms/tests/test_graphical.py | 163 + .../algorithms/tests/test_hierarchy.py | 39 + .../networkx/algorithms/tests/test_hybrid.py | 24 + .../networkx/algorithms/tests/test_isolate.py | 26 + .../algorithms/tests/test_link_prediction.py | 582 + .../tests/test_lowest_common_ancestors.py | 313 + .../algorithms/tests/test_matching.py | 572 + .../tests/test_max_weight_clique.py | 181 + .../networkx/algorithms/tests/test_mis.py | 62 + .../networkx/algorithms/tests/test_moral.py | 15 + .../tests/test_node_classification.py | 140 + .../test_node_classification_deprecations.py | 41 + .../algorithms/tests/test_non_randomness.py | 37 + .../algorithms/tests/test_planar_drawing.py | 274 + .../algorithms/tests/test_planarity.py | 442 + .../algorithms/tests/test_polynomials.py | 57 + .../algorithms/tests/test_reciprocity.py | 38 + .../networkx/algorithms/tests/test_regular.py | 86 + .../algorithms/tests/test_richclub.py | 86 + .../algorithms/tests/test_similarity.py | 920 + .../algorithms/tests/test_simple_paths.py | 765 + .../algorithms/tests/test_smallworld.py | 70 + .../networkx/algorithms/tests/test_smetric.py | 22 + .../algorithms/tests/test_sparsifiers.py | 137 + .../algorithms/tests/test_structuralholes.py | 135 + .../algorithms/tests/test_summarization.py | 641 + .../networkx/algorithms/tests/test_swap.py | 94 + .../algorithms/tests/test_threshold.py | 269 + .../algorithms/tests/test_tournament.py | 162 + .../networkx/algorithms/tests/test_triads.py | 272 + .../algorithms/tests/test_vitality.py | 41 + .../networkx/algorithms/tests/test_voronoi.py | 103 + .../networkx/algorithms/tests/test_wiener.py | 66 + .../networkx/algorithms/threshold.py | 974 + .../networkx/algorithms/tournament.py | 391 + .../networkx/algorithms/traversal/__init__.py | 5 + .../algorithms/traversal/beamsearch.py | 104 + .../traversal/breadth_first_search.py | 420 + .../traversal/depth_first_search.py | 443 + .../networkx/algorithms/traversal/edgebfs.py | 176 + .../networkx/algorithms/traversal/edgedfs.py | 174 + .../algorithms/traversal/tests/__init__.py | 0 .../traversal/tests/test_beamsearch.py | 27 + .../algorithms/traversal/tests/test_bfs.py | 119 + .../algorithms/traversal/tests/test_dfs.py | 152 + .../traversal/tests/test_edgebfs.py | 147 + .../traversal/tests/test_edgedfs.py | 131 + .../networkx/algorithms/tree/__init__.py | 6 + .../networkx/algorithms/tree/branchings.py | 1048 + .../networkx/algorithms/tree/coding.py | 398 + .../networkx/algorithms/tree/decomposition.py | 87 + .../networkx/algorithms/tree/mst.py | 1112 + .../networkx/algorithms/tree/operations.py | 106 + .../networkx/algorithms/tree/recognition.py | 269 + .../algorithms/tree/tests/__init__.py | 0 .../algorithms/tree/tests/test_branchings.py | 556 + .../algorithms/tree/tests/test_coding.py | 113 + .../tree/tests/test_decomposition.py | 79 + .../algorithms/tree/tests/test_mst.py | 622 + .../algorithms/tree/tests/test_operations.py | 37 + .../algorithms/tree/tests/test_recognition.py | 164 + .../networkx/algorithms/triads.py | 498 + .../networkx/algorithms/vitality.py | 75 + .../networkx/algorithms/voronoi.py | 85 + .../networkx/algorithms/wiener.py | 76 + .../networkx/classes/__init__.py | 13 + .../networkx/classes/coreviews.py | 482 + .../site-packages/networkx/classes/digraph.py | 1269 + .../site-packages/networkx/classes/filters.py | 75 + .../networkx/classes/function.py | 1311 + .../site-packages/networkx/classes/graph.py | 1940 + .../networkx/classes/graphviews.py | 205 + .../networkx/classes/multidigraph.py | 947 + .../networkx/classes/multigraph.py | 1246 + .../site-packages/networkx/classes/ordered.py | 162 + .../networkx/classes/reportviews.py | 1440 + .../networkx/classes/tests/__init__.py | 0 .../classes/tests/historical_tests.py | 474 + .../networkx/classes/tests/test_coreviews.py | 431 + .../networkx/classes/tests/test_digraph.py | 327 + .../classes/tests/test_digraph_historical.py | 110 + .../networkx/classes/tests/test_filters.py | 177 + .../networkx/classes/tests/test_function.py | 799 + .../networkx/classes/tests/test_graph.py | 897 + .../classes/tests/test_graph_historical.py | 12 + .../networkx/classes/tests/test_graphviews.py | 352 + .../classes/tests/test_multidigraph.py | 455 + .../networkx/classes/tests/test_multigraph.py | 525 + .../networkx/classes/tests/test_ordered.py | 40 + .../classes/tests/test_reportviews.py | 1419 + .../networkx/classes/tests/test_special.py | 187 + .../classes/tests/test_subgraphviews.py | 363 + .../site-packages/networkx/conftest.py | 393 + .../site-packages/networkx/convert.py | 491 + .../site-packages/networkx/convert_matrix.py | 1673 + .../networkx/drawing/__init__.py | 6 + .../site-packages/networkx/drawing/layout.py | 1189 + .../networkx/drawing/nx_agraph.py | 495 + .../networkx/drawing/nx_pydot.py | 452 + .../networkx/drawing/nx_pylab.py | 1517 + .../networkx/drawing/tests/__init__.py | 0 .../tests/baseline/test_house_with_colors.png | Bin 0 -> 21918 bytes .../networkx/drawing/tests/test_agraph.py | 242 + .../networkx/drawing/tests/test_layout.py | 445 + .../networkx/drawing/tests/test_pydot.py | 190 + .../networkx/drawing/tests/test_pylab.py | 753 + .../site-packages/networkx/exception.py | 125 + .../networkx/generators/__init__.py | 31 + .../networkx/generators/atlas.dat.gz | Bin 0 -> 8887 bytes .../networkx/generators/atlas.py | 177 + .../networkx/generators/classic.py | 780 + .../networkx/generators/cographs.py | 66 + .../networkx/generators/community.py | 1061 + .../networkx/generators/degree_seq.py | 861 + .../networkx/generators/directed.py | 530 + .../networkx/generators/duplication.py | 161 + .../site-packages/networkx/generators/ego.py | 64 + .../networkx/generators/expanders.py | 203 + .../networkx/generators/geometric.py | 804 + .../networkx/generators/harary_graph.py | 197 + .../networkx/generators/internet_as_graphs.py | 440 + .../networkx/generators/intersection.py | 121 + .../networkx/generators/interval_graph.py | 70 + .../networkx/generators/joint_degree_seq.py | 670 + .../networkx/generators/lattice.py | 361 + .../site-packages/networkx/generators/line.py | 501 + .../networkx/generators/mycielski.py | 108 + .../generators/nonisomorphic_trees.py | 190 + .../networkx/generators/random_clustered.py | 116 + .../networkx/generators/random_graphs.py | 1316 + .../networkx/generators/small.py | 1065 + .../networkx/generators/social.py | 542 + .../generators/spectral_graph_forge.py | 121 + .../networkx/generators/stochastic.py | 49 + .../networkx/generators/sudoku.py | 130 + .../networkx/generators/tests/__init__.py | 0 .../networkx/generators/tests/test_atlas.py | 75 + .../networkx/generators/tests/test_classic.py | 549 + .../generators/tests/test_cographs.py | 20 + .../generators/tests/test_community.py | 268 + .../generators/tests/test_degree_seq.py | 230 + .../generators/tests/test_directed.py | 128 + .../generators/tests/test_duplication.py | 73 + .../networkx/generators/tests/test_ego.py | 39 + .../generators/tests/test_expanders.py | 73 + .../generators/tests/test_geometric.py | 329 + .../generators/tests/test_harary_graph.py | 134 + .../tests/test_internet_as_graphs.py | 190 + .../generators/tests/test_intersection.py | 28 + .../generators/tests/test_interval_graph.py | 145 + .../generators/tests/test_joint_degree_seq.py | 127 + .../networkx/generators/tests/test_lattice.py | 246 + .../networkx/generators/tests/test_line.py | 277 + .../generators/tests/test_mycielski.py | 26 + .../tests/test_nonisomorphic_trees.py | 64 + .../generators/tests/test_random_clustered.py | 34 + .../generators/tests/test_random_graphs.py | 336 + .../networkx/generators/tests/test_small.py | 214 + .../tests/test_spectral_graph_forge.py | 49 + .../generators/tests/test_stochastic.py | 60 + .../networkx/generators/tests/test_sudoku.py | 92 + .../networkx/generators/tests/test_trees.py | 88 + .../networkx/generators/tests/test_triads.py | 14 + .../networkx/generators/trees.py | 374 + .../networkx/generators/triads.py | 75 + .../site-packages/networkx/lazy_imports.py | 190 + .../site-packages/networkx/linalg/__init__.py | 13 + .../networkx/linalg/algebraicconnectivity.py | 562 + .../networkx/linalg/attrmatrix.py | 475 + .../networkx/linalg/bethehessianmatrix.py | 86 + .../networkx/linalg/graphmatrix.py | 190 + .../networkx/linalg/laplacianmatrix.py | 448 + .../networkx/linalg/modularitymatrix.py | 180 + .../site-packages/networkx/linalg/spectrum.py | 173 + .../networkx/linalg/tests/__init__.py | 0 .../tests/test_algebraic_connectivity.py | 387 + .../networkx/linalg/tests/test_attrmatrix.py | 108 + .../linalg/tests/test_bethehessian.py | 41 + .../networkx/linalg/tests/test_graphmatrix.py | 297 + .../networkx/linalg/tests/test_laplacian.py | 242 + .../networkx/linalg/tests/test_modularity.py | 87 + .../networkx/linalg/tests/test_spectrum.py | 71 + .../networkx/readwrite/__init__.py | 60 + .../networkx/readwrite/adjlist.py | 295 + .../networkx/readwrite/edgelist.py | 486 + .../site-packages/networkx/readwrite/gexf.py | 1060 + .../site-packages/networkx/readwrite/gml.py | 856 + .../networkx/readwrite/gpickle.py | 109 + .../networkx/readwrite/graph6.py | 414 + .../networkx/readwrite/graphml.py | 1050 + .../networkx/readwrite/json_graph/__init__.py | 19 + .../readwrite/json_graph/adjacency.py | 157 + .../readwrite/json_graph/cytoscape.py | 242 + .../networkx/readwrite/json_graph/jit.py | 118 + .../readwrite/json_graph/node_link.py | 201 + .../readwrite/json_graph/tests/__init__.py | 0 .../json_graph/tests/test_adjacency.py | 60 + .../json_graph/tests/test_cytoscape.py | 95 + .../readwrite/json_graph/tests/test_jit.py | 66 + .../json_graph/tests/test_node_link.py | 106 + .../readwrite/json_graph/tests/test_tree.py | 65 + .../networkx/readwrite/json_graph/tree.py | 205 + .../site-packages/networkx/readwrite/leda.py | 106 + .../networkx/readwrite/multiline_adjlist.py | 391 + .../networkx/readwrite/nx_shp.py | 350 + .../networkx/readwrite/nx_yaml.py | 59 + .../site-packages/networkx/readwrite/p2g.py | 102 + .../site-packages/networkx/readwrite/pajek.py | 284 + .../networkx/readwrite/sparse6.py | 374 + .../networkx/readwrite/tests/__init__.py | 0 .../networkx/readwrite/tests/test_adjlist.py | 268 + .../networkx/readwrite/tests/test_edgelist.py | 314 + .../tests/test_getattr_nxyaml_removal.py | 38 + .../networkx/readwrite/tests/test_gexf.py | 547 + .../networkx/readwrite/tests/test_gml.py | 714 + .../networkx/readwrite/tests/test_gpickle.py | 75 + .../networkx/readwrite/tests/test_graph6.py | 169 + .../networkx/readwrite/tests/test_graphml.py | 1540 + .../networkx/readwrite/tests/test_leda.py | 30 + .../networkx/readwrite/tests/test_p2g.py | 62 + .../networkx/readwrite/tests/test_pajek.py | 130 + .../networkx/readwrite/tests/test_shp.py | 288 + .../networkx/readwrite/tests/test_sparse6.py | 173 + .../networkx/readwrite/tests/test_text.py | 317 + .../site-packages/networkx/readwrite/text.py | 192 + .../site-packages/networkx/relabel.py | 282 + .../networkx/testing/__init__.py | 2 + .../site-packages/networkx/testing/test.py | 44 + .../networkx/testing/tests/__init__.py | 0 .../networkx/testing/tests/test_utils.py | 160 + .../site-packages/networkx/testing/utils.py | 54 + .../site-packages/networkx/tests/__init__.py | 0 .../tests/test_all_random_functions.py | 247 + .../networkx/tests/test_convert.py | 321 + .../networkx/tests/test_convert_numpy.py | 674 + .../networkx/tests/test_convert_pandas.py | 322 + .../networkx/tests/test_convert_scipy.py | 293 + .../networkx/tests/test_exceptions.py | 40 + .../networkx/tests/test_import.py | 11 + .../networkx/tests/test_lazy_imports.py | 97 + .../networkx/tests/test_relabel.py | 302 + .../site-packages/networkx/utils/__init__.py | 7 + .../networkx/utils/contextmanagers.py | 47 + .../networkx/utils/decorators.py | 1288 + .../site-packages/networkx/utils/heaps.py | 340 + .../networkx/utils/mapped_queue.py | 267 + .../site-packages/networkx/utils/misc.py | 711 + .../networkx/utils/random_sequence.py | 164 + .../site-packages/networkx/utils/rcm.py | 158 + .../networkx/utils/tests/__init__.py | 0 .../networkx/utils/tests/test__init.py | 11 + .../utils/tests/test_contextmanager.py | 18 + .../networkx/utils/tests/test_decorators.py | 506 + .../networkx/utils/tests/test_heaps.py | 131 + .../networkx/utils/tests/test_mapped_queue.py | 233 + .../networkx/utils/tests/test_misc.py | 322 + .../utils/tests/test_random_sequence.py | 38 + .../networkx/utils/tests/test_rcm.py | 63 + .../networkx/utils/tests/test_unionfind.py | 55 + .../networkx/utils/union_find.py | 105 + .../packaging-21.3.dist-info/INSTALLER | 1 + .../packaging-21.3.dist-info/LICENSE | 3 + .../packaging-21.3.dist-info/LICENSE.APACHE | 177 + .../packaging-21.3.dist-info/LICENSE.BSD | 23 + .../packaging-21.3.dist-info/METADATA | 453 + .../packaging-21.3.dist-info/RECORD | 20 + .../packaging-21.3.dist-info/WHEEL | 5 + .../packaging-21.3.dist-info/top_level.txt | 1 + .../site-packages/packaging/__about__.py | 26 + .../site-packages/packaging/__init__.py | 25 + .../site-packages/packaging/_manylinux.py | 301 + .../site-packages/packaging/_musllinux.py | 136 + .../site-packages/packaging/_structures.py | 61 + .../site-packages/packaging/markers.py | 304 + .../site-packages/packaging/py.typed | 0 .../site-packages/packaging/requirements.py | 146 + .../site-packages/packaging/specifiers.py | 802 + .../python3.9/site-packages/packaging/tags.py | 487 + .../site-packages/packaging/utils.py | 136 + .../site-packages/packaging/version.py | 504 + .../passlib-1.7.4.dist-info/INSTALLER | 1 + .../passlib-1.7.4.dist-info/LICENSE | 116 + .../passlib-1.7.4.dist-info/METADATA | 40 + .../passlib-1.7.4.dist-info/RECORD | 108 + .../passlib-1.7.4.dist-info/WHEEL | 6 + .../passlib-1.7.4.dist-info/top_level.txt | 1 + .../passlib-1.7.4.dist-info/zip-safe | 1 + .../site-packages/passlib/__init__.py | 3 + .../passlib/_data/wordsets/bip39.txt | 2049 + .../passlib/_data/wordsets/eff_long.txt | 7776 + .../passlib/_data/wordsets/eff_prefixed.txt | 1296 + .../passlib/_data/wordsets/eff_short.txt | 1296 + .../python3.9/site-packages/passlib/apache.py | 1255 + .../python3.9/site-packages/passlib/apps.py | 245 + .../site-packages/passlib/context.py | 2637 + .../site-packages/passlib/crypto/__init__.py | 1 + .../passlib/crypto/_blowfish/__init__.py | 169 + .../passlib/crypto/_blowfish/_gen_files.py | 204 + .../passlib/crypto/_blowfish/base.py | 441 + .../passlib/crypto/_blowfish/unrolled.py | 771 + .../site-packages/passlib/crypto/_md4.py | 244 + .../site-packages/passlib/crypto/des.py | 848 + .../site-packages/passlib/crypto/digest.py | 1057 + .../passlib/crypto/scrypt/__init__.py | 281 + .../passlib/crypto/scrypt/_builtin.py | 244 + .../passlib/crypto/scrypt/_gen_files.py | 154 + .../passlib/crypto/scrypt/_salsa.py | 170 + .../python3.9/site-packages/passlib/exc.py | 397 + .../site-packages/passlib/ext/__init__.py | 1 + .../passlib/ext/django/__init__.py | 6 + .../passlib/ext/django/models.py | 36 + .../site-packages/passlib/ext/django/utils.py | 1276 + .../passlib/handlers/__init__.py | 1 + .../site-packages/passlib/handlers/argon2.py | 1009 + .../site-packages/passlib/handlers/bcrypt.py | 1243 + .../site-packages/passlib/handlers/cisco.py | 440 + .../passlib/handlers/des_crypt.py | 607 + .../site-packages/passlib/handlers/digests.py | 168 + .../site-packages/passlib/handlers/django.py | 512 + .../site-packages/passlib/handlers/fshp.py | 214 + .../passlib/handlers/ldap_digests.py | 359 + .../passlib/handlers/md5_crypt.py | 346 + .../site-packages/passlib/handlers/misc.py | 269 + .../site-packages/passlib/handlers/mssql.py | 244 + .../site-packages/passlib/handlers/mysql.py | 128 + .../site-packages/passlib/handlers/oracle.py | 172 + .../site-packages/passlib/handlers/pbkdf2.py | 475 + .../site-packages/passlib/handlers/phpass.py | 135 + .../passlib/handlers/postgres.py | 55 + .../site-packages/passlib/handlers/roundup.py | 29 + .../site-packages/passlib/handlers/scram.py | 582 + .../site-packages/passlib/handlers/scrypt.py | 383 + .../passlib/handlers/sha1_crypt.py | 158 + .../passlib/handlers/sha2_crypt.py | 534 + .../passlib/handlers/sun_md5_crypt.py | 363 + .../site-packages/passlib/handlers/windows.py | 334 + .../python3.9/site-packages/passlib/hash.py | 68 + .../python3.9/site-packages/passlib/hosts.py | 106 + .../python3.9/site-packages/passlib/ifc.py | 353 + .../python3.9/site-packages/passlib/pwd.py | 809 + .../site-packages/passlib/registry.py | 547 + .../site-packages/passlib/tests/__init__.py | 1 + .../site-packages/passlib/tests/__main__.py | 6 + .../passlib/tests/_test_bad_register.py | 15 + .../site-packages/passlib/tests/backports.py | 67 + .../site-packages/passlib/tests/sample1.cfg | 9 + .../site-packages/passlib/tests/sample1b.cfg | 9 + .../site-packages/passlib/tests/sample1c.cfg | Bin 0 -> 490 bytes .../passlib/tests/sample_config_1s.cfg | 8 + .../passlib/tests/test_apache.py | 769 + .../site-packages/passlib/tests/test_apps.py | 139 + .../passlib/tests/test_context.py | 1786 + .../passlib/tests/test_context_deprecated.py | 743 + .../passlib/tests/test_crypto_builtin_md4.py | 160 + .../passlib/tests/test_crypto_des.py | 194 + .../passlib/tests/test_crypto_digest.py | 544 + .../passlib/tests/test_crypto_scrypt.py | 634 + .../passlib/tests/test_ext_django.py | 1080 + .../passlib/tests/test_ext_django_source.py | 250 + .../passlib/tests/test_handlers.py | 1819 + .../passlib/tests/test_handlers_argon2.py | 507 + .../passlib/tests/test_handlers_bcrypt.py | 688 + .../passlib/tests/test_handlers_cisco.py | 457 + .../passlib/tests/test_handlers_django.py | 413 + .../passlib/tests/test_handlers_pbkdf2.py | 480 + .../passlib/tests/test_handlers_scrypt.py | 111 + .../site-packages/passlib/tests/test_hosts.py | 97 + .../site-packages/passlib/tests/test_pwd.py | 205 + .../passlib/tests/test_registry.py | 228 + .../site-packages/passlib/tests/test_totp.py | 1604 + .../site-packages/passlib/tests/test_utils.py | 1171 + .../passlib/tests/test_utils_handlers.py | 870 + .../passlib/tests/test_utils_md4.py | 41 + .../passlib/tests/test_utils_pbkdf2.py | 323 + .../site-packages/passlib/tests/test_win32.py | 50 + .../passlib/tests/tox_support.py | 83 + .../site-packages/passlib/tests/utils.py | 3621 + .../python3.9/site-packages/passlib/totp.py | 1908 + .../site-packages/passlib/utils/__init__.py | 1220 + .../site-packages/passlib/utils/binary.py | 884 + .../passlib/utils/compat/__init__.py | 474 + .../passlib/utils/compat/_ordered_dict.py | 242 + .../site-packages/passlib/utils/decor.py | 233 + .../site-packages/passlib/utils/des.py | 46 + .../site-packages/passlib/utils/handlers.py | 2711 + .../site-packages/passlib/utils/md4.py | 29 + .../site-packages/passlib/utils/pbkdf2.py | 193 + .../python3.9/site-packages/passlib/win32.py | 68 + .../pathspec-0.9.0.dist-info/INSTALLER | 1 + .../pathspec-0.9.0.dist-info/LICENSE | 373 + .../pathspec-0.9.0.dist-info/METADATA | 411 + .../pathspec-0.9.0.dist-info/RECORD | 18 + .../pathspec-0.9.0.dist-info/WHEEL | 6 + .../pathspec-0.9.0.dist-info/top_level.txt | 1 + .../site-packages/pathspec/__init__.py | 43 + .../python3.9/site-packages/pathspec/_meta.py | 43 + .../site-packages/pathspec/compat.py | 41 + .../site-packages/pathspec/pathspec.py | 243 + .../site-packages/pathspec/pattern.py | 164 + .../pathspec/patterns/__init__.py | 8 + .../pathspec/patterns/gitwildmatch.py | 400 + .../site-packages/pathspec/tests/__init__.py | 0 .../pathspec/tests/test_gitwildmatch.py | 548 + .../pathspec/tests/test_pathspec.py | 226 + .../site-packages/pathspec/tests/test_util.py | 380 + .../python3.9/site-packages/pathspec/util.py | 665 + .../pip-20.2.3.dist-info/INSTALLER | 1 + .../pip-20.2.3.dist-info/LICENSE.txt | 20 + .../pip-20.2.3.dist-info/METADATA | 88 + .../site-packages/pip-20.2.3.dist-info/RECORD | 752 + .../pip-20.2.3.dist-info/REQUESTED | 0 .../site-packages/pip-20.2.3.dist-info/WHEEL | 6 + .../pip-20.2.3.dist-info/entry_points.txt | 5 + .../pip-20.2.3.dist-info/top_level.txt | 1 + .../python3.9/site-packages/pip/__init__.py | 18 + .../python3.9/site-packages/pip/__main__.py | 26 + .../site-packages/pip/_internal/__init__.py | 17 + .../site-packages/pip/_internal/build_env.py | 241 + .../site-packages/pip/_internal/cache.py | 346 + .../pip/_internal/cli/__init__.py | 4 + .../pip/_internal/cli/autocompletion.py | 164 + .../pip/_internal/cli/base_command.py | 265 + .../pip/_internal/cli/cmdoptions.py | 975 + .../pip/_internal/cli/command_context.py | 36 + .../site-packages/pip/_internal/cli/main.py | 75 + .../pip/_internal/cli/main_parser.py | 99 + .../site-packages/pip/_internal/cli/parser.py | 266 + .../pip/_internal/cli/progress_bars.py | 280 + .../pip/_internal/cli/req_command.py | 402 + .../pip/_internal/cli/spinners.py | 173 + .../pip/_internal/cli/status_codes.py | 8 + .../pip/_internal/commands/__init__.py | 122 + .../pip/_internal/commands/cache.py | 182 + .../pip/_internal/commands/check.py | 51 + .../pip/_internal/commands/completion.py | 98 + .../pip/_internal/commands/configuration.py | 284 + .../pip/_internal/commands/debug.py | 229 + .../pip/_internal/commands/download.py | 143 + .../pip/_internal/commands/freeze.py | 103 + .../pip/_internal/commands/hash.py | 63 + .../pip/_internal/commands/help.py | 44 + .../pip/_internal/commands/install.py | 749 + .../pip/_internal/commands/list.py | 320 + .../pip/_internal/commands/search.py | 160 + .../pip/_internal/commands/show.py | 186 + .../pip/_internal/commands/uninstall.py | 95 + .../pip/_internal/commands/wheel.py | 188 + .../pip/_internal/configuration.py | 418 + .../pip/_internal/distributions/__init__.py | 24 + .../pip/_internal/distributions/base.py | 45 + .../pip/_internal/distributions/installed.py | 24 + .../pip/_internal/distributions/sdist.py | 104 + .../pip/_internal/distributions/wheel.py | 36 + .../site-packages/pip/_internal/exceptions.py | 381 + .../pip/_internal/index/__init__.py | 2 + .../pip/_internal/index/collector.py | 692 + .../pip/_internal/index/package_finder.py | 1014 + .../site-packages/pip/_internal/locations.py | 194 + .../site-packages/pip/_internal/main.py | 16 + .../pip/_internal/models/__init__.py | 2 + .../pip/_internal/models/candidate.py | 38 + .../pip/_internal/models/direct_url.py | 245 + .../pip/_internal/models/format_control.py | 92 + .../pip/_internal/models/index.py | 34 + .../pip/_internal/models/link.py | 245 + .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 135 + .../pip/_internal/models/selection_prefs.py | 49 + .../pip/_internal/models/target_python.py | 120 + .../pip/_internal/models/wheel.py | 78 + .../pip/_internal/network/__init__.py | 2 + .../pip/_internal/network/auth.py | 310 + .../pip/_internal/network/cache.py | 79 + .../pip/_internal/network/download.py | 182 + .../pip/_internal/network/lazy_wheel.py | 235 + .../pip/_internal/network/session.py | 421 + .../pip/_internal/network/utils.py | 97 + .../pip/_internal/network/xmlrpc.py | 52 + .../pip/_internal/operations/__init__.py | 0 .../_internal/operations/build/__init__.py | 0 .../_internal/operations/build/metadata.py | 37 + .../operations/build/metadata_legacy.py | 77 + .../pip/_internal/operations/build/wheel.py | 46 + .../operations/build/wheel_legacy.py | 115 + .../pip/_internal/operations/check.py | 158 + .../pip/_internal/operations/freeze.py | 272 + .../_internal/operations/install/__init__.py | 2 + .../operations/install/editable_legacy.py | 52 + .../_internal/operations/install/legacy.py | 130 + .../pip/_internal/operations/install/wheel.py | 861 + .../pip/_internal/operations/prepare.py | 562 + .../site-packages/pip/_internal/pyproject.py | 196 + .../pip/_internal/req/__init__.py | 103 + .../pip/_internal/req/constructors.py | 486 + .../pip/_internal/req/req_file.py | 592 + .../pip/_internal/req/req_install.py | 905 + .../pip/_internal/req/req_set.py | 203 + .../pip/_internal/req/req_tracker.py | 150 + .../pip/_internal/req/req_uninstall.py | 648 + .../pip/_internal/resolution/__init__.py | 0 .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../_internal/resolution/legacy/resolver.py | 485 + .../resolution/resolvelib/__init__.py | 0 .../_internal/resolution/resolvelib/base.py | 82 + .../resolution/resolvelib/candidates.py | 600 + .../resolution/resolvelib/factory.py | 459 + .../resolution/resolvelib/provider.py | 153 + .../resolution/resolvelib/requirements.py | 137 + .../resolution/resolvelib/resolver.py | 259 + .../pip/_internal/self_outdated_check.py | 205 + .../pip/_internal/utils/__init__.py | 0 .../pip/_internal/utils/appdirs.py | 44 + .../pip/_internal/utils/compat.py | 271 + .../pip/_internal/utils/compatibility_tags.py | 166 + .../pip/_internal/utils/datetime.py | 14 + .../pip/_internal/utils/deprecation.py | 104 + .../pip/_internal/utils/direct_url_helpers.py | 130 + .../pip/_internal/utils/distutils_args.py | 48 + .../pip/_internal/utils/encoding.py | 41 + .../pip/_internal/utils/entrypoints.py | 31 + .../pip/_internal/utils/filesystem.py | 224 + .../pip/_internal/utils/filetypes.py | 16 + .../pip/_internal/utils/glibc.py | 98 + .../pip/_internal/utils/hashes.py | 145 + .../_internal/utils/inject_securetransport.py | 36 + .../pip/_internal/utils/logging.py | 399 + .../site-packages/pip/_internal/utils/misc.py | 959 + .../pip/_internal/utils/models.py | 44 + .../pip/_internal/utils/packaging.py | 94 + .../pip/_internal/utils/parallel.py | 107 + .../pip/_internal/utils/pkg_resources.py | 44 + .../pip/_internal/utils/setuptools_build.py | 181 + .../pip/_internal/utils/subprocess.py | 280 + .../pip/_internal/utils/temp_dir.py | 274 + .../pip/_internal/utils/typing.py | 38 + .../pip/_internal/utils/unpacking.py | 281 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 119 + .../pip/_internal/utils/wheel.py | 225 + .../pip/_internal/vcs/__init__.py | 15 + .../site-packages/pip/_internal/vcs/bazaar.py | 119 + .../site-packages/pip/_internal/vcs/git.py | 397 + .../pip/_internal/vcs/mercurial.py | 158 + .../pip/_internal/vcs/subversion.py | 336 + .../pip/_internal/vcs/versioncontrol.py | 811 + .../pip/_internal/wheel_builder.py | 308 + .../site-packages/pip/_vendor/__init__.py | 110 + .../site-packages/pip/_vendor/appdirs.py | 633 + .../pip/_vendor/cachecontrol/__init__.py | 11 + .../pip/_vendor/cachecontrol/_cmd.py | 57 + .../pip/_vendor/cachecontrol/adapter.py | 133 + .../pip/_vendor/cachecontrol/cache.py | 39 + .../_vendor/cachecontrol/caches/__init__.py | 2 + .../_vendor/cachecontrol/caches/file_cache.py | 146 + .../cachecontrol/caches/redis_cache.py | 33 + .../pip/_vendor/cachecontrol/compat.py | 29 + .../pip/_vendor/cachecontrol/controller.py | 376 + .../pip/_vendor/cachecontrol/filewrapper.py | 80 + .../pip/_vendor/cachecontrol/heuristics.py | 135 + .../pip/_vendor/cachecontrol/serialize.py | 188 + .../pip/_vendor/cachecontrol/wrapper.py | 29 + .../pip/_vendor/certifi/__init__.py | 3 + .../pip/_vendor/certifi/__main__.py | 12 + .../pip/_vendor/certifi/cacert.pem | 4620 + .../site-packages/pip/_vendor/certifi/core.py | 60 + .../pip/_vendor/chardet/__init__.py | 39 + .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 233 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 145 + .../pip/_vendor/chardet/cli/__init__.py | 1 + .../pip/_vendor/chardet/cli/chardetect.py | 85 + .../pip/_vendor/chardet/codingstatemachine.py | 88 + .../pip/_vendor/chardet/compat.py | 34 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 76 + .../pip/_vendor/chardet/escprober.py | 101 + .../pip/_vendor/chardet/escsm.py | 246 + .../pip/_vendor/chardet/eucjpprober.py | 92 + .../pip/_vendor/chardet/euckrfreq.py | 195 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 387 + .../pip/_vendor/chardet/euctwprober.py | 46 + .../pip/_vendor/chardet/gb2312freq.py | 283 + .../pip/_vendor/chardet/gb2312prober.py | 46 + .../pip/_vendor/chardet/hebrewprober.py | 292 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/jpcntx.py | 233 + .../pip/_vendor/chardet/langbulgarianmodel.py | 228 + .../pip/_vendor/chardet/langcyrillicmodel.py | 333 + .../pip/_vendor/chardet/langgreekmodel.py | 225 + .../pip/_vendor/chardet/langhebrewmodel.py | 200 + .../pip/_vendor/chardet/langhungarianmodel.py | 225 + .../pip/_vendor/chardet/langthaimodel.py | 199 + .../pip/_vendor/chardet/langturkishmodel.py | 193 + .../pip/_vendor/chardet/latin1prober.py | 145 + .../pip/_vendor/chardet/mbcharsetprober.py | 91 + .../pip/_vendor/chardet/mbcsgroupprober.py | 54 + .../pip/_vendor/chardet/mbcssm.py | 572 + .../pip/_vendor/chardet/sbcharsetprober.py | 132 + .../pip/_vendor/chardet/sbcsgroupprober.py | 73 + .../pip/_vendor/chardet/sjisprober.py | 92 + .../pip/_vendor/chardet/universaldetector.py | 286 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 6 + .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 257 + .../pip/_vendor/colorama/initialise.py | 80 + .../pip/_vendor/colorama/win32.py | 152 + .../pip/_vendor/colorama/winterm.py | 169 + .../site-packages/pip/_vendor/contextlib2.py | 518 + .../pip/_vendor/distlib/__init__.py | 23 + .../pip/_vendor/distlib/_backport/__init__.py | 6 + .../pip/_vendor/distlib/_backport/misc.py | 41 + .../pip/_vendor/distlib/_backport/shutil.py | 764 + .../_vendor/distlib/_backport/sysconfig.cfg | 84 + .../_vendor/distlib/_backport/sysconfig.py | 786 + .../pip/_vendor/distlib/_backport/tarfile.py | 2607 + .../pip/_vendor/distlib/compat.py | 1120 + .../pip/_vendor/distlib/database.py | 1339 + .../pip/_vendor/distlib/index.py | 516 + .../pip/_vendor/distlib/locators.py | 1302 + .../pip/_vendor/distlib/manifest.py | 393 + .../pip/_vendor/distlib/markers.py | 131 + .../pip/_vendor/distlib/metadata.py | 1056 + .../pip/_vendor/distlib/resources.py | 355 + .../pip/_vendor/distlib/scripts.py | 419 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 96768 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 105984 bytes .../site-packages/pip/_vendor/distlib/util.py | 1761 + .../pip/_vendor/distlib/version.py | 736 + .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 90112 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 99840 bytes .../pip/_vendor/distlib/wheel.py | 1018 + .../site-packages/pip/_vendor/distro.py | 1230 + .../pip/_vendor/html5lib/__init__.py | 35 + .../pip/_vendor/html5lib/_ihatexml.py | 289 + .../pip/_vendor/html5lib/_inputstream.py | 918 + .../pip/_vendor/html5lib/_tokenizer.py | 1735 + .../pip/_vendor/html5lib/_trie/__init__.py | 5 + .../pip/_vendor/html5lib/_trie/_base.py | 40 + .../pip/_vendor/html5lib/_trie/py.py | 67 + .../pip/_vendor/html5lib/_utils.py | 159 + .../pip/_vendor/html5lib/constants.py | 2946 + .../pip/_vendor/html5lib/filters/__init__.py | 0 .../filters/alphabeticalattributes.py | 29 + .../pip/_vendor/html5lib/filters/base.py | 12 + .../html5lib/filters/inject_meta_charset.py | 73 + .../pip/_vendor/html5lib/filters/lint.py | 93 + .../_vendor/html5lib/filters/optionaltags.py | 207 + .../pip/_vendor/html5lib/filters/sanitizer.py | 916 + .../_vendor/html5lib/filters/whitespace.py | 38 + .../pip/_vendor/html5lib/html5parser.py | 2795 + .../pip/_vendor/html5lib/serializer.py | 409 + .../_vendor/html5lib/treeadapters/__init__.py | 30 + .../_vendor/html5lib/treeadapters/genshi.py | 54 + .../pip/_vendor/html5lib/treeadapters/sax.py | 50 + .../_vendor/html5lib/treebuilders/__init__.py | 88 + .../pip/_vendor/html5lib/treebuilders/base.py | 417 + .../pip/_vendor/html5lib/treebuilders/dom.py | 239 + .../_vendor/html5lib/treebuilders/etree.py | 343 + .../html5lib/treebuilders/etree_lxml.py | 392 + .../_vendor/html5lib/treewalkers/__init__.py | 154 + .../pip/_vendor/html5lib/treewalkers/base.py | 252 + .../pip/_vendor/html5lib/treewalkers/dom.py | 43 + .../pip/_vendor/html5lib/treewalkers/etree.py | 131 + .../html5lib/treewalkers/etree_lxml.py | 215 + .../_vendor/html5lib/treewalkers/genshi.py | 69 + .../pip/_vendor/idna/__init__.py | 2 + .../site-packages/pip/_vendor/idna/codec.py | 118 + .../site-packages/pip/_vendor/idna/compat.py | 12 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 2050 + .../pip/_vendor/idna/intranges.py | 53 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8357 + .../site-packages/pip/_vendor/ipaddress.py | 2420 + .../pip/_vendor/msgpack/__init__.py | 54 + .../pip/_vendor/msgpack/_version.py | 1 + .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 191 + .../pip/_vendor/msgpack/fallback.py | 1063 + .../pip/_vendor/packaging/__about__.py | 27 + .../pip/_vendor/packaging/__init__.py | 26 + .../pip/_vendor/packaging/_compat.py | 38 + .../pip/_vendor/packaging/_structures.py | 86 + .../pip/_vendor/packaging/_typing.py | 48 + .../pip/_vendor/packaging/markers.py | 328 + .../pip/_vendor/packaging/requirements.py | 145 + .../pip/_vendor/packaging/specifiers.py | 863 + .../pip/_vendor/packaging/tags.py | 751 + .../pip/_vendor/packaging/utils.py | 65 + .../pip/_vendor/packaging/version.py | 535 + .../pip/_vendor/pep517/__init__.py | 4 + .../pip/_vendor/pep517/_in_process.py | 280 + .../site-packages/pip/_vendor/pep517/build.py | 124 + .../site-packages/pip/_vendor/pep517/check.py | 203 + .../pip/_vendor/pep517/colorlog.py | 115 + .../pip/_vendor/pep517/compat.py | 34 + .../pip/_vendor/pep517/dirtools.py | 44 + .../pip/_vendor/pep517/envbuild.py | 167 + .../site-packages/pip/_vendor/pep517/meta.py | 92 + .../pip/_vendor/pep517/wrappers.py | 308 + .../pip/_vendor/pkg_resources/__init__.py | 3296 + .../pip/_vendor/pkg_resources/py31compat.py | 23 + .../pip/_vendor/progress/__init__.py | 177 + .../site-packages/pip/_vendor/progress/bar.py | 91 + .../pip/_vendor/progress/counter.py | 41 + .../pip/_vendor/progress/spinner.py | 43 + .../site-packages/pip/_vendor/pyparsing.py | 7107 + .../pip/_vendor/requests/__init__.py | 144 + .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 42 + .../pip/_vendor/requests/adapters.py | 533 + .../site-packages/pip/_vendor/requests/api.py | 161 + .../pip/_vendor/requests/auth.py | 305 + .../pip/_vendor/requests/certs.py | 18 + .../pip/_vendor/requests/compat.py | 76 + .../pip/_vendor/requests/cookies.py | 549 + .../pip/_vendor/requests/exceptions.py | 123 + .../pip/_vendor/requests/help.py | 119 + .../pip/_vendor/requests/hooks.py | 34 + .../pip/_vendor/requests/models.py | 954 + .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 769 + .../pip/_vendor/requests/status_codes.py | 123 + .../pip/_vendor/requests/structures.py | 105 + .../pip/_vendor/requests/utils.py | 982 + .../pip/_vendor/resolvelib/__init__.py | 26 + .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 109 + .../pip/_vendor/resolvelib/reporters.py | 42 + .../pip/_vendor/resolvelib/resolvers.py | 428 + .../pip/_vendor/resolvelib/structs.py | 68 + .../site-packages/pip/_vendor/retrying.py | 267 + .../site-packages/pip/_vendor/six.py | 982 + .../pip/_vendor/toml/__init__.py | 25 + .../site-packages/pip/_vendor/toml/common.py | 6 + .../site-packages/pip/_vendor/toml/decoder.py | 1052 + .../site-packages/pip/_vendor/toml/encoder.py | 304 + .../site-packages/pip/_vendor/toml/ordered.py | 15 + .../site-packages/pip/_vendor/toml/tz.py | 21 + .../pip/_vendor/urllib3/__init__.py | 86 + .../pip/_vendor/urllib3/_collections.py | 336 + .../pip/_vendor/urllib3/connection.py | 423 + .../pip/_vendor/urllib3/connectionpool.py | 1033 + .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 493 + .../contrib/_securetransport/low_level.py | 328 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 121 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 501 + .../urllib3/contrib/securetransport.py | 864 + .../pip/_vendor/urllib3/contrib/socks.py | 210 + .../pip/_vendor/urllib3/exceptions.py | 272 + .../pip/_vendor/urllib3/fields.py | 273 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 5 + .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 52 + .../pip/_vendor/urllib3/packages/six.py | 1021 + .../packages/ssl_match_hostname/__init__.py | 19 + .../ssl_match_hostname/_implementation.py | 160 + .../pip/_vendor/urllib3/poolmanager.py | 492 + .../pip/_vendor/urllib3/request.py | 171 + .../pip/_vendor/urllib3/response.py | 821 + .../pip/_vendor/urllib3/util/__init__.py | 46 + .../pip/_vendor/urllib3/util/connection.py | 138 + .../pip/_vendor/urllib3/util/queue.py | 21 + .../pip/_vendor/urllib3/util/request.py | 135 + .../pip/_vendor/urllib3/util/response.py | 86 + .../pip/_vendor/urllib3/util/retry.py | 453 + .../pip/_vendor/urllib3/util/ssl_.py | 414 + .../pip/_vendor/urllib3/util/timeout.py | 261 + .../pip/_vendor/urllib3/util/url.py | 430 + .../pip/_vendor/urllib3/util/wait.py | 153 + .../site-packages/pip/_vendor/vendor.txt | 24 + .../pip/_vendor/webencodings/__init__.py | 342 + .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../site-packages/pkg_resources/__init__.py | 3302 + .../pkg_resources/_vendor/__init__.py | 0 .../pkg_resources/_vendor/appdirs.py | 608 + .../_vendor/packaging/__about__.py | 27 + .../_vendor/packaging/__init__.py | 26 + .../_vendor/packaging/_compat.py | 31 + .../_vendor/packaging/_structures.py | 68 + .../_vendor/packaging/markers.py | 296 + .../_vendor/packaging/requirements.py | 138 + .../_vendor/packaging/specifiers.py | 749 + .../pkg_resources/_vendor/packaging/tags.py | 404 + .../pkg_resources/_vendor/packaging/utils.py | 57 + .../_vendor/packaging/version.py | 420 + .../pkg_resources/_vendor/pyparsing.py | 5742 + .../pkg_resources/_vendor/six.py | 868 + .../pkg_resources/extern/__init__.py | 66 + .../platformdirs-2.5.2.dist-info/INSTALLER | 1 + .../platformdirs-2.5.2.dist-info/METADATA | 250 + .../platformdirs-2.5.2.dist-info/RECORD | 15 + .../platformdirs-2.5.2.dist-info/WHEEL | 4 + .../entry_points.txt | 0 .../license_files/LICENSE.txt | 22 + .../site-packages/platformdirs/__init__.py | 340 + .../site-packages/platformdirs/__main__.py | 46 + .../site-packages/platformdirs/android.py | 120 + .../site-packages/platformdirs/api.py | 156 + .../site-packages/platformdirs/macos.py | 64 + .../site-packages/platformdirs/py.typed | 0 .../site-packages/platformdirs/unix.py | 181 + .../site-packages/platformdirs/version.py | 4 + .../site-packages/platformdirs/windows.py | 182 + .../pluggy-1.0.0.dist-info/INSTALLER | 1 + .../pluggy-1.0.0.dist-info/LICENSE | 21 + .../pluggy-1.0.0.dist-info/METADATA | 143 + .../pluggy-1.0.0.dist-info/RECORD | 13 + .../pluggy-1.0.0.dist-info/WHEEL | 6 + .../pluggy-1.0.0.dist-info/top_level.txt | 1 + .../site-packages/pluggy/__init__.py | 18 + .../site-packages/pluggy/_callers.py | 60 + .../python3.9/site-packages/pluggy/_hooks.py | 325 + .../site-packages/pluggy/_manager.py | 373 + .../python3.9/site-packages/pluggy/_result.py | 60 + .../site-packages/pluggy/_tracing.py | 62 + .../site-packages/pluggy/_version.py | 5 + .../py-1.11.0.dist-info/INSTALLER | 1 + .../site-packages/py-1.11.0.dist-info/LICENSE | 19 + .../py-1.11.0.dist-info/METADATA | 69 + .../site-packages/py-1.11.0.dist-info/RECORD | 65 + .../site-packages/py-1.11.0.dist-info/WHEEL | 6 + .../py-1.11.0.dist-info/top_level.txt | 1 + .../python3.9/site-packages/py/__init__.py | 156 + .../python3.9/site-packages/py/__init__.pyi | 20 + .../python3.9/site-packages/py/__metainfo.py | 2 + .../python3.9/site-packages/py/_builtin.py | 149 + .../site-packages/py/_code/__init__.py | 1 + .../site-packages/py/_code/_assertionnew.py | 322 + .../site-packages/py/_code/_assertionold.py | 556 + .../site-packages/py/_code/_py2traceback.py | 79 + .../site-packages/py/_code/assertion.py | 90 + .../python3.9/site-packages/py/_code/code.py | 796 + .../site-packages/py/_code/source.py | 410 + .../lib/python3.9/site-packages/py/_error.py | 91 + .../site-packages/py/_io/__init__.py | 1 + .../python3.9/site-packages/py/_io/capture.py | 371 + .../site-packages/py/_io/saferepr.py | 71 + .../site-packages/py/_io/terminalwriter.py | 423 + .../site-packages/py/_log/__init__.py | 2 + .../python3.9/site-packages/py/_log/log.py | 206 + .../site-packages/py/_log/warning.py | 79 + .../site-packages/py/_path/__init__.py | 1 + .../site-packages/py/_path/cacheutil.py | 114 + .../site-packages/py/_path/common.py | 459 + .../python3.9/site-packages/py/_path/local.py | 1030 + .../site-packages/py/_path/svnurl.py | 380 + .../python3.9/site-packages/py/_path/svnwc.py | 1240 + .../site-packages/py/_process/__init__.py | 1 + .../site-packages/py/_process/cmdexec.py | 49 + .../site-packages/py/_process/forkedfunc.py | 120 + .../site-packages/py/_process/killproc.py | 23 + myenv/lib/python3.9/site-packages/py/_std.py | 27 + .../py/_vendored_packages/__init__.py | 0 .../apipkg-2.0.0.dist-info/INSTALLER | 1 + .../apipkg-2.0.0.dist-info/LICENSE | 18 + .../apipkg-2.0.0.dist-info/METADATA | 125 + .../apipkg-2.0.0.dist-info/RECORD | 11 + .../apipkg-2.0.0.dist-info/REQUESTED | 0 .../apipkg-2.0.0.dist-info/WHEEL | 6 + .../apipkg-2.0.0.dist-info/top_level.txt | 1 + .../py/_vendored_packages/apipkg/__init__.py | 217 + .../py/_vendored_packages/apipkg/version.py | 5 + .../iniconfig-1.1.1.dist-info/INSTALLER | 1 + .../iniconfig-1.1.1.dist-info/LICENSE | 19 + .../iniconfig-1.1.1.dist-info/METADATA | 78 + .../iniconfig-1.1.1.dist-info/RECORD | 11 + .../iniconfig-1.1.1.dist-info/REQUESTED | 0 .../iniconfig-1.1.1.dist-info/WHEEL | 6 + .../iniconfig-1.1.1.dist-info/top_level.txt | 1 + .../_vendored_packages/iniconfig/__init__.py | 165 + .../_vendored_packages/iniconfig/__init__.pyi | 31 + .../py/_vendored_packages/iniconfig/py.typed | 0 .../python3.9/site-packages/py/_version.py | 5 + .../lib/python3.9/site-packages/py/_xmlgen.py | 255 + .../lib/python3.9/site-packages/py/error.pyi | 129 + .../python3.9/site-packages/py/iniconfig.pyi | 31 + myenv/lib/python3.9/site-packages/py/io.pyi | 130 + myenv/lib/python3.9/site-packages/py/path.pyi | 197 + myenv/lib/python3.9/site-packages/py/py.typed | 0 myenv/lib/python3.9/site-packages/py/test.py | 10 + myenv/lib/python3.9/site-packages/py/xml.pyi | 25 + .../pyasn1-0.4.8.dist-info/INSTALLER | 1 + .../pyasn1-0.4.8.dist-info/LICENSE.rst | 24 + .../pyasn1-0.4.8.dist-info/METADATA | 38 + .../pyasn1-0.4.8.dist-info/RECORD | 43 + .../pyasn1-0.4.8.dist-info/WHEEL | 6 + .../pyasn1-0.4.8.dist-info/top_level.txt | 1 + .../pyasn1-0.4.8.dist-info/zip-safe | 1 + .../site-packages/pyasn1/__init__.py | 7 + .../site-packages/pyasn1/codec/__init__.py | 1 + .../pyasn1/codec/ber/__init__.py | 1 + .../site-packages/pyasn1/codec/ber/decoder.py | 1682 + .../site-packages/pyasn1/codec/ber/encoder.py | 890 + .../site-packages/pyasn1/codec/ber/eoo.py | 28 + .../pyasn1/codec/cer/__init__.py | 1 + .../site-packages/pyasn1/codec/cer/decoder.py | 114 + .../site-packages/pyasn1/codec/cer/encoder.py | 313 + .../pyasn1/codec/der/__init__.py | 1 + .../site-packages/pyasn1/codec/der/decoder.py | 94 + .../site-packages/pyasn1/codec/der/encoder.py | 107 + .../pyasn1/codec/native/__init__.py | 1 + .../pyasn1/codec/native/decoder.py | 213 + .../pyasn1/codec/native/encoder.py | 256 + .../site-packages/pyasn1/compat/__init__.py | 1 + .../site-packages/pyasn1/compat/binary.py | 33 + .../site-packages/pyasn1/compat/calling.py | 20 + .../pyasn1/compat/dateandtime.py | 22 + .../site-packages/pyasn1/compat/integer.py | 110 + .../site-packages/pyasn1/compat/octets.py | 46 + .../site-packages/pyasn1/compat/string.py | 26 + .../python3.9/site-packages/pyasn1/debug.py | 157 + .../python3.9/site-packages/pyasn1/error.py | 75 + .../site-packages/pyasn1/type/__init__.py | 1 + .../site-packages/pyasn1/type/base.py | 707 + .../site-packages/pyasn1/type/char.py | 335 + .../site-packages/pyasn1/type/constraint.py | 756 + .../site-packages/pyasn1/type/error.py | 11 + .../site-packages/pyasn1/type/namedtype.py | 561 + .../site-packages/pyasn1/type/namedval.py | 192 + .../site-packages/pyasn1/type/opentype.py | 104 + .../site-packages/pyasn1/type/tag.py | 335 + .../site-packages/pyasn1/type/tagmap.py | 96 + .../site-packages/pyasn1/type/univ.py | 3321 + .../site-packages/pyasn1/type/useful.py | 191 + .../pycparser-2.21.dist-info/INSTALLER | 1 + .../pycparser-2.21.dist-info/LICENSE | 27 + .../pycparser-2.21.dist-info/METADATA | 31 + .../pycparser-2.21.dist-info/RECORD | 24 + .../pycparser-2.21.dist-info/WHEEL | 6 + .../pycparser-2.21.dist-info/top_level.txt | 1 + .../site-packages/pycparser/__init__.py | 90 + .../site-packages/pycparser/_ast_gen.py | 336 + .../site-packages/pycparser/_build_tables.py | 37 + .../site-packages/pycparser/_c_ast.cfg | 195 + .../site-packages/pycparser/ast_transforms.py | 164 + .../site-packages/pycparser/c_ast.py | 1125 + .../site-packages/pycparser/c_generator.py | 502 + .../site-packages/pycparser/c_lexer.py | 554 + .../site-packages/pycparser/c_parser.py | 1936 + .../site-packages/pycparser/lextab.py | 10 + .../site-packages/pycparser/ply/__init__.py | 5 + .../site-packages/pycparser/ply/cpp.py | 905 + .../site-packages/pycparser/ply/ctokens.py | 133 + .../site-packages/pycparser/ply/lex.py | 1099 + .../site-packages/pycparser/ply/yacc.py | 3494 + .../site-packages/pycparser/ply/ygen.py | 74 + .../site-packages/pycparser/plyparser.py | 133 + .../site-packages/pycparser/yacctab.py | 366 + .../pydantic-1.9.1.dist-info/INSTALLER | 1 + .../pydantic-1.9.1.dist-info/LICENSE | 21 + .../pydantic-1.9.1.dist-info/METADATA | 1115 + .../pydantic-1.9.1.dist-info/RECORD | 59 + .../pydantic-1.9.1.dist-info/WHEEL | 5 + .../pydantic-1.9.1.dist-info/entry_points.txt | 2 + .../pydantic-1.9.1.dist-info/top_level.txt | 1 + .../pydantic/__init__.cpython-39-darwin.so | Bin 0 -> 73592 bytes .../site-packages/pydantic/__init__.py | 124 + .../_hypothesis_plugin.cpython-39-darwin.so | Bin 0 -> 369376 bytes .../pydantic/_hypothesis_plugin.py | 364 + .../annotated_types.cpython-39-darwin.so | Bin 0 -> 91768 bytes .../site-packages/pydantic/annotated_types.py | 52 + .../class_validators.cpython-39-darwin.so | Bin 0 -> 328808 bytes .../pydantic/class_validators.py | 337 + .../pydantic/color.cpython-39-darwin.so | Bin 0 -> 406464 bytes .../python3.9/site-packages/pydantic/color.py | 488 + .../pydantic/config.cpython-39-darwin.so | Bin 0 -> 125184 bytes .../site-packages/pydantic/config.py | 126 + .../pydantic/dataclasses.cpython-39-darwin.so | Bin 0 -> 268248 bytes .../site-packages/pydantic/dataclasses.py | 277 + .../datetime_parse.cpython-39-darwin.so | Bin 0 -> 193192 bytes .../site-packages/pydantic/datetime_parse.py | 248 + .../pydantic/decorator.cpython-39-darwin.so | Bin 0 -> 257608 bytes .../site-packages/pydantic/decorator.py | 259 + .../env_settings.cpython-39-darwin.so | Bin 0 -> 297904 bytes .../site-packages/pydantic/env_settings.py | 306 + .../error_wrappers.cpython-39-darwin.so | Bin 0 -> 206104 bytes .../site-packages/pydantic/error_wrappers.py | 162 + .../pydantic/errors.cpython-39-darwin.so | Bin 0 -> 406296 bytes .../site-packages/pydantic/errors.py | 641 + .../pydantic/fields.cpython-39-darwin.so | Bin 0 -> 820632 bytes .../site-packages/pydantic/fields.py | 1217 + .../site-packages/pydantic/generics.py | 360 + .../pydantic/json.cpython-39-darwin.so | Bin 0 -> 143776 bytes .../python3.9/site-packages/pydantic/json.py | 119 + .../pydantic/main.cpython-39-darwin.so | Bin 0 -> 746376 bytes .../python3.9/site-packages/pydantic/main.py | 1071 + .../pydantic/mypy.cpython-39-darwin.so | Bin 0 -> 607640 bytes .../python3.9/site-packages/pydantic/mypy.py | 739 + .../pydantic/networks.cpython-39-darwin.so | Bin 0 -> 419464 bytes .../site-packages/pydantic/networks.py | 580 + .../pydantic/parse.cpython-39-darwin.so | Bin 0 -> 95528 bytes .../python3.9/site-packages/pydantic/parse.py | 66 + .../python3.9/site-packages/pydantic/py.typed | 0 .../pydantic/schema.cpython-39-darwin.so | Bin 0 -> 842224 bytes .../site-packages/pydantic/schema.py | 1150 + .../pydantic/tools.cpython-39-darwin.so | Bin 0 -> 141112 bytes .../python3.9/site-packages/pydantic/tools.py | 92 + .../pydantic/types.cpython-39-darwin.so | Bin 0 -> 762120 bytes .../python3.9/site-packages/pydantic/types.py | 1118 + .../pydantic/typing.cpython-39-darwin.so | Bin 0 -> 439696 bytes .../site-packages/pydantic/typing.py | 600 + .../pydantic/utils.cpython-39-darwin.so | Bin 0 -> 586976 bytes .../python3.9/site-packages/pydantic/utils.py | 789 + .../pydantic/validators.cpython-39-darwin.so | Bin 0 -> 689776 bytes .../site-packages/pydantic/validators.py | 723 + .../pydantic/version.cpython-39-darwin.so | Bin 0 -> 94808 bytes .../site-packages/pydantic/version.py | 30 + .../pylint-2.13.9.dist-info/CONTRIBUTORS.txt | 549 + .../pylint-2.13.9.dist-info/INSTALLER | 1 + .../pylint-2.13.9.dist-info/LICENSE | 340 + .../pylint-2.13.9.dist-info/METADATA | 239 + .../pylint-2.13.9.dist-info/RECORD | 159 + .../pylint-2.13.9.dist-info/WHEEL | 5 + .../pylint-2.13.9.dist-info/entry_points.txt | 5 + .../pylint-2.13.9.dist-info/top_level.txt | 1 + .../site-packages/pylint/__init__.py | 86 + .../site-packages/pylint/__main__.py | 10 + .../site-packages/pylint/__pkginfo__.py | 37 + .../site-packages/pylint/checkers/__init__.py | 138 + .../site-packages/pylint/checkers/async.py | 96 + .../pylint/checkers/base/__init__.py | 45 + .../pylint/checkers/base/basic_checker.py | 830 + .../checkers/base/basic_error_checker.py | 572 + .../checkers/base/comparison_checker.py | 295 + .../pylint/checkers/base/docstring_checker.py | 209 + .../checkers/base/name_checker/__init__.py | 25 + .../checkers/base/name_checker/checker.py | 590 + .../base/name_checker/naming_style.py | 175 + .../pylint/checkers/base/pass_checker.py | 28 + .../pylint/checkers/base_checker.py | 190 + .../pylint/checkers/classes/__init__.py | 16 + .../pylint/checkers/classes/class_checker.py | 2151 + .../classes/special_methods_checker.py | 391 + .../pylint/checkers/deprecated.py | 247 + .../pylint/checkers/design_analysis.py | 651 + .../pylint/checkers/ellipsis_checker.py | 57 + .../pylint/checkers/exceptions.py | 544 + .../site-packages/pylint/checkers/format.py | 782 + .../site-packages/pylint/checkers/imports.py | 952 + .../site-packages/pylint/checkers/logging.py | 384 + .../pylint/checkers/mapreduce_checker.py | 17 + .../site-packages/pylint/checkers/misc.py | 182 + .../checkers/modified_iterating_checker.py | 156 + .../site-packages/pylint/checkers/newstyle.py | 123 + .../pylint/checkers/non_ascii_names.py | 201 + .../pylint/checkers/raw_metrics.py | 117 + .../pylint/checkers/refactoring/__init__.py | 32 + .../implicit_booleaness_checker.py | 222 + .../checkers/refactoring/not_checker.py | 83 + .../refactoring/recommendation_checker.py | 411 + .../refactoring/refactoring_checker.py | 1966 + .../site-packages/pylint/checkers/similar.py | 946 + .../site-packages/pylint/checkers/spelling.py | 448 + .../site-packages/pylint/checkers/stdlib.py | 770 + .../site-packages/pylint/checkers/strings.py | 980 + .../pylint/checkers/threading_checker.py | 60 + .../pylint/checkers/typecheck.py | 2080 + .../site-packages/pylint/checkers/unicode.py | 536 + .../pylint/checkers/unsupported_version.py | 86 + .../site-packages/pylint/checkers/utils.py | 1738 + .../pylint/checkers/variables.py | 2871 + .../site-packages/pylint/config/__init__.py | 112 + .../pylint/config/config_initialization.py | 77 + .../pylint/config/configuration_mixin.py | 28 + .../config/find_default_config_files.py | 82 + .../pylint/config/man_help_formatter.py | 121 + .../site-packages/pylint/config/option.py | 203 + .../pylint/config/option_manager_mixin.py | 392 + .../pylint/config/option_parser.py | 47 + .../pylint/config/options_provider_mixin.py | 111 + .../site-packages/pylint/constants.py | 198 + .../python3.9/site-packages/pylint/epylint.py | 181 + .../site-packages/pylint/exceptions.py | 29 + .../pylint/extensions/__init__.py | 18 + .../pylint/extensions/_check_docs_utils.py | 821 + .../pylint/extensions/bad_builtin.py | 65 + .../pylint/extensions/broad_try_clause.py | 72 + .../pylint/extensions/check_elif.py | 61 + .../pylint/extensions/code_style.py | 314 + .../pylint/extensions/comparetozero.py | 77 + .../pylint/extensions/comparison_placement.py | 71 + .../pylint/extensions/confusing_elif.py | 53 + .../extensions/consider_ternary_expression.py | 57 + .../pylint/extensions/docparams.py | 649 + .../pylint/extensions/docstyle.py | 88 + .../pylint/extensions/empty_comment.py | 67 + .../pylint/extensions/emptystring.py | 72 + .../pylint/extensions/eq_without_hash.py | 41 + .../pylint/extensions/for_any_all.py | 73 + .../site-packages/pylint/extensions/mccabe.py | 195 + .../extensions/overlapping_exceptions.py | 91 + .../pylint/extensions/private_import.py | 252 + .../extensions/redefined_variable_type.py | 109 + .../pylint/extensions/set_membership.py | 55 + .../site-packages/pylint/extensions/typing.py | 436 + .../pylint/extensions/while_used.py | 36 + .../python3.9/site-packages/pylint/graph.py | 201 + .../site-packages/pylint/interfaces.py | 106 + .../site-packages/pylint/lint/__init__.py | 48 + .../pylint/lint/expand_modules.py | 158 + .../site-packages/pylint/lint/parallel.py | 184 + .../site-packages/pylint/lint/pylinter.py | 1842 + .../pylint/lint/report_functions.py | 85 + .../site-packages/pylint/lint/run.py | 462 + .../site-packages/pylint/lint/utils.py | 137 + .../site-packages/pylint/message/__init__.py | 17 + .../site-packages/pylint/message/message.py | 94 + .../pylint/message/message_definition.py | 117 + .../message/message_definition_store.py | 112 + .../pylint/message/message_id_store.py | 135 + .../pylint/pyreverse/__init__.py | 7 + .../pylint/pyreverse/diadefslib.py | 222 + .../pylint/pyreverse/diagrams.py | 260 + .../pylint/pyreverse/dot_printer.py | 158 + .../pylint/pyreverse/inspector.py | 333 + .../site-packages/pylint/pyreverse/main.py | 234 + .../pylint/pyreverse/mermaidjs_printer.py | 110 + .../pylint/pyreverse/plantuml_printer.py | 97 + .../site-packages/pylint/pyreverse/printer.py | 127 + .../pylint/pyreverse/printer_factory.py | 24 + .../site-packages/pylint/pyreverse/utils.py | 306 + .../pylint/pyreverse/vcg_printer.py | 283 + .../site-packages/pylint/pyreverse/writer.py | 161 + .../pylint/reporters/__init__.py | 30 + .../pylint/reporters/base_reporter.py | 91 + .../pylint/reporters/collecting_reporter.py | 26 + .../pylint/reporters/json_reporter.py | 52 + .../pylint/reporters/multi_reporter.py | 110 + .../reporters/reports_handler_mix_in.py | 86 + .../site-packages/pylint/reporters/text.py | 340 + .../pylint/reporters/ureports/__init__.py | 7 + .../pylint/reporters/ureports/base_writer.py | 99 + .../pylint/reporters/ureports/nodes.py | 180 + .../pylint/reporters/ureports/text_writer.py | 106 + .../pylint/testutils/__init__.py | 33 + .../pylint/testutils/checker_test_case.py | 95 + .../pylint/testutils/configuration_test.py | 158 + .../pylint/testutils/constants.py | 29 + .../pylint/testutils/decorator.py | 89 + .../pylint/testutils/functional/__init__.py | 23 + .../functional/find_functional_tests.py | 84 + .../functional/lint_module_output_update.py | 55 + .../pylint/testutils/functional/test_file.py | 111 + .../pylint/testutils/functional_test_file.py | 23 + .../pylint/testutils/get_test_info.py | 49 + .../pylint/testutils/global_test_linter.py | 20 + .../pylint/testutils/lint_module_test.py | 266 + .../pylint/testutils/output_line.py | 193 + .../site-packages/pylint/testutils/primer.py | 111 + .../pylint/testutils/pyreverse.py | 51 + .../pylint/testutils/reporter_for_tests.py | 82 + .../pylint/testutils/testing_pylintrc | 9 + .../pylint/testutils/tokenize_str.py | 12 + .../pylint/testutils/unittest_linter.py | 88 + .../python3.9/site-packages/pylint/typing.py | 73 + .../site-packages/pylint/utils/__init__.py | 55 + .../site-packages/pylint/utils/ast_walker.py | 85 + .../site-packages/pylint/utils/docs.py | 79 + .../site-packages/pylint/utils/file_state.py | 184 + .../site-packages/pylint/utils/linterstats.py | 376 + .../pylint/utils/pragma_parser.py | 131 + .../site-packages/pylint/utils/utils.py | 406 + .../pyparsing-3.0.9.dist-info/INSTALLER | 1 + .../pyparsing-3.0.9.dist-info/LICENSE | 18 + .../pyparsing-3.0.9.dist-info/METADATA | 105 + .../pyparsing-3.0.9.dist-info/RECORD | 17 + .../pyparsing-3.0.9.dist-info/WHEEL | 4 + .../site-packages/pyparsing/__init__.py | 331 + .../site-packages/pyparsing/actions.py | 207 + .../site-packages/pyparsing/common.py | 424 + .../python3.9/site-packages/pyparsing/core.py | 5814 + .../pyparsing/diagram/__init__.py | 642 + .../site-packages/pyparsing/exceptions.py | 267 + .../site-packages/pyparsing/helpers.py | 1088 + .../site-packages/pyparsing/py.typed | 0 .../site-packages/pyparsing/results.py | 760 + .../site-packages/pyparsing/testing.py | 331 + .../site-packages/pyparsing/unicode.py | 352 + .../python3.9/site-packages/pyparsing/util.py | 235 + .../pytest-6.2.5.dist-info/INSTALLER | 1 + .../pytest-6.2.5.dist-info/LICENSE | 21 + .../pytest-6.2.5.dist-info/METADATA | 215 + .../pytest-6.2.5.dist-info/RECORD | 75 + .../pytest-6.2.5.dist-info/WHEEL | 5 + .../pytest-6.2.5.dist-info/entry_points.txt | 4 + .../pytest-6.2.5.dist-info/top_level.txt | 2 + .../site-packages/pytest/__init__.py | 121 + .../site-packages/pytest/__main__.py | 5 + .../python3.9/site-packages/pytest/collect.py | 39 + .../python3.9/site-packages/pytest/py.typed | 0 .../pytest_asyncio-0.16.0.dist-info/INSTALLER | 1 + .../pytest_asyncio-0.16.0.dist-info/LICENSE | 202 + .../pytest_asyncio-0.16.0.dist-info/METADATA | 317 + .../pytest_asyncio-0.16.0.dist-info/RECORD | 9 + .../pytest_asyncio-0.16.0.dist-info/WHEEL | 5 + .../entry_points.txt | 3 + .../top_level.txt | 1 + .../site-packages/pytest_asyncio/__init__.py | 2 + .../site-packages/pytest_asyncio/plugin.py | 260 + .../pytest_depends-1.0.1.dist-info/INSTALLER | 1 + .../pytest_depends-1.0.1.dist-info/LICENSE | 21 + .../pytest_depends-1.0.1.dist-info/METADATA | 151 + .../pytest_depends-1.0.1.dist-info/RECORD | 11 + .../pytest_depends-1.0.1.dist-info/WHEEL | 5 + .../entry_points.txt | 3 + .../top_level.txt | 1 + .../site-packages/pytest_depends/__init__.py | 159 + .../site-packages/pytest_depends/constants.py | 10 + .../site-packages/pytest_depends/main.py | 224 + .../site-packages/pytest_depends/util.py | 124 + .../python_dotenv-0.20.0.dist-info/INSTALLER | 1 + .../python_dotenv-0.20.0.dist-info/LICENSE | 87 + .../python_dotenv-0.20.0.dist-info/METADATA | 594 + .../python_dotenv-0.20.0.dist-info/RECORD | 16 + .../python_dotenv-0.20.0.dist-info/WHEEL | 5 + .../entry_points.txt | 3 + .../top_level.txt | 1 + .../python_jose-3.3.0.dist-info/INSTALLER | 1 + .../python_jose-3.3.0.dist-info/LICENSE | 22 + .../python_jose-3.3.0.dist-info/METADATA | 148 + .../python_jose-3.3.0.dist-info/RECORD | 21 + .../python_jose-3.3.0.dist-info/WHEEL | 6 + .../python_jose-3.3.0.dist-info/top_level.txt | 2 + .../INSTALLER | 1 + .../LICENSE.txt | 14 + .../python_multipart-0.0.5.dist-info/METADATA | 22 + .../python_multipart-0.0.5.dist-info/RECORD | 14 + .../python_multipart-0.0.5.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../rfc3986-1.5.0.dist-info/AUTHORS.rst | 14 + .../rfc3986-1.5.0.dist-info/INSTALLER | 1 + .../rfc3986-1.5.0.dist-info/LICENSE | 13 + .../rfc3986-1.5.0.dist-info/METADATA | 230 + .../rfc3986-1.5.0.dist-info/RECORD | 20 + .../rfc3986-1.5.0.dist-info/WHEEL | 6 + .../rfc3986-1.5.0.dist-info/top_level.txt | 1 + .../site-packages/rfc3986/__init__.py | 56 + .../python3.9/site-packages/rfc3986/_mixin.py | 373 + .../site-packages/rfc3986/abnf_regexp.py | 282 + .../python3.9/site-packages/rfc3986/api.py | 106 + .../site-packages/rfc3986/builder.py | 389 + .../python3.9/site-packages/rfc3986/compat.py | 60 + .../site-packages/rfc3986/exceptions.py | 124 + .../python3.9/site-packages/rfc3986/iri.py | 162 + .../python3.9/site-packages/rfc3986/misc.py | 135 + .../site-packages/rfc3986/normalizers.py | 172 + .../site-packages/rfc3986/parseresult.py | 479 + .../python3.9/site-packages/rfc3986/uri.py | 161 + .../site-packages/rfc3986/validators.py | 447 + .../site-packages/rsa-4.8.dist-info/INSTALLER | 1 + .../site-packages/rsa-4.8.dist-info/LICENSE | 13 + .../site-packages/rsa-4.8.dist-info/METADATA | 72 + .../site-packages/rsa-4.8.dist-info/RECORD | 31 + .../site-packages/rsa-4.8.dist-info/WHEEL | 4 + .../rsa-4.8.dist-info/entry_points.txt | 8 + .../python3.9/site-packages/rsa/__init__.py | 60 + .../python3.9/site-packages/rsa/_compat.py | 48 + myenv/lib/python3.9/site-packages/rsa/asn1.py | 52 + myenv/lib/python3.9/site-packages/rsa/cli.py | 321 + .../lib/python3.9/site-packages/rsa/common.py | 184 + myenv/lib/python3.9/site-packages/rsa/core.py | 53 + myenv/lib/python3.9/site-packages/rsa/key.py | 859 + .../python3.9/site-packages/rsa/parallel.py | 96 + myenv/lib/python3.9/site-packages/rsa/pem.py | 134 + .../lib/python3.9/site-packages/rsa/pkcs1.py | 484 + .../python3.9/site-packages/rsa/pkcs1_v2.py | 100 + .../lib/python3.9/site-packages/rsa/prime.py | 198 + .../lib/python3.9/site-packages/rsa/py.typed | 1 + .../python3.9/site-packages/rsa/randnum.py | 95 + .../python3.9/site-packages/rsa/transform.py | 72 + myenv/lib/python3.9/site-packages/rsa/util.py | 97 + .../setuptools-49.2.1.dist-info/INSTALLER | 1 + .../setuptools-49.2.1.dist-info/LICENSE | 19 + .../setuptools-49.2.1.dist-info/METADATA | 109 + .../setuptools-49.2.1.dist-info/RECORD | 297 + .../setuptools-49.2.1.dist-info/REQUESTED | 0 .../setuptools-49.2.1.dist-info/WHEEL | 5 + .../dependency_links.txt | 2 + .../entry_points.txt | 68 + .../setuptools-49.2.1.dist-info/top_level.txt | 3 + .../setuptools-49.2.1.dist-info/zip-safe | 1 + .../site-packages/setuptools/__init__.py | 253 + .../setuptools/_deprecation_warning.py | 7 + .../setuptools/_distutils/__init__.py | 15 + .../setuptools/_distutils/_msvccompiler.py | 537 + .../setuptools/_distutils/archive_util.py | 256 + .../setuptools/_distutils/bcppcompiler.py | 393 + .../setuptools/_distutils/ccompiler.py | 1116 + .../setuptools/_distutils/cmd.py | 403 + .../setuptools/_distutils/command/__init__.py | 31 + .../setuptools/_distutils/command/bdist.py | 143 + .../_distutils/command/bdist_dumb.py | 123 + .../_distutils/command/bdist_msi.py | 749 + .../_distutils/command/bdist_rpm.py | 579 + .../_distutils/command/bdist_wininst.py | 377 + .../setuptools/_distutils/command/build.py | 157 + .../_distutils/command/build_clib.py | 209 + .../_distutils/command/build_ext.py | 754 + .../setuptools/_distutils/command/build_py.py | 416 + .../_distutils/command/build_scripts.py | 160 + .../setuptools/_distutils/command/check.py | 148 + .../setuptools/_distutils/command/clean.py | 76 + .../setuptools/_distutils/command/config.py | 344 + .../setuptools/_distutils/command/install.py | 677 + .../_distutils/command/install_data.py | 79 + .../_distutils/command/install_egg_info.py | 77 + .../_distutils/command/install_headers.py | 47 + .../_distutils/command/install_lib.py | 217 + .../_distutils/command/install_scripts.py | 60 + .../setuptools/_distutils/command/register.py | 304 + .../setuptools/_distutils/command/sdist.py | 494 + .../setuptools/_distutils/command/upload.py | 214 + .../setuptools/_distutils/config.py | 130 + .../setuptools/_distutils/core.py | 234 + .../setuptools/_distutils/cygwinccompiler.py | 403 + .../setuptools/_distutils/debug.py | 5 + .../setuptools/_distutils/dep_util.py | 92 + .../setuptools/_distutils/dir_util.py | 210 + .../setuptools/_distutils/dist.py | 1257 + .../setuptools/_distutils/errors.py | 97 + .../setuptools/_distutils/extension.py | 240 + .../setuptools/_distutils/fancy_getopt.py | 457 + .../setuptools/_distutils/file_util.py | 238 + .../setuptools/_distutils/filelist.py | 327 + .../setuptools/_distutils/log.py | 77 + .../setuptools/_distutils/msvc9compiler.py | 788 + .../setuptools/_distutils/msvccompiler.py | 643 + .../setuptools/_distutils/spawn.py | 125 + .../setuptools/_distutils/sysconfig.py | 573 + .../setuptools/_distutils/text_file.py | 286 + .../setuptools/_distutils/unixccompiler.py | 328 + .../setuptools/_distutils/util.py | 559 + .../setuptools/_distutils/version.py | 347 + .../setuptools/_distutils/versionpredicate.py | 166 + .../site-packages/setuptools/_imp.py | 82 + .../setuptools/_vendor/__init__.py | 0 .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__about__.py | 27 + .../setuptools/_vendor/packaging/__init__.py | 26 + .../setuptools/_vendor/packaging/_compat.py | 31 + .../_vendor/packaging/_structures.py | 68 + .../setuptools/_vendor/packaging/markers.py | 296 + .../_vendor/packaging/requirements.py | 138 + .../_vendor/packaging/specifiers.py | 749 + .../setuptools/_vendor/packaging/tags.py | 404 + .../setuptools/_vendor/packaging/utils.py | 57 + .../setuptools/_vendor/packaging/version.py | 420 + .../setuptools/_vendor/pyparsing.py | 5742 + .../site-packages/setuptools/_vendor/six.py | 868 + .../site-packages/setuptools/archive_util.py | 175 + .../site-packages/setuptools/build_meta.py | 271 + .../site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .../site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 17 + .../site-packages/setuptools/command/alias.py | 80 + .../setuptools/command/bdist_egg.py | 510 + .../setuptools/command/bdist_rpm.py | 43 + .../setuptools/command/bdist_wininst.py | 30 + .../setuptools/command/build_clib.py | 101 + .../setuptools/command/build_ext.py | 332 + .../setuptools/command/build_py.py | 276 + .../setuptools/command/develop.py | 220 + .../setuptools/command/dist_info.py | 36 + .../setuptools/command/easy_install.py | 2339 + .../setuptools/command/egg_info.py | 721 + .../setuptools/command/install.py | 125 + .../setuptools/command/install_egg_info.py | 62 + .../setuptools/command/install_lib.py | 122 + .../setuptools/command/install_scripts.py | 68 + .../setuptools/command/launcher manifest.xml | 15 + .../setuptools/command/py36compat.py | 136 + .../setuptools/command/register.py | 18 + .../setuptools/command/rotate.py | 66 + .../setuptools/command/saveopts.py | 22 + .../site-packages/setuptools/command/sdist.py | 252 + .../setuptools/command/setopt.py | 149 + .../site-packages/setuptools/command/test.py | 280 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 206 + .../site-packages/setuptools/config.py | 701 + .../site-packages/setuptools/dep_util.py | 25 + .../site-packages/setuptools/depends.py | 176 + .../site-packages/setuptools/dist.py | 1035 + .../setuptools/distutils_patch.py | 61 + .../site-packages/setuptools/errors.py | 16 + .../site-packages/setuptools/extension.py | 57 + .../setuptools/extern/__init__.py | 66 + .../site-packages/setuptools/glob.py | 174 + .../site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .../site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/installer.py | 150 + .../site-packages/setuptools/launch.py | 36 + .../site-packages/setuptools/lib2to3_ex.py | 71 + .../site-packages/setuptools/monkey.py | 179 + .../site-packages/setuptools/msvc.py | 1831 + .../site-packages/setuptools/namespaces.py | 111 + .../site-packages/setuptools/package_index.py | 1140 + .../site-packages/setuptools/py27compat.py | 60 + .../site-packages/setuptools/py31compat.py | 32 + .../site-packages/setuptools/py33compat.py | 59 + .../site-packages/setuptools/py34compat.py | 13 + .../site-packages/setuptools/sandbox.py | 492 + .../setuptools/script (dev).tmpl | 6 + .../site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/ssl_support.py | 265 + .../site-packages/setuptools/unicode_utils.py | 44 + .../site-packages/setuptools/version.py | 6 + .../site-packages/setuptools/wheel.py | 217 + .../setuptools/windows_support.py | 29 + .../six-1.16.0.dist-info/INSTALLER | 1 + .../six-1.16.0.dist-info/LICENSE | 18 + .../six-1.16.0.dist-info/METADATA | 49 + .../site-packages/six-1.16.0.dist-info/RECORD | 7 + .../site-packages/six-1.16.0.dist-info/WHEEL | 6 + .../six-1.16.0.dist-info/top_level.txt | 1 + myenv/lib/python3.9/site-packages/six.py | 998 + .../sniffio-1.2.0.dist-info/INSTALLER | 1 + .../sniffio-1.2.0.dist-info/LICENSE | 3 + .../sniffio-1.2.0.dist-info/LICENSE.APACHE2 | 202 + .../sniffio-1.2.0.dist-info/LICENSE.MIT | 20 + .../sniffio-1.2.0.dist-info/METADATA | 103 + .../sniffio-1.2.0.dist-info/RECORD | 14 + .../sniffio-1.2.0.dist-info/WHEEL | 5 + .../sniffio-1.2.0.dist-info/top_level.txt | 1 + .../site-packages/sniffio/__init__.py | 14 + .../python3.9/site-packages/sniffio/_impl.py | 83 + .../site-packages/sniffio/_tests/__init__.py | 0 .../sniffio/_tests/test_sniffio.py | 67 + .../site-packages/sniffio/_version.py | 3 + .../python3.9/site-packages/sniffio/py.typed | 0 .../starlette-0.16.0.dist-info/INSTALLER | 1 + .../starlette-0.16.0.dist-info/LICENSE.md | 27 + .../starlette-0.16.0.dist-info/METADATA | 211 + .../starlette-0.16.0.dist-info/RECORD | 39 + .../starlette-0.16.0.dist-info/WHEEL | 5 + .../starlette-0.16.0.dist-info/top_level.txt | 1 + .../site-packages/starlette/__init__.py | 1 + .../site-packages/starlette/applications.py | 201 + .../site-packages/starlette/authentication.py | 142 + .../site-packages/starlette/background.py | 35 + .../site-packages/starlette/concurrency.py | 61 + .../site-packages/starlette/config.py | 109 + .../site-packages/starlette/convertors.py | 81 + .../site-packages/starlette/datastructures.py | 667 + .../site-packages/starlette/endpoints.py | 117 + .../site-packages/starlette/exceptions.py | 98 + .../site-packages/starlette/formparsers.py | 234 + .../site-packages/starlette/graphql.py | 275 + .../starlette/middleware/__init__.py | 17 + .../starlette/middleware/authentication.py | 52 + .../starlette/middleware/base.py | 62 + .../starlette/middleware/cors.py | 177 + .../starlette/middleware/errors.py | 251 + .../starlette/middleware/gzip.py | 104 + .../starlette/middleware/httpsredirect.py | 19 + .../starlette/middleware/sessions.py | 77 + .../starlette/middleware/trustedhost.py | 60 + .../starlette/middleware/wsgi.py | 133 + .../site-packages/starlette/py.typed | 0 .../site-packages/starlette/requests.py | 283 + .../site-packages/starlette/responses.py | 313 + .../site-packages/starlette/routing.py | 762 + .../site-packages/starlette/schemas.py | 135 + .../site-packages/starlette/staticfiles.py | 227 + .../site-packages/starlette/status.py | 92 + .../site-packages/starlette/templating.py | 94 + .../site-packages/starlette/testclient.py | 576 + .../site-packages/starlette/types.py | 9 + .../site-packages/starlette/websockets.py | 150 + .../toml-0.10.2.dist-info/INSTALLER | 1 + .../toml-0.10.2.dist-info/LICENSE | 27 + .../toml-0.10.2.dist-info/METADATA | 255 + .../toml-0.10.2.dist-info/RECORD | 11 + .../site-packages/toml-0.10.2.dist-info/WHEEL | 6 + .../toml-0.10.2.dist-info/top_level.txt | 1 + .../python3.9/site-packages/toml/__init__.py | 25 + .../python3.9/site-packages/toml/decoder.py | 1057 + .../python3.9/site-packages/toml/encoder.py | 304 + .../python3.9/site-packages/toml/ordered.py | 15 + myenv/lib/python3.9/site-packages/toml/tz.py | 24 + .../tomli-1.2.3.dist-info/INSTALLER | 1 + .../tomli-1.2.3.dist-info/LICENSE | 21 + .../tomli-1.2.3.dist-info/METADATA | 208 + .../tomli-1.2.3.dist-info/RECORD | 10 + .../site-packages/tomli-1.2.3.dist-info/WHEEL | 4 + .../python3.9/site-packages/tomli/__init__.py | 9 + .../python3.9/site-packages/tomli/_parser.py | 663 + .../lib/python3.9/site-packages/tomli/_re.py | 101 + .../python3.9/site-packages/tomli/_types.py | 6 + .../python3.9/site-packages/tomli/py.typed | 1 + .../tomlkit-0.7.2.dist-info/INSTALLER | 1 + .../tomlkit-0.7.2.dist-info/LICENSE | 20 + .../tomlkit-0.7.2.dist-info/METADATA | 194 + .../tomlkit-0.7.2.dist-info/RECORD | 18 + .../tomlkit-0.7.2.dist-info/WHEEL | 4 + .../site-packages/tomlkit/__init__.py | 25 + .../site-packages/tomlkit/_compat.py | 179 + .../python3.9/site-packages/tomlkit/_utils.py | 144 + .../python3.9/site-packages/tomlkit/api.py | 142 + .../site-packages/tomlkit/container.py | 791 + .../site-packages/tomlkit/exceptions.py | 223 + .../python3.9/site-packages/tomlkit/items.py | 1331 + .../python3.9/site-packages/tomlkit/parser.py | 1302 + .../python3.9/site-packages/tomlkit/py.typed | 0 .../python3.9/site-packages/tomlkit/source.py | 193 + .../site-packages/tomlkit/toml_char.py | 67 + .../site-packages/tomlkit/toml_document.py | 7 + .../site-packages/tomlkit/toml_file.py | 24 + .../INSTALLER | 1 + .../typing_extensions-4.3.0.dist-info/LICENSE | 254 + .../METADATA | 176 + .../typing_extensions-4.3.0.dist-info/RECORD | 6 + .../typing_extensions-4.3.0.dist-info/WHEEL | 4 + .../site-packages/typing_extensions.py | 2069 + .../uvicorn-0.16.0.dist-info/INSTALLER | 1 + .../uvicorn-0.16.0.dist-info/LICENSE.md | 27 + .../uvicorn-0.16.0.dist-info/METADATA | 129 + .../uvicorn-0.16.0.dist-info/RECORD | 49 + .../uvicorn-0.16.0.dist-info/WHEEL | 5 + .../uvicorn-0.16.0.dist-info/entry_points.txt | 4 + .../uvicorn-0.16.0.dist-info/top_level.txt | 9 + .../site-packages/uvicorn/__init__.py | 5 + .../site-packages/uvicorn/__main__.py | 4 + .../uvicorn/_handlers/__init__.py | 0 .../site-packages/uvicorn/_handlers/http.py | 99 + .../python3.9/site-packages/uvicorn/_types.py | 14 + .../python3.9/site-packages/uvicorn/config.py | 568 + .../site-packages/uvicorn/importer.py | 38 + .../uvicorn/lifespan/__init__.py | 0 .../site-packages/uvicorn/lifespan/off.py | 12 + .../site-packages/uvicorn/lifespan/on.py | 135 + .../site-packages/uvicorn/logging.py | 117 + .../site-packages/uvicorn/loops/__init__.py | 0 .../site-packages/uvicorn/loops/asyncio.py | 11 + .../site-packages/uvicorn/loops/auto.py | 11 + .../site-packages/uvicorn/loops/uvloop.py | 7 + .../python3.9/site-packages/uvicorn/main.py | 461 + .../uvicorn/middleware/__init__.py | 0 .../site-packages/uvicorn/middleware/asgi2.py | 17 + .../site-packages/uvicorn/middleware/debug.py | 112 + .../uvicorn/middleware/message_logger.py | 85 + .../uvicorn/middleware/proxy_headers.py | 75 + .../site-packages/uvicorn/middleware/wsgi.py | 179 + .../uvicorn/protocols/__init__.py | 0 .../uvicorn/protocols/http/__init__.py | 0 .../uvicorn/protocols/http/auto.py | 14 + .../uvicorn/protocols/http/flow_control.py | 66 + .../uvicorn/protocols/http/h11_impl.py | 516 + .../uvicorn/protocols/http/httptools_impl.py | 545 + .../site-packages/uvicorn/protocols/utils.py | 56 + .../uvicorn/protocols/websockets/__init__.py | 0 .../uvicorn/protocols/websockets/auto.py | 19 + .../protocols/websockets/websockets_impl.py | 305 + .../protocols/websockets/wsproto_impl.py | 325 + .../python3.9/site-packages/uvicorn/server.py | 316 + .../site-packages/uvicorn/subprocess.py | 76 + .../uvicorn/supervisors/__init__.py | 14 + .../uvicorn/supervisors/basereload.py | 93 + .../uvicorn/supervisors/multiprocess.py | 74 + .../uvicorn/supervisors/statreload.py | 52 + .../uvicorn/supervisors/watchgodreload.py | 152 + .../site-packages/uvicorn/workers.py | 92 + .../uvloop-0.16.0.dist-info/INSTALLER | 1 + .../uvloop-0.16.0.dist-info/LICENSE-APACHE | 203 + .../uvloop-0.16.0.dist-info/LICENSE-MIT | 21 + .../uvloop-0.16.0.dist-info/METADATA | 157 + .../uvloop-0.16.0.dist-info/RECORD | 66 + .../uvloop-0.16.0.dist-info/WHEEL | 5 + .../uvloop-0.16.0.dist-info/top_level.txt | 1 + .../site-packages/uvloop/__init__.py | 54 + .../python3.9/site-packages/uvloop/_noop.py | 3 + .../site-packages/uvloop/_testbase.py | 547 + .../site-packages/uvloop/_version.py | 13 + .../site-packages/uvloop/cbhandles.pxd | 38 + .../site-packages/uvloop/cbhandles.pyx | 428 + .../python3.9/site-packages/uvloop/dns.pyx | 422 + .../python3.9/site-packages/uvloop/errors.pyx | 113 + .../site-packages/uvloop/handles/async_.pxd | 11 + .../site-packages/uvloop/handles/async_.pyx | 54 + .../uvloop/handles/basetransport.pxd | 54 + .../uvloop/handles/basetransport.pyx | 293 + .../site-packages/uvloop/handles/check.pxd | 14 + .../site-packages/uvloop/handles/check.pyx | 70 + .../site-packages/uvloop/handles/handle.pxd | 48 + .../site-packages/uvloop/handles/handle.pyx | 393 + .../site-packages/uvloop/handles/idle.pxd | 14 + .../site-packages/uvloop/handles/idle.pyx | 70 + .../site-packages/uvloop/handles/pipe.pxd | 33 + .../site-packages/uvloop/handles/pipe.pyx | 223 + .../site-packages/uvloop/handles/poll.pxd | 25 + .../site-packages/uvloop/handles/poll.pyx | 230 + .../site-packages/uvloop/handles/process.pxd | 80 + .../site-packages/uvloop/handles/process.pyx | 774 + .../site-packages/uvloop/handles/stream.pxd | 42 + .../site-packages/uvloop/handles/stream.pyx | 995 + .../uvloop/handles/streamserver.pxd | 26 + .../uvloop/handles/streamserver.pyx | 148 + .../site-packages/uvloop/handles/tcp.pxd | 26 + .../site-packages/uvloop/handles/tcp.pyx | 225 + .../site-packages/uvloop/handles/timer.pxd | 18 + .../site-packages/uvloop/handles/timer.pyx | 87 + .../site-packages/uvloop/handles/udp.pxd | 22 + .../site-packages/uvloop/handles/udp.pyx | 404 + .../site-packages/uvloop/includes/__init__.py | 23 + .../site-packages/uvloop/includes/compat.h | 85 + .../site-packages/uvloop/includes/consts.pxi | 25 + .../site-packages/uvloop/includes/debug.h | 3 + .../site-packages/uvloop/includes/debug.pxd | 3 + .../uvloop/includes/flowcontrol.pxd | 23 + .../uvloop/includes/fork_handler.h | 27 + .../site-packages/uvloop/includes/python.pxd | 31 + .../site-packages/uvloop/includes/stdlib.pxi | 173 + .../site-packages/uvloop/includes/system.pxd | 91 + .../site-packages/uvloop/includes/uv.pxd | 484 + .../lib/python3.9/site-packages/uvloop/loop.c | 174850 +++++++++++++++ .../uvloop/loop.cpython-39-darwin.so | Bin 0 -> 1993608 bytes .../python3.9/site-packages/uvloop/loop.pxd | 229 + .../python3.9/site-packages/uvloop/loop.pyi | 289 + .../python3.9/site-packages/uvloop/loop.pyx | 3335 + .../python3.9/site-packages/uvloop/lru.pyx | 79 + .../site-packages/uvloop/pseudosock.pyx | 209 + .../python3.9/site-packages/uvloop/py.typed | 0 .../site-packages/uvloop/request.pxd | 8 + .../site-packages/uvloop/request.pyx | 65 + .../python3.9/site-packages/uvloop/server.pxd | 19 + .../python3.9/site-packages/uvloop/server.pyx | 136 + .../site-packages/uvloop/sslproto.pxd | 138 + .../site-packages/uvloop/sslproto.pyx | 950 + .../watchgod-0.8.2.dist-info/INSTALLER | 1 + .../watchgod-0.8.2.dist-info/LICENSE | 21 + .../watchgod-0.8.2.dist-info/METADATA | 219 + .../watchgod-0.8.2.dist-info/RECORD | 16 + .../watchgod-0.8.2.dist-info/WHEEL | 5 + .../watchgod-0.8.2.dist-info/entry_points.txt | 2 + .../watchgod-0.8.2.dist-info/top_level.txt | 1 + .../watchgod-0.8.2.dist-info/zip-safe | 1 + .../site-packages/watchgod/__init__.py | 18 + .../site-packages/watchgod/__main__.py | 4 + .../python3.9/site-packages/watchgod/cli.py | 145 + .../python3.9/site-packages/watchgod/main.py | 229 + .../python3.9/site-packages/watchgod/py.typed | 1 + .../site-packages/watchgod/version.py | 3 + .../site-packages/watchgod/watcher.py | 141 + .../websockets-10.3.dist-info/INSTALLER | 1 + .../websockets-10.3.dist-info/LICENSE | 25 + .../websockets-10.3.dist-info/METADATA | 174 + .../websockets-10.3.dist-info/RECORD | 39 + .../websockets-10.3.dist-info/WHEEL | 5 + .../websockets-10.3.dist-info/top_level.txt | 3 + .../site-packages/websockets/__init__.py | 114 + .../site-packages/websockets/__main__.py | 230 + .../site-packages/websockets/auth.py | 4 + .../site-packages/websockets/client.py | 347 + .../site-packages/websockets/connection.py | 702 + .../websockets/datastructures.py | 200 + .../site-packages/websockets/exceptions.py | 398 + .../websockets/extensions/__init__.py | 4 + .../websockets/extensions/base.py | 128 + .../extensions/permessage_deflate.py | 661 + .../site-packages/websockets/frames.py | 443 + .../site-packages/websockets/headers.py | 587 + .../site-packages/websockets/http.py | 30 + .../site-packages/websockets/http11.py | 366 + .../site-packages/websockets/imports.py | 99 + .../websockets/legacy/__init__.py | 0 .../site-packages/websockets/legacy/auth.py | 188 + .../site-packages/websockets/legacy/client.py | 709 + .../websockets/legacy/compatibility.py | 13 + .../websockets/legacy/framing.py | 174 + .../websockets/legacy/handshake.py | 165 + .../site-packages/websockets/legacy/http.py | 201 + .../websockets/legacy/protocol.py | 1605 + .../site-packages/websockets/legacy/server.py | 1156 + .../site-packages/websockets/py.typed | 0 .../site-packages/websockets/server.py | 521 + .../site-packages/websockets/speedups.c | 223 + .../websockets/speedups.cpython-39-darwin.so | Bin 0 -> 34664 bytes .../site-packages/websockets/streams.py | 151 + .../site-packages/websockets/typing.py | 60 + .../python3.9/site-packages/websockets/uri.py | 108 + .../site-packages/websockets/utils.py | 51 + .../site-packages/websockets/version.py | 78 + .../wrapt-1.14.1.dist-info/INSTALLER | 1 + .../wrapt-1.14.1.dist-info/LICENSE | 24 + .../wrapt-1.14.1.dist-info/METADATA | 174 + .../wrapt-1.14.1.dist-info/RECORD | 12 + .../wrapt-1.14.1.dist-info/WHEEL | 5 + .../wrapt-1.14.1.dist-info/top_level.txt | 1 + .../python3.9/site-packages/wrapt/__init__.py | 27 + .../wrapt/_wrappers.cpython-39-darwin.so | Bin 0 -> 74856 bytes .../site-packages/wrapt/arguments.py | 38 + .../site-packages/wrapt/decorators.py | 541 + .../python3.9/site-packages/wrapt/importer.py | 286 + .../python3.9/site-packages/wrapt/wrappers.py | 986 + .../python3.9/site-packages/yaml/__init__.py | 390 + .../yaml/_yaml.cpython-39-darwin.so | Bin 0 -> 462160 bytes .../python3.9/site-packages/yaml/composer.py | 139 + .../site-packages/yaml/constructor.py | 748 + .../lib/python3.9/site-packages/yaml/cyaml.py | 101 + .../python3.9/site-packages/yaml/dumper.py | 62 + .../python3.9/site-packages/yaml/emitter.py | 1137 + .../lib/python3.9/site-packages/yaml/error.py | 75 + .../python3.9/site-packages/yaml/events.py | 86 + .../python3.9/site-packages/yaml/loader.py | 63 + .../lib/python3.9/site-packages/yaml/nodes.py | 49 + .../python3.9/site-packages/yaml/parser.py | 589 + .../python3.9/site-packages/yaml/reader.py | 185 + .../site-packages/yaml/representer.py | 389 + .../python3.9/site-packages/yaml/resolver.py | 227 + .../python3.9/site-packages/yaml/scanner.py | 1435 + .../site-packages/yaml/serializer.py | 111 + .../python3.9/site-packages/yaml/tokens.py | 104 + myenv/pyvenv.cfg | 3 + myenv/share/doc/networkx-2.8.5/LICENSE.txt | 37 + .../examples/3d_drawing/README.txt | 2 + .../examples/3d_drawing/mayavi2_spring.py | 43 + .../examples/3d_drawing/plot_basic.py | 51 + .../doc/networkx-2.8.5/examples/README.txt | 8 + .../examples/algorithms/README.txt | 2 + .../algorithms/WormNet.v3.benchmark.txt | 78736 +++++++ .../algorithms/hartford_drug.edgelist | 338 + .../examples/algorithms/plot_beam_search.py | 112 + .../algorithms/plot_betweenness_centrality.py | 83 + .../examples/algorithms/plot_blockmodel.py | 79 + .../examples/algorithms/plot_circuits.py | 103 + .../examples/algorithms/plot_davis_club.py | 43 + .../algorithms/plot_dedensification.py | 92 + .../plot_iterated_dynamical_systems.py | 210 + .../algorithms/plot_krackhardt_centrality.py | 31 + .../algorithms/plot_parallel_betweenness.py | 82 + .../examples/algorithms/plot_rcm.py | 40 + .../examples/algorithms/plot_snap.py | 108 + .../examples/algorithms/plot_subgraphs.py | 170 + .../networkx-2.8.5/examples/basic/README.txt | 2 + .../examples/basic/plot_properties.py | 49 + .../examples/basic/plot_read_write.py | 24 + .../examples/basic/plot_simple_graph.py | 60 + .../examples/drawing/README.txt | 2 + .../drawing/chess_masters_WCC.pgn.bz2 | Bin 0 -> 100224 bytes .../examples/drawing/knuth_miles.txt.gz | Bin 0 -> 20317 bytes .../examples/drawing/plot_chess_masters.py | 152 + .../drawing/plot_custom_node_icons.py | 75 + .../examples/drawing/plot_degree.py | 50 + .../examples/drawing/plot_directed.py | 46 + .../examples/drawing/plot_edge_colormap.py | 23 + .../examples/drawing/plot_ego_graph.py | 35 + .../examples/drawing/plot_eigenvalues.py | 22 + .../examples/drawing/plot_four_grids.py | 52 + .../drawing/plot_house_with_colors.py | 26 + .../examples/drawing/plot_knuth_miles.py | 142 + .../drawing/plot_labels_and_colors.py | 54 + .../drawing/plot_multipartite_graph.py | 41 + .../examples/drawing/plot_node_colormap.py | 15 + .../examples/drawing/plot_rainbow_coloring.py | 68 + .../drawing/plot_random_geometric_graph.py | 44 + .../examples/drawing/plot_sampson.py | 47 + .../examples/drawing/plot_selfloops.py | 29 + .../examples/drawing/plot_simple_path.py | 14 + .../examples/drawing/plot_spectral_grid.py | 58 + .../examples/drawing/plot_tsp.py | 52 + .../examples/drawing/plot_unix_email.py | 62 + .../examples/drawing/plot_weighted_graph.py | 44 + .../examples/drawing/unix_email.mbox | 84 + .../networkx-2.8.5/examples/graph/README.txt | 2 + .../examples/graph/plot_degree_sequence.py | 34 + .../examples/graph/plot_erdos_renyi.py | 36 + .../graph/plot_expected_degree_sequence.py | 20 + .../examples/graph/plot_football.py | 44 + .../examples/graph/plot_karate_club.py | 25 + .../examples/graph/plot_morse_trie.py | 96 + .../graph/plot_napoleon_russian_campaign.py | 133 + .../examples/graph/plot_roget.py | 80 + .../examples/graph/plot_words.py | 88 + .../examples/graph/roget_dat.txt.gz | Bin 0 -> 15758 bytes .../examples/graph/words_dat.txt.gz | Bin 0 -> 33695 bytes .../examples/subclass/README.txt | 2 + .../examples/subclass/plot_antigraph.py | 192 + .../examples/subclass/plot_printgraph.py | 88 + pyproject.toml | 2 +- test_melli.py | 7 +- 3048 files changed, 1055131 insertions(+), 44 deletions(-) create mode 100644 .melli.py.swp create mode 100644 .test_melli.py.swp create mode 100644 myenv/bin/Activate.ps1 create mode 100644 myenv/bin/activate create mode 100644 myenv/bin/activate.csh create mode 100644 myenv/bin/activate.fish create mode 100755 myenv/bin/black create mode 100755 myenv/bin/black-primer create mode 100755 myenv/bin/blackd create mode 100755 myenv/bin/dotenv create mode 100755 myenv/bin/easy_install create mode 100755 myenv/bin/easy_install-3.9 create mode 100755 myenv/bin/epylint create mode 100755 myenv/bin/future-fstrings-show create mode 100755 myenv/bin/get_objgraph create mode 100755 myenv/bin/httpx create mode 100755 myenv/bin/isort create mode 100755 myenv/bin/isort-identify-imports create mode 100755 myenv/bin/pip create mode 100755 myenv/bin/pip3 create mode 100755 myenv/bin/pip3.9 create mode 100755 myenv/bin/py.test create mode 100755 myenv/bin/pylint create mode 100755 myenv/bin/pyreverse create mode 100755 myenv/bin/pyrsa-decrypt create mode 100755 myenv/bin/pyrsa-encrypt create mode 100755 myenv/bin/pyrsa-keygen create mode 100755 myenv/bin/pyrsa-priv2pub create mode 100755 myenv/bin/pyrsa-sign create mode 100755 myenv/bin/pyrsa-verify create mode 100755 myenv/bin/pytest create mode 120000 myenv/bin/python create mode 120000 myenv/bin/python3 create mode 120000 myenv/bin/python3.9 create mode 100755 myenv/bin/symilar create mode 100755 myenv/bin/undill create mode 100755 myenv/bin/uvicorn create mode 100755 myenv/bin/watchgod create mode 100644 myenv/lib/python3.9/site-packages/CHANGELOG.md create mode 100644 myenv/lib/python3.9/site-packages/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/README.md create mode 100644 myenv/lib/python3.9/site-packages/_black_version.py create mode 100755 myenv/lib/python3.9/site-packages/_cffi_backend.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/_pytest/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_argcomplete.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_code/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_code/code.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_code/source.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_io/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_io/saferepr.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_io/terminalwriter.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_io/wcwidth.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/_version.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/assertion/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/assertion/rewrite.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/assertion/truncate.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/assertion/util.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/cacheprovider.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/capture.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/compat.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/config/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/config/argparsing.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/config/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/config/findpaths.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/debugging.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/deprecated.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/doctest.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/faulthandler.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/fixtures.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/freeze_support.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/helpconfig.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/hookspec.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/junitxml.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/logging.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/main.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/mark/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/mark/expression.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/mark/structures.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/monkeypatch.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/nodes.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/nose.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/outcomes.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/pastebin.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/pathlib.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/py.typed create mode 100644 myenv/lib/python3.9/site-packages/_pytest/pytester.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/pytester_assertions.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/python.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/python_api.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/recwarn.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/reports.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/runner.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/setuponly.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/setupplan.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/skipping.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/stepwise.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/store.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/terminal.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/threadexception.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/timing.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/tmpdir.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/unittest.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/unraisableexception.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/warning_types.py create mode 100644 myenv/lib/python3.9/site-packages/_pytest/warnings.py create mode 100644 myenv/lib/python3.9/site-packages/_yaml/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/aaaaa_future_fstrings.pth create mode 100644 myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/anyio/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_backends/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_backends/_asyncio.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_backends/_trio.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_eventloop.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_fileio.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_resources.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_signals.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_sockets.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_streams.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_subprocesses.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_synchronization.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_tasks.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_testing.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/_core/_typedattr.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/abc/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/abc/_resources.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/abc/_sockets.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/abc/_streams.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/abc/_subprocesses.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/abc/_tasks.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/abc/_testing.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/from_thread.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/lowlevel.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/py.typed create mode 100644 myenv/lib/python3.9/site-packages/anyio/pytest_plugin.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/streams/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/streams/buffered.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/streams/file.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/streams/memory.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/streams/stapled.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/streams/text.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/streams/tls.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/to_process.py create mode 100644 myenv/lib/python3.9/site-packages/anyio/to_thread.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/asgiref/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/compatibility.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/current_thread_executor.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/local.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/py.typed create mode 100644 myenv/lib/python3.9/site-packages/asgiref/server.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/sync.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/testing.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/timeout.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/typing.py create mode 100644 myenv/lib/python3.9/site-packages/asgiref/wsgi.py create mode 100644 myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/CONTRIBUTORS.txt create mode 100644 myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/astroid/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/__pkginfo__.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/_ast.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/arguments.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/astroid_manager.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/bases.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_argparse.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_attrs.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_boto3.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_builtin_inference.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_collections.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_crypt.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_ctypes.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_curses.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_dataclasses.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_dateutil.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_fstrings.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_functools.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_gi.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_hashlib.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_http.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_hypothesis.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_io.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_mechanize.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_multiprocessing.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_namedtuple_enum.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_nose.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_fromnumeric.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_function_base.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_multiarray.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numeric.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numerictypes.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_umath.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ma.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ndarray.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_random_mtrand.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_utils.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_pkg_resources.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_pytest.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_qt.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_random.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_re.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_responses.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_scipy_signal.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_signal.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_six.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_sqlalchemy.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_ssl.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_subprocess.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_threading.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_type.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_typing.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_unittest.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/brain_uuid.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/brain/helpers.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/builder.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/const.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/context.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/decorators.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/filter_statements.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/helpers.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/inference.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/inference_tip.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/interpreter/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/interpreter/_import/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/interpreter/_import/spec.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/interpreter/_import/util.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/interpreter/dunder_lookup.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/interpreter/objectmodel.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/manager.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/mixins.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/modutils.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/node_classes.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/as_string.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/const.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/node_classes.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/node_ng.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/mixin.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/utils.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/nodes/utils.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/objects.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/protocols.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/raw_building.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/rebuilder.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/scoped_nodes.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/test_utils.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/transforms.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/typing.py create mode 100644 myenv/lib/python3.9/site-packages/astroid/util.py create mode 100644 myenv/lib/python3.9/site-packages/attr/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/attr/__init__.pyi create mode 100644 myenv/lib/python3.9/site-packages/attr/_cmp.py create mode 100644 myenv/lib/python3.9/site-packages/attr/_cmp.pyi create mode 100644 myenv/lib/python3.9/site-packages/attr/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/attr/_config.py create mode 100644 myenv/lib/python3.9/site-packages/attr/_funcs.py create mode 100644 myenv/lib/python3.9/site-packages/attr/_make.py create mode 100644 myenv/lib/python3.9/site-packages/attr/_next_gen.py create mode 100644 myenv/lib/python3.9/site-packages/attr/_version_info.py create mode 100644 myenv/lib/python3.9/site-packages/attr/_version_info.pyi create mode 100644 myenv/lib/python3.9/site-packages/attr/converters.py create mode 100644 myenv/lib/python3.9/site-packages/attr/converters.pyi create mode 100644 myenv/lib/python3.9/site-packages/attr/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/attr/exceptions.pyi create mode 100644 myenv/lib/python3.9/site-packages/attr/filters.py create mode 100644 myenv/lib/python3.9/site-packages/attr/filters.pyi create mode 100644 myenv/lib/python3.9/site-packages/attr/py.typed create mode 100644 myenv/lib/python3.9/site-packages/attr/setters.py create mode 100644 myenv/lib/python3.9/site-packages/attr/setters.pyi create mode 100644 myenv/lib/python3.9/site-packages/attr/validators.py create mode 100644 myenv/lib/python3.9/site-packages/attr/validators.pyi create mode 100644 myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/AUTHORS.rst create mode 100644 myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/attrs/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/attrs/__init__.pyi create mode 100644 myenv/lib/python3.9/site-packages/attrs/converters.py create mode 100644 myenv/lib/python3.9/site-packages/attrs/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/attrs/filters.py create mode 100644 myenv/lib/python3.9/site-packages/attrs/py.typed create mode 100644 myenv/lib/python3.9/site-packages/attrs/setters.py create mode 100644 myenv/lib/python3.9/site-packages/attrs/validators.py create mode 100644 myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/bcrypt/__about__.py create mode 100644 myenv/lib/python3.9/site-packages/bcrypt/__init__.py create mode 100755 myenv/lib/python3.9/site-packages/bcrypt/_bcrypt.abi3.so create mode 100644 myenv/lib/python3.9/site-packages/bcrypt/_bcrypt.pyi create mode 100644 myenv/lib/python3.9/site-packages/bcrypt/py.typed create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/AUTHORS.md create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/black/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/black/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/black/brackets.py create mode 100644 myenv/lib/python3.9/site-packages/black/cache.py create mode 100644 myenv/lib/python3.9/site-packages/black/comments.py create mode 100644 myenv/lib/python3.9/site-packages/black/concurrency.py create mode 100644 myenv/lib/python3.9/site-packages/black/const.py create mode 100644 myenv/lib/python3.9/site-packages/black/debug.py create mode 100644 myenv/lib/python3.9/site-packages/black/files.py create mode 100644 myenv/lib/python3.9/site-packages/black/handle_ipynb_magics.py create mode 100644 myenv/lib/python3.9/site-packages/black/linegen.py create mode 100644 myenv/lib/python3.9/site-packages/black/lines.py create mode 100644 myenv/lib/python3.9/site-packages/black/mode.py create mode 100644 myenv/lib/python3.9/site-packages/black/nodes.py create mode 100644 myenv/lib/python3.9/site-packages/black/numerics.py create mode 100644 myenv/lib/python3.9/site-packages/black/output.py create mode 100644 myenv/lib/python3.9/site-packages/black/parsing.py create mode 100644 myenv/lib/python3.9/site-packages/black/py.typed create mode 100644 myenv/lib/python3.9/site-packages/black/report.py create mode 100644 myenv/lib/python3.9/site-packages/black/rusty.py create mode 100644 myenv/lib/python3.9/site-packages/black/strings.py create mode 100644 myenv/lib/python3.9/site-packages/black/trans.py create mode 100644 myenv/lib/python3.9/site-packages/black_primer/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/black_primer/cli.py create mode 100644 myenv/lib/python3.9/site-packages/black_primer/lib.py create mode 100644 myenv/lib/python3.9/site-packages/black_primer/primer.json create mode 100644 myenv/lib/python3.9/site-packages/blackd/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/blackd/middlewares.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/Grammar.txt create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/PatternGrammar.txt create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/conv.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/driver.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/grammar.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/literals.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/parse.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/pgen.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/token.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pgen2/tokenize.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pygram.py create mode 100644 myenv/lib/python3.9/site-packages/blib2to3/pytree.py create mode 100644 myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/certifi/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/certifi/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/certifi/cacert.pem create mode 100644 myenv/lib/python3.9/site-packages/certifi/core.py create mode 100644 myenv/lib/python3.9/site-packages/certifi/py.typed create mode 100644 myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/cffi/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/_cffi_errors.h create mode 100644 myenv/lib/python3.9/site-packages/cffi/_cffi_include.h create mode 100644 myenv/lib/python3.9/site-packages/cffi/_embedding.h create mode 100644 myenv/lib/python3.9/site-packages/cffi/api.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/backend_ctypes.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/cffi_opcode.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/commontypes.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/cparser.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/error.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/ffiplatform.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/lock.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/model.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/parse_c_type.h create mode 100644 myenv/lib/python3.9/site-packages/cffi/pkgconfig.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/recompiler.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/setuptools_ext.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/vengine_cpy.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/vengine_gen.py create mode 100644 myenv/lib/python3.9/site-packages/cffi/verifier.py create mode 100644 myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/LICENSE.rst create mode 100644 myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/click/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/click/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/click/_termui_impl.py create mode 100644 myenv/lib/python3.9/site-packages/click/_textwrap.py create mode 100644 myenv/lib/python3.9/site-packages/click/_winconsole.py create mode 100644 myenv/lib/python3.9/site-packages/click/core.py create mode 100644 myenv/lib/python3.9/site-packages/click/decorators.py create mode 100644 myenv/lib/python3.9/site-packages/click/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/click/formatting.py create mode 100644 myenv/lib/python3.9/site-packages/click/globals.py create mode 100644 myenv/lib/python3.9/site-packages/click/parser.py create mode 100644 myenv/lib/python3.9/site-packages/click/py.typed create mode 100644 myenv/lib/python3.9/site-packages/click/shell_completion.py create mode 100644 myenv/lib/python3.9/site-packages/click/termui.py create mode 100644 myenv/lib/python3.9/site-packages/click/testing.py create mode 100644 myenv/lib/python3.9/site-packages/click/types.py create mode 100644 myenv/lib/python3.9/site-packages/click/utils.py create mode 100644 myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/LICENSE.txt create mode 100644 myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/colorama/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/colorama/ansi.py create mode 100644 myenv/lib/python3.9/site-packages/colorama/ansitowin32.py create mode 100644 myenv/lib/python3.9/site-packages/colorama/initialise.py create mode 100644 myenv/lib/python3.9/site-packages/colorama/win32.py create mode 100644 myenv/lib/python3.9/site-packages/colorama/winterm.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.APACHE create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.BSD create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.PSF create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/cryptography/__about__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/fernet.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/_oid.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/aead.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ciphers.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/cmac.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dh.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dsa.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ec.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed25519.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed448.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hashes.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hmac.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/poly1305.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/rsa.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/utils.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x25519.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x448.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x509.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py create mode 100755 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_openssl.abi3.so create mode 100755 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_asymmetric.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/_serialization.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/types.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/aead.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/base.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/ciphers/modes.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/cmac.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/constant_time.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/hmac.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/keywrap.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/padding.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/poly1305.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/base.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/serialization/ssh.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/hazmat/primitives/twofactor/totp.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/py.typed create mode 100644 myenv/lib/python3.9/site-packages/cryptography/utils.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/base.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/certificate_transparency.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/extensions.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/general_name.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/name.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/ocsp.py create mode 100644 myenv/lib/python3.9/site-packages/cryptography/x509/oid.py create mode 100644 myenv/lib/python3.9/site-packages/dill-0.3.5.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/dill-0.3.5.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/dill-0.3.5.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/dill-0.3.5.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/dill-0.3.5.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/dill-0.3.5.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/dill/__diff.py create mode 100644 myenv/lib/python3.9/site-packages/dill/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/dill/_dill.py create mode 100644 myenv/lib/python3.9/site-packages/dill/_objects.py create mode 100644 myenv/lib/python3.9/site-packages/dill/_shims.py create mode 100644 myenv/lib/python3.9/site-packages/dill/detect.py create mode 100644 myenv/lib/python3.9/site-packages/dill/objtypes.py create mode 100644 myenv/lib/python3.9/site-packages/dill/pointers.py create mode 100644 myenv/lib/python3.9/site-packages/dill/settings.py create mode 100644 myenv/lib/python3.9/site-packages/dill/source.py create mode 100644 myenv/lib/python3.9/site-packages/dill/temp.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_check.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_classdef.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_detect.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_dictviews.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_diff.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_extendpickle.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_fglobals.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_file.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_functions.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_functors.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_mixins.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_module.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_moduledict.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_nested.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_objects.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_properties.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_recursive.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_restricted.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_selected.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_session.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_source.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_temp.py create mode 100644 myenv/lib/python3.9/site-packages/dill/tests/test_weakref.py create mode 100644 myenv/lib/python3.9/site-packages/dotenv/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/dotenv/cli.py create mode 100644 myenv/lib/python3.9/site-packages/dotenv/ipython.py create mode 100644 myenv/lib/python3.9/site-packages/dotenv/main.py create mode 100644 myenv/lib/python3.9/site-packages/dotenv/parser.py create mode 100644 myenv/lib/python3.9/site-packages/dotenv/py.typed create mode 100644 myenv/lib/python3.9/site-packages/dotenv/variables.py create mode 100644 myenv/lib/python3.9/site-packages/dotenv/version.py create mode 100644 myenv/lib/python3.9/site-packages/easy_install.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa-0.18.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/ecdsa-0.18.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/ecdsa-0.18.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/ecdsa-0.18.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/ecdsa-0.18.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/ecdsa-0.18.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/_rwlock.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/_sha3.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/_version.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/curves.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/der.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/ecdh.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/ecdsa.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/eddsa.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/ellipticcurve.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/errors.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/keys.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/numbertheory.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/rfc6979.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_curves.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_der.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_ecdh.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_ecdsa.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_eddsa.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_ellipticcurve.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_jacobi.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_keys.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_malformed_sigs.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_numbertheory.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_pyecdsa.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_rw_lock.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/test_sha3.py create mode 100644 myenv/lib/python3.9/site-packages/ecdsa/util.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi-0.70.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/fastapi-0.70.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/fastapi-0.70.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/fastapi-0.70.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/fastapi-0.70.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/fastapi/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/applications.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/background.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/concurrency.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/datastructures.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/dependencies/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/dependencies/models.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/dependencies/utils.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/encoders.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/exception_handlers.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/logger.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/middleware/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/middleware/cors.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/middleware/gzip.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/middleware/httpsredirect.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/middleware/trustedhost.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/middleware/wsgi.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/openapi/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/openapi/constants.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/openapi/docs.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/openapi/models.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/openapi/utils.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/param_functions.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/params.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/py.typed create mode 100644 myenv/lib/python3.9/site-packages/fastapi/requests.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/responses.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/routing.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/security/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/security/api_key.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/security/base.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/security/http.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/security/oauth2.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/security/open_id_connect_url.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/security/utils.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/staticfiles.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/templating.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/testclient.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/types.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/utils.py create mode 100644 myenv/lib/python3.9/site-packages/fastapi/websockets.py create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings-1.2.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings-1.2.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings-1.2.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings-1.2.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings-1.2.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings-1.2.0.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings-1.2.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/future_fstrings.py create mode 100644 myenv/lib/python3.9/site-packages/h11-0.12.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/h11-0.12.0.dist-info/LICENSE.txt create mode 100644 myenv/lib/python3.9/site-packages/h11-0.12.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/h11-0.12.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/h11-0.12.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/h11-0.12.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/h11/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_abnf.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_connection.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_events.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_headers.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_readers.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_receivebuffer.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_state.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_util.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_version.py create mode 100644 myenv/lib/python3.9/site-packages/h11/_writers.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/data/test-file create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/helpers.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_against_stdlib_http.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_connection.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_events.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_headers.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_helpers.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_io.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_receivebuffer.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_state.py create mode 100644 myenv/lib/python3.9/site-packages/h11/tests/test_util.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore-0.15.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/httpcore-0.15.0.dist-info/LICENSE.md create mode 100644 myenv/lib/python3.9/site-packages/httpcore-0.15.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/httpcore-0.15.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/httpcore-0.15.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/httpcore-0.15.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/httpcore/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_api.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/connection.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/connection_pool.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/http11.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/http2.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/http_proxy.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/interfaces.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_async/socks_proxy.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_models.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_ssl.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/connection.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/http11.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/http2.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/http_proxy.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/interfaces.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_sync/socks_proxy.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_synchronization.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_trace.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/_utils.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/backends/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/backends/asyncio.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/backends/auto.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/backends/base.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/backends/mock.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/backends/sync.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/backends/trio.py create mode 100644 myenv/lib/python3.9/site-packages/httpcore/py.typed create mode 100644 myenv/lib/python3.9/site-packages/httptools-0.3.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/httptools-0.3.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/httptools-0.3.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/httptools-0.3.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/httptools-0.3.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/httptools-0.3.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/httptools/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httptools/_version.py create mode 100644 myenv/lib/python3.9/site-packages/httptools/parser/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httptools/parser/errors.py create mode 100644 myenv/lib/python3.9/site-packages/httptools/parser/parser.c create mode 100755 myenv/lib/python3.9/site-packages/httptools/parser/parser.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/httptools/parser/url_parser.c create mode 100755 myenv/lib/python3.9/site-packages/httptools/parser/url_parser.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/httpx-0.23.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/httpx-0.23.0.dist-info/LICENSE.md create mode 100644 myenv/lib/python3.9/site-packages/httpx-0.23.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/httpx-0.23.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/httpx-0.23.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/httpx-0.23.0.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/httpx-0.23.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/httpx/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/__version__.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_api.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_auth.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_client.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_config.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_content.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_decoders.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_main.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_models.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_multipart.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_status_codes.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_transports/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_transports/asgi.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_transports/base.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_transports/default.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_transports/mock.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_transports/wsgi.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_types.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_urls.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/_utils.py create mode 100644 myenv/lib/python3.9/site-packages/httpx/py.typed create mode 100644 myenv/lib/python3.9/site-packages/idna-3.3.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/idna-3.3.dist-info/LICENSE.md create mode 100644 myenv/lib/python3.9/site-packages/idna-3.3.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/idna-3.3.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/idna-3.3.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/idna-3.3.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/idna/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/idna/codec.py create mode 100644 myenv/lib/python3.9/site-packages/idna/compat.py create mode 100644 myenv/lib/python3.9/site-packages/idna/core.py create mode 100644 myenv/lib/python3.9/site-packages/idna/idnadata.py create mode 100644 myenv/lib/python3.9/site-packages/idna/intranges.py create mode 100644 myenv/lib/python3.9/site-packages/idna/package_data.py create mode 100644 myenv/lib/python3.9/site-packages/idna/py.typed create mode 100644 myenv/lib/python3.9/site-packages/idna/uts46data.py create mode 100644 myenv/lib/python3.9/site-packages/iniconfig-1.1.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/iniconfig-1.1.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/iniconfig-1.1.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/iniconfig-1.1.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/iniconfig-1.1.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/iniconfig-1.1.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/iniconfig/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/iniconfig/__init__.pyi create mode 100644 myenv/lib/python3.9/site-packages/iniconfig/py.typed create mode 100644 myenv/lib/python3.9/site-packages/isort-5.10.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/isort-5.10.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/isort-5.10.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/isort-5.10.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/isort-5.10.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/isort-5.10.1.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/isort/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/isort/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/isort/_future/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/isort/_future/_dataclasses.py create mode 100644 myenv/lib/python3.9/site-packages/isort/_vendored/tomli/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/isort/_vendored/tomli/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/isort/_vendored/tomli/_parser.py create mode 100644 myenv/lib/python3.9/site-packages/isort/_vendored/tomli/_re.py create mode 100644 myenv/lib/python3.9/site-packages/isort/_vendored/tomli/py.typed create mode 100644 myenv/lib/python3.9/site-packages/isort/_version.py create mode 100644 myenv/lib/python3.9/site-packages/isort/api.py create mode 100644 myenv/lib/python3.9/site-packages/isort/comments.py create mode 100644 myenv/lib/python3.9/site-packages/isort/core.py create mode 100644 myenv/lib/python3.9/site-packages/isort/deprecated/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/isort/deprecated/finders.py create mode 100644 myenv/lib/python3.9/site-packages/isort/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/isort/files.py create mode 100644 myenv/lib/python3.9/site-packages/isort/format.py create mode 100644 myenv/lib/python3.9/site-packages/isort/hooks.py create mode 100644 myenv/lib/python3.9/site-packages/isort/identify.py create mode 100644 myenv/lib/python3.9/site-packages/isort/io.py create mode 100644 myenv/lib/python3.9/site-packages/isort/literal.py create mode 100644 myenv/lib/python3.9/site-packages/isort/logo.py create mode 100644 myenv/lib/python3.9/site-packages/isort/main.py create mode 100644 myenv/lib/python3.9/site-packages/isort/output.py create mode 100644 myenv/lib/python3.9/site-packages/isort/parse.py create mode 100644 myenv/lib/python3.9/site-packages/isort/place.py create mode 100644 myenv/lib/python3.9/site-packages/isort/profiles.py create mode 100644 myenv/lib/python3.9/site-packages/isort/py.typed create mode 100644 myenv/lib/python3.9/site-packages/isort/pylama_isort.py create mode 100644 myenv/lib/python3.9/site-packages/isort/sections.py create mode 100644 myenv/lib/python3.9/site-packages/isort/settings.py create mode 100644 myenv/lib/python3.9/site-packages/isort/setuptools_commands.py create mode 100644 myenv/lib/python3.9/site-packages/isort/sorting.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/all.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py2.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py27.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py3.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py310.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py35.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py36.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py37.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py38.py create mode 100644 myenv/lib/python3.9/site-packages/isort/stdlibs/py39.py create mode 100644 myenv/lib/python3.9/site-packages/isort/utils.py create mode 100644 myenv/lib/python3.9/site-packages/isort/wrap.py create mode 100644 myenv/lib/python3.9/site-packages/isort/wrap_modes.py create mode 100644 myenv/lib/python3.9/site-packages/jose/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/jose/backends/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/jose/backends/_asn1.py create mode 100644 myenv/lib/python3.9/site-packages/jose/backends/base.py create mode 100644 myenv/lib/python3.9/site-packages/jose/backends/cryptography_backend.py create mode 100644 myenv/lib/python3.9/site-packages/jose/backends/ecdsa_backend.py create mode 100644 myenv/lib/python3.9/site-packages/jose/backends/native.py create mode 100644 myenv/lib/python3.9/site-packages/jose/backends/rsa_backend.py create mode 100644 myenv/lib/python3.9/site-packages/jose/constants.py create mode 100644 myenv/lib/python3.9/site-packages/jose/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/jose/jwe.py create mode 100644 myenv/lib/python3.9/site-packages/jose/jwk.py create mode 100644 myenv/lib/python3.9/site-packages/jose/jws.py create mode 100644 myenv/lib/python3.9/site-packages/jose/jwt.py create mode 100644 myenv/lib/python3.9/site-packages/jose/utils.py create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy-1.7.1.dist-info/AUTHORS.rst create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy-1.7.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy-1.7.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy-1.7.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy-1.7.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy-1.7.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy-1.7.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy/_version.py create mode 100755 myenv/lib/python3.9/site-packages/lazy_object_proxy/cext.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy/compat.py create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy/simple.py create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy/slots.py create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy/utils.py create mode 100644 myenv/lib/python3.9/site-packages/lazy_object_proxy/utils_py3.py create mode 100644 myenv/lib/python3.9/site-packages/mccabe-0.7.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/mccabe-0.7.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/mccabe-0.7.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/mccabe-0.7.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/mccabe-0.7.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/mccabe-0.7.0.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/mccabe-0.7.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/mccabe.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/_version.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/decoders.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/multipart.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/tests/compat.py create mode 100644 myenv/lib/python3.9/site-packages/multipart/tests/test_multipart.py create mode 100644 myenv/lib/python3.9/site-packages/mypy_extensions-0.4.3.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/mypy_extensions-0.4.3.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/mypy_extensions-0.4.3.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/mypy_extensions-0.4.3.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/mypy_extensions-0.4.3.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/mypy_extensions-0.4.3.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/mypy_extensions.py create mode 100644 myenv/lib/python3.9/site-packages/networkx-2.8.5.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/networkx-2.8.5.dist-info/LICENSE.txt create mode 100644 myenv/lib/python3.9/site-packages/networkx-2.8.5.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/networkx-2.8.5.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/networkx-2.8.5.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/networkx-2.8.5.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/networkx/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/clique.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/clustering_coefficient.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/connectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/distance_measures.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/dominating_set.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/kcomponents.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/matching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/maxcut.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/ramsey.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/steinertree.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_clique.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_connectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_distance_measures.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_dominating_set.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_kcomponents.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_matching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_maxcut.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_ramsey.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_steinertree.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_traveling_salesman.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_treewidth.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/tests/test_vertex_cover.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/traveling_salesman.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/treewidth.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/approximation/vertex_cover.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/connectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/correlation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/mixing.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/neighbor_degree.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/pairs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/tests/base_test.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/tests/test_connectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/tests/test_correlation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/tests/test_mixing.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/tests/test_neighbor_degree.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/assortativity/tests/test_pairs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/asteroidal.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/basic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/cluster.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/covering.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/edgelist.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/generators.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/matching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/matrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/projection.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/redundancy.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/spectral.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_basic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_cluster.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_covering.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_edgelist.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_generators.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_matching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_matrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_project.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_redundancy.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/boundary.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/bridges.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/betweenness.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/betweenness_subset.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/closeness.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/current_flow_betweenness.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/current_flow_betweenness_subset.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/current_flow_closeness.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/degree_alg.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/dispersion.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/eigenvector.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/flow_matrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/group.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/harmonic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/katz.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/load.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/percolation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/reaching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/second_order.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/subgraph_alg.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_closeness_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_current_flow_closeness.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_degree_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_dispersion.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_group.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_harmonic_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_katz_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_load_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_percolation_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_reaching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_second_order_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_subgraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_trophic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/tests/test_voterank.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/trophic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/centrality/voterank_alg.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/chains.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/chordal.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/clique.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/cluster.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/coloring/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/coloring/equitable_coloring.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/coloring/greedy_coloring.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/coloring/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/coloring/tests/test_coloring.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/communicability_alg.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/asyn_fluid.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/community_utils.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/kclique.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/kernighan_lin.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/label_propagation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/louvain.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/lukes.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/modularity_max.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/quality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_asyn_fluid.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_centrality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_kclique.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_kernighan_lin.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_label_propagation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_louvain.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_lukes.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_modularity_max.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_quality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/community/tests/test_utils.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/attracting.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/biconnected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/connected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/semiconnected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/strongly_connected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/tests/test_attracting.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/tests/test_biconnected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/tests/test_connected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/tests/test_semiconnected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/tests/test_strongly_connected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/tests/test_weakly_connected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/components/weakly_connected.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/connectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/cuts.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/disjoint_paths.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/edge_augmentation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/edge_kcomponents.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/kcomponents.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/kcutsets.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/stoerwagner.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_connectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_cuts.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_disjoint_paths.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_edge_augmentation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_kcomponents.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_kcutsets.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/tests/test_stoer_wagner.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/connectivity/utils.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/core.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/covering.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/cuts.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/cycles.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/d_separation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/dag.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/distance_measures.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/distance_regular.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/dominance.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/dominating.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/efficiency_measures.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/euler.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/boykovkolmogorov.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/capacityscaling.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/dinitz_alg.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/edmondskarp.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/gomory_hu.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/maxflow.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/mincost.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/networksimplex.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/preflowpush.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/shortestaugmentingpath.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/gl1.gpickle.bz2 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/gw1.gpickle.bz2 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/test_gomory_hu.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/test_maxflow.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/test_maxflow_large_graph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/test_mincost.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/test_networksimplex.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/flow/utils.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/graph_hashing.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/graphical.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/hierarchy.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/hybrid.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isolate.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/ismags.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/isomorph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/isomorphvf2.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/matchhelpers.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/temporalisomorphvf2.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/test_ismags.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphism.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/test_match_helpers.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/tree_isomorphism.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/isomorphism/vf2userfunc.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/link_analysis/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/link_analysis/hits_alg.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/link_analysis/pagerank_alg.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/link_analysis/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/link_analysis/tests/test_hits.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/link_analysis/tests/test_pagerank.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/link_prediction.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/lowest_common_ancestors.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/matching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/minors/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/minors/contraction.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/minors/tests/test_contraction.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/mis.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/moral.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/node_classification/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/node_classification/hmn.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/node_classification/lgc.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/node_classification/utils.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/non_randomness.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/all.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/binary.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/product.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/tests/test_all.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/tests/test_binary.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/tests/test_product.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/tests/test_unary.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/operators/unary.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/planar_drawing.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/planarity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/polynomials.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/reciprocity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/regular.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/richclub.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/astar.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/dense.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/generic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/tests/test_astar.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/tests/test_dense.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/tests/test_generic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/tests/test_unweighted.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/tests/test_weighted.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/unweighted.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/shortest_paths/weighted.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/similarity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/simple_paths.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/smallworld.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/smetric.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/sparsifiers.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/structuralholes.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/summarization.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/swap.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_asteroidal.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_boundary.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_bridges.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_chains.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_chordal.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_clique.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_cluster.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_communicability.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_core.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_covering.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_cuts.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_cycles.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_d_separation.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_dag.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_distance_measures.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_distance_regular.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_dominance.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_dominating.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_efficiency.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_euler.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_graph_hashing.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_graphical.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_hierarchy.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_hybrid.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_isolate.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_link_prediction.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_lowest_common_ancestors.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_matching.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_max_weight_clique.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_mis.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_moral.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_node_classification.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_node_classification_deprecations.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_non_randomness.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_planar_drawing.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_planarity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_polynomials.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_reciprocity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_regular.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_richclub.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_similarity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_simple_paths.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_smallworld.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_smetric.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_sparsifiers.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_structuralholes.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_summarization.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_swap.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_threshold.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_tournament.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_triads.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_vitality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_voronoi.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tests/test_wiener.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/threshold.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tournament.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/beamsearch.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/breadth_first_search.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/depth_first_search.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/edgebfs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/edgedfs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/tests/test_beamsearch.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/tests/test_bfs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/tests/test_dfs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/tests/test_edgebfs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/traversal/tests/test_edgedfs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/branchings.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/coding.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/decomposition.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/mst.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/operations.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/recognition.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/tests/test_branchings.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/tests/test_coding.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/tests/test_decomposition.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/tests/test_mst.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/tests/test_operations.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/tree/tests/test_recognition.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/triads.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/vitality.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/voronoi.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/algorithms/wiener.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/coreviews.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/digraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/filters.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/function.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/graph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/graphviews.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/multidigraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/multigraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/ordered.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/reportviews.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/historical_tests.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_coreviews.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_digraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_digraph_historical.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_filters.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_function.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_graph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_graph_historical.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_graphviews.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_multidigraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_multigraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_ordered.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_reportviews.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_special.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/classes/tests/test_subgraphviews.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/conftest.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/convert.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/convert_matrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/layout.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/nx_agraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/nx_pydot.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/nx_pylab.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/tests/baseline/test_house_with_colors.png create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/tests/test_agraph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/tests/test_layout.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/tests/test_pydot.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/drawing/tests/test_pylab.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/exception.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/atlas.dat.gz create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/atlas.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/classic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/cographs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/community.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/degree_seq.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/directed.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/duplication.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/ego.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/expanders.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/geometric.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/harary_graph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/internet_as_graphs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/intersection.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/interval_graph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/joint_degree_seq.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/lattice.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/line.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/mycielski.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/nonisomorphic_trees.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/random_clustered.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/random_graphs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/small.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/social.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/spectral_graph_forge.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/stochastic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/sudoku.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_atlas.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_classic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_cographs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_community.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_degree_seq.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_directed.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_duplication.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_ego.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_expanders.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_geometric.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_harary_graph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_internet_as_graphs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_intersection.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_interval_graph.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_joint_degree_seq.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_lattice.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_line.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_mycielski.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_nonisomorphic_trees.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_random_clustered.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_random_graphs.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_small.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_spectral_graph_forge.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_stochastic.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_sudoku.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_trees.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/tests/test_triads.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/trees.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/generators/triads.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/lazy_imports.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/algebraicconnectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/attrmatrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/bethehessianmatrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/graphmatrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/laplacianmatrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/modularitymatrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/spectrum.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/test_algebraic_connectivity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/test_attrmatrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/test_bethehessian.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/test_graphmatrix.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/test_laplacian.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/test_modularity.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/linalg/tests/test_spectrum.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/adjlist.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/edgelist.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/gexf.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/gml.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/gpickle.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/graph6.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/graphml.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/adjacency.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/cytoscape.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/jit.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/node_link.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/tests/test_adjacency.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/tests/test_cytoscape.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/tests/test_jit.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/tests/test_node_link.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/tests/test_tree.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/json_graph/tree.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/leda.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/multiline_adjlist.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/nx_shp.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/nx_yaml.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/p2g.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/pajek.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/sparse6.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_adjlist.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_edgelist.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_getattr_nxyaml_removal.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_gexf.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_gml.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_gpickle.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_graph6.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_graphml.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_leda.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_p2g.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_pajek.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_shp.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_sparse6.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/tests/test_text.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/readwrite/text.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/relabel.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/testing/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/testing/test.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/testing/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/testing/tests/test_utils.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/testing/utils.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_all_random_functions.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_convert.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_convert_numpy.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_convert_pandas.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_convert_scipy.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_import.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_lazy_imports.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/tests/test_relabel.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/contextmanagers.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/decorators.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/heaps.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/mapped_queue.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/misc.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/random_sequence.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/rcm.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test__init.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_contextmanager.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_decorators.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_heaps.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_mapped_queue.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_misc.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_random_sequence.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_rcm.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/tests/test_unionfind.py create mode 100644 myenv/lib/python3.9/site-packages/networkx/utils/union_find.py create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/LICENSE.APACHE create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/LICENSE.BSD create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/packaging-21.3.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/packaging/__about__.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/_manylinux.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/_musllinux.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/_structures.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/markers.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/py.typed create mode 100644 myenv/lib/python3.9/site-packages/packaging/requirements.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/specifiers.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/tags.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/utils.py create mode 100644 myenv/lib/python3.9/site-packages/packaging/version.py create mode 100644 myenv/lib/python3.9/site-packages/passlib-1.7.4.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/passlib-1.7.4.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/passlib-1.7.4.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/passlib-1.7.4.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/passlib-1.7.4.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/passlib-1.7.4.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/passlib-1.7.4.dist-info/zip-safe create mode 100644 myenv/lib/python3.9/site-packages/passlib/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/_data/wordsets/bip39.txt create mode 100644 myenv/lib/python3.9/site-packages/passlib/_data/wordsets/eff_long.txt create mode 100644 myenv/lib/python3.9/site-packages/passlib/_data/wordsets/eff_prefixed.txt create mode 100644 myenv/lib/python3.9/site-packages/passlib/_data/wordsets/eff_short.txt create mode 100644 myenv/lib/python3.9/site-packages/passlib/apache.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/apps.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/context.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/_blowfish/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/_blowfish/_gen_files.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/_blowfish/base.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/_blowfish/unrolled.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/_md4.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/des.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/digest.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/scrypt/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/scrypt/_builtin.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/scrypt/_gen_files.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/crypto/scrypt/_salsa.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/exc.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/ext/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/ext/django/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/ext/django/models.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/ext/django/utils.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/argon2.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/bcrypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/cisco.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/des_crypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/digests.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/django.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/fshp.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/ldap_digests.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/md5_crypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/misc.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/mssql.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/mysql.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/oracle.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/pbkdf2.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/phpass.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/postgres.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/roundup.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/scram.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/scrypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/sha1_crypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/sha2_crypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/sun_md5_crypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/handlers/windows.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/hash.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/hosts.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/ifc.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/pwd.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/registry.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/_test_bad_register.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/backports.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/sample1.cfg create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/sample1b.cfg create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/sample1c.cfg create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/sample_config_1s.cfg create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_apache.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_apps.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_context.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_context_deprecated.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_crypto_builtin_md4.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_crypto_des.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_crypto_digest.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_crypto_scrypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_ext_django.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_ext_django_source.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_handlers.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_handlers_argon2.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_handlers_bcrypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_handlers_cisco.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_handlers_django.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_handlers_pbkdf2.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_handlers_scrypt.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_hosts.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_pwd.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_registry.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_totp.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_utils.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_utils_handlers.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_utils_md4.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_utils_pbkdf2.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/test_win32.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/tox_support.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/tests/utils.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/totp.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/binary.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/compat/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/compat/_ordered_dict.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/decor.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/des.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/handlers.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/md4.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/utils/pbkdf2.py create mode 100644 myenv/lib/python3.9/site-packages/passlib/win32.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec-0.9.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pathspec-0.9.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pathspec-0.9.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pathspec-0.9.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pathspec-0.9.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pathspec-0.9.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pathspec/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/_meta.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/pathspec.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/pattern.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/patterns/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/patterns/gitwildmatch.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/tests/test_gitwildmatch.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/tests/test_pathspec.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/tests/test_util.py create mode 100644 myenv/lib/python3.9/site-packages/pathspec/util.py create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/LICENSE.txt create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/REQUESTED create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/pip-20.2.3.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pip/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/build_env.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cache.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/base_command.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/command_context.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/main.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/main_parser.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/parser.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/req_command.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/spinners.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/cli/status_codes.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/cache.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/check.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/completion.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/configuration.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/debug.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/download.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/freeze.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/hash.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/help.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/install.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/list.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/search.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/show.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/uninstall.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/commands/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/configuration.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/distributions/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/distributions/base.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/distributions/installed.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/distributions/sdist.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/distributions/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/index/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/index/collector.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/index/package_finder.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/locations.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/main.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/candidate.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/direct_url.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/format_control.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/index.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/link.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/scheme.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/search_scope.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/target_python.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/models/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/auth.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/cache.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/download.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/session.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/check.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/freeze.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/install/legacy.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/operations/prepare.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/pyproject.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/req/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/req/constructors.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/req/req_file.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/req/req_install.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/req/req_set.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/req/req_tracker.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/base.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/self_outdated_check.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/appdirs.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/datetime.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/deprecation.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/distutils_args.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/encoding.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/filesystem.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/filetypes.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/glibc.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/hashes.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/logging.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/misc.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/models.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/packaging.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/parallel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/pkg_resources.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/subprocess.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/typing.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/unpacking.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/urls.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/utils/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/vcs/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/vcs/git.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/vcs/subversion.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_internal/wheel_builder.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/appdirs.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/certifi/core.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/enums.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/langcyrillicmodel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/chardet/version.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/colorama/win32.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/contextlib2.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/misc.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/shutil.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/sysconfig.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/_backport/tarfile.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/database.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/index.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/locators.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/markers.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/resources.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/util.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/version.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/distro.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/_ihatexml.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/_inputstream.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/_tokenizer.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/_base.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/py.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/_utils.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/constants.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/base.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/lint.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/optionaltags.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/sanitizer.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/filters/whitespace.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/html5parser.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/serializer.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/sax.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/base.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/dom.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/etree.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treewalkers/base.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treewalkers/dom.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treewalkers/etree.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/html5lib/treewalkers/genshi.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/codec.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/core.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/intranges.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/package_data.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/ipaddress.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/msgpack/_version.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/_typing.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/markers.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/tags.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/packaging/version.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/_in_process.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/build.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/check.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/colorlog.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/dirtools.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/envbuild.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/meta.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pep517/wrappers.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pkg_resources/py31compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/progress/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/progress/bar.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/progress/counter.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/progress/spinner.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/pyparsing.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/__version__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/adapters.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/api.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/auth.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/certs.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/compat.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/cookies.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/help.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/hooks.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/models.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/packages.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/sessions.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/structures.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/requests/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/retrying.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/six.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/toml/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/toml/common.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/toml/decoder.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/toml/encoder.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/toml/ordered.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/toml/tz.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/request.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/response.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/vendor.txt create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 myenv/lib/python3.9/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/tags.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/pyparsing.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/_vendor/six.py create mode 100644 myenv/lib/python3.9/site-packages/pkg_resources/extern/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs-2.5.2.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/platformdirs-2.5.2.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/platformdirs-2.5.2.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/platformdirs-2.5.2.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/platformdirs-2.5.2.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/platformdirs-2.5.2.dist-info/license_files/LICENSE.txt create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/android.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/api.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/macos.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/py.typed create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/unix.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/version.py create mode 100644 myenv/lib/python3.9/site-packages/platformdirs/windows.py create mode 100644 myenv/lib/python3.9/site-packages/pluggy-1.0.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pluggy-1.0.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pluggy-1.0.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pluggy-1.0.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pluggy-1.0.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pluggy-1.0.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pluggy/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pluggy/_callers.py create mode 100644 myenv/lib/python3.9/site-packages/pluggy/_hooks.py create mode 100644 myenv/lib/python3.9/site-packages/pluggy/_manager.py create mode 100644 myenv/lib/python3.9/site-packages/pluggy/_result.py create mode 100644 myenv/lib/python3.9/site-packages/pluggy/_tracing.py create mode 100644 myenv/lib/python3.9/site-packages/pluggy/_version.py create mode 100644 myenv/lib/python3.9/site-packages/py-1.11.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/py-1.11.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/py-1.11.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/py-1.11.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/py-1.11.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/py-1.11.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/py/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/__init__.pyi create mode 100644 myenv/lib/python3.9/site-packages/py/__metainfo.py create mode 100644 myenv/lib/python3.9/site-packages/py/_builtin.py create mode 100644 myenv/lib/python3.9/site-packages/py/_code/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_code/_assertionnew.py create mode 100644 myenv/lib/python3.9/site-packages/py/_code/_assertionold.py create mode 100644 myenv/lib/python3.9/site-packages/py/_code/_py2traceback.py create mode 100644 myenv/lib/python3.9/site-packages/py/_code/assertion.py create mode 100644 myenv/lib/python3.9/site-packages/py/_code/code.py create mode 100644 myenv/lib/python3.9/site-packages/py/_code/source.py create mode 100644 myenv/lib/python3.9/site-packages/py/_error.py create mode 100644 myenv/lib/python3.9/site-packages/py/_io/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_io/capture.py create mode 100644 myenv/lib/python3.9/site-packages/py/_io/saferepr.py create mode 100644 myenv/lib/python3.9/site-packages/py/_io/terminalwriter.py create mode 100644 myenv/lib/python3.9/site-packages/py/_log/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_log/log.py create mode 100644 myenv/lib/python3.9/site-packages/py/_log/warning.py create mode 100644 myenv/lib/python3.9/site-packages/py/_path/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_path/cacheutil.py create mode 100644 myenv/lib/python3.9/site-packages/py/_path/common.py create mode 100644 myenv/lib/python3.9/site-packages/py/_path/local.py create mode 100644 myenv/lib/python3.9/site-packages/py/_path/svnurl.py create mode 100644 myenv/lib/python3.9/site-packages/py/_path/svnwc.py create mode 100644 myenv/lib/python3.9/site-packages/py/_process/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_process/cmdexec.py create mode 100644 myenv/lib/python3.9/site-packages/py/_process/forkedfunc.py create mode 100644 myenv/lib/python3.9/site-packages/py/_process/killproc.py create mode 100644 myenv/lib/python3.9/site-packages/py/_std.py create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg-2.0.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg-2.0.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg-2.0.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg-2.0.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg-2.0.0.dist-info/REQUESTED create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg-2.0.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg-2.0.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/apipkg/version.py create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig-1.1.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig-1.1.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig-1.1.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig-1.1.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig-1.1.1.dist-info/REQUESTED create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig-1.1.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig-1.1.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig/__init__.pyi create mode 100644 myenv/lib/python3.9/site-packages/py/_vendored_packages/iniconfig/py.typed create mode 100644 myenv/lib/python3.9/site-packages/py/_version.py create mode 100644 myenv/lib/python3.9/site-packages/py/_xmlgen.py create mode 100644 myenv/lib/python3.9/site-packages/py/error.pyi create mode 100644 myenv/lib/python3.9/site-packages/py/iniconfig.pyi create mode 100644 myenv/lib/python3.9/site-packages/py/io.pyi create mode 100644 myenv/lib/python3.9/site-packages/py/path.pyi create mode 100644 myenv/lib/python3.9/site-packages/py/py.typed create mode 100644 myenv/lib/python3.9/site-packages/py/test.py create mode 100644 myenv/lib/python3.9/site-packages/py/xml.pyi create mode 100644 myenv/lib/python3.9/site-packages/pyasn1-0.4.8.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pyasn1-0.4.8.dist-info/LICENSE.rst create mode 100644 myenv/lib/python3.9/site-packages/pyasn1-0.4.8.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pyasn1-0.4.8.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pyasn1-0.4.8.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pyasn1-0.4.8.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pyasn1-0.4.8.dist-info/zip-safe create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/ber/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/ber/decoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/ber/encoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/ber/eoo.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/cer/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/cer/decoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/cer/encoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/der/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/der/decoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/der/encoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/native/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/native/decoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/codec/native/encoder.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/compat/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/compat/binary.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/compat/calling.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/compat/dateandtime.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/compat/integer.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/compat/octets.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/compat/string.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/debug.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/error.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/base.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/char.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/constraint.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/error.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/namedtype.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/namedval.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/opentype.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/tag.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/tagmap.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/univ.py create mode 100644 myenv/lib/python3.9/site-packages/pyasn1/type/useful.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser-2.21.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pycparser-2.21.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pycparser-2.21.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pycparser-2.21.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pycparser-2.21.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pycparser-2.21.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pycparser/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/_ast_gen.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/_build_tables.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/_c_ast.cfg create mode 100644 myenv/lib/python3.9/site-packages/pycparser/ast_transforms.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/c_ast.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/c_generator.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/c_lexer.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/c_parser.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/lextab.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/ply/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/ply/cpp.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/ply/ctokens.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/ply/lex.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/ply/yacc.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/ply/ygen.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/plyparser.py create mode 100644 myenv/lib/python3.9/site-packages/pycparser/yacctab.py create mode 100644 myenv/lib/python3.9/site-packages/pydantic-1.9.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pydantic-1.9.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pydantic-1.9.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pydantic-1.9.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pydantic-1.9.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pydantic-1.9.1.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/pydantic-1.9.1.dist-info/top_level.txt create mode 100755 myenv/lib/python3.9/site-packages/pydantic/__init__.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/__init__.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/_hypothesis_plugin.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/_hypothesis_plugin.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/annotated_types.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/annotated_types.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/class_validators.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/class_validators.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/color.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/color.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/config.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/config.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/dataclasses.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/dataclasses.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/datetime_parse.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/datetime_parse.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/decorator.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/decorator.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/env_settings.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/env_settings.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/error_wrappers.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/error_wrappers.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/errors.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/errors.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/fields.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/fields.py create mode 100644 myenv/lib/python3.9/site-packages/pydantic/generics.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/json.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/json.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/main.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/main.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/mypy.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/mypy.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/networks.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/networks.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/parse.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/parse.py create mode 100644 myenv/lib/python3.9/site-packages/pydantic/py.typed create mode 100755 myenv/lib/python3.9/site-packages/pydantic/schema.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/schema.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/tools.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/tools.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/types.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/types.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/typing.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/typing.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/utils.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/utils.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/validators.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/validators.py create mode 100755 myenv/lib/python3.9/site-packages/pydantic/version.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/pydantic/version.py create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/CONTRIBUTORS.txt create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/pylint-2.13.9.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pylint/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/__pkginfo__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/async.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/basic_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/basic_error_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/comparison_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/docstring_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/name_checker/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/name_checker/checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/name_checker/naming_style.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base/pass_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/base_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/classes/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/classes/class_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/classes/special_methods_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/deprecated.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/design_analysis.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/ellipsis_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/format.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/imports.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/logging.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/mapreduce_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/misc.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/modified_iterating_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/newstyle.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/non_ascii_names.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/raw_metrics.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/refactoring/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/refactoring/implicit_booleaness_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/refactoring/not_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/refactoring/recommendation_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/refactoring/refactoring_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/similar.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/spelling.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/stdlib.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/strings.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/threading_checker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/typecheck.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/unicode.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/unsupported_version.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/checkers/variables.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/config_initialization.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/configuration_mixin.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/find_default_config_files.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/man_help_formatter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/option.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/option_manager_mixin.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/option_parser.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/config/options_provider_mixin.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/constants.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/epylint.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/_check_docs_utils.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/bad_builtin.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/broad_try_clause.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/check_elif.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/code_style.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/comparetozero.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/comparison_placement.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/confusing_elif.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/consider_ternary_expression.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/docparams.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/docstyle.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/empty_comment.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/emptystring.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/eq_without_hash.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/for_any_all.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/mccabe.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/overlapping_exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/private_import.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/redefined_variable_type.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/set_membership.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/typing.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/extensions/while_used.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/graph.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/interfaces.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/lint/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/lint/expand_modules.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/lint/parallel.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/lint/pylinter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/lint/report_functions.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/lint/run.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/lint/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/message/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/message/message.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/message/message_definition.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/message/message_definition_store.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/message/message_id_store.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/diadefslib.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/diagrams.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/dot_printer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/inspector.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/main.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/mermaidjs_printer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/plantuml_printer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/printer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/printer_factory.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/vcg_printer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/pyreverse/writer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/base_reporter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/collecting_reporter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/json_reporter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/multi_reporter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/reports_handler_mix_in.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/text.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/ureports/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/ureports/base_writer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/ureports/nodes.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/reporters/ureports/text_writer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/checker_test_case.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/configuration_test.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/constants.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/decorator.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/functional/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/functional/find_functional_tests.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/functional/lint_module_output_update.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/functional/test_file.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/functional_test_file.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/get_test_info.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/global_test_linter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/lint_module_test.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/output_line.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/primer.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/pyreverse.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/reporter_for_tests.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/testing_pylintrc create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/tokenize_str.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/testutils/unittest_linter.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/typing.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/utils/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/utils/ast_walker.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/utils/docs.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/utils/file_state.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/utils/linterstats.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/utils/pragma_parser.py create mode 100644 myenv/lib/python3.9/site-packages/pylint/utils/utils.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing-3.0.9.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pyparsing-3.0.9.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pyparsing-3.0.9.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pyparsing-3.0.9.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pyparsing-3.0.9.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/actions.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/common.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/core.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/diagram/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/helpers.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/py.typed create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/results.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/testing.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/unicode.py create mode 100644 myenv/lib/python3.9/site-packages/pyparsing/util.py create mode 100644 myenv/lib/python3.9/site-packages/pytest-6.2.5.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pytest-6.2.5.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pytest-6.2.5.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pytest-6.2.5.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pytest-6.2.5.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pytest-6.2.5.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/pytest-6.2.5.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pytest/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pytest/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/pytest/collect.py create mode 100644 myenv/lib/python3.9/site-packages/pytest/py.typed create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio-0.16.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio-0.16.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio-0.16.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio-0.16.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio-0.16.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio-0.16.0.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio-0.16.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pytest_asyncio/plugin.py create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends-1.0.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends-1.0.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends-1.0.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends-1.0.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends-1.0.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends-1.0.1.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends-1.0.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends/constants.py create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends/main.py create mode 100644 myenv/lib/python3.9/site-packages/pytest_depends/util.py create mode 100644 myenv/lib/python3.9/site-packages/python_dotenv-0.20.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/python_dotenv-0.20.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/python_dotenv-0.20.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/python_dotenv-0.20.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/python_dotenv-0.20.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/python_dotenv-0.20.0.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/python_dotenv-0.20.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/python_jose-3.3.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/python_jose-3.3.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/python_jose-3.3.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/python_jose-3.3.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/python_jose-3.3.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/python_jose-3.3.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/python_multipart-0.0.5.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/python_multipart-0.0.5.dist-info/LICENSE.txt create mode 100644 myenv/lib/python3.9/site-packages/python_multipart-0.0.5.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/python_multipart-0.0.5.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/python_multipart-0.0.5.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/python_multipart-0.0.5.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/rfc3986-1.5.0.dist-info/AUTHORS.rst create mode 100644 myenv/lib/python3.9/site-packages/rfc3986-1.5.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/rfc3986-1.5.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/rfc3986-1.5.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/rfc3986-1.5.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/rfc3986-1.5.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/rfc3986-1.5.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/_mixin.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/abnf_regexp.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/api.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/builder.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/compat.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/iri.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/misc.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/normalizers.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/parseresult.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/uri.py create mode 100644 myenv/lib/python3.9/site-packages/rfc3986/validators.py create mode 100644 myenv/lib/python3.9/site-packages/rsa-4.8.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/rsa-4.8.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/rsa-4.8.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/rsa-4.8.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/rsa-4.8.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/rsa-4.8.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/rsa/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/asn1.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/cli.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/common.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/core.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/key.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/parallel.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/pem.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/pkcs1.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/pkcs1_v2.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/prime.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/py.typed create mode 100644 myenv/lib/python3.9/site-packages/rsa/randnum.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/transform.py create mode 100644 myenv/lib/python3.9/site-packages/rsa/util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/REQUESTED create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/dependency_links.txt create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/setuptools-49.2.1.dist-info/zip-safe create mode 100644 myenv/lib/python3.9/site-packages/setuptools/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_deprecation_warning.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/_msvccompiler.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/archive_util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/bcppcompiler.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/ccompiler.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/cmd.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/bdist.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/bdist_dumb.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/bdist_msi.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/bdist_rpm.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/bdist_wininst.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/build.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/build_clib.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/build_ext.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/build_py.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/build_scripts.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/check.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/clean.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/config.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/install.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/install_data.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/install_egg_info.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/install_headers.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/install_lib.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/install_scripts.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/register.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/sdist.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/command/upload.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/config.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/core.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/cygwinccompiler.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/debug.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/dep_util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/dir_util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/dist.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/errors.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/extension.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/fancy_getopt.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/file_util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/filelist.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/log.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/msvc9compiler.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/msvccompiler.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/spawn.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/sysconfig.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/text_file.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/unixccompiler.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/version.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_distutils/versionpredicate.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_imp.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/pyparsing.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/_vendor/six.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/archive_util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/build_meta.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/cli-32.exe create mode 100644 myenv/lib/python3.9/site-packages/setuptools/cli-64.exe create mode 100644 myenv/lib/python3.9/site-packages/setuptools/cli.exe create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/alias.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/bdist_egg.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/bdist_rpm.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/bdist_wininst.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/build_clib.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/build_ext.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/build_py.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/develop.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/dist_info.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/easy_install.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/egg_info.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/install.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/install_egg_info.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/install_lib.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/install_scripts.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/launcher manifest.xml create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/py36compat.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/register.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/rotate.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/saveopts.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/sdist.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/setopt.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/test.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/upload.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/command/upload_docs.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/config.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/dep_util.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/depends.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/dist.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/distutils_patch.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/errors.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/extension.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/extern/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/glob.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/gui-32.exe create mode 100644 myenv/lib/python3.9/site-packages/setuptools/gui-64.exe create mode 100644 myenv/lib/python3.9/site-packages/setuptools/gui.exe create mode 100644 myenv/lib/python3.9/site-packages/setuptools/installer.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/launch.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/lib2to3_ex.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/monkey.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/msvc.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/namespaces.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/package_index.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/py27compat.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/py31compat.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/py33compat.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/py34compat.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/sandbox.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/script (dev).tmpl create mode 100644 myenv/lib/python3.9/site-packages/setuptools/script.tmpl create mode 100644 myenv/lib/python3.9/site-packages/setuptools/ssl_support.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/unicode_utils.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/version.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/wheel.py create mode 100644 myenv/lib/python3.9/site-packages/setuptools/windows_support.py create mode 100644 myenv/lib/python3.9/site-packages/six-1.16.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/six-1.16.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/six-1.16.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/six-1.16.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/six-1.16.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/six-1.16.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/six.py create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/LICENSE.APACHE2 create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/LICENSE.MIT create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/sniffio-1.2.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/sniffio/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/sniffio/_impl.py create mode 100644 myenv/lib/python3.9/site-packages/sniffio/_tests/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/sniffio/_tests/test_sniffio.py create mode 100644 myenv/lib/python3.9/site-packages/sniffio/_version.py create mode 100644 myenv/lib/python3.9/site-packages/sniffio/py.typed create mode 100644 myenv/lib/python3.9/site-packages/starlette-0.16.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/starlette-0.16.0.dist-info/LICENSE.md create mode 100644 myenv/lib/python3.9/site-packages/starlette-0.16.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/starlette-0.16.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/starlette-0.16.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/starlette-0.16.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/starlette/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/applications.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/authentication.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/background.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/concurrency.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/config.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/convertors.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/datastructures.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/endpoints.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/formparsers.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/graphql.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/authentication.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/base.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/cors.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/errors.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/gzip.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/httpsredirect.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/sessions.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/trustedhost.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/middleware/wsgi.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/py.typed create mode 100644 myenv/lib/python3.9/site-packages/starlette/requests.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/responses.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/routing.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/schemas.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/staticfiles.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/status.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/templating.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/testclient.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/types.py create mode 100644 myenv/lib/python3.9/site-packages/starlette/websockets.py create mode 100644 myenv/lib/python3.9/site-packages/toml-0.10.2.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/toml-0.10.2.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/toml-0.10.2.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/toml-0.10.2.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/toml-0.10.2.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/toml-0.10.2.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/toml/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/toml/decoder.py create mode 100644 myenv/lib/python3.9/site-packages/toml/encoder.py create mode 100644 myenv/lib/python3.9/site-packages/toml/ordered.py create mode 100644 myenv/lib/python3.9/site-packages/toml/tz.py create mode 100644 myenv/lib/python3.9/site-packages/tomli-1.2.3.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/tomli-1.2.3.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/tomli-1.2.3.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/tomli-1.2.3.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/tomli-1.2.3.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/tomli/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/tomli/_parser.py create mode 100644 myenv/lib/python3.9/site-packages/tomli/_re.py create mode 100644 myenv/lib/python3.9/site-packages/tomli/_types.py create mode 100644 myenv/lib/python3.9/site-packages/tomli/py.typed create mode 100644 myenv/lib/python3.9/site-packages/tomlkit-0.7.2.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/tomlkit-0.7.2.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/tomlkit-0.7.2.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/tomlkit-0.7.2.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/tomlkit-0.7.2.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/_compat.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/_utils.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/api.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/container.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/items.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/parser.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/py.typed create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/source.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/toml_char.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/toml_document.py create mode 100644 myenv/lib/python3.9/site-packages/tomlkit/toml_file.py create mode 100644 myenv/lib/python3.9/site-packages/typing_extensions-4.3.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/typing_extensions-4.3.0.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/typing_extensions-4.3.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/typing_extensions-4.3.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/typing_extensions-4.3.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/typing_extensions.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn-0.16.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/uvicorn-0.16.0.dist-info/LICENSE.md create mode 100644 myenv/lib/python3.9/site-packages/uvicorn-0.16.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/uvicorn-0.16.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/uvicorn-0.16.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/uvicorn-0.16.0.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/uvicorn-0.16.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/_handlers/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/_handlers/http.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/_types.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/config.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/importer.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/lifespan/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/lifespan/off.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/lifespan/on.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/logging.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/loops/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/loops/asyncio.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/loops/auto.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/loops/uvloop.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/main.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/middleware/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/middleware/asgi2.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/middleware/debug.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/middleware/message_logger.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/middleware/wsgi.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/http/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/http/auto.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/http/flow_control.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/utils.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/websockets/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/websockets/auto.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/websockets/websockets_impl.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/protocols/websockets/wsproto_impl.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/server.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/subprocess.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/supervisors/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/supervisors/basereload.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/supervisors/multiprocess.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/supervisors/statreload.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/supervisors/watchgodreload.py create mode 100644 myenv/lib/python3.9/site-packages/uvicorn/workers.py create mode 100644 myenv/lib/python3.9/site-packages/uvloop-0.16.0.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/uvloop-0.16.0.dist-info/LICENSE-APACHE create mode 100644 myenv/lib/python3.9/site-packages/uvloop-0.16.0.dist-info/LICENSE-MIT create mode 100644 myenv/lib/python3.9/site-packages/uvloop-0.16.0.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/uvloop-0.16.0.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/uvloop-0.16.0.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/uvloop-0.16.0.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/uvloop/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvloop/_noop.py create mode 100644 myenv/lib/python3.9/site-packages/uvloop/_testbase.py create mode 100644 myenv/lib/python3.9/site-packages/uvloop/_version.py create mode 100644 myenv/lib/python3.9/site-packages/uvloop/cbhandles.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/cbhandles.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/dns.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/errors.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/async_.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/async_.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/basetransport.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/basetransport.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/check.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/check.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/handle.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/handle.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/idle.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/idle.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/pipe.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/pipe.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/poll.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/poll.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/process.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/process.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/stream.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/stream.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/streamserver.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/streamserver.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/tcp.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/tcp.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/timer.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/timer.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/udp.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/handles/udp.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/compat.h create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/consts.pxi create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/debug.h create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/debug.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/flowcontrol.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/fork_handler.h create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/python.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/stdlib.pxi create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/system.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/includes/uv.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/loop.c create mode 100755 myenv/lib/python3.9/site-packages/uvloop/loop.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/uvloop/loop.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/loop.pyi create mode 100644 myenv/lib/python3.9/site-packages/uvloop/loop.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/lru.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/pseudosock.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/py.typed create mode 100644 myenv/lib/python3.9/site-packages/uvloop/request.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/request.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/server.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/server.pyx create mode 100644 myenv/lib/python3.9/site-packages/uvloop/sslproto.pxd create mode 100644 myenv/lib/python3.9/site-packages/uvloop/sslproto.pyx create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/entry_points.txt create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/watchgod-0.8.2.dist-info/zip-safe create mode 100644 myenv/lib/python3.9/site-packages/watchgod/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/watchgod/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/watchgod/cli.py create mode 100644 myenv/lib/python3.9/site-packages/watchgod/main.py create mode 100644 myenv/lib/python3.9/site-packages/watchgod/py.typed create mode 100644 myenv/lib/python3.9/site-packages/watchgod/version.py create mode 100644 myenv/lib/python3.9/site-packages/watchgod/watcher.py create mode 100644 myenv/lib/python3.9/site-packages/websockets-10.3.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/websockets-10.3.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/websockets-10.3.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/websockets-10.3.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/websockets-10.3.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/websockets-10.3.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/websockets/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/__main__.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/auth.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/client.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/connection.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/datastructures.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/exceptions.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/extensions/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/extensions/base.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/extensions/permessage_deflate.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/frames.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/headers.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/http.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/http11.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/imports.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/__init__.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/auth.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/client.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/compatibility.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/framing.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/handshake.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/http.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/protocol.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/legacy/server.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/py.typed create mode 100644 myenv/lib/python3.9/site-packages/websockets/server.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/speedups.c create mode 100755 myenv/lib/python3.9/site-packages/websockets/speedups.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/websockets/streams.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/typing.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/uri.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/utils.py create mode 100644 myenv/lib/python3.9/site-packages/websockets/version.py create mode 100644 myenv/lib/python3.9/site-packages/wrapt-1.14.1.dist-info/INSTALLER create mode 100644 myenv/lib/python3.9/site-packages/wrapt-1.14.1.dist-info/LICENSE create mode 100644 myenv/lib/python3.9/site-packages/wrapt-1.14.1.dist-info/METADATA create mode 100644 myenv/lib/python3.9/site-packages/wrapt-1.14.1.dist-info/RECORD create mode 100644 myenv/lib/python3.9/site-packages/wrapt-1.14.1.dist-info/WHEEL create mode 100644 myenv/lib/python3.9/site-packages/wrapt-1.14.1.dist-info/top_level.txt create mode 100644 myenv/lib/python3.9/site-packages/wrapt/__init__.py create mode 100755 myenv/lib/python3.9/site-packages/wrapt/_wrappers.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/wrapt/arguments.py create mode 100644 myenv/lib/python3.9/site-packages/wrapt/decorators.py create mode 100644 myenv/lib/python3.9/site-packages/wrapt/importer.py create mode 100644 myenv/lib/python3.9/site-packages/wrapt/wrappers.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/__init__.py create mode 100755 myenv/lib/python3.9/site-packages/yaml/_yaml.cpython-39-darwin.so create mode 100644 myenv/lib/python3.9/site-packages/yaml/composer.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/constructor.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/cyaml.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/dumper.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/emitter.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/error.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/events.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/loader.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/nodes.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/parser.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/reader.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/representer.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/resolver.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/scanner.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/serializer.py create mode 100644 myenv/lib/python3.9/site-packages/yaml/tokens.py create mode 100644 myenv/pyvenv.cfg create mode 100644 myenv/share/doc/networkx-2.8.5/LICENSE.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/3d_drawing/README.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/3d_drawing/mayavi2_spring.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/3d_drawing/plot_basic.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/README.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/README.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/WormNet.v3.benchmark.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/hartford_drug.edgelist create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_beam_search.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_betweenness_centrality.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_blockmodel.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_circuits.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_davis_club.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_dedensification.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_iterated_dynamical_systems.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_krackhardt_centrality.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_parallel_betweenness.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_rcm.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_snap.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/algorithms/plot_subgraphs.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/basic/README.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/basic/plot_properties.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/basic/plot_read_write.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/basic/plot_simple_graph.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/README.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/chess_masters_WCC.pgn.bz2 create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/knuth_miles.txt.gz create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_chess_masters.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_custom_node_icons.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_degree.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_directed.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_edge_colormap.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_ego_graph.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_eigenvalues.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_four_grids.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_house_with_colors.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_knuth_miles.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_labels_and_colors.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_multipartite_graph.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_node_colormap.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_rainbow_coloring.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_random_geometric_graph.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_sampson.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_selfloops.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_simple_path.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_spectral_grid.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_tsp.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_unix_email.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/plot_weighted_graph.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/drawing/unix_email.mbox create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/README.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_degree_sequence.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_erdos_renyi.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_expected_degree_sequence.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_football.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_karate_club.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_morse_trie.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_napoleon_russian_campaign.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_roget.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/plot_words.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/roget_dat.txt.gz create mode 100644 myenv/share/doc/networkx-2.8.5/examples/graph/words_dat.txt.gz create mode 100644 myenv/share/doc/networkx-2.8.5/examples/subclass/README.txt create mode 100644 myenv/share/doc/networkx-2.8.5/examples/subclass/plot_antigraph.py create mode 100644 myenv/share/doc/networkx-2.8.5/examples/subclass/plot_printgraph.py diff --git a/.melli.py.swp b/.melli.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..124def3633d507d8a9e2aca9fe590425c7f63360 GIT binary patch literal 28672 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 literal 0 HcmV?d00001 diff --git a/melli.py b/melli.py index d6854d2..7fb0346 100644 --- a/melli.py +++ b/melli.py @@ -1,4 +1,5 @@ from fastapi import FastAPI +from typing import Any, Dict, List app = FastAPI( title="Melli Hiring Challenge 👩‍💻", @@ -12,25 +13,35 @@ @app.get("/task1/greet/{name}", tags=["Task 1"], summary="👋🇩🇪🇬🇧🇪🇸") -async def task1_greet(name: str) -> str: +async def task1_greet(name: str, language: str = "de") -> str: """Greet somebody in German, English or Spanish!""" # Write your code below - ... - return f"Hello {name}, I am Melli." - + greetings: Dict[str, str] = { + "en": f"Hello {name}, I am Melli.", + "de": f"Hallo {name}, ich bin Melli.", + "es": f"Hola {name}, soy Melli.", + } + try: + return greetings[language] + except: + return f"Hallo {name}, leider spreche ich nicht '{language}'!" """ Task 2 - snake_case to cameCase """ -from typing import Any - - -def camelize(key: str): +def camelize(key: str) -> str: """Takes string in snake_case format returns camelCase formatted version.""" # Write your code below - ... - return key + temp: List[str] = [c for c in key[::-1]] + ret: str = "" + while temp: + c: str = temp.pop() + if c != '_': + ret += c + else: + temp[-1] = temp[-1].upper() + return ret @app.post("/task2/camelize", tags=["Task 2"], summary="🐍➡️🐪") @@ -45,7 +56,7 @@ async def task2_camelize(data: dict[str, Any]) -> dict[str, Any]: from pydantic import BaseModel -friends = { +friends: Dict[str, List[str]] = { "Matthias": ["Sahar", "Franziska", "Hans"], "Stefan": ["Felix", "Ben", "Philip"], } @@ -60,28 +71,27 @@ class ActionResponse(BaseModel): message: str -def handle_call_action(action: str): +def handle_call_action(action: str, user: str = None) -> str: # Write your code below - ... - return "🤙 Why don't you call them yourself!" + for f in friends[user]: + if f in action: + return {"message": f"🤙 Calling {f} ..."} + return {"message": f"{user}, I can't find this person in your contacts."} -def handle_reminder_action(action: str): +def handle_reminder_action(action: str, user: str = None) -> str: # Write your code below - ... - return "🔔 I can't even remember my own stuff!" + return {"message": "🔔 Alright, I will remind you!"} -def handle_timer_action(action: str): +def handle_timer_action(action: str, user: str = None) -> str: # Write your code below - ... - return "⏰ I don't know how to read the clock!" + return {"message": "⏰ Alright, the timer is set!"} -def handle_unknown_action(action: str): +def handle_unknown_action(action: str, user: str = None) -> str: # Write your code below - ... - return "🤬 #$!@" + return {"message": "👀 Sorry , but I can't help with that!"} @app.post("/task3/action", tags=["Task 3"], summary="🤌") @@ -90,19 +100,18 @@ def task3_action(request: ActionRequest): # tip: you have to use the response model above and also might change the signature # of the action handlers # Write your code below - ... - from random import choice - - # There must be a better way! - handler = choice( - [ - handle_call_action, - handle_reminder_action, - handle_timer_action, - handle_unknown_action, - ] - ) - return handler(request.action) + if request.username not in friends: + return {"message": f"Hi {request.username}, I don't know you yet. But I would love to meet you!"} + if "call" in request.action.lower(): + handler = handle_call_action + elif "remind" in request.action.lower(): + handler = handle_reminder_action + elif "timer" in request.action.lower(): + handler = handle_timer_action + else: + handler = handle_unknown_action + + return handler(request.action, request.username) """ @@ -167,6 +176,17 @@ async def login(form_data: OAuth2PasswordRequestForm = Depends()): # tip: check the verify_password above # Write your code below ... + user = fake_users_db.get(form_data.username) + + if user is None or not verify_password(form_data.password, user["hashed_password"]): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + + # If the user is found and the password is correct, create a JWT token + payload = { "sub": form_data.username, "exp": datetime.utcnow() + timedelta(minutes=30), @@ -193,18 +213,41 @@ async def get_current_user(token: str = Depends(oauth2_scheme)) -> User: # otherwise raise the credentials_exception above # Write your code below ... + try: + payload = decode_jwt(token) + username = payload["sub"] + user = fake_users_db.get(username) + + if user is None: + raise credentials_exception + return User(**user) + except JWTError: + raise credentials_exception + @app.get("/task4/users/{username}/secret", summary="🤫", tags=["Task 4"]) async def read_user_secret( username: str, current_user: User = Depends(get_current_user) -): +) -> str: """Read a user's secret.""" # uppps 🤭 maybe we should check if the requested secret actually belongs to the user # Write your code below ... - if user := get_user(username): - return user.secret + user: User = get_user(username) + + if user is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found", + ) + if user.username != current_user.username: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Don't spy on other user!", + ) + + return user.secret """ diff --git a/myenv/bin/Activate.ps1 b/myenv/bin/Activate.ps1 new file mode 100644 index 0000000..2fb3852 --- /dev/null +++ b/myenv/bin/Activate.ps1 @@ -0,0 +1,241 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/myenv/bin/activate b/myenv/bin/activate new file mode 100644 index 0000000..251f6b5 --- /dev/null +++ b/myenv/bin/activate @@ -0,0 +1,66 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/Users/kerianyousfi/fun/python-challenge/myenv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(myenv) ${PS1:-}" + export PS1 +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null +fi diff --git a/myenv/bin/activate.csh b/myenv/bin/activate.csh new file mode 100644 index 0000000..4a73a1a --- /dev/null +++ b/myenv/bin/activate.csh @@ -0,0 +1,25 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/Users/kerianyousfi/fun/python-challenge/myenv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(myenv) $prompt" +endif + +alias pydoc python -m pydoc + +rehash diff --git a/myenv/bin/activate.fish b/myenv/bin/activate.fish new file mode 100644 index 0000000..9f39418 --- /dev/null +++ b/myenv/bin/activate.fish @@ -0,0 +1,64 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/); you cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + functions -e fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + + set -e VIRTUAL_ENV + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/Users/kerianyousfi/fun/python-challenge/myenv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) "(myenv) " (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/myenv/bin/black b/myenv/bin/black new file mode 100755 index 0000000..581e566 --- /dev/null +++ b/myenv/bin/black @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from black import patched_main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(patched_main()) diff --git a/myenv/bin/black-primer b/myenv/bin/black-primer new file mode 100755 index 0000000..f8f3bb0 --- /dev/null +++ b/myenv/bin/black-primer @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from black_primer.cli import main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/blackd b/myenv/bin/blackd new file mode 100755 index 0000000..c81e4e0 --- /dev/null +++ b/myenv/bin/blackd @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from blackd import patched_main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(patched_main()) diff --git a/myenv/bin/dotenv b/myenv/bin/dotenv new file mode 100755 index 0000000..3d1efb7 --- /dev/null +++ b/myenv/bin/dotenv @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from dotenv.cli import cli +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(cli()) diff --git a/myenv/bin/easy_install b/myenv/bin/easy_install new file mode 100755 index 0000000..28a43f0 --- /dev/null +++ b/myenv/bin/easy_install @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python3.9 +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/easy_install-3.9 b/myenv/bin/easy_install-3.9 new file mode 100755 index 0000000..28a43f0 --- /dev/null +++ b/myenv/bin/easy_install-3.9 @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python3.9 +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/epylint b/myenv/bin/epylint new file mode 100755 index 0000000..a0d8d7c --- /dev/null +++ b/myenv/bin/epylint @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pylint import run_epylint +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(run_epylint()) diff --git a/myenv/bin/future-fstrings-show b/myenv/bin/future-fstrings-show new file mode 100755 index 0000000..9c35bed --- /dev/null +++ b/myenv/bin/future-fstrings-show @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from future_fstrings import main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/get_objgraph b/myenv/bin/get_objgraph new file mode 100755 index 0000000..9f437d9 --- /dev/null +++ b/myenv/bin/get_objgraph @@ -0,0 +1,54 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# +# Author: Mike McKerns (mmckerns @caltech and @uqfoundation) +# Copyright (c) 2008-2016 California Institute of Technology. +# Copyright (c) 2016-2022 The Uncertainty Quantification Foundation. +# License: 3-clause BSD. The full license text is available at: +# - https://github.com/uqfoundation/dill/blob/master/LICENSE +""" +display the reference paths for objects in ``dill.types`` or a .pkl file + +Notes: + the generated image is useful in showing the pointer references in + objects that are or can be pickled. Any object in ``dill.objects`` + listed in ``dill.load_types(picklable=True, unpicklable=True)`` works. + +Examples:: + + $ get_objgraph FrameType + Image generated as FrameType.png +""" + +import dill as pickle +#pickle.debug.trace(True) +#import pickle + +# get all objects for testing +from dill import load_types +load_types(pickleable=True,unpickleable=True) +from dill import objects + +if __name__ == "__main__": + import sys + if len(sys.argv) != 2: + print ("Please provide exactly one file or type name (e.g. 'IntType')") + msg = "\n" + for objtype in list(objects.keys())[:40]: + msg += objtype + ', ' + print (msg + "...") + else: + objtype = str(sys.argv[-1]) + try: + obj = objects[objtype] + except KeyError: + obj = pickle.load(open(objtype,'rb')) + import os + objtype = os.path.splitext(objtype)[0] + try: + import objgraph + objgraph.show_refs(obj, filename=objtype+'.png') + except ImportError: + print ("Please install 'objgraph' to view object graphs") + + +# EOF diff --git a/myenv/bin/httpx b/myenv/bin/httpx new file mode 100755 index 0000000..4650911 --- /dev/null +++ b/myenv/bin/httpx @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from httpx import main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/isort b/myenv/bin/isort new file mode 100755 index 0000000..133a8c2 --- /dev/null +++ b/myenv/bin/isort @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from isort.main import main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/isort-identify-imports b/myenv/bin/isort-identify-imports new file mode 100755 index 0000000..9e7e113 --- /dev/null +++ b/myenv/bin/isort-identify-imports @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from isort.main import identify_imports_main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(identify_imports_main()) diff --git a/myenv/bin/pip b/myenv/bin/pip new file mode 100755 index 0000000..7a69eac --- /dev/null +++ b/myenv/bin/pip @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python3.9 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/pip3 b/myenv/bin/pip3 new file mode 100755 index 0000000..7a69eac --- /dev/null +++ b/myenv/bin/pip3 @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python3.9 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/pip3.9 b/myenv/bin/pip3.9 new file mode 100755 index 0000000..7a69eac --- /dev/null +++ b/myenv/bin/pip3.9 @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python3.9 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/py.test b/myenv/bin/py.test new file mode 100755 index 0000000..bff0c09 --- /dev/null +++ b/myenv/bin/py.test @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pytest import console_main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(console_main()) diff --git a/myenv/bin/pylint b/myenv/bin/pylint new file mode 100755 index 0000000..25dd42d --- /dev/null +++ b/myenv/bin/pylint @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pylint import run_pylint +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(run_pylint()) diff --git a/myenv/bin/pyreverse b/myenv/bin/pyreverse new file mode 100755 index 0000000..ab48604 --- /dev/null +++ b/myenv/bin/pyreverse @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pylint import run_pyreverse +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(run_pyreverse()) diff --git a/myenv/bin/pyrsa-decrypt b/myenv/bin/pyrsa-decrypt new file mode 100755 index 0000000..e32a47e --- /dev/null +++ b/myenv/bin/pyrsa-decrypt @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from rsa.cli import decrypt +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(decrypt()) diff --git a/myenv/bin/pyrsa-encrypt b/myenv/bin/pyrsa-encrypt new file mode 100755 index 0000000..e8dced7 --- /dev/null +++ b/myenv/bin/pyrsa-encrypt @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from rsa.cli import encrypt +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(encrypt()) diff --git a/myenv/bin/pyrsa-keygen b/myenv/bin/pyrsa-keygen new file mode 100755 index 0000000..d8cf5c0 --- /dev/null +++ b/myenv/bin/pyrsa-keygen @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from rsa.cli import keygen +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(keygen()) diff --git a/myenv/bin/pyrsa-priv2pub b/myenv/bin/pyrsa-priv2pub new file mode 100755 index 0000000..68cf697 --- /dev/null +++ b/myenv/bin/pyrsa-priv2pub @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from rsa.util import private_to_public +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(private_to_public()) diff --git a/myenv/bin/pyrsa-sign b/myenv/bin/pyrsa-sign new file mode 100755 index 0000000..46756be --- /dev/null +++ b/myenv/bin/pyrsa-sign @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from rsa.cli import sign +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(sign()) diff --git a/myenv/bin/pyrsa-verify b/myenv/bin/pyrsa-verify new file mode 100755 index 0000000..4afcbd2 --- /dev/null +++ b/myenv/bin/pyrsa-verify @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from rsa.cli import verify +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(verify()) diff --git a/myenv/bin/pytest b/myenv/bin/pytest new file mode 100755 index 0000000..bff0c09 --- /dev/null +++ b/myenv/bin/pytest @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pytest import console_main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(console_main()) diff --git a/myenv/bin/python b/myenv/bin/python new file mode 120000 index 0000000..e616d26 --- /dev/null +++ b/myenv/bin/python @@ -0,0 +1 @@ +python3.9 \ No newline at end of file diff --git a/myenv/bin/python3 b/myenv/bin/python3 new file mode 120000 index 0000000..e616d26 --- /dev/null +++ b/myenv/bin/python3 @@ -0,0 +1 @@ +python3.9 \ No newline at end of file diff --git a/myenv/bin/python3.9 b/myenv/bin/python3.9 new file mode 120000 index 0000000..c03713e --- /dev/null +++ b/myenv/bin/python3.9 @@ -0,0 +1 @@ +/Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 \ No newline at end of file diff --git a/myenv/bin/symilar b/myenv/bin/symilar new file mode 100755 index 0000000..5a5f2ac --- /dev/null +++ b/myenv/bin/symilar @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pylint import run_symilar +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(run_symilar()) diff --git a/myenv/bin/undill b/myenv/bin/undill new file mode 100755 index 0000000..da19feb --- /dev/null +++ b/myenv/bin/undill @@ -0,0 +1,22 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# +# Author: Mike McKerns (mmckerns @caltech and @uqfoundation) +# Copyright (c) 2008-2016 California Institute of Technology. +# Copyright (c) 2016-2022 The Uncertainty Quantification Foundation. +# License: 3-clause BSD. The full license text is available at: +# - https://github.com/uqfoundation/dill/blob/master/LICENSE +""" +unpickle the contents of a pickled object file + +Examples:: + + $ undill hello.pkl + ['hello', 'world'] +""" + +if __name__ == '__main__': + import sys + import dill + for file in sys.argv[1:]: + print (dill.load(open(file,'rb'))) + diff --git a/myenv/bin/uvicorn b/myenv/bin/uvicorn new file mode 100755 index 0000000..a7b06ce --- /dev/null +++ b/myenv/bin/uvicorn @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from uvicorn.main import main +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(main()) diff --git a/myenv/bin/watchgod b/myenv/bin/watchgod new file mode 100755 index 0000000..4a948f9 --- /dev/null +++ b/myenv/bin/watchgod @@ -0,0 +1,8 @@ +#!/Users/kerianyousfi/fun/python-challenge/myenv/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from watchgod.cli import cli +if __name__ == "__main__": + sys.argv[0] = re.sub(r"(-script\.pyw|\.exe)?$", "", sys.argv[0]) + sys.exit(cli()) diff --git a/myenv/lib/python3.9/site-packages/CHANGELOG.md b/myenv/lib/python3.9/site-packages/CHANGELOG.md new file mode 100644 index 0000000..3781be9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/CHANGELOG.md @@ -0,0 +1,235 @@ +# Python-RSA changelog + +## Version 4.8 - in development + +- Switch to [Poetry](https://python-poetry.org/) for dependency and release management. +- Compatibility with Python 3.10. +- Chain exceptions using `raise new_exception from old_exception` + ([#157](https://github.com/sybrenstuvel/python-rsa/pull/157)) +- Added marker file for PEP 561. This will allow type checking tools in dependent projects + to use type annotations from Python-RSA + ([#136](https://github.com/sybrenstuvel/python-rsa/pull/136)). +- Use the Chinese Remainder Theorem when decrypting with a private key. This + makes decryption 2-4x faster + ([#163](https://github.com/sybrenstuvel/python-rsa/pull/163)). + +## Version 4.7.2 - released 2021-02-24 + +- Fix picking/unpickling issue introduced in 4.7 + ([#173](https://github.com/sybrenstuvel/python-rsa/issues/173)) + +## Version 4.7.1 - released 2021-02-15 + +- Fix threading issue introduced in 4.7 + ([#173](https://github.com/sybrenstuvel/python-rsa/issues/173)) + +## Version 4.7 - released 2021-01-10 + +- Fix [#165](https://github.com/sybrenstuvel/python-rsa/issues/165): + CVE-2020-25658 - Bleichenbacher-style timing oracle in PKCS#1 v1.5 decryption + code +- Add padding length check as described by PKCS#1 v1.5 (Fixes + [#164](https://github.com/sybrenstuvel/python-rsa/issues/164)) +- Reuse of blinding factors to speed up blinding operations. + Fixes [#162](https://github.com/sybrenstuvel/python-rsa/issues/162). +- Declare & test support for Python 3.9 + + +## Version 4.4 & 4.6 - released 2020-06-12 + +Version 4.4 and 4.6 are almost a re-tagged release of version 4.2. It requires +Python 3.5+. To avoid older Python installations from trying to upgrade to RSA +4.4, this is now made explicit in the `python_requires` argument in `setup.py`. +There was a mistake releasing 4.4 as "3.5+ only", which made it necessary to +retag 4.4 as 4.6 as well. + +No functional changes compared to version 4.2. + + +## Version 4.3 & 4.5 - released 2020-06-12 + +Version 4.3 and 4.5 are almost a re-tagged release of version 4.0. It is the +last to support Python 2.7. This is now made explicit in the `python_requires` +argument in `setup.py`. Python 3.4 is not supported by this release. There was a +mistake releasing 4.4 as "3.5+ only", which made it necessary to retag 4.3 as +4.5 as well. + +Two security fixes have also been backported, so 4.3 = 4.0 + these two fixes. + +- Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. +- Reject cyphertexts (when decrypting) and signatures (when verifying) that have + been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks + Carnil for pointing this out. + + +## Version 4.2 - released 2020-06-10 + +- Rolled back the switch to Poetry, and reverted back to using Pipenv + setup.py + for dependency management. There apparently is an issue no-binary installs of + packages build with Poetry. This fixes + [#148](https://github.com/sybrenstuvel/python-rsa/issues/148) +- Limited SHA3 support to those Python versions (3.6+) that support it natively. + The third-party library that adds support for this to Python 3.5 is a binary + package, and thus breaks the pure-Python nature of Python-RSA. + This should fix [#147](https://github.com/sybrenstuvel/python-rsa/issues/147). + + +## Version 4.1 - released 2020-06-10 + +- Added support for Python 3.8. +- Dropped support for Python 2 and 3.4. +- Added type annotations to the source code. This will make Python-RSA easier to use in + your IDE, and allows better type checking. +- Added static type checking via [MyPy](http://mypy-lang.org/). +- Fix [#129](https://github.com/sybrenstuvel/python-rsa/issues/129) Installing from source + gives UnicodeDecodeError. +- Switched to using [Poetry](https://poetry.eustace.io/) for package + management. +- Added support for SHA3 hashing: SHA3-256, SHA3-384, SHA3-512. This + is natively supported by Python 3.6+ and supported via a third-party + library on Python 3.5. +- Choose blinding factor relatively prime to N. Thanks Christian Heimes for pointing this out. +- Reject cyphertexts (when decrypting) and signatures (when verifying) that have + been modified by prepending zero bytes. This resolves CVE-2020-13757. Thanks + Adelapie for pointing this out. + + +## Version 4.0 - released 2018-09-16 + +- Removed deprecated modules: + - rsa.varblock + - rsa.bigfile + - rsa._version133 + - rsa._version200 +- Removed CLI commands that use the VARBLOCK/bigfile format. +- Ensured that PublicKey.save_pkcs1() and PrivateKey.save_pkcs1() always return bytes. +- Dropped support for Python 2.6 and 3.3. +- Dropped support for Psyco. +- Miller-Rabin iterations determined by bitsize of key. + [#58](https://github.com/sybrenstuvel/python-rsa/pull/58) +- Added function `rsa.find_signature_hash()` to return the name of the hashing + algorithm used to sign a message. `rsa.verify()` now also returns that name, + instead of always returning `True`. + [#78](https://github.com/sybrenstuvel/python-rsa/issues/13) +- Add support for SHA-224 for PKCS1 signatures. + [#104](https://github.com/sybrenstuvel/python-rsa/pull/104) +- Transitioned from `requirements.txt` to Pipenv for package management. + + +## Version 3.4.2 - released 2016-03-29 + +- Fixed dates in CHANGELOG.txt + + +## Version 3.4.1 - released 2016-03-26 + +- Included tests/private.pem in MANIFEST.in +- Included README.md and CHANGELOG.txt in MANIFEST.in + + +## Version 3.4 - released 2016-03-17 + +- Moved development to GitHub: https://github.com/sybrenstuvel/python-rsa +- Solved side-channel vulnerability by implementing blinding, fixes #19 +- Deprecated the VARBLOCK format and rsa.bigfile module due to security issues, see + https://github.com/sybrenstuvel/python-rsa/issues/13 +- Integration with Travis-CI [1], Coveralls [2] and Code Climate [3] +- Deprecated the old rsa._version133 and rsa._version200 submodules, they will be + completely removed in version 4.0. +- Add an 'exponent' argument to key.newkeys() +- Switched from Solovay-Strassen to Miller-Rabin primality testing, to + comply with NIST FIPS 186-4 [4] as probabilistic primality test + (Appendix C, subsection C.3): +- Fixed bugs #12, #14, #27, #30, #49 + +[1] https://travis-ci.org/sybrenstuvel/python-rsa +[2] https://coveralls.io/github/sybrenstuvel/python-rsa +[3] https://codeclimate.com/github/sybrenstuvel/python-rsa +[4] http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + + +## Version 3.3 - released 2016-01-13 + +- Thanks to Filippo Valsorda: Fix BB'06 attack in verify() by + switching from parsing to comparison. See [1] for more information. +- Simplified Tox configuration and dropped Python 3.2 support. The + coverage package uses a u'' prefix, which was reintroduced in 3.3 + for ease of porting. + +[1] https://blog.filippo.io/bleichenbacher-06-signature-forgery-in-python-rsa/ + + +## Version 3.2.3 - released 2015-11-05 + +- Added character encoding markers for Python 2.x + + +## Version 3.2.1 - released 2015-11-05 + +- Added per-file licenses +- Added support for wheel packages +- Made example code more consistent and up to date with Python 3.4 + + +## Version 3.2 - released 2015-07-29 + +- Mentioned support for Python 3 in setup.py + + +## Version 3.1.4 - released 2014-02-22 + +- Fixed some bugs + + +## Version 3.1.3 - released 2014-02-02 + +- Dropped support for Python 2.5 + + +## Version 3.1.2 - released 2013-09-15 + +- Added Python 3.3 to the test environment. +- Removed dependency on Distribute +- Added support for loading public keys from OpenSSL + + +## Version 3.1.1 - released 2012-06-18 + +- Fixed doctests for Python 2.7 +- Removed obsolete unittest so all tests run fine on Python 3.2 + +## Version 3.1 - released 2012-06-17 + +- Big, big credits to Yesudeep Mangalapilly for all the changes listed + below! +- Added ability to generate keys on multiple cores simultaneously. +- Massive speedup +- Partial Python 3.2 compatibility (core functionality works, but + saving or loading keys doesn't, for that the pyasn1 package needs to + be ported to Python 3 first) +- Lots of bug fixes + + + +## Version 3.0.1 - released 2011-08-07 + +- Removed unused import of abc module + + +## Version 3.0 - released 2011-08-05 + +- Changed the meaning of the keysize to mean the size of ``n`` rather than + the size of both ``p`` and ``q``. This is the common interpretation of + RSA keysize. To get the old behaviour, double the keysize when generating a + new key. +- Added a lot of doctests +- Added random-padded encryption and decryption using PKCS#1 version 1.5 +- Added hash-based signatures and verification using PKCS#1v1.5 +- Modeling private and public key as real objects rather than dicts. +- Support for saving and loading keys as PEM and DER files. +- Ability to extract a public key from a private key (PEM+DER) + + +## Version 2.0 + +- Security improvements by Barry Mead. diff --git a/myenv/lib/python3.9/site-packages/LICENSE b/myenv/lib/python3.9/site-packages/LICENSE new file mode 100644 index 0000000..67589cb --- /dev/null +++ b/myenv/lib/python3.9/site-packages/LICENSE @@ -0,0 +1,13 @@ +Copyright 2011 Sybren A. Stüvel + +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. diff --git a/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/LICENSE new file mode 100644 index 0000000..2f1b8e1 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2017-2021 Ingy döt Net +Copyright (c) 2006-2016 Kirill Simonov + +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. diff --git a/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/METADATA b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/METADATA new file mode 100644 index 0000000..9a91076 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/METADATA @@ -0,0 +1,46 @@ +Metadata-Version: 2.1 +Name: PyYAML +Version: 6.0 +Summary: YAML parser and emitter for Python +Home-page: https://pyyaml.org/ +Author: Kirill Simonov +Author-email: xi@resolvent.net +License: MIT +Download-URL: https://pypi.org/project/PyYAML/ +Project-URL: Bug Tracker, https://github.com/yaml/pyyaml/issues +Project-URL: CI, https://github.com/yaml/pyyaml/actions +Project-URL: Documentation, https://pyyaml.org/wiki/PyYAMLDocumentation +Project-URL: Mailing lists, http://lists.sourceforge.net/lists/listinfo/yaml-core +Project-URL: Source Code, https://github.com/yaml/pyyaml +Platform: Any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Cython +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup +Requires-Python: >=3.6 +License-File: LICENSE + +YAML is a data serialization format designed for human readability +and interaction with scripting languages. PyYAML is a YAML parser +and emitter for Python. + +PyYAML features a complete YAML 1.1 parser, Unicode support, pickle +support, capable extension API, and sensible error messages. PyYAML +supports standard YAML tags and provides Python-specific tags that +allow to represent an arbitrary Python object. + +PyYAML is applicable for a broad range of tasks from complex +configuration files to object serialization and persistence. + diff --git a/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/RECORD b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/RECORD new file mode 100644 index 0000000..ac2b633 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/RECORD @@ -0,0 +1,25 @@ +PyYAML-6.0.dist-info/LICENSE,sha256=jTko-dxEkP1jVwfLiOsmvXZBAqcoKVQwfT5RZ6V36KQ,1101 +PyYAML-6.0.dist-info/WHEEL,sha256=JIE30nfOWUuazI4Vcfiuv_cYm-SkZCh6YOqQQjhm90A,109 +PyYAML-6.0.dist-info/top_level.txt,sha256=rpj0IVMTisAjh_1vG3Ccf9v5jpCQwAz6cD1IVU5ZdhQ,11 +PyYAML-6.0.dist-info/METADATA,sha256=QmHx9kGp_0yezQCXYaft4eEFeJ6W4oyFfYwHDLP1kdg,2006 +_yaml/__init__.py,sha256=04Ae_5osxahpJHa3XBZUAf4wi6XX32gR8D6X6p64GEA,1402 +yaml/scanner.py,sha256=YEM3iLZSaQwXcQRg2l2R4MdT0zGP2F9eHkKGKnHyWQY,51279 +yaml/_yaml.cpython-39-darwin.so,sha256=MwASErZMw1iveBOlLW1RJRrd4yYWYf2bWYq_nhpnFD0,462160 +yaml/error.py,sha256=Ah9z-toHJUbE9j-M8YpxgSRM5CgLCcwVzJgLLRF2Fxo,2533 +yaml/constructor.py,sha256=kNgkfaeLUkwQYY_Q6Ff1Tz2XVw_pG1xVE9Ak7z-viLA,28639 +yaml/composer.py,sha256=_Ko30Wr6eDWUeUpauUGT3Lcg9QPBnOPVlTnIMRGJ9FM,4883 +yaml/events.py,sha256=50_TksgQiE4up-lKo_V-nBy-tAIxkIPQxY5qDhKCeHw,2445 +yaml/__init__.py,sha256=NDS7S8XgA72-hY6LRmGzUWTPvzGzjWVrWk-OGA-77AA,12309 +yaml/representer.py,sha256=IuWP-cAW9sHKEnS0gCqSa894k1Bg4cgTxaDwIcbRQ-Y,14190 +yaml/tokens.py,sha256=lTQIzSVw8Mg9wv459-TjiOQe6wVziqaRlqX2_89rp54,2573 +yaml/dumper.py,sha256=PLctZlYwZLp7XmeUdwRuv4nYOZ2UBnDIUy8-lKfLF-o,2837 +yaml/cyaml.py,sha256=6ZrAG9fAYvdVe2FK_w0hmXoG7ZYsoYUwapG8CiC72H0,3851 +yaml/parser.py,sha256=ilWp5vvgoHFGzvOZDItFoGjD6D42nhlZrZyjAwa0oJo,25495 +yaml/reader.py,sha256=0dmzirOiDG4Xo41RnuQS7K9rkY3xjHiVasfDMNTqCNw,6794 +yaml/loader.py,sha256=UVa-zIqmkFSCIYq_PgSGm4NSJttHY2Rf_zQ4_b1fHN0,2061 +yaml/resolver.py,sha256=9L-VYfm4mWHxUD1Vg4X7rjDRK_7VZd6b92wzq7Y2IKY,9004 +yaml/serializer.py,sha256=ChuFgmhU01hj4xgI8GaKv6vfM2Bujwa9i7d2FAHj7cA,4165 +yaml/nodes.py,sha256=gPKNj8pKCdh2d4gr3gIYINnPOaOxGhJAUiYhGRnPE84,1440 +yaml/emitter.py,sha256=jghtaU7eFwg31bG0B7RZea_29Adi9CKmXq_QjgQpCkQ,43006 +PyYAML-6.0.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +PyYAML-6.0.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/WHEEL new file mode 100644 index 0000000..9c3644e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: false +Tag: cp39-cp39-macosx_10_9_x86_64 + diff --git a/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/top_level.txt new file mode 100644 index 0000000..e6475e9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/PyYAML-6.0.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_yaml +yaml diff --git a/myenv/lib/python3.9/site-packages/README.md b/myenv/lib/python3.9/site-packages/README.md new file mode 100644 index 0000000..02761da --- /dev/null +++ b/myenv/lib/python3.9/site-packages/README.md @@ -0,0 +1,43 @@ +# Pure Python RSA implementation + +[![PyPI](https://img.shields.io/pypi/v/rsa.svg)](https://pypi.org/project/rsa/) +[![Build Status](https://travis-ci.org/sybrenstuvel/python-rsa.svg?branch=master)](https://travis-ci.org/sybrenstuvel/python-rsa) +[![Coverage Status](https://coveralls.io/repos/github/sybrenstuvel/python-rsa/badge.svg?branch=master)](https://coveralls.io/github/sybrenstuvel/python-rsa?branch=master) +[![Code Climate](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](https://codeclimate.com/github/codeclimate/codeclimate/maintainability) + +[Python-RSA](https://stuvel.eu/rsa) is a pure-Python RSA implementation. It supports +encryption and decryption, signing and verifying signatures, and key +generation according to PKCS#1 version 1.5. It can be used as a Python +library as well as on the commandline. The code was mostly written by +Sybren A. Stüvel. + +Documentation can be found at the [Python-RSA homepage](https://stuvel.eu/rsa). For all changes, check [the changelog](https://github.com/sybrenstuvel/python-rsa/blob/master/CHANGELOG.md). + +Download and install using: + + pip install rsa + +or download it from the [Python Package Index](https://pypi.org/project/rsa/). + +The source code is maintained at [GitHub](https://github.com/sybrenstuvel/python-rsa/) and is +licensed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0) + +## Security + +Because of how Python internally stores numbers, it is very hard (if not impossible) to make a pure-Python program secure against timing attacks. This library is no exception, so use it with care. See https://securitypitfalls.wordpress.com/2018/08/03/constant-time-compare-in-python/ for more info. + +## Setup of Development Environment + +``` +python3 -m venv .venv +. ./.venv/bin/activate +pip install poetry +poetry install +``` + +## Publishing a New Release + +``` +. ./.venv/bin/activate +poetry publish --build +``` diff --git a/myenv/lib/python3.9/site-packages/_black_version.py b/myenv/lib/python3.9/site-packages/_black_version.py new file mode 100644 index 0000000..8c76549 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_black_version.py @@ -0,0 +1 @@ +version = "21.12b0" diff --git a/myenv/lib/python3.9/site-packages/_cffi_backend.cpython-39-darwin.so b/myenv/lib/python3.9/site-packages/_cffi_backend.cpython-39-darwin.so new file mode 100755 index 0000000000000000000000000000000000000000..bdcbe38ce98443aedda178f6db5b44c48ff3086d GIT binary patch literal 202424 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

7~ly>LVqttkjRWY0V>b|1` z)-O<<1k4I4SzHn0vqvn(lve>054y?(xIq|ehSCP%ON6rZKBahXk&%C#M7%~WtRCoB zKD2T{CVV?a^392S+J48}6fKjZA<|?DWBF$N(RY}TkJC;{ed)YwuPOuhTUHpz32dC} z5^vMruar?BTJ#1F>snIU`vZ|7{c&b{RsWKzKKa`2Hu@tE@4cKC(r9Kyd=A9xB0q3J zbBEbW_3XMeh3Z{W{_m6*cjcNqHQ8EX-4bFT&*(~F2%Dc&d8z;5_VPDL`I}SqM`{XO zVQ#eaTrLPYJa%p>{2lo)p}ZYpupMHNKs;3-?yzx!5n8QBq$@zF8&E~Hbu>X?)eiYs z9jPgI%@YKVhEok}8wI$Rj&u;nZsMg5yf`wXB7P3(ov|ykLoVz<$nd#~C8 z(dub}P3C5+86-rXk=c2vir!^4gL}M=7nTVeI*D*Vf8JENO9R)_)M(o_&#Nhl7OgH|(&N@KwLI!$pMm-EM~mh!%Ph zourWO6+T|x&lTjmA9Gu6`+U}0nhF}?HWxqf80;N>@9ZBuT{p0ZWZyf78aafaOe&Le zT1Oy3xP065>1>H-q0b5FXiO7F->S-hfo)Y*VDE zpm2w5G@;8U1`2{Z@3&{V&jpC=xpCz`T9lJJQ!n1GiFX(WHE-U9(ILFd@8*h$27#)Z z6SwEeo~)3-0J;`n$8_L(SOBni<%CvXHK`TvL*w3glHGVy-17c@nxaVPx7v~gQYTYf ziCDjD*wx>sM@Mnnq+BJ}95B8~{1gaF^yuOoYrRlk8e5H095CouZs=;xQ5+mzB17hN zNFqBqgh8{Gdn%+-YsMe!_OV!HskkT>KUwHed}z@S*kvQbP)2vr?_@lho)xp&nTby4 ztP%bG{+EcDbQFG?xZLiKX6r9DI-vm!d)dci{#>ms&83cxk7A{BF9rj(a8vv<9>9w~ zk0H+b1MuW!7HxKVLi|8vp8y-}vY`7T>v^)!yQ>it7d(cm$;phaGJL+;sI|-(MmMeC z5_)=cQB0{7d#s@}-r7#G=`zv<8EcNfFvH7b8=`wCPrADQGHimzdZ^G6f7K>Oi(s;r zuu=*oh3_^4u6% zrd=jkb%#aS+l2WT1$X(Vb*&lLN!8v=v5Ng9P`p3XFHpQ&Zj3E@s*b`$h(lm$M1?s_ zNo8c0d8f6hJ2w*Zt)BFnN9gibATW#-z87LYdJeMS!FPnS#ix*NH9Sw)=~}}t;hV%l zWek-oui1gfi&v;XO|CWJ3&mZuPMB}G@@|~eXf#<%cMId-g}}gtCg{8sE8<01%k4Hp z{sdQ{WdHOQX>qYK0PAA8x&n>M&SI;DS07YdBR!ND5irlbg#uz(Ok`Teoi3tcy==3d zg#7oLXNV9U3r2pfEkQHik`SlSmj_C z2f4{P=4EmiiSSv;Y&B|WKIz7-TOr2+`^P*x+>1IdYWXH+qPP6>VZ6CG(L+9knJD&}7vG^{0f;f)lKQsY z#uk0s=X%>_u7Tp)D|zfvTyYG)90g%Mmf5A$(M|sWX_vn31B%)p+`9mw57^~EIq?`M zj{)VFsHjBo4RYE~55L31(uK~^k_C2@AyGv{F&4%DZ3HOGz3_{jXX>8#p}fo2(@y94 z3_rPaNS>+R34~MU@7nbtY%YAfPrkzVy+aNcSKC@rEdBq?6wBM;`lrEIIYi_cP+Kn1B#9TU(h60nNgdOB!Y0vvcPM%#v48e8j9j6(FF# z!@87!FleRFotRC^!atF1e9`z2aBAPDgj|V#e6M`^N-aR<$~}%;jmm`^B?s%ksQ9pa zC81k%e|x{DRK_MvghZyscSQFWNm#J(`_heL_Zr z*;l@)tc)>Q{Uc2A+{)4LJD#{%+ou~w$(-eUCM}x%s)z^_@A)XzKU4L$u=I~+fA%Xo z{#wGnQuVilCds*RRrobw<7oD8?7~|88v8viHeI<|@=5#saT|zM|FHdDXanLLKJP)} zlQ_0a&dtiA%knIN2}HpX8#L1i+aai?rFMO6TuXiZQuPhD-{+_5Q)cRDc5$k{)9v&o zMMUt)5|}B2)`_q{(AaCdlWI;wA*?QFgwc!_OiH*ZpwW&tu%WR z4tk}U_K2PS53&CUDSl(WUywqjPGHJukW5jDZijE=%4T(a#Lb`3N^T1=KI+I&O$IQx zznUw2IEje3AQm~|(QaQY&{#>zrMm`BAVnLcx~ksyv8R!IUl90hjH?4G;zIGl9SZKs z#AC|9-HTDdCWe&`MA>vOJ%^`(Gy};z!CB5EO3(u2)}9Kse5J6~FcVtEuj8KpzYpNy zp)lR#YQ|!bMBO9xeVXVm;d>>#hpRgY-!ECS65Awvx5T5y^&LjBc6(6gk%;UXNgXTr zVJJ_o;r9~1xA>{~pY-Cp1lSdgJ|NU3b&=>=s<5@hCPpuW06?E<)j=~R2~qya&Q$nvR|FKvhAns z`pCoyUN+vSOI953S?4z>E(&oWD#l%oLa=TUsrV)nte|iuU5#xwbiMRy1o}$k9B0Gi zfY6(L5`^JiNs5+ixMQV8~|^@M1Ad1yt=h3-HG#d{Os+|cExvY*M8qb=1jR9vtk|Jh)k>2CT}{Zt!>GW z?~t|dRW_AUt>w5Sg-@L}X}^~<^O=0HtWV5-Un?LsJ3wI5b5DU@?AP(IRtl#_ODgTC znm1m(+a>sLCVC#edD6#}&4R z<$w6+=9m=auM={Ml|R}C*6pA?AF&;#{IVL;acq&@BjZggQfCj?N=BBY5LYOS&&B^hKDjPp-W(yFq}9JoSalTZVd*Ho-gITm z3Q1`edW$*YVr#?05t#$k-|4sjRqSgP70pFgq> z3?5~5V%w4x8W3PSXW!YYp?O-vHS_^TlPB{4oZD)&p@shyA50W|oIFW&d-ln6=(7SU zS~8t5oDi0%$B4RU=|YCg$*ErQV~G| z)C&s2u7Yw2CQ;UPm9|!GYb&8sCQSY`K}WZQc!+lNcMIerpCf zO$^eF`93Gwen(k|bMorkO+`oFP)lcK5 zs^T>q^jZifu|w)+Wj2cUEv&n)W!*KRkUH8N>u5XSXGXZ@)AZyn^*%OLtxq**hj6KP zU-*Cq+4UHsC^nqwx_&_i!v+1=r8z6rTb{gVe;ygjv~Qz<3eV$xD;KvRzA2=HM`)lc zI34huTIpHl_LSHSSbOq*V#+A4N3*xqXFH(X@zcbx#TpNj>ILR+J`ap`3z*oUb|KV` z^pusRaT7ex0i~y96Wc^cfIn{^w?ddC+Yg_xK zFrY@D2+7RnyT47&PDEQV?`+P~Gv>V@%X2>>5yYanw z9V8GrEKb$UY;^cSg|TrHlBMPoZ3I~Zm;pd!bq^g>xkj$%<1tUJSOp3GVshf)rz=L@b{}0T`+#=h>``4mkQ9!4 zxz?S;U0$u@8PQ#>oF-0z;_}1hU)plUv6?o#MQ$r{6 zWR`ljKqa@UitXK2ajd|elmQD3sJonvj&`iS0h7h6K*vQ;rfKaUCi;*uBLLI>2ijBJ zZEO*}_Fp0_21lb%c_)4;&-Ft?M*>8!Jp^NoLFJa5KqfG~TF zXC~WihDB4joESs}S&A*?+i2=YN$vAhvcx^>T|<=cy{uBM#45C4KnT$tVp|I7J(zn= z77a~KmbIuDGoUwvy>q%Z`MiaNQFo*mIMwg5(`f&7?pfr9DZ=*O5ni1FwB%~!^a4)ag!%*m+~Qid zS@P`?i2wSM;go%7l5MX|A14aG(%)D=oTkEk42g9u}rs@jO6Nl5f`C$05QJcThlajPhgS$48FZ zv!2)^Hwh-YI!LS82K<=9V6>a8__ur z@Fl);s$?z`-xy4m2RlS6VNxB|KAwAzBV~+pU9=ZS%8W8#BAB3Q#fzJ|!CP0gzyFZi zy_X;gx!HUAfLB7%mlF>HnqT~kMVY%Is)@kM&f_l!II_hpE(Zf8`|ug4+q{NPc!G^< zNU&}ZmpynK>ZULqs&2GlPb z`V)JFcsRysMD_}14HwH@0tr!%%nhx zNut2|E=ec#A<2CWM>#7B(^ju`{$L)y+SZ5{KYpq;AHIUb+F-GAYR?znrd%zzDm7kw zCmH37S^I`Xooj5h>-Og(ZHqR%W+w~z3mu>x8q@bt(rm}O`}wNET`0_`U(OHLp-_Cd z2lXrq)v5g#Up%wm+o?2}8<>cI_$MGTd4{7KSYTjY{DZ|fe3|B{Xd_Npr_)#I{nn!` z>bb%(-eWFc;2!q`kP-1iwgrDb#WW0Cqx&(G1HI_ElG^B7=g^Ae3DoNdP|WwzI754P zx*Ci3&=J!2{tB8&?Av?YBgvJrm|kY5VY9xA7vIJ{p1bl@TQ6=k*wc1UZ0ZJmhyQ+P zN4KXr85BX!wYy9nPbQ*(!8t{2KQ%E_Z2`fDaT|azj>&94U7>vS9wVn#hz1{HOujJ3 ztbKdhCVA?|B)S7exXcu_Rt95T$Pf3x#1JWTE+xEV69%!SsfmwXVMUamd4H96#>l;g ziP*)D@Z&xJJ-@q@|~qQydVY#Py} zMQ(g6;A6g1GTG-+^#ZDHAOF-HDm-Go?*vP5ZGZh&Jf|kQP#{BMtN$8%A<|=ye8R_= z4FP-(Oc=6B&F(_sqA<#P258XNs@oV1!_ou3MSRMksOfTfVHMJZ4&Us~q8Q?>&EbGG z%2)GTk=Y&~D8V+WXklgQx<{Mlk`N;yHpzu-kN4Gah20fIB`8oE8C@&Ixbp#$zg@pI_oH)azhv=T6DbOX!vhB6``($ zq6r%JI~tedPJ_~mQmKj&7gv+zE{?gz2-iEBN#L0ENy4bge3dMDNKYVogp#)il-b6r zR&F!vq`bou$C8xR-?a9?=%Quv1n)?Ioa>9sSv`9ip@$(*%Efbz>iNElr+bOgYi=pb ziaej(n%S>lfV^((gKSgabjVh##*MZhF1~`cGv)P*as$$S%eP$^YyAQ-v^VQ!flmb{ zqzmzadu8ESEPf70DMI19xGY(SX$Y-we3`DFyEwHabP0t?b{-#J#>vge(DMF15)xAr zBWZ;AGu>YpGBJzE-ZW{9#sWl6+nbW38AA|eyZfUrjS&c*OWnOb!cdBQEIWxS@H!Hg=GPYY@_&9i;dxo&|6{S=$(&PHba*TE;#*(}ZVya%%4r)c?@{ z^~}rA-%L|4$~eQk{h(49ESLZ91}La7jy8KHr|_`kF~)bCZMc~4+%_Njx+`HGH~S?6 z*{S^uEyWnDx@R&)INYkmU7P0X3iEQ0{>J~*eM=CqVj;EYd6=fs95(PY$Jl%vYnIUK zoD#8q$@^)`vrP2uLxxP*q$x05srhV*VRZ4|F-aW_!M#il&GjOJ*wXTH(A1ma<=^R} zkQd-8=Qe^iaDK@@Xc@moAuu5L&+!cMpL<~?5g6Mo!lDV>pKDSMk~pU3L9X|rw9 zJV%=`=w>~Pea{;QV`b1~9GszX@K$;pC`>}zae&X983#^OoTrejf6#9sw5I~d-&MB-eHcS>r6sz^|(ql~{dSvmFBt*gpYAS=+^$IPF2kAnublD-L z_bNSJ`i^mC>G6VoQcf0}Y!UNm&jKgqz3yl#^1OJgz)cO--V7?GBzA9Q5M%}}d%1@U z-0g)LxF+u%Ku_tvSW1u)`D`s}#irio7sgj!b6rFU@Z1UsASYu;g_AOI2YqDU;%&rd|) z31Dg}IfUN{Fp5N7n&QF@&jT~WLG3j4?_$0DF7jM`gv08 zXL|KCYfm7$hBn_jX_2WtL;u46(pPQpGg&xYS5|1)9R(mqXt}piOMCph^%y5OR+5#N zUYzqYK4--*jX)+208_@=Ak_O2?3w+WG%opor%|_7pu-T{U{90Da=QDIMzyNfCh{au zjd(65iZ$Hd>i*m0S@;YavfojSTw??AC(2mq@D&(;voMZxD+MEt59>Cj0)QS# zX!w;JFfm@Zu<`|_>xw3d`fe%*Bocg)&`L!$B*^4u=Qs7yhU6*c@g6<)G><>mBW55n zJg7(CUcwlhShrc5#=V{%js(Upw$~OOOf$Nx8S!V-QrD+vdn9Ywb1SJYy+WpM*_>*{ z@wN4S{(i@w&YB9_35<0~Q!)wn4R1%ye}d zE!fk*eDy1lj&pc^VZnGeyP=zV(Q&7PB36CPkSj4l2JKE3oW=X#d#RA0Z+PrWIREmr>6ndCqA=a{$B`+-vCjM&abwXKNdTl&jJ;M56>T`yg znmDZb#;FV-Tc>83-GMJaOXNHFq$w4OKhq3Zo&qC{wsqvzatC1l63fMWPhViFdW!F4 zIOrBr2e!^Dz1|JQ3|W&s!4WE9YOXZ&r!MDlQ`yp=Va8@xu5>HgitY)5id3jD>zL_m zff|3`LR^2-Gc1$mv$iFhOy%0K*%s+5RdU&LV%;?J8-4SkOeQ=*yHG(|-i<0~D^Ib1 zF6gOws^q4EB}W80j>=!BRvD|tA5p+*Z5?(^yJ-LVSg;+w!IODLKFWZ*C*TCpqsA4$ zeF10eRs!8(FjYg+F=Jhm~;XxynLM>I=kmLh;^LW-;3x3OH86%T`2d!BJ3Nug#{ELxv^pe zpJfMRhpEyDd>brzFX)VY5BW@Zumhp~2LdIpMtW9uB<@Dcp6RIy&hHb8uR!X zkC4!pCgI%$kZ>LtSnQHaNxnCSf`3}<{E{5duppD?L<1^nLH*Io954R0K%Gi9yU{l} zv$oUZT?_UZdV6=Ge5EZtRJnnM1e`^Ql^zGYVC+1tEFU6O>osjyp_06_pj6HU$ugq} z4)I+@PEjcDRD(jQ&!-7r4f|R3G`rlri64d*(JQ1rXKz?g$c{GGvUj{Z#pgQJUw|4Z z1!?WG5?2?%JBJ@bb0$-m(PUO@UKY%p3THEE8y8!*2+b7+`32j|@yi%#-gox~;a{`3 zB|9<*Pl#svg=^?Rg|V{FAXBoNvBJ39%UC%`wB;bZ=bi@!v^seQJyAKt_C&mR3fLsB zgUj18aM}0P>o|Zi^FUUnpuO(9fI_I8N@TPR*nsg72J&_{D2jM=9VogE)BaJ?@6k1% zN@@lsaaMNxI5yHl>`vhV8i?DrYS$YijXG@ha+}nT0$U;p? z%X5x}gOh`F)E^Qz^nk?wLAc`U9?P5FuBt73qZ1$EtF6j%6`hc>(x@Zq>4+veqFL?g zM7vUhYyme*;N?TKjZ`l8LlL%SadWl~Pg9a;9EkQ%^b2LmN+kkAyl)whh#id>oO;vPmG^D>E?lS8pJ$)Jydc}tYrKSBQtk^}InO7% zyNgYuQXeB9k#W_bCF|Rl9BoUEuqC~ZrX(tpLEKa0Pck_&YJ9r?tu5k*$3wgI%(E$6 zGD{kGJ>9lUD*Mo>HXO42G2NBP_}`X4Ws)N zzMA?%@yhBz^a*q1RIF<5o3{F?!NWh{BL77fvBLCUa*?#)_|)b4Z_P#SEZ7;zI6XC_ zoLc8F23Ymt3%N3nky3wdYNT9Gt?rpmqfvc^*BEz2`ZrZvn9bm;W?8Zv2hdioQRFOL zE`vX@MUG|hWvy?~_R`i4Sy}V6Ezr{gW)Ges8_I#H@&6Q1?^6*jc_)t8lA8k!$qodn z$Mu7`a~73K&8(eiv#<#y|Ci0F`NnzjoQ54Zp5B}tXxNz_sM-_ge2}*eyyXTu?{%J> z&@s^Y8(q4hawyt4=HemZ%9lJJS&zR}GamI^y6~Ho)P@kRHDt z4s6{Q;CyDFp(Te)Y0;Ql-RHsF1IoEpK>f{8~H#WAYsF04`5Y^?6~>eF9Z)jE+v6pFcXr=M`9L@=c&B-$UW^orwpg-n$1rxpO%Yr~hw)%M}Og;2V zJro%`T|Cs~TMXAZ%$kvxpf5)L_{1*@2JA8Rfk15Nm&TY750$Xxha17}NRq2@edFS1 zRF94yPoRkHiner?N1oaR0~gqBnA# zCzteT*a_J$@7wTEe&++cp8_X#-cHJ?owq9w7Z-2p7mN;igP`JXNsh& ze=WFX1^csag7;B{^W^A04IgNL^tA(IbD;Bn=gE1e1mK21=a=|!D&vHK0Zxm4iA(Rq zUvltl17|Xtg7QB3iu!}GiN_a`vyi5hJ5LTjDcI1$SZfV+ZUlaB$PXx>-h47Y!D!cC zvOE6E-Jr&u2{Pv#Zrwggv*eRyExY9QeJ7n``HAU3bi zc`1rr6yik3?^B?+ntG0oJRf=2*1WD-wMKt)4?i?zm8v}%yKKHY+>#)CxpC`k%??KI z(qtZt-lp0EvACHLbUjJkRiZxy6@8g(^)_1*KT_6uNwwOC1>H8zJ(WjtvvJU!C##h$ zXrq<2osg}5dhtaNdcdC6`;2`>()vxI5Z&PZ>>mb}QwwECc*~q{Y4itpV}kUTdB20b z-y-j~pZ8nn{T6t?`QC4?{S~JJwPuxm8vS!^s{bnQce?jG+5V0w^nN{PBP_Hiy9{yP z3?@|Ekc%2e3|@^uou!*+pw;_HqPlo~oC|3~%3FY2CNuWRw)z12Idkw{ceN#=bC(u< zG6d+BXx5s(ue7BsnX-ltyw?Q0_iH3$;=XrAdheIo_kk7OJG)Ez{*_EdDvvU)_gk>` znfKH59`hYIi+64;iT60@@DwlZoUfm}PqD*jI7GJuqYSvs1L|An7x*W*C;gpboGeJ< zXysdH3sb679y9(BzS$Pr1ymcwym&SlI8fb(<_IhrI`?BS)uC_8Aupfy!*RG0E^cz) zvRn}UyJktVP+EYnec!$MZ=$ixWD1wG7#;t8meOncrc#~SH<)759k35DtieRZ3VA`4 zG&;4W)k8`jJCmiNJd7Xa!M%Wt;=*Sji48iFkIn6O=51s_;sNu35T|0NwkLzbSkuOj zHz!$o?pfawi9n3M0?OJ%dUs`Q_Bn!Z&-&d?Egb^I_IFq`{%JTxttWn8N*}=~?Ym%X z(DnhZ2$*vp`&sOnRW`d-CsRuG$x}Ae@j8|*W3mx52ZKYVVLy3((MFx#`;6@Fs+bwB zPHi<=Az7t4n;b9Qhr!4FfIhJ_b7~<1XBddw%fPNja8*W^z<-zHoHVi!%%EHosZQMx z;3Ni^R&$m$m;!$i$w(L{N5zr_q=0d#KlX5i8${a*@bv!TRrc`G6ZtD zP&dl6Red2|k98tP%ooSJs`?bD5nm|kr2Amko~zM9kD_)%OG`DMUb#ebrHZPJ*BeeD zWMxSJc9J)<-BrcQOIHqH)T^4$r2<3yjEkMISNBv#=9yC_T&-NU6(EV#M7H1vMB-2U z!qo(I)dSM^1O`Ilr@Vj-VO?UqDyp=a$5?Qi2pli|u8SRJY_pgnme)QGak%=sZaRge z7`{us#6`Tsd_TG(b%%T*Eq;d)Vk!KzYnYYRo=NG%DP-2g=BJU}cvgJQ33RSvcY_=f zY0W#5WYdWUSUbZAl_f*_M7oVDIb&~_D-SEO#zoJ-(|i|R7mq^ z{y@Wmfb-5~*Z-KMRccP@OI91Z5LW@?2i|seE%)qc2Kz#b{m<}625UEkJ{jS7Q2`O?Vi-a_{Vs3UnVQKTV;r36)M?^9hw(}O)p5NW_ZKoi|IP3%Au zWhvW43$GFokwKCu1~Nl@2UyO93k(U|W2Oj<*$VHUJP|eYWXNy_Xjvbo&F=YsPG?}f zgNL8s85>-oc6-~LkTU)%ru_)X-6BD}xCZAuFu`#N$=X8qgVD;rn11O`b6hnCt)Dyl z)Ev;n6%4;7*yOGmrru0&4SSq0L-Wk~o|UrBa6&x-{81rh-@)v5tKLdQyg%DkhzbZ7 z#U>XaA;Onn$}gf~h`OM_UHB(GRKOy03pL1Zw+WNyOtRMnFXO z0#yu!bh6vs@kjgeBZfPt=;*VNC?kyUgu07dXRA}=BPXLMu{6FGiGB+k7&_9`FBGjR zidDQ89f52m%ohF!=Or(YD2Ppc%?1-VU#yQ!i4Jdd&*TMy@x0TW!!u;H#Zt~LU4>Z6 zDx20jy#2h)cxbF>5xpBLKGhE+nb>}2@9r?uWqB`7QkO9nwlR=lf%I5#ucl2jsa*Ek ztni6&$hI`!>_tOVd)azv6ze2$(~KYnAeP8#26fDC?%>5Bu46 z9=p$*qee4FeI=VV^VKk($H@xJGj5f6M-H~nr||rsOqHbTsQ1Zzc{Xm9d%7b+S3WAD zB`fhCQM9*w;~UzFqnGm7?L?P+#!fzrybM8E$7xibK+WK+B?ADzP4?K5fH}cB83zsm z4s1g-;HHX}=KHM&jJPELO2%P_PKKz(-S}~DfHS@QCZqqF@dBUkMIbdHkkD^@D{UuS z#kL?Ds3lmm)E5${R+<`t)FQ6)1ky%2kswY?ru4>;(m#Mg_`*s;SX23>nmOLIEb7$$ zLfwsOg#FV_I)^FVlQFtSN5Gg>=@XrBXAz7#SVM5SC{g9RYdj2dUX?RT01K6rSFcDEz!B-T^-Yj#fZeDC<#Y+ z*AsLfZhIRi!D>RmmmU0|3Zkblz zU2rrBv|zd&;mvn+B9g`Bp;+-qaC|zejCcvox_#~r%Gc~$def1dR*03~HuNL}SS9X3 zk)x9skI98BSWO>@MY{nFr~FT3|Z5~}#9H&ObZRq5nO zZRBYRo+!@&k@$#KoORBm=Y;3EQk_~p~{wdDS*H`cFM+ktz zW=3f}mJ2r;d5)ihTK7+;NvqvAsFz7>bbQc)5H|savOf=GzfT;yRWy;nwy{SHMeVUh zX+hce2oNbFHgi?5YGR*>z*s{Utab+pP8Ang1+yDN9TzvDmXD4v8p17E;hf3A{+o0p zAU~C-G9LC38e;Kt6}7G5PTY9a50ir|g*r^2cciM`1zMA{P8GfiUn#rKzbWSgw*M80 zSFR-2{=o?JjMnuE3HDUg;5Li))cWL5|IY%;e^)cP!*mD78#NQAV+glrx)Q*O=}v>` z*n}tq)kqKb?+<(QdBdpsxRG$i%pkqfjp>`|Xs7l|h7j8qw5tNPGH1r#F4Qj6GI3G7 z_|tBh2zR+>rr=#~;Blhd0%6WrM@p94kM*=h^52y1Rn*%S(lk$WxFLDf2J+7YS(8e< zc=t|egs#@&u$@y|X@H}-6w4*d3opE$9AB%uJ(N3}@}fV}@!Rg}zccM$u9g_x9gW;z zawSkTrLCl_dcmpd#FxZ3!nQiaKGy2Al$aEg;dT6C=V(G%O@ zG+l7Di1Mb+FL{^R{9_FQ8n-de0Q>_#plW>>{-}Db0>%`(*Ij4ucqcs2U_Re0E4RC= zNKMS*1%rNalHni@NbGV~kWNq*sJscvYDuD-A#Egvum>qGy(+(w6!M4!zb1Qz5rce? z0lj?$d1*sNXJ~b=Pi22A`Eon{wECV=_IzKk_J%WS$9fZaTZPtr7zoG_PWKtDkKqtH z(GnVIc7{9kw}!Yla=pVm3{NSkKcTy_H}; z;HYbKt`Q~Dg@kttL~L;jzOzJ9D_%8-A&Co=xxE!YSp$JbfT`MBl`oz*d4PEj-^lav zXW3`GIPzAVZJ#e^XL~vP@QS->r4>GA&c)+nogWD9hrdy3WRmgLc!w7#^X+kzHEQB6 z41VUc+5U9W+sHI`)`N_CNkA`*MG;mugExEpZ5&Z(2WkQBz@O_{kQ#B0MQR$)4;I;H z_7U@{&a}@8E3(UL1ZSY17|e?ODQd}bJA24CtCsjP`e5&251jk{ul0;4%Vw~cfa;*EW=NK1Nga%oqpCAC08kD28B z7kOtU`Ry$IwpouHD$LUBkv96e#pwczQxkYKH&(o>USlcst~U(oESeKiXns#MIKiN4 z*;*l38F9^M?+HX&g3d9iJV#%6q+Rb0m@2&knXSz`EnSviw5yG&_ zXT^8%F)2b^g|gtjN;8tz*)Z(ettuZroa{9E5;@p(STxNuHM1UAye%WWX07n-&DhN| z_GU~6?$;id924p|6WdVA)OkA{uu+o=h6)xHDS8xyPbq3CU9HjTGuMhVx&us|z zNjceaOI<&Odc*ZrN%CC{*i$+SA5k4s6ZaYL+`&j~XLG1TC$W^i)TEcruB57(`pM`Y zKlkxythv8tHEVqzIq;Jy5~4^-U-$g!_M%v{APHH8q>Yw03Qj!lON`{KvR}ne)P9xi zE}hy`K_l>31rM9?y2CqEp@rT;oLVF8+-zIYP38{jMXS8JlH{&tB@E zcyV!#A)nmqv>@mRL<8a?Kqy<7Yah=K6@uz0Z#X3>D1|ZIih|+2PX%3aiYL?(TyD--;LRkuLN-i z2eO&U8`q0f`FL**A17o-zD~(^x85RWg=ot0vb{YC+4+=Ds9weY>h4_IrOA*n;0!5U zgQbKJw6WsHWq274L^7RO$+ijHnqL?>(wKwddDTYG!p_w_*$cTB&zs{Vgu9t(J1qqV zyd!(kXF;yn(;iRcBlin*69a{f{>rMQ#GpTUTx`&{exgoC4rfAOAr`qRxi;qecvNcB z1y4ucED*92-AG1}(KprtDfv@vxU3~BlZct+J}gI8Z>xezdB0V%m{+^?uxF^`}0n*K;3tkoNj#^3`dX;(~l?CM3$-WKFOUs`CSJtA6#%?c% z;tcIYfk1pTl4VPzbExhMr}kv9?Mt21@-b64VUPSZFC31t&sEw{?u+D;~lA|nC~&K=vGQphbQ0zKj} z*nUORt9NfDm?87M`r>A4l>i?d%}EeYs#zDV4!N$$iGRUj-e2?W;WureQ@G;k7~G(hbY(i;r}Ro0vHf|Jqg1L@9SJRr947Hc{(n!XU_&Y207^Y zeRGnj9=!H!=zz^F?ki$79xNG2yHU+a%?VFbURdz=+O*J$7qw7w<{$#bytClY`^6ZI z&3kA2el&`NdEXCszW)Y|z`Q5SdymWh&7h6v6~3lwvV%_fRy3Z@pBYpto$>~}UUJP_ z4sTnl&(HGTk>%9hMq#)r75DqAPhpK}(m1mhial;O`8~uhfe&Fe^dF17t;Zyu@RsgFCO?ha-Rq-Ks2BF zA*d9xC~wBAs$(;T`E&dr2>B+ELZdDNE$%{UN*<>fEICy7+?{8$xtb_ zlYi`T2wZ#yAAp>4=9x%!QsV8Fa$EbaW{2~CVwx9>m&@s`Vx??U&^^SRBmBu`C0zu` zQr-tqg>Y}I(3%|_7q4_j^za@|I}Qhs%6h`tQZ{_Xvi%+OI~!nnfI(LWPFFO;%9VjA zXItXFKbyS`e_;~3auq3#liVcx++@}pjLOhuFg0TOJm`+?kzUYPz3MKRlrlEYgDYqz zGfeavST)&&qEZ73k2H->bVFJk%D-CQaX~S|obU!|zKvWWGi5W-y>4EP@s=wd$72ME zs->|pEYJL9!gLXF+8Tq=!xSoNVVMam|2LDxR}Ht?+5P@quo40;tL~M^;eg3k_~$8_ z|LVhYaoI0q6<{F?-<#vqAl}mE)vTHYg_w+fYe80|L9YFrfnPyKpOa4dL`mnkcc+Sn ztaR+2&hU^jVEy(TWLa%7JAowk7E0)P-X?e=*YhvX+;VDA-V#gLe$l-J2i*_uw20OH z*g{@v!RXUDfJi>A;4NC1K#t^U_b`h{~BKwaK8*UEdOgut{V9iqE?cBx01Awy0w2R4#aFX>j5RE8l}v=tXL>dM2^D24-5ltLnWD<+8-Kl+JLhd_*h z3cXe%<=(r4u7AoO-5zY%=^GOZmE=25ZjBHB&(@}zea=mD$HWJfpbp&72>?|&w+FKK zwYGqF6Sm{)uGI|u9H$7H%{bC?YgUpNTQ&_=F|-#V4T;=P)dyo^gFce_?bO{(zgQLA zbV=Ra9U;3>pSZV3Yhq&tecR#-mgj+GqPyX6@!NK@K+{<~`({=>T~lw6F3WwK|G`Ay z+3s>`x2g|pH{s>zu192OeU-Y7cQO=W2^W2gY>7wsZ(OXrL&3Hd=yRq* z>{{0wO*V0a1x}G7FF%fIJLIV5)M;BQ?X31wq4Kd+H`?R|`VIsAs6(Ki1nm<4Ab-sF z?)lz2$kdD7DJx5Bo{c1{%Z+@0+ud<7-H^9hiIRs4DQer*6euZhYX3ngjlIObc!>Fy zw}-hGRJjjsmEd029`0QR?&K8QlMaFVi3b;_tyPK74D2&fu$?$oOoQvO2If?jNE&JYFbnAxTYV0WVm|Nox8NN>tOA z0L!cqkS`_7LK{=?UNrFHZQ(5{WLS1#xoa?7 zRbRKZ^$m{XjVU>PC)ZN7b{rEuey5`AFi=B3Y$xb*+5Sr zqKxx@F?%cxcFvhHok#ViY*jU-9C3NOD9Y)NQTH$}(Ts z8e^^f@;7#^ea&)+{wy!1O;7TG-GDZ6D&qlIi$gJZTk#N-{(A=xD2Lap8{);Ex1=!! z{)50*(+u=`E4PyeC>ft|M_zx8R0}cL%+dBTX zC58V57XN`4gTJ;avv4f9Ne!4eCE{thlg>oa0yyv=}s-&)EAZk@O(Aso3)$n z4mS>)+!`JY^~tY{&hAr?iG~Q9^h=-uXTew&e~-C@ekZNpOGZHcP;7nycj!#6tXeX0 zOguE~MRbG8Ei=O)#eoX)wP^|(pNl`aG4zso{UU4iB_K|(~GQT=kYKmz6fc{ zq%yfs&M05Ii_+YMC={fvH4cko?%43T>^Z#kFxR7w^)R@ z*QmU@6x~5&QKuliL(!{Hw(U`Vod5dqkz}~!1rU-=jk!f?U<&+;oiaq_)H6#+G}%4w z?@u%so030ON%VU;N>G|(IQUv~hK6Kq&VNO3Ca&SdonOP#Fo3|OrsQOkWv|<;EMs`V zo_0Uqzy5*0qxjsLzasuN@Ll;9^Za-3Js&a+_Hs3v>1-M{d+HdaKxttk1_iL3C4_+@?3{I~lX zcAeboveeca&%64?QuQ%OSVARR+VwtIBaHZKwMr-s1isChhuAZ1rj~$=6~= zd2Hqj7*=L1VLJCM$GmJs@PY<}R*zfJeuitGCTqzMf9rEvkG+#xk8rQp`;>_^m!mK| zt_c{7PjfdcGwc-UrfVCAT%Nz^O?m&*!7^pFRm51QBoj!EL7WFfa`b&q!vgdsH6uA@ z0wwu;hMaBfr)K@W>{AidAAL<4c+5A)Ag&IBfNTXd;N_uMN>TRNxtcB%>*pQ~Qw6G? z$9v#KB9)*RG%=Pj^wWkQ85S05F3_UpHs*ZJYofGQtcj1vUd!Yoev41+(jidwN^66^ zdeQ4yPGnbkbmns?^D6>XEJQvG#Jj%ei1IZb><;wb!s38=@wLGHT>QF`lcxvqXkSf* z1Gvv+7ol^PnwwPhD{p)KDxeLWvzl8}1921Hh6RDybmRyeVMcUEXtYI93(w&$C ztl~Mpxsj=I^;gcEY%F6-kqP*`)StnjHW7_A)7V0P^m10*b(7TyZm-$Y2KDGS4D(eS zjq=dGg;NG_@qj?=8D$T&zD&2@|BgDr#C^|J2XToej-RaE_R`SLSRSE{1hssD&N>yK z*v;-{nkKdN?hANJyv2X&i?rsq=o5lOH)cn=dp%mG#M)Z&+MbPEpXf`XyI`^D z0=OO8m_Cn8OmyMPe^+b15^>_izgnN_ynet)t2L^|sbwt>2`mrQ{)+~ReeRN8%#{Vn z?#AD!^@U)~x7p5J(&q3G+PPbC0ut_JOA$pMjw^wyAfjoM&WUsy7gb6;uPd;FCF61l z!XKOVUo@BT7R7xHDHQ7#85E7?;zW*>2QBVF3Y6u1Lje?Hjzu+8eY&Lh}tpLa7(NEAe}+)eEOz# zi;NxYOX8^`5*TGmZ=uP3aj`A(GS9P_f9qxTb`U0$E$x$#_Ly%se}f-^%5(;1rlAG- znF(lUv#=}un(n``D~I~(*TH@0?U({DFAKy&1xFfr9sQ8|2DsWau=lM{^y5uAhaYan z32h4ZN<}_rnuJbpmG~Il~VM*2sNj z%ei;&MULPGn`up3OTXb2*+Y6x} z_n+_4kL5x_3$|lH_bQl8{jqFmVF!pCAsS9;q5uiLp$I2mfu;IU$g$9ns1JAZlA>vKv~~{^yjX| z6@l#a+|^jqz@_nQW!xUHU%N8>b5-2(Kz2jx2WzGcpEJil&>){v^Tq7W4Ne_8cq_nyaH*GH~n;b6aGZBNx(S1D+-X3x1I)6}p)72B*`Q&~B2*;}Bv z_OAHq>uDf;+M(u)@GND{wVCr$nW^_bNLpGkd(QPgcIsSSz>5v7R4ZzC(00@EI^8wB zX8u)k<{g5;-)$i$Rfz41uhNC?RiViBSGVb*>xIb@TS(*FP?kclvq#x0_y|rn&bfMq zQ#aA(l-XzM29U!?BHb}Ovdc0)JG!-cb7A%V1x{TVN$N5>QC~W&)k6Z=m9?g7&h_&T zL46K|X9>8qJD)K`&Ce9u?$`Qdqy%-5>0?a3!C1eW${2Q3wlnKObV zteSplzu_=pzTG%y_7&l)XU{a>WO@NI#tyzY>o!Nn6>1m>b&`b5v}si{sBi6znN_p> z0|OmJwSX;!Ka+ttZN!}G=FXnEz(731e$zB6Or}knAD&Tl#q6LR8Qi|`#q5A!W1QfxqXgUHX@BWGks10XJA!{5LasG=E8#H9JG<6L!oRHX8<6nVU9wIbAl(P%*yo#-im0u%V|L1H6(H;{w z{;$~55V$f!#*&eJ~{n=ZqYX{gX+VG z`Tseat89yvt#y;4kYWMHz82pOPN2eKvZ6VDe6~OOzQ5sfEC}!Ww;l{uvEIt5ChO`@ z?2HDqE7nhI(Al}EHexIY`FyKq!HS(70}r5BfIY}jXf)a8lBPw!PgIj;IPU^=?KAv` zez?;;d!IUbV+WXK!6on))8k1(ZCy71i@3hm0ZGrVvOT{p8$lVJ5ql>TNp))lLiLbjLKs0z=g?ntkaQ zR-_ec@V`9*8w>$vM1zv&o%p{&4pP>a#|Ir-5#1|GOhxwIv?YcOPFZ5kz!D=mHbciI z_g+LXnyu*Al%nIEz=4jx#lxxO`9+Tq%F%86!8?Mc1Zm$xHK((uRG%P;}7lKzt-&VA#D+p0iFP*#Ob_4fk$C`9ma56I4g| zF!$|rF9)II>231Zo?f`O!#v199I9f=q%cjfW z_RjXDi+TB01MPq0maT&Jn1zN(1^|k43$(+{i%|{NWp_0%@^E28w{=l|Mf4!idUAs` zFZD>=MXH>+4s&ijh7qLEu5PbhlzkBGI;VY7YuKs#!bmh7SuD$`seid<-w5aS_mmdT z3sEa`4pJ0nD*?r{u%1tAB3EA@25R%bZ0Dar^v?n38m*;v1emXp;`#$0>y}fJmYhQi z69|Ty0|%EbW=@ofL!^|N#r3(7BhfE{x~_=IiAjIJx$ z&`2z%QQoX|15?z&rMI*#Q=ck>RnL^ER+%7WOu*-yYH*Och-);QzWR>x^{WFz213@Nt;stxog^JI`U#W~WOZr}@K=>fb~ z&|N$-Pf`9u$vhC+QKWXK`ruG9dmrnxZwb7Cz`NChNBvz6foJL;topyOQuqk+Pw?`y z$hbuk0^V6Rc>dKl&va^+iX+TBjTr3IJ#9;Mr_}KotREp&t-P*n|6j4dU|qM|7CDO| z36v@|w6jw;Peta2=gp9q8Q5X%jH_qO8aUc$rI*+OJt<&YFxu<`wf*XTWe|ZeZCL;lX@U`?^~wCjez$rrHBQ@#t%+4PSS~0IfIm|} zTXgLTfU{RX=0zxu3sEB9D*(lRp#nG2OKp36o-kT!^P~SIT2Q#W9=}@oY0KQUvlMMx!i+`Jse@F-@izZ4|7Rvv%w1Auf&UFXiFu$9`-Es9mH@O=9&^L+cR0=jqs_Noq?Zfo$u%h_pS%LYD1 z{e{V4ZD*6_LuZpmp0n8!4Jf%ZJYOz;b~5gs$d=+OrN^!}exuj_asD3+wB%|y;V3v^ zgY>|4*+=uZ#y%d;qtOo6Wf$`JTbtUC$NTJKZyxWokEijt%s!sM17Q)FtntZw^_5=y6n>dLO47Fgs~>~Vh_mo#~MH+7qr%<}qW-<2T~{P3QLx{)WTm`qhP2Kk=URej(3FOZ_P=l~2E6;6BLr2Wi@$`4fq! zlQxL7Ql3ZicL{%AkycAuZ!WjeUy#3v-m~7P@i&LRv&mP^Un-w|o2W;BdLGKRXMp!L zEYyc_5JdROXJ(=I8zxQf|3Cgc?BVwIAvpdM+;@8T3-3HccM5;`Fx0krf5Lm-;r$*> zIniJ)UHt@qSHYY&GkHGd{q7=7@Bcskoe7Q^6VvzO30&ome$AE)cCHZT5Lw6giN+VN z`HrPY&Ay{1E)nI!I&c56>+Hmw-U@B8mxN3gk-JR z+>w0>mib-R6RDP!;n*StL4QJ^!U7e2uRXM%B2Nh&C#hE0$%dh~qMjerjEef21O1%3Dd>>QH~2fud_fg;@o^m)dT+O~I;U0vt)%|Iu#xB^YRCYq$TECU`N8zc?!B- zYr}$}1NLAdhF%=pi4kA2%F@&fiz z^-Rsa{!Z#6TsHZB9v;f2`yIG{*u4vOD_bO2LTiMr>l>f_PcTau_f_9GX-B3?6ZU#15%t{+l`@4AB1O`-dJ|P zDl$KZ>KSauGN{I4^Ex^Z9W8V3s%M1o=)%PHWD~@9Ke74gvQrGA-PLog8Sb(a|E>e{K|`ookzHXioa z>eRTvP^)2&CTtVhIh4dm9E9@5q!ylBs*N8GlR^MDI*mO#vKgMr$L)?V6+fTO8=feV z9kH=o89|iw%GFNY;VLkh0`fFm-kZ0Y!M&Y2c|a$Q;tl^GBQL;6o2QtQV}T+W=?3so z&`3go#h)fxu@Ws5Yjc@;6MG%UOxyOLdbC1@$;uV}l9!$MZV@J0xng+y_!3E)hR-kx zzvtijU9f6n$}21s>w__KCnFJlp0v{445FS}*-G5Xx^k5)%IfdSqX|GR`fK6=VB%Tk z-1##eNLBQ4kixqxH|b3?Jm^vb?;H%OwM3m=gf z1UT=_S$>^h<8-EOR?j{6fyP{0G2hb+!N!~hhOYI<9EmLK#w3vJuK^_XYdcVGg!OKO zYB#`l#jidsy4+C6eBsn|A*X-!0V}L zrZapZH=BAw<>w|Ip+Ks7?(EcCdP=d}uPrNBf4o6qTw!89dF+reM~R%;D}SI+X2@Li zlu&2L5H!!0%T(9z2TFP)?SoV?@$mOiGMg{YkSBRb2Ha~q!v~-;}*FLlsEGDOOO-SeRrsPb{+m!Pxxm;YU z4zscmQ*ZkzJd^)VIgF%nB|jU2na9ee^Oe(84OGh! zB&5*^8RX1-Y2{Hx$xbJ}83-fd#}EB4a)^T#DfiZTc0}oE-R}J|EmB@{eqf}#lWRPF!H8Q-&x~t(se>}2BzOm<5L_cQ% zF6q^zTO$aX*Pr{wVw?r!9Q-wScHu6!CNfjs$Ho^G<+~AJ24hZg0)8+L;X45ed)CN2 z0>65c5@|6PC&;agom0cX&lr4F-b`?-mBsK8f0s56C@m5?KY*cwg<1 zC*J%%G&)aerJ>UeyvYTtnbtNtKb zDD{u}l~@1klTxngIuwMbJ(V!CB=(`rn*&4#wBrz)v|RI(nR0aW=zZ=Maz8fx)|fd= z)P){3j<$`IaVwY(z&lL%F=Fh=shl2(g^O}EH=HY?^RYsQQkcjT)!`er56I|rQe{@S zlq1XGiaL?GdEteL2oTfZ(zh0mAT!5H5*^5hJZR^S=G{NNXVit+CVuG!Kv0+J zs@`~U%ahvm=d|D3#uu#ur+XdgeBFz%|LsL~EI$k7LPLsgp=>x`(;Om zd5xHZh2AD#J-=l{;_2l77t1Y<+>UFZ7WrQ9a37$kVUJaO(a@GQQ?s$qc;xMH?>5}c zH8MkbbX9f7*geqtSmkT3&O9&xmshJ~y!3YA@_wJ^f&jtc8Ihqg&Xx#SY zJvj{Gm1`GH$9lO)(O$*n1A>Wq&_DHw)tLR%olnBK-mL;*IXl+0kAEPKM!MWbreup- zPw(pKjTHSazQ}!TBK1jNEEB%EPvTzNc7*~aG)i$&$Nz|K(UZogKKB&EBS;osv-w2q zTv7Xx32LZuY#ib~tQR=(G;^e>_zz?xk52U7%NNXjYB)N`cJ~b7#O0Em+`IT<1cM2i zmEsR#=IZ1*zWGbaIxQ{a&h$sK7z2^hiCJ?52kyr`sx=&Edm35rhz8X1He~RQxhDF2 zeXun!q}R-s$fVGJAHS$(N?LS#g2r4Sbe?5+wkAUo+oLQ1_cN|LvFV7~bA;%Wjtp5{ zPnVr-a2-Ekv>ijJV$>Ab_H2>LbrWx>OF3Bc zD3IWQ$37(e($whCVoV39k@)a{=)sW*U~LQCFVQg1^uWeb*)6=Ws}-#5Ne$e zuKPf>$9(p^KGOZ!UL?5Lrb)gNOs;y)AvgNENfFFPh17pv2AtD;xuksQ{Kz++iTBHp zb4CkZ&!K4FFK~O|QqPva+CTl#{!@6>y&nXlZ%X#Sdpk_TskI#dH&0^Zm}q3)s&1yK=$( zof#+QY|-5$80{6Xb3L#%>n8)+Aus&+*4PYO%@h-p#0l#mqeZ4CUj!}qu}*;~LM8KA zGvBW7G2gH>qNf4P-EasjX1P}PoACw}Yl``d7siA=FH@8b-~*`B(a*T_0*al)lPL0L z^2I=`*O5vWq3Wqz^2VdviL7K28-x&bltH27A2U7T>6gSKjUFH_R$(A|Qz0XfGiHMr zTSS&VH0F2vc1ikyh?F{#q z>!epDMS8l0l#CWwsgic<{=Pgh{^#ym%A^EvYxPRtyHC<4b3u%jDC*Oj$YYIn37zY6 zm+BpTaWTJ03H-l1;gA?A>07`L2Yo1(p$K~4u_POB757)_r&2vq8IWvnvqt<<|z462Wuo%(84HK`Z5LGs{{nJ&h>r=@teG#&P_C{82;AEHQZEH z`iP!eXp!_FCYp%bT^}Umeobyot?|;bJ+x|VD!oonkYUobXwyW4vw zGp2BUm<)Iky;q>KX(jJQ-c9}pt0^6V1*R}iv!E=?xm&!HSj&Ikk4Fo=2eFhp31qd(F0vC0?RPgwea z+w!x`Otw8CcVJU?YO_v1rVv|tRPt2brRS#8mT>>({Cf}<%UUryEucZQa6BKnXQBhbRHg$#V z+<<3{ibtwx&vLim`>?nD#lj9o-*S&Nus!<~MYMj2=WQVeEz?Z5?J7 zVnA1b0IQfV>pv%ae0o@&rJio@IwtXZjFM^p$H})%TQjSO?+nR_K4uT?s;1OU5g*!5 z5WF?K46WBO8`SReBquma$1N^>KX^H}5vF*oc10#HHS_l)9|+-v{V}8UX+U>4sAiFEY!v ziFcW~Kg^!j3`YNBPw70nK@ccd(HvVkes3e^qp}Ekh)SHb;KpFAlKG^^2(&}p4nK(J z2j8~O2(=yuw%O<7d4BeF`<&17m^aO{Jv{=9e0(0p?`;rh8>rZxEH8~w#&R9wuI@HI zCt5HIm+fi9{AVqOrv54m+qs85rsB`v5b!UYdp6|0N?kWu9PGCa206af=QihV<7@OC zi^)CfbJtgYlO37PnP;#m8~>;0K zDJ@?nu0f80C*k}KU>p#pR1@ju{;9&NBCIOnrM}mw_j4MjdTXbVh~CXfMth&uT+Ob9 zRGXC;#ivT>7sMK9`_><;ER1ex_;-hz4?D5xeFe&c`1wWqmmsh;}pWF9yQ>eesdkS^5 z2;fIxNfw`uy43_YEnQkfkvRQ?#+SG@S+n+<81e$F2O61}OkU5mm4O>0hV z)0zWg&FS@de)4*u%(760ma;oU(qhm-sIdndNQB_yxmh!E~_m?-@BECp=1~ z5^0@9K>WS!Uvnv32d`GzpSP*m)~ZY4CfHgd?4gXxM~HCn>Mv##wz@X}`b(#Kor%23 z{At!3ca$qJ-z4fI5``1!XZcP;d5GlS+|6zE16<;u2{72eFe)_`xg`)#nlCylX>d)f0P+= zR8-S!<6XvY<#H(&hA=nK9=AiP@y`P`-T0yZhrPFfkE*)X#?Jszj6$N7idOAG!6XPF zpjZeWCM0060a65|DjkMoLLwoPW@aELXcSP#7|ZoqtF5)E*Q)JpEn15owF+njwbj^q zE%=F6+Y@8G)KA)a$^UuQUi-|MAz0e??Y;N?{r-X3d!7Bg*Is+=wbx!}pBc9E)z6yF zpNJ6Y{J$~Xr*wWD;@M;LZ)W?tyt(T-X@qKvSU)h(=X~&^82pSE~^AMDl;6%SB z-w#=0Zk+>9Y=|KSywJT(GO}fw}r?zhG8Gt*haZz>hth?M~7z$>rr%q1_DZy+8tfaSgqbz84 zHCtMSK&t>f6%SgesEm4Rc_sAdyIkID{>2h#eX8y%10n9pyMJKs8CgM_2lk$fl*eWU z_YRR(-0$?_82ti#$uhNtdaW(Eob|{tzydtH>Y3i!B~o_qz~2 zmWJK@@hETnOEQB}cn=@n^h4XYRG;=V>W9>TR|qIa*a6S8t>T zb#cXde5?Ek32SeMM}2$6a7uoIAgMi$kdE19xSQ2n$-tMKH}I|C_w(}cJAX?LhYvKv ztei$+bg!?QN^(40hIuy_$oby=Kn_mMt|DcP!Y_o_UT%WFiQtzC zcfI>s&nr9gz6q|ib@0}_&AWQ8Kse?gZVNo`$@lWM?T|5g8e`Pcz=Aq*p4n_G`t^5F z(HCt+(y~gV>4~6POt{I-NZ2`X7CdhiI@7=Y3Hk|Kck9e zxc)wZyZ~a#2~VMJa~V1eRB*9?(nnlI9ikcyy+9LBlZ#Qx%rVa=3(4U5Ll)IJNbeL(=Ut(E>*0yo40U-jRGB1UWEy$hv0+q>|_t z3i^hW{0o6QQ78>zHc&A1Rv`w{a^z3xO{SSc=fok}(iA@8?zK-w8xX*@_uMQsO>9F= z(iMKjR+`g=p#wdx;lUupDtr@gzMC9@{`Ugqq$Q)QtuYxom1V>fXn{>ND*zC zcO{AQUBsP$!e;Y=aI79V0v}So{ZLfx^nMOSUaduTPMqu)_u?dG=0Vi(z$y_qpI?AW zF+RaZ1WIrj8VceuefnP3ybZS?tQ-n;thJ8!A=-vP$Xm~DgVe|WdL}OW_&V(3UZZmD z0YoGA>Q)RJX450(%<~^#FbF9BsB&Ztc6XRK*buE5Sw+$6>J9Q#IkJp~8P)i%{k2s2 z^l${wq3uvQ%l_i=MZo?wUnA=>pRpc@ZuQVe5UIXvQX$1d-$8{ZGU{U#;JuBidHbnM z?Q`&e#0fv~G8E_iiAlC03C-}Kyla85xG$81_&paNso#PbfJUt?L&h&=wBFDc}w5lQ#6(G^_g-;wjey+K6ep>l(UPtGu%TdDpL$e?F-`hi1h@5uE7 z7&;y!=Pf~MGReb0M~izdMxMow`R8AHzcly-G?(~7N^%Fj3vpL|awJyM1~la~(-b`m z{s>YMMH6iM$Xj@Q92A{pRA^pJmJ7+TCbe}-&w%#VL$iPL=3Ss2>X@lXfzcB9%nz7r z%GiY{6$bfu=<%eS+OpZ(pCE5#QPfCa@OTMga))<3a3`F-B{4kHE|l2moi+u3|-|G=q#cC- z@JB2l@hJ4ExTzKw*Zsv~l#~G8!I^3f5Qkx?%^v6#EU)Au$0#W*vS)m8rd-N6gGnq1?kh*x8ZyS)&#J>##&fP{o!g1*pF{D)1TkdxX?5^Z~Y}o0<=5q z9P%vih0#vb13nen4#MXHzUmhSo(uSknC%RQ8h6NVA2TpsJ{xkuj{(b7^`Nqe|ANYT za7qrX$o7)*b!%~5@OsQT5I~>zEGqBe1B|%A&&fGa7gAn29I5^)5zv0fnenu#Xp;9J z=to9_kyI+-ESM4yz7v5vWj^%_sa2^jP9iIqemZKf=)4N$Nu!dNnrmiBr%RR5W=HHhTCj5mwR3e**Y44q0Grb5;rN(Vmhs6p0{@ zruf}&eDfm34{+st18Wxs`KVVhY@IWA^CMo>WNI(q>;m0!fDqsV9S(fN>+4;@TcF43 zU>UpxZ@VXNI0nDqg@etEk729*2K3XN)2956=ZGD{rTo-z@6V^96}7{?Kfx!N;K|oF ze>@(|{(L(Fefj=l@8<~R*g;8!PnFj`RyBDizN3V7?uQ7+u;8n>#OoPIrmqawc!&EB z7~^D_w+^+T@-^_}bn|;}uvIwPyeQp_j-1y}B3`ZMhlk~C;#oX4N?K9h2EV>hC}HUM)#?&(-doitcU0md14NM0W2yB!dOV1g7R% z1q(n?(m&?i34%i3y5LFQo_t;VMoLo@cjOEtwqWsOG6{XjCbPB*mn_3DcwiOG;Bl+W z*4?-{;b=_PV>&7a59ZhD{qd0V2Jb1fVBIB?aET@6S_!#Pj<*0c$$Es-6A&sc5(R*5 z#wEB5HIG&{_C(=wWcGG)Kux0LOWsrFi7AsWcn{;L_gN#4@vcX2ETcQ89S$5oroz{! zdI}JddEN*-zAq;cmksxRUW{2Ohpx$EF)_i2abh?0HnE};o?~{tIscCRow1z5wZW7; zc4y7p*&P>-bioWjJ?~4IxSeC#irvI5)(i~zIJ6@*yu5D#zf$m+=i;#gvf-g*2R}m& zp5n`Xj-L|1Bs4hiSwqj4pQ1+nHSddNNb}b327fh7>Ic%kQf@d8DZN|A za$O$v^!LHtUzBaw3Fo~IoIzI2_r5Vssu&6pndg}3oA8h|$RnFSZwVl*lh}v14aWW8 z51~Xud+Gl3z9nyxpAPf~7KSg>dxs!QhU!^l!dL>2*ImdKZ2g^BiVYD{x5>SE>t{*3 zW_F+5F}2Y99NR=}T`$?TW6KMyKjHoR7zyVZ%^C7m(r=$CXh7eR#{$)+4^z+wL+9qZn7sZK z%T~^Bu)rF+#@A+ZX5NX`bquEt`lEI*6rLwt%c1BT*3pJ8br9~zIZ=|4mA((b(CbBo zJ(nYj8xt2BljJn-Kcx{gTWEZRa{z=|*)ho*jXqSSCdn+owD69@bBB`}$TNh^$ihR_ zxiSHOR7j6mSQ_;!QLcGsamZ6Vn%js5pp#gT#v!|?oHFx3S~%eutYL-_hcaX5#0^(T zE)>!G3$bUm_~c!O0bG(@VZHvSyzjTbCe~B=^hF>D3muqNMydgJY`;<-&ftf>d`5jj zYT@(csgJOCtg3yLv+l2>IkT%?`PCtCCRVuSc2~!w3Lwj?JF`ZT#R0$$Cpk-Z)b0POB!eTC+%y*2(u&j zOgLV(u-^cl{7Mpgm5=Z#bnFvIGic&ZP+&$AZ$MVRi7=-01+MJ%3X2FVee=NQxL*Qr zJh_!Q-~J;?_0DD^OkDC!Zz`U8UrF0jt$W9%?IUasA^q&e2Id{_9=wgtR^t{%E(tU4 zMIrA4g$#o!=3}tf0oz-<(>tE%hY;B@^PLpUde`m-VI@!M9S!+SABOdwKztpITKzz4 zFmMmc6g%{6>#ekW#imVs=Npo{b0IBv&y>MTz_eoR9`D9HG!>$gl!6oe$1?O`B7Y$N zR^$gmIPxc^m^mzFuOM8Dc{G$=jI6)@w;nquUT=zc2Dm^!I_K6wY zPdazlfIzE;vvWRms(l3KCCYM9tI@0P!FY{E8z0HR6!RvbaU8VEh$20p4wzqISw{T! zGHepzgSS0}Mm$k*p|ibW(MsGm2xePR#}pN1klp*L9&~0&XLkQ(d(ip-qXZyBP*Mium z?E~kcVbM?y6EGD%NKAE|B6z71yeNJuQ_E|tL8nZ??TbVc@P^lg(koM!EWnJ{7cYVn z8YEk(`+@ZLY7GL)zpe<_2?Wf-=nw(d8U*ZQ&slPyJL9xFXBt9FEIr8XJO@<*SKH+xRWz^UKfiYKUokNehF6X#);}eOkxDJsopC@MaG_sQDq5-EU$44w7Z1 z$FS1QVFPV#9;Pxm!ta3u)B-+=soar7(qYTa!7TdqJ6YBE<7NAYLVx+MQs~`xYZq*x z|6&Ryzm!6~8(!M4w00mx_Jf#kD^NfcKa6o4=Jf-&;z2fmD^a{R@njUf1qV17_*agT zn>+SUq4!;coBd7-8|k@FjO1*-pT%sYG9>4y%?5@tB&Yd4149{-GvOWs<4h~(5%3JA z9}W2J9|>%)Hp!Xbx1x}(`0+{F3cMEG(ZVAiH@N^)=`&Ka{dVsPDUjdpMFRihy-(mg z#!29NPxB#}oXry>p8i0IhL87NOsQlwHirC2?~AAeP!)r)T|*r2FXRV&dzrKh;cbU3 z?)ix%%jx3Y$=6@hUC#!3&y6tc46K*>{p6bkAv+SViyrc!w0Z|VrwTippRnUQu*P)` z8HSle_!Pk36-4cjAsMAr!ALX(WZb5e@H@uXd}gmd;Lq4PeGJ0q5Q9t(N83PGSN#xe z<1zwDpUJP;e}D$pV;Dhy6P3z$b}ak=DLn7q>p?My07WbW%boV(zn}~X9i|8EYpc$BVMRq3OI0pL5E#AvOD=KWm8AdnFh(9W? z*^@XCOm_#YB5Lw+3fYl!JojWmn@drceDsW84mUyHyBN5+(q$)mC*X5k!=e9#d@=1& zP`7s%2Mxvl4o&AtcnAtiq@Yk?*C;C#_&V*f{oYrCI0Z}3oKaFIr#2UaJsYK8h5xST z<@pkAJ`a};>467c1FG)41iZP=ivWQXa`=kjLV+L0_nb;#`m%e^?9^Mci|`uPJ5{yk zEP%AnkFfn#=nX2V+C>YhL%rYFmy@5`D$I$*;6<~Go{<#q zdEa6RQ_Lbz4LLKuPs@#|p6?$;DJJWt>PL_=%}+U=0iKg*dRzJf?JWpt=5F-%1Y`n! zn=oKIX~yCvPexVCxsUU0w|@IIW-{9DJ5R&_PKPPyZVXX12;ciNhK@s2V1`J>CWQ&8 zz0^zQYrT;*4u`UhkJNZr)I|36E{nD4~WWu)i!}iYeg>=@KfW1io06I1*ce zwqt?w825VkjGCOpZ$nnTY4wM!?bdoU+wgxYuYUPDgPw(C3-geT%l;`LY&>Uv04?D$ zt4>C9E;y7uA3|%Q^qpdz(-t7O=RFjN>aV_u-Xw3&@hq?BO@>0AXNqnE&m#P|fzKxV zfPue47^r3XR>EBdzLM|_ggbKXHKq4#Fi{ zi@zIyT-gf|jh_p^MxpO>_!Z!H8h&Tu$8SQMhaWFm=S?a!cDWqCYw-J5{BFVTd-&ar z-~IT}(DX_CevKcN@jhHSfmbO5<0taCY*}u*mN**5Z$t~D2a(U@XkHE~0r{MXk-Td# zwa#-O7NiVzhh2@{RHcr*E1wY%uRGdJ#E|bu#9$}}PT)QS-;xMc0GAxKzx*9t*g{#U0651o%;NO>a7_YuoGW>&A; z9l}i>zu3W%Mj8m65A7zLHXW>6HzJM?YWv;p)5e zg`I3KE77n?KrF7^C@a(FD)npBU!?vL@l)F$`EVdA{*U7fH;2R@?fFks>%Da>szi@B z&~6gg_&nrkvqI%}pwiBqd(P%A`%Rpn;Y}|L&n?W*k@Kvi6SJ$l^$#O&Pa7+^2C-Z& zh{Lb3#Lj8MATxMR*&bhvKvH4`K{4x>zmVeZLCdL|8xaE(UC` zXpv5AuORaHyhMHJr2j!L0)jFEg2UOV3!#{W9QP|$ipyqsP1~eRgRo){stMt!Nml!9 z*RT;#4Zh+15Di1?uYL}7Z~@!_lu38CAfPHW6EX!Vk&rGEvICvmflk6gdbvrQxCBPe z5NLVHa}`Kr&KBNUtEbzzwZx2~-B#kQY*Rf-M}}=)ku;%gK1|-r_>s2t9mFK8B|vak zcqcoFC73bm*6f0*U*`q*RDJJ!c^P{IG>W|x&iO`dGRKRvHGJPvo}zf7qP8RFGhk1; zq~>kdD)`@>wXC9ixh?xO?@Afb^&>Y)XJ7MH%Ja-6vpXI(VI1mBY#=|ibf=WIViQ{X z0Lh49Kt3w|qxbwVOoY_uFg2MFO{dOEfjl~Z(%Bu?N`YsmDvKbx$ZZFSqd^WxbP5yI z6Yr_5SWBNo@u;F~$=RvuLTGdj$H%Fte}39)N9*`TBC+-kTgHQ@GZiQ zBS88S|LZD}F%O7;H;gzogN83&%DoA>hBVGb?%CVT7^Bxnwsr}6Yqe0PO7zSnjOuxi zZ=v}6yE12AS>7X0kja|;S?%_!&>lV-c@#YH3nKDYn)RDjYVYMO+KModKkPGYWfA6U zZ*2Z^YP_dGHXXy)J(lNf1*ESR+WZd;$IFca4^8Df`!0IknX?04u)eaq&D*#BXMSjV z-lN<5E5GXUce>FleB%0)ydp9D%qub`yhRJ!^NR2qQc<)kuV}@lyrSfmyrQ+;RjHqn z^;V_6PK{4hs*@Ul>Xdx!t2))Wh=CnB_iQu+l$yD>s&fO3Gmw%yYrI^L!m9PaVANTH zAD(vO%aW7u^~61u9Se7tr}ma(CE>MV6?kC@%i!nB*Zrj^Z{5$4xH9$J?9h|t>$VN9 zOfB5qgDo0lIjD^)r84T1_U3Kix&#wgc53lsm8mC+_TfJJBV@cnJMh_>#1Bwl;i{8S zSarIvj>8^3_t8T>+3;j?MDGZ@Udqbbxq5I_YOUudNDN3l%O=H-%q*dI$VQX?OGv-a z3+?Tg{Gb%sm$)kR=iYVbp*On|SC*#cc;y|3ZFuq_#^%j@F4T=KTuz}^EIs$;t)B*T zd4B-42FXF`hvS*|AydVD- zC!j8@hY#D4u|Ir2D?Oi4Lw(+*xI##4vG}4sT;dCdY{gQacixV?qes~da^h1%Ffi* zqCfA-*@Oxa^3<*;(@1;e#a&x=BIM;AulD>cXx-L9yPit^>Xn@&xmR|w@QttRLarg_ zvScZvZwG^u-YdJ(^BXrT)ek&tz)k3;&ga<7qw#sUIV0=yV#EFdX|q1BW!H!Gc^^Cl z;7Je8ule*F0(e@A;MlM?OuC(n*@hVG^t00;c;D8JIj3)Z{V>Gsn2X090Jgrxa1KXk z$H1BSL6T5?&t6n8GoMYGRG;@3Sm0lFC_`L^RB6ar`5kjgPMxy|pH)E>r_Q-BHE$%8 zNZ^2Z9Mrr=4sG1R%UtlCl@~yq0s1LVJy!*)=^Qq1o8vr)B$(3JEjBnOCugQN*B~tJxer-_^dkFNoL}wpF5PNgzRG(z5E|Fq!*rvM z!XDyId)^~90Oqago^5=$=!vRn6k%JB^S*&xY*W713CNgYuu-^dVvjk(lg%&IL+?e? z{KQ+71UhnlOA!bw7h2vD|NBx*L$L_l`8Zr`tz-&Be>}EIRK| z#n)elnzrS6e**L=_@eyHMk~IinU)a`w=<@5;#G_24f$((pk*6SrjM_`AYH%sdJuzX z@CAecU(2*j`QBncpNg*^7}Q#P-3f_E@io-6>QCoMt6GAs`p+QdcR~=A+K$KJ_TJzYQq#=Lrueot|VhRCoVD#>%A<1u5(eQkFKYYuJ=weKd8UK z$;n?0eWfsn#Mf5OO&sS<)+Xh9;{bgsw$>QLT5PR`xTe_J&6v)KkDW_zNF>;(tw$it zV(SbxDu6A+-xl|LgiorZ*AHpt;-1%mJi~9+y@MrwEjYs3z1}5v0i{sPlU*u*H`*yA z5o49kwJ^VW&pR34e1PEr-h`Ox^`0&kgkxy;&(}v2C&A$BFOL#+u(L$BL6~`74qD29 z6vR=;!!$g==|YA9mT9l$AAS7BM8LR=@>ORAK7YCwFV3%<+UKnPlUL2|qxcEH_=cC- zic>Gi%l2Q@V7!br7jpTaU42ilezO-R#cIen1PF!2lzd9m-f5GT|A3FOtJgwgUfXAe z^vzt>xU!mK;?{5 zj`#~`jg)4`a0qaH$pU&qt^+M$t6})`5SC|Y_6nryy(4@5Fz1DM*#X9*-dZFP6R|sf zW=zCpo3|aFBc9KH7&j;4?kZfv>V1W+;blujtO3`^ugB2_WYFJvb(?Xlf#DGrfxwgDod&Q6UPx%GGXa-nYC{l7d6-BrzHBg@wWDYf-;r}UL@(LUqlL*cQTuj|wtrU;Fm)($mFInXdoNxt zoA&l=(ga@7hbBA^qVC9f6=9QiUiz)xP2RsF0Q+%VOVbk)Cl7fM&mgPb zZ{a)Wc$NQIWI_=?F-3H;h#^0gA}S~UIqz$&nEL=os6EtkcMQ2v%KKB^*QolgocyOX zZ%v+dr75$g5%l9bj6ci7^J@p=KT7?|8;9srPsgw? zAe>Fl`x-~DXDUj=^y!>-j7eW8={zp_-5LzUmST*)m^W%gw zOs%H{QXFcFJ%w?+J89zSfoLyB8+EAE`Z%IT2cn;3G$HVX2j1ZI{CH-G}P2cI8) z2n}|;E0`M-ZMb(SAih1sX^7NU7qBFWxkJYOP(n2dtUUr|B2jumjWx@Yp{`?gaq(P zswV#;3G<4?$g+oA7MFVML2QQx(~263IBG3>SFx61xi8Thawt5UL=2LrH6zQg_Wp2? z$UrC`t1oK-h6a0QAk^UMO-v8c|5|#2iY55Idge7g-nxuAw6SJTCSA%Ie zE6Em2TrS>_Kfrrv0tUnzjjVm6&PMTlqpHQ7D{hUr^Tk~t?z!SF68C&@FBJDH;w}+) zskr=hbKj_XaT~4SlnE3j}UjLxcTB9CGOGUepcM!;vOgN@#3B+t}E_I;*J#e6mbj19WCw{af`(* z5qE;Pr;B@rxRb;!6?dw*)5R?lcZRr?;?5GcO5C%>trmB#xHaO=7k7cU=Zd>X-1Eh~ zP~5MGyF}cj;?{{>ZnL;8;(R zE$%hqUMuc(;%*f8dU0Fr zLg=T2t|zpE(A9)qCUhyG_X#Bk{%(2z`rC zF`;`2jU>ba`kvzmy-g^ekOQXNa|of&5&8s913$~q^B$qugs8=Bh!A>}&`Ltj6S{#A zza!sp51}oDo+h-J5SNpl9}?;#bQ_^#QBluLgw7;%9ij6HttZq*=wd?G5o#fH521QO z+X-Dr=tV;F3B5L#=o z$Z6;$^e&;pv0nGQNoX9Q7YUtBsGHDYLQfECCB%Jl!}WxS_J$u3x{J^ggl;ADI-wf~ zeN5;YLdQaO?cv}xQ0DDfNk~j?nh3=iwv}+LB{Y}N&j?i#`YoYSLLU<YR7dDeLgy3OOsIy?@6268Z#t>4q*s?-ANW$RkAJ=y??o zf$YCMkN)bH{QKZc#Iy&0NZ-yM!sHLrEW-y6kw2hb{#-nj;n$8I_BRe#le`EVb^X>P8IKP0`NbTJ|Gw=9}K z0kyG~)o!fbZA`e0ruWN`wbhL$T2TWF_A@uuwfWg2apa97MN`z}N0lSBiD)_{s+r~% z7Z+z{l^~bNo0mleLA5bptT`bgRNc4&D6ey)Urjcyj5Hybm?Vx1PAPC>Ez#CU0=+~d zE6}0w#V!XlQdid+jmKm4g;NE~ZUNeztWAuKwT?|T16u{ti!fvySvJ_Dk#TIqvkqCS zsR$t^Gm$Boi*s`)^k2{PF>ZZhw5g8uG&a{o+tAr`MQpUTjHr#|N?I9UjxKN=U4f3o z8|w@j44s(DldVxd;TSZ%HrW~n8DUt_^V&!pvGs0qG)`3cIpThnINE&Ler<*+RBNPl zHClaAb7V#IqysjUEoX|lTuW{&d0A6zX{5B#1OME^A)F zk>jM|P;rK#arH8ek=A8N#un$!PM|A7-yk9(G}dY;y24GYZixy-NBr3WWF;b)bf#*l zzuc{h*2aV=FkQ+MiAZgOPD+gchH6$P8e+|^-x;N-3XpwWGz_2{LLTC@#x z-0YrYGM-eB&Z?b=13QAE;@pZzQxn_Fj1}pGs~Ve{7}g8~tc)!;L!8wRjMBUo&Sqjw z(Go9p3yAvy7nEqwimJ5Qbopc4#`;`-@SAKX;nugtR!His8m54m)VT%G*49{Sfq`S_ zEuV5R0qZbtSCOB^YDr-zv%f;X-WuaTD#j|>RvVQT=N87JrcZUT+PGk@E}DomHpPnq zqvJR}Kdl9tmPTrqTQ&+*N77^Gu81rr6649*2F}pT#KpPbm(kj$0>dwf9wbU5!)KnP z8Rf8k5eEH&%iK6vW+SE{P|_ka5oR({bAem9s-Y2;ufWVC$8C+R#KZ(60_%*X*(xSN z?#jkUutarTOqSSx5VQ7Q=ZE7vu{vU%|2Br05;yBt{LL|GXX)PavS#mLFcko(!S zF{TTkPdmzna*613z%R+DLDIwsSOc2ivpN!=nKG7wWLmowxx^GA8xxIa#l`3+mk4RQ zE?4nbvb8p9*DLb`lFVfdNWL_hSQQoGPDGbQK{^;uUBYChN1CztaWrI>rk#qW7?@YY zRbB*Y0MRtt`pL}en!x3o3yIb8dQ3w!3NwKy8RJH3vEl+pF`qF>#g-+34lRak`7#ab zL6>e}OAKFNU)r?VbTyJ2k1iu0if{tD^^s�F3Vi`2qHuLA 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.5.6 for python 3.2/3.3 (older versions fail +to find the magic string, so _ARGCOMPLETE env. var is never set, and +this does not need special code). + +Function try_argcomplete(parser) should be called directly before +the call to ArgumentParser.parse_args(). + +The filescompleter is what you normally would use on the positional +arguments specification, in order to get "dirname/" after "dirn" +instead of the default "dirname ": + + optparser.add_argument(Config._file_or_dir, nargs='*').completer=filescompleter + +Other, application specific, completers should go in the file +doing the add_argument calls as they need to be specified as .completer +attributes as well. (If argcomplete is not installed, the function the +attribute points to will not be used). + +SPEEDUP +======= + +The generic argcomplete script for bash-completion +(/etc/bash_completion.d/python-argcomplete.sh) +uses a python program to determine startup script generated by pip. +You can speed up completion somewhat by changing this script to include + # PYTHON_ARGCOMPLETE_OK +so the python-argcomplete-check-easy-install-script does not +need to be called to find the entry point of the code and see if that is +marked with PYTHON_ARGCOMPLETE_OK. + +INSTALL/DEBUGGING +================= + +To include this support in another application that has setup.py generated +scripts: + +- Add the line: + # PYTHON_ARGCOMPLETE_OK + near the top of the main python entry point. + +- Include in the file calling parse_args(): + from _argcomplete import try_argcomplete, filescompleter + Call try_argcomplete just before parse_args(), and optionally add + filescompleter to the positional arguments' add_argument(). + +If things do not work right away: + +- Switch on argcomplete debugging with (also helpful when doing custom + completers): + export _ARC_DEBUG=1 + +- Run: + python-argcomplete-check-easy-install-script $(which appname) + echo $? + will echo 0 if the magic line has been found, 1 if not. + +- Sometimes it helps to find early on errors using: + _ARGCOMPLETE=1 _ARC_DEBUG=1 appname + which should throw a KeyError: 'COMPLINE' (which is properly set by the + global argcomplete script). +""" +import argparse +import os +import sys +from glob import glob +from typing import Any +from typing import List +from typing import Optional + + +class FastFilesCompleter: + """Fast file completer class.""" + + def __init__(self, directories: bool = True) -> None: + self.directories = directories + + def __call__(self, prefix: str, **kwargs: Any) -> List[str]: + # Only called on non option completions. + if os.path.sep in prefix[1:]: + prefix_dir = len(os.path.dirname(prefix) + os.path.sep) + else: + prefix_dir = 0 + completion = [] + globbed = [] + if "*" not in prefix and "?" not in prefix: + # We are on unix, otherwise no bash. + if not prefix or prefix[-1] == os.path.sep: + globbed.extend(glob(prefix + ".*")) + prefix += "*" + globbed.extend(glob(prefix)) + for x in sorted(globbed): + if os.path.isdir(x): + x += "/" + # Append stripping the prefix (like bash, not like compgen). + completion.append(x[prefix_dir:]) + return completion + + +if os.environ.get("_ARGCOMPLETE"): + try: + import argcomplete.completers + except ImportError: + sys.exit(-1) + filescompleter: Optional[FastFilesCompleter] = FastFilesCompleter() + + def try_argcomplete(parser: argparse.ArgumentParser) -> None: + argcomplete.autocomplete(parser, always_complete_options=False) + + +else: + + def try_argcomplete(parser: argparse.ArgumentParser) -> None: + pass + + filescompleter = None diff --git a/myenv/lib/python3.9/site-packages/_pytest/_code/__init__.py b/myenv/lib/python3.9/site-packages/_pytest/_code/__init__.py new file mode 100644 index 0000000..511d0dd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_code/__init__.py @@ -0,0 +1,22 @@ +"""Python inspection/code generation API.""" +from .code import Code +from .code import ExceptionInfo +from .code import filter_traceback +from .code import Frame +from .code import getfslineno +from .code import Traceback +from .code import TracebackEntry +from .source import getrawcode +from .source import Source + +__all__ = [ + "Code", + "ExceptionInfo", + "filter_traceback", + "Frame", + "getfslineno", + "getrawcode", + "Traceback", + "TracebackEntry", + "Source", +] diff --git a/myenv/lib/python3.9/site-packages/_pytest/_code/code.py b/myenv/lib/python3.9/site-packages/_pytest/_code/code.py new file mode 100644 index 0000000..4230693 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_code/code.py @@ -0,0 +1,1259 @@ +import inspect +import re +import sys +import traceback +from inspect import CO_VARARGS +from inspect import CO_VARKEYWORDS +from io import StringIO +from pathlib import Path +from traceback import format_exception_only +from types import CodeType +from types import FrameType +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generic +from typing import Iterable +from typing import List +from typing import Mapping +from typing import Optional +from typing import overload +from typing import Pattern +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union +from weakref import ref + +import attr +import pluggy +import py + +import _pytest +from _pytest._code.source import findsource +from _pytest._code.source import getrawcode +from _pytest._code.source import getstatementrange_ast +from _pytest._code.source import Source +from _pytest._io import TerminalWriter +from _pytest._io.saferepr import safeformat +from _pytest._io.saferepr import saferepr +from _pytest.compat import final +from _pytest.compat import get_real_func + +if TYPE_CHECKING: + from typing_extensions import Literal + from weakref import ReferenceType + + _TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"] + + +class Code: + """Wrapper around Python code objects.""" + + __slots__ = ("raw",) + + def __init__(self, obj: CodeType) -> None: + self.raw = obj + + @classmethod + def from_function(cls, obj: object) -> "Code": + return cls(getrawcode(obj)) + + def __eq__(self, other): + return self.raw == other.raw + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + @property + def firstlineno(self) -> int: + return self.raw.co_firstlineno - 1 + + @property + def name(self) -> str: + return self.raw.co_name + + @property + def path(self) -> Union[py.path.local, str]: + """Return a path object pointing to source code, or an ``str`` in + case of ``OSError`` / non-existing file.""" + if not self.raw.co_filename: + return "" + try: + p = py.path.local(self.raw.co_filename) + # maybe don't try this checking + if not p.check(): + raise OSError("py.path check failed.") + return p + except OSError: + # XXX maybe try harder like the weird logic + # in the standard lib [linecache.updatecache] does? + return self.raw.co_filename + + @property + def fullsource(self) -> Optional["Source"]: + """Return a _pytest._code.Source object for the full source file of the code.""" + full, _ = findsource(self.raw) + return full + + def source(self) -> "Source": + """Return a _pytest._code.Source object for the code object's source only.""" + # return source only for that part of code + return Source(self.raw) + + def getargs(self, var: bool = False) -> Tuple[str, ...]: + """Return a tuple with the argument names for the code object. + + If 'var' is set True also return the names of the variable and + keyword arguments when present. + """ + # Handy shortcut for getting args. + raw = self.raw + argcount = raw.co_argcount + if var: + argcount += raw.co_flags & CO_VARARGS + argcount += raw.co_flags & CO_VARKEYWORDS + return raw.co_varnames[:argcount] + + +class Frame: + """Wrapper around a Python frame holding f_locals and f_globals + in which expressions can be evaluated.""" + + __slots__ = ("raw",) + + def __init__(self, frame: FrameType) -> None: + self.raw = frame + + @property + def lineno(self) -> int: + return self.raw.f_lineno - 1 + + @property + def f_globals(self) -> Dict[str, Any]: + return self.raw.f_globals + + @property + def f_locals(self) -> Dict[str, Any]: + return self.raw.f_locals + + @property + def code(self) -> Code: + return Code(self.raw.f_code) + + @property + def statement(self) -> "Source": + """Statement this frame is at.""" + if self.code.fullsource is None: + return Source("") + return self.code.fullsource.getstatement(self.lineno) + + def eval(self, code, **vars): + """Evaluate 'code' in the frame. + + 'vars' are optional additional local variables. + + Returns the result of the evaluation. + """ + f_locals = self.f_locals.copy() + f_locals.update(vars) + return eval(code, self.f_globals, f_locals) + + def repr(self, object: object) -> str: + """Return a 'safe' (non-recursive, one-line) string repr for 'object'.""" + return saferepr(object) + + def getargs(self, var: bool = False): + """Return a list of tuples (name, value) for all arguments. + + If 'var' is set True, also include the variable and keyword arguments + when present. + """ + retval = [] + for arg in self.code.getargs(var): + try: + retval.append((arg, self.f_locals[arg])) + except KeyError: + pass # this can occur when using Psyco + return retval + + +class TracebackEntry: + """A single entry in a Traceback.""" + + __slots__ = ("_rawentry", "_excinfo", "_repr_style") + + def __init__( + self, + rawentry: TracebackType, + excinfo: Optional["ReferenceType[ExceptionInfo[BaseException]]"] = None, + ) -> None: + self._rawentry = rawentry + self._excinfo = excinfo + self._repr_style: Optional['Literal["short", "long"]'] = None + + @property + def lineno(self) -> int: + return self._rawentry.tb_lineno - 1 + + def set_repr_style(self, mode: "Literal['short', 'long']") -> None: + assert mode in ("short", "long") + self._repr_style = mode + + @property + def frame(self) -> Frame: + return Frame(self._rawentry.tb_frame) + + @property + def relline(self) -> int: + return self.lineno - self.frame.code.firstlineno + + def __repr__(self) -> str: + return "" % (self.frame.code.path, self.lineno + 1) + + @property + def statement(self) -> "Source": + """_pytest._code.Source object for the current statement.""" + source = self.frame.code.fullsource + assert source is not None + return source.getstatement(self.lineno) + + @property + def path(self) -> Union[py.path.local, str]: + """Path to the source code.""" + return self.frame.code.path + + @property + def locals(self) -> Dict[str, Any]: + """Locals of underlying frame.""" + return self.frame.f_locals + + def getfirstlinesource(self) -> int: + return self.frame.code.firstlineno + + def getsource(self, astcache=None) -> Optional["Source"]: + """Return failing source code.""" + # we use the passed in astcache to not reparse asttrees + # within exception info printing + source = self.frame.code.fullsource + if source is None: + return None + key = astnode = None + if astcache is not None: + key = self.frame.code.path + if key is not None: + astnode = astcache.get(key, None) + start = self.getfirstlinesource() + try: + astnode, _, end = getstatementrange_ast( + self.lineno, source, astnode=astnode + ) + except SyntaxError: + end = self.lineno + 1 + else: + if key is not None: + astcache[key] = astnode + return source[start:end] + + source = property(getsource) + + def ishidden(self) -> bool: + """Return True if the current frame has a var __tracebackhide__ + resolving to True. + + If __tracebackhide__ is a callable, it gets called with the + ExceptionInfo instance and can decide whether to hide the traceback. + + Mostly for internal use. + """ + tbh: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]] = ( + False + ) + for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals): + # in normal cases, f_locals and f_globals are dictionaries + # however via `exec(...)` / `eval(...)` they can be other types + # (even incorrect types!). + # as such, we suppress all exceptions while accessing __tracebackhide__ + try: + tbh = maybe_ns_dct["__tracebackhide__"] + except Exception: + pass + else: + break + if tbh and callable(tbh): + return tbh(None if self._excinfo is None else self._excinfo()) + return tbh + + def __str__(self) -> str: + name = self.frame.code.name + try: + line = str(self.statement).lstrip() + except KeyboardInterrupt: + raise + except BaseException: + line = "???" + # This output does not quite match Python's repr for traceback entries, + # but changing it to do so would break certain plugins. See + # https://github.com/pytest-dev/pytest/pull/7535/ for details. + return " File %r:%d in %s\n %s\n" % ( + str(self.path), + self.lineno + 1, + name, + line, + ) + + @property + def name(self) -> str: + """co_name of underlying code.""" + return self.frame.code.raw.co_name + + +class Traceback(List[TracebackEntry]): + """Traceback objects encapsulate and offer higher level access to Traceback entries.""" + + def __init__( + self, + tb: Union[TracebackType, Iterable[TracebackEntry]], + excinfo: Optional["ReferenceType[ExceptionInfo[BaseException]]"] = None, + ) -> None: + """Initialize from given python traceback object and ExceptionInfo.""" + self._excinfo = excinfo + if isinstance(tb, TracebackType): + + def f(cur: TracebackType) -> Iterable[TracebackEntry]: + cur_: Optional[TracebackType] = cur + while cur_ is not None: + yield TracebackEntry(cur_, excinfo=excinfo) + cur_ = cur_.tb_next + + super().__init__(f(tb)) + else: + super().__init__(tb) + + def cut( + self, + path=None, + lineno: Optional[int] = None, + firstlineno: Optional[int] = None, + excludepath: Optional[py.path.local] = None, + ) -> "Traceback": + """Return a Traceback instance wrapping part of this Traceback. + + By providing any combination of path, lineno and firstlineno, the + first frame to start the to-be-returned traceback is determined. + + This allows cutting the first part of a Traceback instance e.g. + for formatting reasons (removing some uninteresting bits that deal + with handling of the exception/traceback). + """ + for x in self: + code = x.frame.code + codepath = code.path + if ( + (path is None or codepath == path) + and ( + excludepath is None + or not isinstance(codepath, py.path.local) + or not codepath.relto(excludepath) + ) + and (lineno is None or x.lineno == lineno) + and (firstlineno is None or x.frame.code.firstlineno == firstlineno) + ): + return Traceback(x._rawentry, self._excinfo) + return self + + @overload + def __getitem__(self, key: int) -> TracebackEntry: + ... + + @overload + def __getitem__(self, key: slice) -> "Traceback": + ... + + def __getitem__(self, key: Union[int, slice]) -> Union[TracebackEntry, "Traceback"]: + if isinstance(key, slice): + return self.__class__(super().__getitem__(key)) + else: + return super().__getitem__(key) + + def filter( + self, fn: Callable[[TracebackEntry], bool] = lambda x: not x.ishidden() + ) -> "Traceback": + """Return a Traceback instance with certain items removed + + fn is a function that gets a single argument, a TracebackEntry + instance, and should return True when the item should be added + to the Traceback, False when not. + + By default this removes all the TracebackEntries which are hidden + (see ishidden() above). + """ + return Traceback(filter(fn, self), self._excinfo) + + def getcrashentry(self) -> TracebackEntry: + """Return last non-hidden traceback entry that lead to the exception of a traceback.""" + for i in range(-1, -len(self) - 1, -1): + entry = self[i] + if not entry.ishidden(): + return entry + return self[-1] + + def recursionindex(self) -> Optional[int]: + """Return the index of the frame/TracebackEntry where recursion originates if + appropriate, None if no recursion occurred.""" + cache: Dict[Tuple[Any, int, int], List[Dict[str, Any]]] = {} + for i, entry in enumerate(self): + # id for the code.raw is needed to work around + # the strange metaprogramming in the decorator lib from pypi + # which generates code objects that have hash/value equality + # XXX needs a test + key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno + # print "checking for recursion at", key + values = cache.setdefault(key, []) + if values: + f = entry.frame + loc = f.f_locals + for otherloc in values: + if f.eval( + co_equal, + __recursioncache_locals_1=loc, + __recursioncache_locals_2=otherloc, + ): + return i + values.append(entry.frame.f_locals) + return None + + +co_equal = compile( + "__recursioncache_locals_1 == __recursioncache_locals_2", "?", "eval" +) + + +_E = TypeVar("_E", bound=BaseException, covariant=True) + + +@final +@attr.s(repr=False) +class ExceptionInfo(Generic[_E]): + """Wraps sys.exc_info() objects and offers help for navigating the traceback.""" + + _assert_start_repr = "AssertionError('assert " + + _excinfo = attr.ib(type=Optional[Tuple[Type["_E"], "_E", TracebackType]]) + _striptext = attr.ib(type=str, default="") + _traceback = attr.ib(type=Optional[Traceback], default=None) + + @classmethod + def from_exc_info( + cls, + exc_info: Tuple[Type[_E], _E, TracebackType], + exprinfo: Optional[str] = None, + ) -> "ExceptionInfo[_E]": + """Return an ExceptionInfo for an existing exc_info tuple. + + .. warning:: + + Experimental API + + :param exprinfo: + A text string helping to determine if we should strip + ``AssertionError`` from the output. Defaults to the exception + message/``__str__()``. + """ + _striptext = "" + if exprinfo is None and isinstance(exc_info[1], AssertionError): + exprinfo = getattr(exc_info[1], "msg", None) + if exprinfo is None: + exprinfo = saferepr(exc_info[1]) + if exprinfo and exprinfo.startswith(cls._assert_start_repr): + _striptext = "AssertionError: " + + return cls(exc_info, _striptext) + + @classmethod + def from_current( + cls, exprinfo: Optional[str] = None + ) -> "ExceptionInfo[BaseException]": + """Return an ExceptionInfo matching the current traceback. + + .. warning:: + + Experimental API + + :param exprinfo: + A text string helping to determine if we should strip + ``AssertionError`` from the output. Defaults to the exception + message/``__str__()``. + """ + tup = sys.exc_info() + assert tup[0] is not None, "no current exception" + assert tup[1] is not None, "no current exception" + assert tup[2] is not None, "no current exception" + exc_info = (tup[0], tup[1], tup[2]) + return ExceptionInfo.from_exc_info(exc_info, exprinfo) + + @classmethod + def for_later(cls) -> "ExceptionInfo[_E]": + """Return an unfilled ExceptionInfo.""" + return cls(None) + + def fill_unfilled(self, exc_info: Tuple[Type[_E], _E, TracebackType]) -> None: + """Fill an unfilled ExceptionInfo created with ``for_later()``.""" + assert self._excinfo is None, "ExceptionInfo was already filled" + self._excinfo = exc_info + + @property + def type(self) -> Type[_E]: + """The exception class.""" + assert ( + self._excinfo is not None + ), ".type can only be used after the context manager exits" + return self._excinfo[0] + + @property + def value(self) -> _E: + """The exception value.""" + assert ( + self._excinfo is not None + ), ".value can only be used after the context manager exits" + return self._excinfo[1] + + @property + def tb(self) -> TracebackType: + """The exception raw traceback.""" + assert ( + self._excinfo is not None + ), ".tb can only be used after the context manager exits" + return self._excinfo[2] + + @property + def typename(self) -> str: + """The type name of the exception.""" + assert ( + self._excinfo is not None + ), ".typename can only be used after the context manager exits" + return self.type.__name__ + + @property + def traceback(self) -> Traceback: + """The traceback.""" + if self._traceback is None: + self._traceback = Traceback(self.tb, excinfo=ref(self)) + return self._traceback + + @traceback.setter + def traceback(self, value: Traceback) -> None: + self._traceback = value + + def __repr__(self) -> str: + if self._excinfo is None: + return "" + return "<{} {} tblen={}>".format( + self.__class__.__name__, saferepr(self._excinfo[1]), len(self.traceback) + ) + + def exconly(self, tryshort: bool = False) -> str: + """Return the exception as a string. + + When 'tryshort' resolves to True, and the exception is a + _pytest._code._AssertionError, only the actual exception part of + the exception representation is returned (so 'AssertionError: ' is + removed from the beginning). + """ + lines = format_exception_only(self.type, self.value) + text = "".join(lines) + text = text.rstrip() + if tryshort: + if text.startswith(self._striptext): + text = text[len(self._striptext) :] + return text + + def errisinstance( + self, exc: Union[Type[BaseException], Tuple[Type[BaseException], ...]] + ) -> bool: + """Return True if the exception is an instance of exc. + + Consider using ``isinstance(excinfo.value, exc)`` instead. + """ + return isinstance(self.value, exc) + + def _getreprcrash(self) -> "ReprFileLocation": + exconly = self.exconly(tryshort=True) + entry = self.traceback.getcrashentry() + path, lineno = entry.frame.code.raw.co_filename, entry.lineno + return ReprFileLocation(path, lineno + 1, exconly) + + def getrepr( + self, + showlocals: bool = False, + style: "_TracebackStyle" = "long", + abspath: bool = False, + tbfilter: bool = True, + funcargs: bool = False, + truncate_locals: bool = True, + chain: bool = True, + ) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]: + """Return str()able representation of this exception info. + + :param bool showlocals: + Show locals per traceback entry. + Ignored if ``style=="native"``. + + :param str style: + long|short|no|native|value traceback style. + + :param bool abspath: + If paths should be changed to absolute or left unchanged. + + :param bool tbfilter: + Hide entries that contain a local variable ``__tracebackhide__==True``. + Ignored if ``style=="native"``. + + :param bool funcargs: + Show fixtures ("funcargs" for legacy purposes) per traceback entry. + + :param bool truncate_locals: + With ``showlocals==True``, make sure locals can be safely represented as strings. + + :param bool chain: + If chained exceptions in Python 3 should be shown. + + .. versionchanged:: 3.9 + + Added the ``chain`` parameter. + """ + if style == "native": + return ReprExceptionInfo( + ReprTracebackNative( + traceback.format_exception( + self.type, self.value, self.traceback[0]._rawentry + ) + ), + self._getreprcrash(), + ) + + fmt = FormattedExcinfo( + showlocals=showlocals, + style=style, + abspath=abspath, + tbfilter=tbfilter, + funcargs=funcargs, + truncate_locals=truncate_locals, + chain=chain, + ) + return fmt.repr_excinfo(self) + + def match(self, regexp: Union[str, Pattern[str]]) -> "Literal[True]": + """Check whether the regular expression `regexp` matches the string + representation of the exception using :func:`python:re.search`. + + If it matches `True` is returned, otherwise an `AssertionError` is raised. + """ + __tracebackhide__ = True + msg = "Regex pattern {!r} does not match {!r}." + if regexp == str(self.value): + msg += " Did you mean to `re.escape()` the regex?" + assert re.search(regexp, str(self.value)), msg.format(regexp, str(self.value)) + # Return True to allow for "assert excinfo.match()". + return True + + +@attr.s +class FormattedExcinfo: + """Presenting information about failing Functions and Generators.""" + + # for traceback entries + flow_marker = ">" + fail_marker = "E" + + showlocals = attr.ib(type=bool, default=False) + style = attr.ib(type="_TracebackStyle", default="long") + abspath = attr.ib(type=bool, default=True) + tbfilter = attr.ib(type=bool, default=True) + funcargs = attr.ib(type=bool, default=False) + truncate_locals = attr.ib(type=bool, default=True) + chain = attr.ib(type=bool, default=True) + astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False) + + def _getindent(self, source: "Source") -> int: + # Figure out indent for the given source. + try: + s = str(source.getstatement(len(source) - 1)) + except KeyboardInterrupt: + raise + except BaseException: + try: + s = str(source[-1]) + except KeyboardInterrupt: + raise + except BaseException: + return 0 + return 4 + (len(s) - len(s.lstrip())) + + def _getentrysource(self, entry: TracebackEntry) -> Optional["Source"]: + source = entry.getsource(self.astcache) + if source is not None: + source = source.deindent() + return source + + def repr_args(self, entry: TracebackEntry) -> Optional["ReprFuncArgs"]: + if self.funcargs: + args = [] + for argname, argvalue in entry.frame.getargs(var=True): + args.append((argname, saferepr(argvalue))) + return ReprFuncArgs(args) + return None + + def get_source( + self, + source: Optional["Source"], + line_index: int = -1, + excinfo: Optional[ExceptionInfo[BaseException]] = None, + short: bool = False, + ) -> List[str]: + """Return formatted and marked up source lines.""" + lines = [] + if source is None or line_index >= len(source.lines): + source = Source("???") + line_index = 0 + if line_index < 0: + line_index += len(source) + space_prefix = " " + if short: + lines.append(space_prefix + source.lines[line_index].strip()) + else: + for line in source.lines[:line_index]: + lines.append(space_prefix + line) + lines.append(self.flow_marker + " " + source.lines[line_index]) + for line in source.lines[line_index + 1 :]: + lines.append(space_prefix + line) + if excinfo is not None: + indent = 4 if short else self._getindent(source) + lines.extend(self.get_exconly(excinfo, indent=indent, markall=True)) + return lines + + def get_exconly( + self, + excinfo: ExceptionInfo[BaseException], + indent: int = 4, + markall: bool = False, + ) -> List[str]: + lines = [] + indentstr = " " * indent + # Get the real exception information out. + exlines = excinfo.exconly(tryshort=True).split("\n") + failindent = self.fail_marker + indentstr[1:] + for line in exlines: + lines.append(failindent + line) + if not markall: + failindent = indentstr + return lines + + def repr_locals(self, locals: Mapping[str, object]) -> Optional["ReprLocals"]: + if self.showlocals: + lines = [] + keys = [loc for loc in locals if loc[0] != "@"] + keys.sort() + for name in keys: + value = locals[name] + if name == "__builtins__": + lines.append("__builtins__ = ") + else: + # This formatting could all be handled by the + # _repr() function, which is only reprlib.Repr in + # disguise, so is very configurable. + if self.truncate_locals: + str_repr = saferepr(value) + else: + str_repr = safeformat(value) + # if len(str_repr) < 70 or not isinstance(value, (list, tuple, dict)): + lines.append(f"{name:<10} = {str_repr}") + # else: + # self._line("%-10s =\\" % (name,)) + # # XXX + # pprint.pprint(value, stream=self.excinfowriter) + return ReprLocals(lines) + return None + + def repr_traceback_entry( + self, + entry: TracebackEntry, + excinfo: Optional[ExceptionInfo[BaseException]] = None, + ) -> "ReprEntry": + lines: List[str] = [] + style = entry._repr_style if entry._repr_style is not None else self.style + if style in ("short", "long"): + source = self._getentrysource(entry) + if source is None: + source = Source("???") + line_index = 0 + else: + line_index = entry.lineno - entry.getfirstlinesource() + short = style == "short" + reprargs = self.repr_args(entry) if not short else None + s = self.get_source(source, line_index, excinfo, short=short) + lines.extend(s) + if short: + message = "in %s" % (entry.name) + else: + message = excinfo and excinfo.typename or "" + path = self._makepath(entry.path) + reprfileloc = ReprFileLocation(path, entry.lineno + 1, message) + localsrepr = self.repr_locals(entry.locals) + return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style) + elif style == "value": + if excinfo: + lines.extend(str(excinfo.value).split("\n")) + return ReprEntry(lines, None, None, None, style) + else: + if excinfo: + lines.extend(self.get_exconly(excinfo, indent=4)) + return ReprEntry(lines, None, None, None, style) + + def _makepath(self, path): + if not self.abspath: + try: + np = py.path.local().bestrelpath(path) + except OSError: + return path + if len(np) < len(str(path)): + path = np + return path + + def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback": + traceback = excinfo.traceback + if self.tbfilter: + traceback = traceback.filter() + + if isinstance(excinfo.value, RecursionError): + traceback, extraline = self._truncate_recursive_traceback(traceback) + else: + extraline = None + + last = traceback[-1] + entries = [] + if self.style == "value": + reprentry = self.repr_traceback_entry(last, excinfo) + entries.append(reprentry) + return ReprTraceback(entries, None, style=self.style) + + for index, entry in enumerate(traceback): + einfo = (last == entry) and excinfo or None + reprentry = self.repr_traceback_entry(entry, einfo) + entries.append(reprentry) + return ReprTraceback(entries, extraline, style=self.style) + + def _truncate_recursive_traceback( + self, traceback: Traceback + ) -> Tuple[Traceback, Optional[str]]: + """Truncate the given recursive traceback trying to find the starting + point of the recursion. + + The detection is done by going through each traceback entry and + finding the point in which the locals of the frame are equal to the + locals of a previous frame (see ``recursionindex()``). + + Handle the situation where the recursion process might raise an + exception (for example comparing numpy arrays using equality raises a + TypeError), in which case we do our best to warn the user of the + error and show a limited traceback. + """ + try: + recursionindex = traceback.recursionindex() + except Exception as e: + max_frames = 10 + extraline: Optional[str] = ( + "!!! Recursion error detected, but an error occurred locating the origin of recursion.\n" + " The following exception happened when comparing locals in the stack frame:\n" + " {exc_type}: {exc_msg}\n" + " Displaying first and last {max_frames} stack frames out of {total}." + ).format( + exc_type=type(e).__name__, + exc_msg=str(e), + max_frames=max_frames, + total=len(traceback), + ) + # Type ignored because adding two instaces of a List subtype + # currently incorrectly has type List instead of the subtype. + traceback = traceback[:max_frames] + traceback[-max_frames:] # type: ignore + else: + if recursionindex is not None: + extraline = "!!! Recursion detected (same locals & position)" + traceback = traceback[: recursionindex + 1] + else: + extraline = None + + return traceback, extraline + + def repr_excinfo( + self, excinfo: ExceptionInfo[BaseException] + ) -> "ExceptionChainRepr": + repr_chain: List[ + Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]] + ] = [] + e: Optional[BaseException] = excinfo.value + excinfo_: Optional[ExceptionInfo[BaseException]] = excinfo + descr = None + seen: Set[int] = set() + while e is not None and id(e) not in seen: + seen.add(id(e)) + if excinfo_: + reprtraceback = self.repr_traceback(excinfo_) + reprcrash: Optional[ReprFileLocation] = ( + excinfo_._getreprcrash() if self.style != "value" else None + ) + else: + # Fallback to native repr if the exception doesn't have a traceback: + # ExceptionInfo objects require a full traceback to work. + reprtraceback = ReprTracebackNative( + traceback.format_exception(type(e), e, None) + ) + reprcrash = None + + repr_chain += [(reprtraceback, reprcrash, descr)] + if e.__cause__ is not None and self.chain: + e = e.__cause__ + excinfo_ = ( + ExceptionInfo((type(e), e, e.__traceback__)) + if e.__traceback__ + else None + ) + descr = "The above exception was the direct cause of the following exception:" + elif ( + e.__context__ is not None and not e.__suppress_context__ and self.chain + ): + e = e.__context__ + excinfo_ = ( + ExceptionInfo((type(e), e, e.__traceback__)) + if e.__traceback__ + else None + ) + descr = "During handling of the above exception, another exception occurred:" + else: + e = None + repr_chain.reverse() + return ExceptionChainRepr(repr_chain) + + +@attr.s(eq=False) +class TerminalRepr: + def __str__(self) -> str: + # FYI this is called from pytest-xdist's serialization of exception + # information. + io = StringIO() + tw = TerminalWriter(file=io) + self.toterminal(tw) + return io.getvalue().strip() + + def __repr__(self) -> str: + return "<{} instance at {:0x}>".format(self.__class__, id(self)) + + def toterminal(self, tw: TerminalWriter) -> None: + raise NotImplementedError() + + +# This class is abstract -- only subclasses are instantiated. +@attr.s(eq=False) +class ExceptionRepr(TerminalRepr): + # Provided by subclasses. + reprcrash: Optional["ReprFileLocation"] + reprtraceback: "ReprTraceback" + + def __attrs_post_init__(self) -> None: + self.sections: List[Tuple[str, str, str]] = [] + + def addsection(self, name: str, content: str, sep: str = "-") -> None: + self.sections.append((name, content, sep)) + + def toterminal(self, tw: TerminalWriter) -> None: + for name, content, sep in self.sections: + tw.sep(sep, name) + tw.line(content) + + +@attr.s(eq=False) +class ExceptionChainRepr(ExceptionRepr): + chain = attr.ib( + type=Sequence[ + Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]] + ] + ) + + def __attrs_post_init__(self) -> None: + super().__attrs_post_init__() + # reprcrash and reprtraceback of the outermost (the newest) exception + # in the chain. + self.reprtraceback = self.chain[-1][0] + self.reprcrash = self.chain[-1][1] + + def toterminal(self, tw: TerminalWriter) -> None: + for element in self.chain: + element[0].toterminal(tw) + if element[2] is not None: + tw.line("") + tw.line(element[2], yellow=True) + super().toterminal(tw) + + +@attr.s(eq=False) +class ReprExceptionInfo(ExceptionRepr): + reprtraceback = attr.ib(type="ReprTraceback") + reprcrash = attr.ib(type="ReprFileLocation") + + def toterminal(self, tw: TerminalWriter) -> None: + self.reprtraceback.toterminal(tw) + super().toterminal(tw) + + +@attr.s(eq=False) +class ReprTraceback(TerminalRepr): + reprentries = attr.ib(type=Sequence[Union["ReprEntry", "ReprEntryNative"]]) + extraline = attr.ib(type=Optional[str]) + style = attr.ib(type="_TracebackStyle") + + entrysep = "_ " + + def toterminal(self, tw: TerminalWriter) -> None: + # The entries might have different styles. + for i, entry in enumerate(self.reprentries): + if entry.style == "long": + tw.line("") + entry.toterminal(tw) + if i < len(self.reprentries) - 1: + next_entry = self.reprentries[i + 1] + if ( + entry.style == "long" + or entry.style == "short" + and next_entry.style == "long" + ): + tw.sep(self.entrysep) + + if self.extraline: + tw.line(self.extraline) + + +class ReprTracebackNative(ReprTraceback): + def __init__(self, tblines: Sequence[str]) -> None: + self.style = "native" + self.reprentries = [ReprEntryNative(tblines)] + self.extraline = None + + +@attr.s(eq=False) +class ReprEntryNative(TerminalRepr): + lines = attr.ib(type=Sequence[str]) + style: "_TracebackStyle" = "native" + + def toterminal(self, tw: TerminalWriter) -> None: + tw.write("".join(self.lines)) + + +@attr.s(eq=False) +class ReprEntry(TerminalRepr): + lines = attr.ib(type=Sequence[str]) + reprfuncargs = attr.ib(type=Optional["ReprFuncArgs"]) + reprlocals = attr.ib(type=Optional["ReprLocals"]) + reprfileloc = attr.ib(type=Optional["ReprFileLocation"]) + style = attr.ib(type="_TracebackStyle") + + def _write_entry_lines(self, tw: TerminalWriter) -> None: + """Write the source code portions of a list of traceback entries with syntax highlighting. + + Usually entries are lines like these: + + " x = 1" + "> assert x == 2" + "E assert 1 == 2" + + This function takes care of rendering the "source" portions of it (the lines without + the "E" prefix) using syntax highlighting, taking care to not highlighting the ">" + character, as doing so might break line continuations. + """ + + if not self.lines: + return + + # separate indents and source lines that are not failures: we want to + # highlight the code but not the indentation, which may contain markers + # such as "> assert 0" + fail_marker = f"{FormattedExcinfo.fail_marker} " + indent_size = len(fail_marker) + indents: List[str] = [] + source_lines: List[str] = [] + failure_lines: List[str] = [] + for index, line in enumerate(self.lines): + is_failure_line = line.startswith(fail_marker) + if is_failure_line: + # from this point on all lines are considered part of the failure + failure_lines.extend(self.lines[index:]) + break + else: + if self.style == "value": + source_lines.append(line) + else: + indents.append(line[:indent_size]) + source_lines.append(line[indent_size:]) + + tw._write_source(source_lines, indents) + + # failure lines are always completely red and bold + for line in failure_lines: + tw.line(line, bold=True, red=True) + + def toterminal(self, tw: TerminalWriter) -> None: + if self.style == "short": + assert self.reprfileloc is not None + self.reprfileloc.toterminal(tw) + self._write_entry_lines(tw) + if self.reprlocals: + self.reprlocals.toterminal(tw, indent=" " * 8) + return + + if self.reprfuncargs: + self.reprfuncargs.toterminal(tw) + + self._write_entry_lines(tw) + + if self.reprlocals: + tw.line("") + self.reprlocals.toterminal(tw) + if self.reprfileloc: + if self.lines: + tw.line("") + self.reprfileloc.toterminal(tw) + + def __str__(self) -> str: + return "{}\n{}\n{}".format( + "\n".join(self.lines), self.reprlocals, self.reprfileloc + ) + + +@attr.s(eq=False) +class ReprFileLocation(TerminalRepr): + path = attr.ib(type=str, converter=str) + lineno = attr.ib(type=int) + message = attr.ib(type=str) + + def toterminal(self, tw: TerminalWriter) -> None: + # Filename and lineno output for each entry, using an output format + # that most editors understand. + msg = self.message + i = msg.find("\n") + if i != -1: + msg = msg[:i] + tw.write(self.path, bold=True, red=True) + tw.line(f":{self.lineno}: {msg}") + + +@attr.s(eq=False) +class ReprLocals(TerminalRepr): + lines = attr.ib(type=Sequence[str]) + + def toterminal(self, tw: TerminalWriter, indent="") -> None: + for line in self.lines: + tw.line(indent + line) + + +@attr.s(eq=False) +class ReprFuncArgs(TerminalRepr): + args = attr.ib(type=Sequence[Tuple[str, object]]) + + def toterminal(self, tw: TerminalWriter) -> None: + if self.args: + linesofar = "" + for name, value in self.args: + ns = f"{name} = {value}" + if len(ns) + len(linesofar) + 2 > tw.fullwidth: + if linesofar: + tw.line(linesofar) + linesofar = ns + else: + if linesofar: + linesofar += ", " + ns + else: + linesofar = ns + if linesofar: + tw.line(linesofar) + tw.line("") + + +def getfslineno(obj: object) -> Tuple[Union[str, py.path.local], int]: + """Return source location (path, lineno) for the given object. + + If the source cannot be determined return ("", -1). + + The line number is 0-based. + """ + # xxx let decorators etc specify a sane ordering + # NOTE: this used to be done in _pytest.compat.getfslineno, initially added + # in 6ec13a2b9. It ("place_as") appears to be something very custom. + obj = get_real_func(obj) + if hasattr(obj, "place_as"): + obj = obj.place_as # type: ignore[attr-defined] + + try: + code = Code.from_function(obj) + except TypeError: + try: + fn = inspect.getsourcefile(obj) or inspect.getfile(obj) # type: ignore[arg-type] + except TypeError: + return "", -1 + + fspath = fn and py.path.local(fn) or "" + lineno = -1 + if fspath: + try: + _, lineno = findsource(obj) + except OSError: + pass + return fspath, lineno + + return code.path, code.firstlineno + + +# Relative paths that we use to filter traceback entries from appearing to the user; +# see filter_traceback. +# note: if we need to add more paths than what we have now we should probably use a list +# for better maintenance. + +_PLUGGY_DIR = Path(pluggy.__file__.rstrip("oc")) +# pluggy is either a package or a single module depending on the version +if _PLUGGY_DIR.name == "__init__.py": + _PLUGGY_DIR = _PLUGGY_DIR.parent +_PYTEST_DIR = Path(_pytest.__file__).parent +_PY_DIR = Path(py.__file__).parent + + +def filter_traceback(entry: TracebackEntry) -> bool: + """Return True if a TracebackEntry instance should be included in tracebacks. + + We hide traceback entries of: + + * dynamically generated code (no code to show up for it); + * internal traceback from pytest or its internal libraries, py and pluggy. + """ + # entry.path might sometimes return a str object when the entry + # points to dynamically generated code. + # See https://bitbucket.org/pytest-dev/py/issues/71. + raw_filename = entry.frame.code.raw.co_filename + is_generated = "<" in raw_filename and ">" in raw_filename + if is_generated: + return False + + # entry.path might point to a non-existing file, in which case it will + # also return a str object. See #1133. + p = Path(entry.path) + + parents = p.parents + if _PLUGGY_DIR in parents: + return False + if _PYTEST_DIR in parents: + return False + if _PY_DIR in parents: + return False + + return True diff --git a/myenv/lib/python3.9/site-packages/_pytest/_code/source.py b/myenv/lib/python3.9/site-packages/_pytest/_code/source.py new file mode 100644 index 0000000..6f54057 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_code/source.py @@ -0,0 +1,212 @@ +import ast +import inspect +import textwrap +import tokenize +import types +import warnings +from bisect import bisect_right +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import overload +from typing import Tuple +from typing import Union + + +class Source: + """An immutable object holding a source code fragment. + + When using Source(...), the source lines are deindented. + """ + + def __init__(self, obj: object = None) -> None: + if not obj: + self.lines: List[str] = [] + elif isinstance(obj, Source): + self.lines = obj.lines + elif isinstance(obj, (tuple, list)): + self.lines = deindent(x.rstrip("\n") for x in obj) + elif isinstance(obj, str): + self.lines = deindent(obj.split("\n")) + else: + try: + rawcode = getrawcode(obj) + src = inspect.getsource(rawcode) + except TypeError: + src = inspect.getsource(obj) # type: ignore[arg-type] + self.lines = deindent(src.split("\n")) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Source): + return NotImplemented + return self.lines == other.lines + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + @overload + def __getitem__(self, key: int) -> str: + ... + + @overload + def __getitem__(self, key: slice) -> "Source": + ... + + def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]: + if isinstance(key, int): + return self.lines[key] + else: + if key.step not in (None, 1): + raise IndexError("cannot slice a Source with a step") + newsource = Source() + newsource.lines = self.lines[key.start : key.stop] + return newsource + + def __iter__(self) -> Iterator[str]: + return iter(self.lines) + + def __len__(self) -> int: + return len(self.lines) + + def strip(self) -> "Source": + """Return new Source object with trailing and leading blank lines removed.""" + start, end = 0, len(self) + while start < end and not self.lines[start].strip(): + start += 1 + while end > start and not self.lines[end - 1].strip(): + end -= 1 + source = Source() + source.lines[:] = self.lines[start:end] + return source + + def indent(self, indent: str = " " * 4) -> "Source": + """Return a copy of the source object with all lines indented by the + given indent-string.""" + newsource = Source() + newsource.lines = [(indent + line) for line in self.lines] + return newsource + + def getstatement(self, lineno: int) -> "Source": + """Return Source statement which contains the given linenumber + (counted from 0).""" + start, end = self.getstatementrange(lineno) + return self[start:end] + + def getstatementrange(self, lineno: int) -> Tuple[int, int]: + """Return (start, end) tuple which spans the minimal statement region + which containing the given lineno.""" + if not (0 <= lineno < len(self)): + raise IndexError("lineno out of range") + ast, start, end = getstatementrange_ast(lineno, self) + return start, end + + def deindent(self) -> "Source": + """Return a new Source object deindented.""" + newsource = Source() + newsource.lines[:] = deindent(self.lines) + return newsource + + def __str__(self) -> str: + return "\n".join(self.lines) + + +# +# helper functions +# + + +def findsource(obj) -> Tuple[Optional[Source], int]: + try: + sourcelines, lineno = inspect.findsource(obj) + except Exception: + return None, -1 + source = Source() + source.lines = [line.rstrip() for line in sourcelines] + return source, lineno + + +def getrawcode(obj: object, trycall: bool = True) -> types.CodeType: + """Return code object for given function.""" + try: + return obj.__code__ # type: ignore[attr-defined,no-any-return] + except AttributeError: + pass + if trycall: + call = getattr(obj, "__call__", None) + if call and not isinstance(obj, type): + return getrawcode(call, trycall=False) + raise TypeError(f"could not get code object for {obj!r}") + + +def deindent(lines: Iterable[str]) -> List[str]: + return textwrap.dedent("\n".join(lines)).splitlines() + + +def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[int]]: + # Flatten all statements and except handlers into one lineno-list. + # AST's line numbers start indexing at 1. + values: List[int] = [] + for x in ast.walk(node): + if isinstance(x, (ast.stmt, ast.ExceptHandler)): + values.append(x.lineno - 1) + for name in ("finalbody", "orelse"): + val: Optional[List[ast.stmt]] = getattr(x, name, None) + if val: + # Treat the finally/orelse part as its own statement. + values.append(val[0].lineno - 1 - 1) + values.sort() + insert_index = bisect_right(values, lineno) + start = values[insert_index - 1] + if insert_index >= len(values): + end = None + else: + end = values[insert_index] + return start, end + + +def getstatementrange_ast( + lineno: int, + source: Source, + assertion: bool = False, + astnode: Optional[ast.AST] = None, +) -> Tuple[ast.AST, int, int]: + if astnode is None: + content = str(source) + # See #4260: + # Don't produce duplicate warnings when compiling source to find AST. + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + astnode = ast.parse(content, "source", "exec") + + start, end = get_statement_startend2(lineno, astnode) + # We need to correct the end: + # - ast-parsing strips comments + # - there might be empty lines + # - we might have lesser indented code blocks at the end + if end is None: + end = len(source.lines) + + if end > start + 1: + # Make sure we don't span differently indented code blocks + # by using the BlockFinder helper used which inspect.getsource() uses itself. + block_finder = inspect.BlockFinder() + # If we start with an indented line, put blockfinder to "started" mode. + block_finder.started = source.lines[start][0].isspace() + it = ((x + "\n") for x in source.lines[start:end]) + try: + for tok in tokenize.generate_tokens(lambda: next(it)): + block_finder.tokeneater(*tok) + except (inspect.EndOfBlock, IndentationError): + end = block_finder.last + start + except Exception: + pass + + # The end might still point to a comment or empty line, correct it. + while end: + line = source.lines[end - 1].lstrip() + if line.startswith("#") or not line: + end -= 1 + else: + break + return astnode, start, end diff --git a/myenv/lib/python3.9/site-packages/_pytest/_io/__init__.py b/myenv/lib/python3.9/site-packages/_pytest/_io/__init__.py new file mode 100644 index 0000000..db001e9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_io/__init__.py @@ -0,0 +1,8 @@ +from .terminalwriter import get_terminal_width +from .terminalwriter import TerminalWriter + + +__all__ = [ + "TerminalWriter", + "get_terminal_width", +] diff --git a/myenv/lib/python3.9/site-packages/_pytest/_io/saferepr.py b/myenv/lib/python3.9/site-packages/_pytest/_io/saferepr.py new file mode 100644 index 0000000..5eb1e08 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_io/saferepr.py @@ -0,0 +1,129 @@ +import pprint +import reprlib +from typing import Any +from typing import Dict +from typing import IO +from typing import Optional + + +def _try_repr_or_str(obj: object) -> str: + try: + return repr(obj) + except (KeyboardInterrupt, SystemExit): + raise + except BaseException: + return '{}("{}")'.format(type(obj).__name__, obj) + + +def _format_repr_exception(exc: BaseException, obj: object) -> str: + try: + exc_info = _try_repr_or_str(exc) + except (KeyboardInterrupt, SystemExit): + raise + except BaseException as exc: + exc_info = "unpresentable exception ({})".format(_try_repr_or_str(exc)) + return "<[{} raised in repr()] {} object at 0x{:x}>".format( + exc_info, type(obj).__name__, id(obj) + ) + + +def _ellipsize(s: str, maxsize: int) -> str: + if len(s) > maxsize: + i = max(0, (maxsize - 3) // 2) + j = max(0, maxsize - 3 - i) + return s[:i] + "..." + s[len(s) - j :] + return s + + +class SafeRepr(reprlib.Repr): + """repr.Repr that limits the resulting size of repr() and includes + information on exceptions raised during the call.""" + + def __init__(self, maxsize: int) -> None: + super().__init__() + self.maxstring = maxsize + self.maxsize = maxsize + + def repr(self, x: object) -> str: + try: + s = super().repr(x) + except (KeyboardInterrupt, SystemExit): + raise + except BaseException as exc: + s = _format_repr_exception(exc, x) + return _ellipsize(s, self.maxsize) + + def repr_instance(self, x: object, level: int) -> str: + try: + s = repr(x) + except (KeyboardInterrupt, SystemExit): + raise + except BaseException as exc: + s = _format_repr_exception(exc, x) + return _ellipsize(s, self.maxsize) + + +def safeformat(obj: object) -> str: + """Return a pretty printed string for the given object. + + Failing __repr__ functions of user instances will be represented + with a short exception info. + """ + try: + return pprint.pformat(obj) + except Exception as exc: + return _format_repr_exception(exc, obj) + + +def saferepr(obj: object, maxsize: int = 240) -> str: + """Return a size-limited safe repr-string for the given object. + + Failing __repr__ functions of user instances will be represented + with a short exception info and 'saferepr' generally takes + care to never raise exceptions itself. + + This function is a wrapper around the Repr/reprlib functionality of the + standard 2.6 lib. + """ + return SafeRepr(maxsize).repr(obj) + + +class AlwaysDispatchingPrettyPrinter(pprint.PrettyPrinter): + """PrettyPrinter that always dispatches (regardless of width).""" + + def _format( + self, + object: object, + stream: IO[str], + indent: int, + allowance: int, + context: Dict[int, Any], + level: int, + ) -> None: + # Type ignored because _dispatch is private. + p = self._dispatch.get(type(object).__repr__, None) # type: ignore[attr-defined] + + objid = id(object) + if objid in context or p is None: + # Type ignored because _format is private. + super()._format( # type: ignore[misc] + object, stream, indent, allowance, context, level, + ) + return + + context[objid] = 1 + p(self, object, stream, indent, allowance, context, level + 1) + del context[objid] + + +def _pformat_dispatch( + object: object, + indent: int = 1, + width: int = 80, + depth: Optional[int] = None, + *, + compact: bool = False, +) -> str: + return AlwaysDispatchingPrettyPrinter( + indent=indent, width=width, depth=depth, compact=compact + ).pformat(object) diff --git a/myenv/lib/python3.9/site-packages/_pytest/_io/terminalwriter.py b/myenv/lib/python3.9/site-packages/_pytest/_io/terminalwriter.py new file mode 100644 index 0000000..8edf4cd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_io/terminalwriter.py @@ -0,0 +1,210 @@ +"""Helper functions for writing to terminals and files.""" +import os +import shutil +import sys +from typing import Optional +from typing import Sequence +from typing import TextIO + +from .wcwidth import wcswidth +from _pytest.compat import final + + +# This code was initially copied from py 1.8.1, file _io/terminalwriter.py. + + +def get_terminal_width() -> int: + width, _ = shutil.get_terminal_size(fallback=(80, 24)) + + # The Windows get_terminal_size may be bogus, let's sanify a bit. + if width < 40: + width = 80 + + return width + + +def should_do_markup(file: TextIO) -> bool: + if os.environ.get("PY_COLORS") == "1": + return True + if os.environ.get("PY_COLORS") == "0": + return False + if "NO_COLOR" in os.environ: + return False + if "FORCE_COLOR" in os.environ: + return True + return ( + hasattr(file, "isatty") and file.isatty() and os.environ.get("TERM") != "dumb" + ) + + +@final +class TerminalWriter: + _esctable = dict( + black=30, + red=31, + green=32, + yellow=33, + blue=34, + purple=35, + cyan=36, + white=37, + Black=40, + Red=41, + Green=42, + Yellow=43, + Blue=44, + Purple=45, + Cyan=46, + White=47, + bold=1, + light=2, + blink=5, + invert=7, + ) + + def __init__(self, file: Optional[TextIO] = None) -> None: + if file is None: + file = sys.stdout + if hasattr(file, "isatty") and file.isatty() and sys.platform == "win32": + try: + import colorama + except ImportError: + pass + else: + file = colorama.AnsiToWin32(file).stream + assert file is not None + self._file = file + self.hasmarkup = should_do_markup(file) + self._current_line = "" + self._terminal_width: Optional[int] = None + self.code_highlight = True + + @property + def fullwidth(self) -> int: + if self._terminal_width is not None: + return self._terminal_width + return get_terminal_width() + + @fullwidth.setter + def fullwidth(self, value: int) -> None: + self._terminal_width = value + + @property + def width_of_current_line(self) -> int: + """Return an estimate of the width so far in the current line.""" + return wcswidth(self._current_line) + + def markup(self, text: str, **markup: bool) -> str: + for name in markup: + if name not in self._esctable: + raise ValueError(f"unknown markup: {name!r}") + if self.hasmarkup: + esc = [self._esctable[name] for name, on in markup.items() if on] + if esc: + text = "".join("\x1b[%sm" % cod for cod in esc) + text + "\x1b[0m" + return text + + def sep( + self, + sepchar: str, + title: Optional[str] = None, + fullwidth: Optional[int] = None, + **markup: bool, + ) -> None: + if fullwidth is None: + fullwidth = self.fullwidth + # The goal is to have the line be as long as possible + # under the condition that len(line) <= fullwidth. + if sys.platform == "win32": + # If we print in the last column on windows we are on a + # new line but there is no way to verify/neutralize this + # (we may not know the exact line width). + # So let's be defensive to avoid empty lines in the output. + fullwidth -= 1 + if title is not None: + # we want 2 + 2*len(fill) + len(title) <= fullwidth + # i.e. 2 + 2*len(sepchar)*N + len(title) <= fullwidth + # 2*len(sepchar)*N <= fullwidth - len(title) - 2 + # N <= (fullwidth - len(title) - 2) // (2*len(sepchar)) + N = max((fullwidth - len(title) - 2) // (2 * len(sepchar)), 1) + fill = sepchar * N + line = f"{fill} {title} {fill}" + else: + # we want len(sepchar)*N <= fullwidth + # i.e. N <= fullwidth // len(sepchar) + line = sepchar * (fullwidth // len(sepchar)) + # In some situations there is room for an extra sepchar at the right, + # in particular if we consider that with a sepchar like "_ " the + # trailing space is not important at the end of the line. + if len(line) + len(sepchar.rstrip()) <= fullwidth: + line += sepchar.rstrip() + + self.line(line, **markup) + + def write(self, msg: str, *, flush: bool = False, **markup: bool) -> None: + if msg: + current_line = msg.rsplit("\n", 1)[-1] + if "\n" in msg: + self._current_line = current_line + else: + self._current_line += current_line + + msg = self.markup(msg, **markup) + + try: + self._file.write(msg) + except UnicodeEncodeError: + # Some environments don't support printing general Unicode + # strings, due to misconfiguration or otherwise; in that case, + # print the string escaped to ASCII. + # When the Unicode situation improves we should consider + # letting the error propagate instead of masking it (see #7475 + # for one brief attempt). + msg = msg.encode("unicode-escape").decode("ascii") + self._file.write(msg) + + if flush: + self.flush() + + def line(self, s: str = "", **markup: bool) -> None: + self.write(s, **markup) + self.write("\n") + + def flush(self) -> None: + self._file.flush() + + def _write_source(self, lines: Sequence[str], indents: Sequence[str] = ()) -> None: + """Write lines of source code possibly highlighted. + + Keeping this private for now because the API is clunky. We should discuss how + to evolve the terminal writer so we can have more precise color support, for example + being able to write part of a line in one color and the rest in another, and so on. + """ + if indents and len(indents) != len(lines): + raise ValueError( + "indents size ({}) should have same size as lines ({})".format( + len(indents), len(lines) + ) + ) + if not indents: + indents = [""] * len(lines) + source = "\n".join(lines) + new_lines = self._highlight(source).splitlines() + for indent, new_line in zip(indents, new_lines): + self.line(indent + new_line) + + def _highlight(self, source: str) -> str: + """Highlight the given source code if we have markup support.""" + if not self.hasmarkup or not self.code_highlight: + return source + try: + from pygments.formatters.terminal import TerminalFormatter + from pygments.lexers.python import PythonLexer + from pygments import highlight + except ImportError: + return source + else: + highlighted: str = highlight( + source, PythonLexer(), TerminalFormatter(bg="dark") + ) + return highlighted diff --git a/myenv/lib/python3.9/site-packages/_pytest/_io/wcwidth.py b/myenv/lib/python3.9/site-packages/_pytest/_io/wcwidth.py new file mode 100644 index 0000000..e5c7bf4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_io/wcwidth.py @@ -0,0 +1,55 @@ +import unicodedata +from functools import lru_cache + + +@lru_cache(100) +def wcwidth(c: str) -> int: + """Determine how many columns are needed to display a character in a terminal. + + Returns -1 if the character is not printable. + Returns 0, 1 or 2 for other characters. + """ + o = ord(c) + + # ASCII fast path. + if 0x20 <= o < 0x07F: + return 1 + + # Some Cf/Zp/Zl characters which should be zero-width. + if ( + o == 0x0000 + or 0x200B <= o <= 0x200F + or 0x2028 <= o <= 0x202E + or 0x2060 <= o <= 0x2063 + ): + return 0 + + category = unicodedata.category(c) + + # Control characters. + if category == "Cc": + return -1 + + # Combining characters with zero width. + if category in ("Me", "Mn"): + return 0 + + # Full/Wide east asian characters. + if unicodedata.east_asian_width(c) in ("F", "W"): + return 2 + + return 1 + + +def wcswidth(s: str) -> int: + """Determine how many columns are needed to display a string in a terminal. + + Returns -1 if the string contains non-printable characters. + """ + width = 0 + for c in unicodedata.normalize("NFC", s): + wc = wcwidth(c) + if wc < 0: + return -1 + width += wc + return width diff --git a/myenv/lib/python3.9/site-packages/_pytest/_version.py b/myenv/lib/python3.9/site-packages/_pytest/_version.py new file mode 100644 index 0000000..8351858 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/_version.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# file generated by setuptools_scm +# don't change, don't track in version control +version = '6.2.5' +version_tuple = (6, 2, 5) diff --git a/myenv/lib/python3.9/site-packages/_pytest/assertion/__init__.py b/myenv/lib/python3.9/site-packages/_pytest/assertion/__init__.py new file mode 100644 index 0000000..a18cf19 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/assertion/__init__.py @@ -0,0 +1,179 @@ +"""Support for presenting detailed information in failing assertions.""" +import sys +from typing import Any +from typing import Generator +from typing import List +from typing import Optional +from typing import TYPE_CHECKING + +from _pytest.assertion import rewrite +from _pytest.assertion import truncate +from _pytest.assertion import util +from _pytest.assertion.rewrite import assertstate_key +from _pytest.config import Config +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.nodes import Item + +if TYPE_CHECKING: + from _pytest.main import Session + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--assert", + action="store", + dest="assertmode", + choices=("rewrite", "plain"), + default="rewrite", + metavar="MODE", + help=( + "Control assertion debugging tools.\n" + "'plain' performs no assertion debugging.\n" + "'rewrite' (the default) rewrites assert statements in test modules" + " on import to provide assert expression information." + ), + ) + parser.addini( + "enable_assertion_pass_hook", + type="bool", + default=False, + help="Enables the pytest_assertion_pass hook." + "Make sure to delete any previously generated pyc cache files.", + ) + + +def register_assert_rewrite(*names: str) -> None: + """Register one or more module names to be rewritten on import. + + This function will make sure that this module or all modules inside + the package will get their assert statements rewritten. + Thus you should make sure to call this before the module is + actually imported, usually in your __init__.py if you are a plugin + using a package. + + :raises TypeError: If the given module names are not strings. + """ + for name in names: + if not isinstance(name, str): + msg = "expected module names as *args, got {0} instead" # type: ignore[unreachable] + raise TypeError(msg.format(repr(names))) + for hook in sys.meta_path: + if isinstance(hook, rewrite.AssertionRewritingHook): + importhook = hook + break + else: + # TODO(typing): Add a protocol for mark_rewrite() and use it + # for importhook and for PytestPluginManager.rewrite_hook. + importhook = DummyRewriteHook() # type: ignore + importhook.mark_rewrite(*names) + + +class DummyRewriteHook: + """A no-op import hook for when rewriting is disabled.""" + + def mark_rewrite(self, *names: str) -> None: + pass + + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config: Config, mode) -> None: + self.mode = mode + self.trace = config.trace.root.get("assertion") + self.hook: Optional[rewrite.AssertionRewritingHook] = None + + +def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: + """Try to install the rewrite hook, raise SystemError if it fails.""" + config._store[assertstate_key] = AssertionState(config, "rewrite") + config._store[assertstate_key].hook = hook = rewrite.AssertionRewritingHook(config) + sys.meta_path.insert(0, hook) + config._store[assertstate_key].trace("installed rewrite import hook") + + def undo() -> None: + hook = config._store[assertstate_key].hook + if hook is not None and hook in sys.meta_path: + sys.meta_path.remove(hook) + + config.add_cleanup(undo) + return hook + + +def pytest_collection(session: "Session") -> None: + # This hook is only called when test modules are collected + # so for example not in the master process of pytest-xdist + # (which does not collect test modules). + assertstate = session.config._store.get(assertstate_key, None) + if assertstate: + if assertstate.hook is not None: + assertstate.hook.set_session(session) + + +@hookimpl(tryfirst=True, hookwrapper=True) +def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]: + """Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks. + + The rewrite module will use util._reprcompare if it exists to use custom + reporting via the pytest_assertrepr_compare hook. This sets up this custom + comparison for the test. + """ + + ihook = item.ihook + + def callbinrepr(op, left: object, right: object) -> Optional[str]: + """Call the pytest_assertrepr_compare hook and prepare the result. + + This uses the first result from the hook and then ensures the + following: + * Overly verbose explanations are truncated unless configured otherwise + (eg. if running in verbose mode). + * Embedded newlines are escaped to help util.format_explanation() + later. + * If the rewrite mode is used embedded %-characters are replaced + to protect later % formatting. + + The result can be formatted by util.format_explanation() for + pretty printing. + """ + hook_result = ihook.pytest_assertrepr_compare( + config=item.config, op=op, left=left, right=right + ) + for new_expl in hook_result: + if new_expl: + new_expl = truncate.truncate_if_required(new_expl, item) + new_expl = [line.replace("\n", "\\n") for line in new_expl] + res = "\n~".join(new_expl) + if item.config.getvalue("assertmode") == "rewrite": + res = res.replace("%", "%%") + return res + return None + + saved_assert_hooks = util._reprcompare, util._assertion_pass + util._reprcompare = callbinrepr + + if ihook.pytest_assertion_pass.get_hookimpls(): + + def call_assertion_pass_hook(lineno: int, orig: str, expl: str) -> None: + ihook.pytest_assertion_pass(item=item, lineno=lineno, orig=orig, expl=expl) + + util._assertion_pass = call_assertion_pass_hook + + yield + + util._reprcompare, util._assertion_pass = saved_assert_hooks + + +def pytest_sessionfinish(session: "Session") -> None: + assertstate = session.config._store.get(assertstate_key, None) + if assertstate: + if assertstate.hook is not None: + assertstate.hook.set_session(None) + + +def pytest_assertrepr_compare( + config: Config, op: str, left: Any, right: Any +) -> Optional[List[str]]: + return util.assertrepr_compare(config=config, op=op, left=left, right=right) diff --git a/myenv/lib/python3.9/site-packages/_pytest/assertion/rewrite.py b/myenv/lib/python3.9/site-packages/_pytest/assertion/rewrite.py new file mode 100644 index 0000000..37ff076 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/assertion/rewrite.py @@ -0,0 +1,1125 @@ +"""Rewrite assertion AST to produce nice error messages.""" +import ast +import errno +import functools +import importlib.abc +import importlib.machinery +import importlib.util +import io +import itertools +import marshal +import os +import struct +import sys +import tokenize +import types +from pathlib import Path +from pathlib import PurePath +from typing import Callable +from typing import Dict +from typing import IO +from typing import Iterable +from typing import List +from typing import Optional +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import py + +from _pytest._io.saferepr import saferepr +from _pytest._version import version +from _pytest.assertion import util +from _pytest.assertion.util import ( # noqa: F401 + format_explanation as _format_explanation, +) +from _pytest.config import Config +from _pytest.main import Session +from _pytest.pathlib import fnmatch_ex +from _pytest.store import StoreKey + +if TYPE_CHECKING: + from _pytest.assertion import AssertionState + + +assertstate_key = StoreKey["AssertionState"]() + + +# pytest caches rewritten pycs in pycache dirs +PYTEST_TAG = f"{sys.implementation.cache_tag}-pytest-{version}" +PYC_EXT = ".py" + (__debug__ and "c" or "o") +PYC_TAIL = "." + PYTEST_TAG + PYC_EXT + + +class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader): + """PEP302/PEP451 import hook which rewrites asserts.""" + + def __init__(self, config: Config) -> None: + self.config = config + try: + self.fnpats = config.getini("python_files") + except ValueError: + self.fnpats = ["test_*.py", "*_test.py"] + self.session: Optional[Session] = None + self._rewritten_names: Set[str] = set() + self._must_rewrite: Set[str] = set() + # flag to guard against trying to rewrite a pyc file while we are already writing another pyc file, + # which might result in infinite recursion (#3506) + self._writing_pyc = False + self._basenames_to_check_rewrite = {"conftest"} + self._marked_for_rewrite_cache: Dict[str, bool] = {} + self._session_paths_checked = False + + def set_session(self, session: Optional[Session]) -> None: + self.session = session + self._session_paths_checked = False + + # Indirection so we can mock calls to find_spec originated from the hook during testing + _find_spec = importlib.machinery.PathFinder.find_spec + + def find_spec( + self, + name: str, + path: Optional[Sequence[Union[str, bytes]]] = None, + target: Optional[types.ModuleType] = None, + ) -> Optional[importlib.machinery.ModuleSpec]: + if self._writing_pyc: + return None + state = self.config._store[assertstate_key] + if self._early_rewrite_bailout(name, state): + return None + state.trace("find_module called for: %s" % name) + + # Type ignored because mypy is confused about the `self` binding here. + spec = self._find_spec(name, path) # type: ignore + if ( + # the import machinery could not find a file to import + spec is None + # this is a namespace package (without `__init__.py`) + # there's nothing to rewrite there + # python3.6: `namespace` + # python3.7+: `None` + or spec.origin == "namespace" + or spec.origin is None + # we can only rewrite source files + or not isinstance(spec.loader, importlib.machinery.SourceFileLoader) + # if the file doesn't exist, we can't rewrite it + or not os.path.exists(spec.origin) + ): + return None + else: + fn = spec.origin + + if not self._should_rewrite(name, fn, state): + return None + + return importlib.util.spec_from_file_location( + name, + fn, + loader=self, + submodule_search_locations=spec.submodule_search_locations, + ) + + def create_module( + self, spec: importlib.machinery.ModuleSpec + ) -> Optional[types.ModuleType]: + return None # default behaviour is fine + + def exec_module(self, module: types.ModuleType) -> None: + assert module.__spec__ is not None + assert module.__spec__.origin is not None + fn = Path(module.__spec__.origin) + state = self.config._store[assertstate_key] + + self._rewritten_names.add(module.__name__) + + # The requested module looks like a test file, so rewrite it. This is + # the most magical part of the process: load the source, rewrite the + # asserts, and load the rewritten source. We also cache the rewritten + # module code in a special pyc. We must be aware of the possibility of + # concurrent pytest processes rewriting and loading pycs. To avoid + # tricky race conditions, we maintain the following invariant: The + # cached pyc is always a complete, valid pyc. Operations on it must be + # atomic. POSIX's atomic rename comes in handy. + write = not sys.dont_write_bytecode + cache_dir = get_cache_dir(fn) + if write: + ok = try_makedirs(cache_dir) + if not ok: + write = False + state.trace(f"read only directory: {cache_dir}") + + cache_name = fn.name[:-3] + PYC_TAIL + pyc = cache_dir / cache_name + # Notice that even if we're in a read-only directory, I'm going + # to check for a cached pyc. This may not be optimal... + co = _read_pyc(fn, pyc, state.trace) + if co is None: + state.trace(f"rewriting {fn!r}") + source_stat, co = _rewrite_test(fn, self.config) + if write: + self._writing_pyc = True + try: + _write_pyc(state, co, source_stat, pyc) + finally: + self._writing_pyc = False + else: + state.trace(f"found cached rewritten pyc for {fn}") + exec(co, module.__dict__) + + def _early_rewrite_bailout(self, name: str, state: "AssertionState") -> bool: + """A fast way to get out of rewriting modules. + + Profiling has shown that the call to PathFinder.find_spec (inside of + the find_spec from this class) is a major slowdown, so, this method + tries to filter what we're sure won't be rewritten before getting to + it. + """ + if self.session is not None and not self._session_paths_checked: + self._session_paths_checked = True + for initial_path in self.session._initialpaths: + # Make something as c:/projects/my_project/path.py -> + # ['c:', 'projects', 'my_project', 'path.py'] + parts = str(initial_path).split(os.path.sep) + # add 'path' to basenames to be checked. + self._basenames_to_check_rewrite.add(os.path.splitext(parts[-1])[0]) + + # Note: conftest already by default in _basenames_to_check_rewrite. + parts = name.split(".") + if parts[-1] in self._basenames_to_check_rewrite: + return False + + # For matching the name it must be as if it was a filename. + path = PurePath(os.path.sep.join(parts) + ".py") + + for pat in self.fnpats: + # if the pattern contains subdirectories ("tests/**.py" for example) we can't bail out based + # on the name alone because we need to match against the full path + if os.path.dirname(pat): + return False + if fnmatch_ex(pat, path): + return False + + if self._is_marked_for_rewrite(name, state): + return False + + state.trace(f"early skip of rewriting module: {name}") + return True + + def _should_rewrite(self, name: str, fn: str, state: "AssertionState") -> bool: + # always rewrite conftest files + if os.path.basename(fn) == "conftest.py": + state.trace(f"rewriting conftest file: {fn!r}") + return True + + if self.session is not None: + if self.session.isinitpath(py.path.local(fn)): + state.trace(f"matched test file (was specified on cmdline): {fn!r}") + return True + + # modules not passed explicitly on the command line are only + # rewritten if they match the naming convention for test files + fn_path = PurePath(fn) + for pat in self.fnpats: + if fnmatch_ex(pat, fn_path): + state.trace(f"matched test file {fn!r}") + return True + + return self._is_marked_for_rewrite(name, state) + + def _is_marked_for_rewrite(self, name: str, state: "AssertionState") -> bool: + try: + return self._marked_for_rewrite_cache[name] + except KeyError: + for marked in self._must_rewrite: + if name == marked or name.startswith(marked + "."): + state.trace(f"matched marked file {name!r} (from {marked!r})") + self._marked_for_rewrite_cache[name] = True + return True + + self._marked_for_rewrite_cache[name] = False + return False + + def mark_rewrite(self, *names: str) -> None: + """Mark import names as needing to be rewritten. + + The named module or package as well as any nested modules will + be rewritten on import. + """ + already_imported = ( + set(names).intersection(sys.modules).difference(self._rewritten_names) + ) + for name in already_imported: + mod = sys.modules[name] + if not AssertionRewriter.is_rewrite_disabled( + mod.__doc__ or "" + ) and not isinstance(mod.__loader__, type(self)): + self._warn_already_imported(name) + self._must_rewrite.update(names) + self._marked_for_rewrite_cache.clear() + + def _warn_already_imported(self, name: str) -> None: + from _pytest.warning_types import PytestAssertRewriteWarning + + self.config.issue_config_time_warning( + PytestAssertRewriteWarning( + "Module already imported so cannot be rewritten: %s" % name + ), + stacklevel=5, + ) + + def get_data(self, pathname: Union[str, bytes]) -> bytes: + """Optional PEP302 get_data API.""" + with open(pathname, "rb") as f: + return f.read() + + +def _write_pyc_fp( + fp: IO[bytes], source_stat: os.stat_result, co: types.CodeType +) -> None: + # Technically, we don't have to have the same pyc format as + # (C)Python, since these "pycs" should never be seen by builtin + # import. However, there's little reason to deviate. + fp.write(importlib.util.MAGIC_NUMBER) + # https://www.python.org/dev/peps/pep-0552/ + if sys.version_info >= (3, 7): + flags = b"\x00\x00\x00\x00" + fp.write(flags) + # as of now, bytecode header expects 32-bit numbers for size and mtime (#4903) + mtime = int(source_stat.st_mtime) & 0xFFFFFFFF + size = source_stat.st_size & 0xFFFFFFFF + # " bool: + try: + with atomic_write(os.fspath(pyc), mode="wb", overwrite=True) as fp: + _write_pyc_fp(fp, source_stat, co) + except OSError as e: + state.trace(f"error writing pyc file at {pyc}: {e}") + # we ignore any failure to write the cache file + # there are many reasons, permission-denied, pycache dir being a + # file etc. + return False + return True + + +else: + + def _write_pyc( + state: "AssertionState", + co: types.CodeType, + source_stat: os.stat_result, + pyc: Path, + ) -> bool: + proc_pyc = f"{pyc}.{os.getpid()}" + try: + fp = open(proc_pyc, "wb") + except OSError as e: + state.trace(f"error writing pyc file at {proc_pyc}: errno={e.errno}") + return False + + try: + _write_pyc_fp(fp, source_stat, co) + os.rename(proc_pyc, os.fspath(pyc)) + except OSError as e: + state.trace(f"error writing pyc file at {pyc}: {e}") + # we ignore any failure to write the cache file + # there are many reasons, permission-denied, pycache dir being a + # file etc. + return False + finally: + fp.close() + return True + + +def _rewrite_test(fn: Path, config: Config) -> Tuple[os.stat_result, types.CodeType]: + """Read and rewrite *fn* and return the code object.""" + fn_ = os.fspath(fn) + stat = os.stat(fn_) + with open(fn_, "rb") as f: + source = f.read() + tree = ast.parse(source, filename=fn_) + rewrite_asserts(tree, source, fn_, config) + co = compile(tree, fn_, "exec", dont_inherit=True) + return stat, co + + +def _read_pyc( + source: Path, pyc: Path, trace: Callable[[str], None] = lambda x: None +) -> Optional[types.CodeType]: + """Possibly read a pytest pyc containing rewritten code. + + Return rewritten code if successful or None if not. + """ + try: + fp = open(os.fspath(pyc), "rb") + except OSError: + return None + with fp: + # https://www.python.org/dev/peps/pep-0552/ + has_flags = sys.version_info >= (3, 7) + try: + stat_result = os.stat(os.fspath(source)) + mtime = int(stat_result.st_mtime) + size = stat_result.st_size + data = fp.read(16 if has_flags else 12) + except OSError as e: + trace(f"_read_pyc({source}): OSError {e}") + return None + # Check for invalid or out of date pyc file. + if len(data) != (16 if has_flags else 12): + trace("_read_pyc(%s): invalid pyc (too short)" % source) + return None + if data[:4] != importlib.util.MAGIC_NUMBER: + trace("_read_pyc(%s): invalid pyc (bad magic number)" % source) + return None + if has_flags and data[4:8] != b"\x00\x00\x00\x00": + trace("_read_pyc(%s): invalid pyc (unsupported flags)" % source) + return None + mtime_data = data[8 if has_flags else 4 : 12 if has_flags else 8] + if int.from_bytes(mtime_data, "little") != mtime & 0xFFFFFFFF: + trace("_read_pyc(%s): out of date" % source) + return None + size_data = data[12 if has_flags else 8 : 16 if has_flags else 12] + if int.from_bytes(size_data, "little") != size & 0xFFFFFFFF: + trace("_read_pyc(%s): invalid pyc (incorrect size)" % source) + return None + try: + co = marshal.load(fp) + except Exception as e: + trace(f"_read_pyc({source}): marshal.load error {e}") + return None + if not isinstance(co, types.CodeType): + trace("_read_pyc(%s): not a code object" % source) + return None + return co + + +def rewrite_asserts( + mod: ast.Module, + source: bytes, + module_path: Optional[str] = None, + config: Optional[Config] = None, +) -> None: + """Rewrite the assert statements in mod.""" + AssertionRewriter(module_path, config, source).run(mod) + + +def _saferepr(obj: object) -> str: + r"""Get a safe repr of an object for assertion error messages. + + The assertion formatting (util.format_explanation()) requires + newlines to be escaped since they are a special character for it. + Normally assertion.util.format_explanation() does this but for a + custom repr it is possible to contain one of the special escape + sequences, especially '\n{' and '\n}' are likely to be present in + JSON reprs. + """ + return saferepr(obj).replace("\n", "\\n") + + +def _format_assertmsg(obj: object) -> str: + r"""Format the custom assertion message given. + + For strings this simply replaces newlines with '\n~' so that + util.format_explanation() will preserve them instead of escaping + newlines. For other objects saferepr() is used first. + """ + # reprlib appears to have a bug which means that if a string + # contains a newline it gets escaped, however if an object has a + # .__repr__() which contains newlines it does not get escaped. + # However in either case we want to preserve the newline. + replaces = [("\n", "\n~"), ("%", "%%")] + if not isinstance(obj, str): + obj = saferepr(obj) + replaces.append(("\\n", "\n~")) + + for r1, r2 in replaces: + obj = obj.replace(r1, r2) + + return obj + + +def _should_repr_global_name(obj: object) -> bool: + if callable(obj): + return False + + try: + return not hasattr(obj, "__name__") + except Exception: + return True + + +def _format_boolop(explanations: Iterable[str], is_or: bool) -> str: + explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")" + return explanation.replace("%", "%%") + + +def _call_reprcompare( + ops: Sequence[str], + results: Sequence[bool], + expls: Sequence[str], + each_obj: Sequence[object], +) -> str: + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +def _call_assertion_pass(lineno: int, orig: str, expl: str) -> None: + if util._assertion_pass is not None: + util._assertion_pass(lineno, orig, expl) + + +def _check_if_assertion_pass_impl() -> bool: + """Check if any plugins implement the pytest_assertion_pass hook + in order not to generate explanation unecessarily (might be expensive).""" + return True if util._assertion_pass else False + + +UNARY_MAP = {ast.Not: "not %s", ast.Invert: "~%s", ast.USub: "-%s", ast.UAdd: "+%s"} + +BINOP_MAP = { + ast.BitOr: "|", + ast.BitXor: "^", + ast.BitAnd: "&", + ast.LShift: "<<", + ast.RShift: ">>", + ast.Add: "+", + ast.Sub: "-", + ast.Mult: "*", + ast.Div: "/", + ast.FloorDiv: "//", + ast.Mod: "%%", # escaped for string formatting + ast.Eq: "==", + ast.NotEq: "!=", + ast.Lt: "<", + ast.LtE: "<=", + ast.Gt: ">", + ast.GtE: ">=", + ast.Pow: "**", + ast.Is: "is", + ast.IsNot: "is not", + ast.In: "in", + ast.NotIn: "not in", + ast.MatMult: "@", +} + + +def set_location(node, lineno, col_offset): + """Set node location information recursively.""" + + def _fix(node, lineno, col_offset): + if "lineno" in node._attributes: + node.lineno = lineno + if "col_offset" in node._attributes: + node.col_offset = col_offset + for child in ast.iter_child_nodes(node): + _fix(child, lineno, col_offset) + + _fix(node, lineno, col_offset) + return node + + +def _get_assertion_exprs(src: bytes) -> Dict[int, str]: + """Return a mapping from {lineno: "assertion test expression"}.""" + ret: Dict[int, str] = {} + + depth = 0 + lines: List[str] = [] + assert_lineno: Optional[int] = None + seen_lines: Set[int] = set() + + def _write_and_reset() -> None: + nonlocal depth, lines, assert_lineno, seen_lines + assert assert_lineno is not None + ret[assert_lineno] = "".join(lines).rstrip().rstrip("\\") + depth = 0 + lines = [] + assert_lineno = None + seen_lines = set() + + tokens = tokenize.tokenize(io.BytesIO(src).readline) + for tp, source, (lineno, offset), _, line in tokens: + if tp == tokenize.NAME and source == "assert": + assert_lineno = lineno + elif assert_lineno is not None: + # keep track of depth for the assert-message `,` lookup + if tp == tokenize.OP and source in "([{": + depth += 1 + elif tp == tokenize.OP and source in ")]}": + depth -= 1 + + if not lines: + lines.append(line[offset:]) + seen_lines.add(lineno) + # a non-nested comma separates the expression from the message + elif depth == 0 and tp == tokenize.OP and source == ",": + # one line assert with message + if lineno in seen_lines and len(lines) == 1: + offset_in_trimmed = offset + len(lines[-1]) - len(line) + lines[-1] = lines[-1][:offset_in_trimmed] + # multi-line assert with message + elif lineno in seen_lines: + lines[-1] = lines[-1][:offset] + # multi line assert with escapd newline before message + else: + lines.append(line[:offset]) + _write_and_reset() + elif tp in {tokenize.NEWLINE, tokenize.ENDMARKER}: + _write_and_reset() + elif lines and lineno not in seen_lines: + lines.append(line) + seen_lines.add(lineno) + + return ret + + +class AssertionRewriter(ast.NodeVisitor): + """Assertion rewriting implementation. + + The main entrypoint is to call .run() with an ast.Module instance, + this will then find all the assert statements and rewrite them to + provide intermediate values and a detailed assertion error. See + http://pybites.blogspot.be/2011/07/behind-scenes-of-pytests-new-assertion.html + for an overview of how this works. + + The entry point here is .run() which will iterate over all the + statements in an ast.Module and for each ast.Assert statement it + finds call .visit() with it. Then .visit_Assert() takes over and + is responsible for creating new ast statements to replace the + original assert statement: it rewrites the test of an assertion + to provide intermediate values and replace it with an if statement + which raises an assertion error with a detailed explanation in + case the expression is false and calls pytest_assertion_pass hook + if expression is true. + + For this .visit_Assert() uses the visitor pattern to visit all the + AST nodes of the ast.Assert.test field, each visit call returning + an AST node and the corresponding explanation string. During this + state is kept in several instance attributes: + + :statements: All the AST statements which will replace the assert + statement. + + :variables: This is populated by .variable() with each variable + used by the statements so that they can all be set to None at + the end of the statements. + + :variable_counter: Counter to create new unique variables needed + by statements. Variables are created using .variable() and + have the form of "@py_assert0". + + :expl_stmts: The AST statements which will be executed to get + data from the assertion. This is the code which will construct + the detailed assertion message that is used in the AssertionError + or for the pytest_assertion_pass hook. + + :explanation_specifiers: A dict filled by .explanation_param() + with %-formatting placeholders and their corresponding + expressions to use in the building of an assertion message. + This is used by .pop_format_context() to build a message. + + :stack: A stack of the explanation_specifiers dicts maintained by + .push_format_context() and .pop_format_context() which allows + to build another %-formatted string while already building one. + + This state is reset on every new assert statement visited and used + by the other visitors. + """ + + def __init__( + self, module_path: Optional[str], config: Optional[Config], source: bytes + ) -> None: + super().__init__() + self.module_path = module_path + self.config = config + if config is not None: + self.enable_assertion_pass_hook = config.getini( + "enable_assertion_pass_hook" + ) + else: + self.enable_assertion_pass_hook = False + self.source = source + + @functools.lru_cache(maxsize=1) + def _assert_expr_to_lineno(self) -> Dict[int, str]: + return _get_assertion_exprs(self.source) + + def run(self, mod: ast.Module) -> None: + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + + # We'll insert some special imports at the top of the module, but after any + # docstrings and __future__ imports, so first figure out where that is. + doc = getattr(mod, "docstring", None) + expect_docstring = doc is None + if doc is not None and self.is_rewrite_disabled(doc): + return + pos = 0 + lineno = 1 + for item in mod.body: + if ( + expect_docstring + and isinstance(item, ast.Expr) + and isinstance(item.value, ast.Str) + ): + doc = item.value.s + if self.is_rewrite_disabled(doc): + return + expect_docstring = False + elif ( + isinstance(item, ast.ImportFrom) + and item.level == 0 + and item.module == "__future__" + ): + pass + else: + break + pos += 1 + # Special case: for a decorated function, set the lineno to that of the + # first decorator, not the `def`. Issue #4984. + if isinstance(item, ast.FunctionDef) and item.decorator_list: + lineno = item.decorator_list[0].lineno + else: + lineno = item.lineno + # Now actually insert the special imports. + if sys.version_info >= (3, 10): + aliases = [ + ast.alias("builtins", "@py_builtins", lineno=lineno, col_offset=0), + ast.alias( + "_pytest.assertion.rewrite", + "@pytest_ar", + lineno=lineno, + col_offset=0, + ), + ] + else: + aliases = [ + ast.alias("builtins", "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar"), + ] + imports = [ + ast.Import([alias], lineno=lineno, col_offset=0) for alias in aliases + ] + mod.body[pos:pos] = imports + + # Collect asserts. + nodes: List[ast.AST] = [mod] + while nodes: + node = nodes.pop() + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new: List[ast.AST] = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif ( + isinstance(field, ast.AST) + # Don't recurse into expressions as they can't contain + # asserts. + and not isinstance(field, ast.expr) + ): + nodes.append(field) + + @staticmethod + def is_rewrite_disabled(docstring: str) -> bool: + return "PYTEST_DONT_REWRITE" in docstring + + def variable(self) -> str: + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.append(name) + return name + + def assign(self, expr: ast.expr) -> ast.Name: + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr: ast.expr) -> ast.expr: + """Call saferepr on the expression.""" + return self.helper("_saferepr", expr) + + def helper(self, name: str, *args: ast.expr) -> ast.expr: + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, name, ast.Load()) + return ast.Call(attr, list(args), []) + + def builtin(self, name: str) -> ast.Attribute: + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr: ast.expr) -> str: + """Return a new named %-formatting placeholder for expr. + + This creates a %-formatting placeholder for expr in the + current formatting context, e.g. ``%(py0)s``. The placeholder + and expr are placed in the current format context so that it + can be used on the next call to .pop_format_context(). + """ + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self) -> None: + """Create a new formatting context. + + The format context is used for when an explanation wants to + have a variable value formatted in the assertion message. In + this case the value required can be added using + .explanation_param(). Finally .pop_format_context() is used + to format a string of %-formatted values as added by + .explanation_param(). + """ + self.explanation_specifiers: Dict[str, ast.expr] = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr: ast.expr) -> ast.Name: + """Format the %-formatted string with current format context. + + The expl_expr should be an str ast.expr instance constructed from + the %-placeholders created by .explanation_param(). This will + add the required code to format said string to .expl_stmts and + return the ast.Name instance of the formatted string. + """ + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [ast.Str(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + if self.enable_assertion_pass_hook: + self.format_variables.append(name) + self.expl_stmts.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node: ast.AST) -> Tuple[ast.Name, str]: + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_: ast.Assert) -> List[ast.stmt]: + """Return the AST statements to replace the ast.Assert instance. + + This rewrites the test of an assertion to provide + intermediate values and replace it with an if statement which + raises an assertion error with a detailed explanation in case + the expression is false. + """ + if isinstance(assert_.test, ast.Tuple) and len(assert_.test.elts) >= 1: + from _pytest.warning_types import PytestAssertRewriteWarning + import warnings + + # TODO: This assert should not be needed. + assert self.module_path is not None + warnings.warn_explicit( + PytestAssertRewriteWarning( + "assertion is always true, perhaps remove parentheses?" + ), + category=None, + filename=os.fspath(self.module_path), + lineno=assert_.lineno, + ) + + self.statements: List[ast.stmt] = [] + self.variables: List[str] = [] + self.variable_counter = itertools.count() + + if self.enable_assertion_pass_hook: + self.format_variables: List[str] = [] + + self.stack: List[Dict[str, ast.expr]] = [] + self.expl_stmts: List[ast.stmt] = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + + negation = ast.UnaryOp(ast.Not(), top_condition) + + if self.enable_assertion_pass_hook: # Experimental pytest_assertion_pass hook + msg = self.pop_format_context(ast.Str(explanation)) + + # Failed + if assert_.msg: + assertmsg = self.helper("_format_assertmsg", assert_.msg) + gluestr = "\n>assert " + else: + assertmsg = ast.Str("") + gluestr = "assert " + err_explanation = ast.BinOp(ast.Str(gluestr), ast.Add(), msg) + err_msg = ast.BinOp(assertmsg, ast.Add(), err_explanation) + err_name = ast.Name("AssertionError", ast.Load()) + fmt = self.helper("_format_explanation", err_msg) + exc = ast.Call(err_name, [fmt], []) + raise_ = ast.Raise(exc, None) + statements_fail = [] + statements_fail.extend(self.expl_stmts) + statements_fail.append(raise_) + + # Passed + fmt_pass = self.helper("_format_explanation", msg) + orig = self._assert_expr_to_lineno()[assert_.lineno] + hook_call_pass = ast.Expr( + self.helper( + "_call_assertion_pass", + ast.Num(assert_.lineno), + ast.Str(orig), + fmt_pass, + ) + ) + # If any hooks implement assert_pass hook + hook_impl_test = ast.If( + self.helper("_check_if_assertion_pass_impl"), + self.expl_stmts + [hook_call_pass], + [], + ) + statements_pass = [hook_impl_test] + + # Test for assertion condition + main_test = ast.If(negation, statements_fail, statements_pass) + self.statements.append(main_test) + if self.format_variables: + variables = [ + ast.Name(name, ast.Store()) for name in self.format_variables + ] + clear_format = ast.Assign(variables, ast.NameConstant(None)) + self.statements.append(clear_format) + + else: # Original assertion rewriting + # Create failure message. + body = self.expl_stmts + self.statements.append(ast.If(negation, body, [])) + if assert_.msg: + assertmsg = self.helper("_format_assertmsg", assert_.msg) + explanation = "\n>assert " + explanation + else: + assertmsg = ast.Str("") + explanation = "assert " + explanation + template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation)) + msg = self.pop_format_context(template) + fmt = self.helper("_format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], []) + raise_ = ast.Raise(exc, None) + + body.append(raise_) + + # Clear temporary variables by setting them to None. + if self.variables: + variables = [ast.Name(name, ast.Store()) for name in self.variables] + clear = ast.Assign(variables, ast.NameConstant(None)) + self.statements.append(clear) + # Fix line numbers. + for stmt in self.statements: + set_location(stmt, assert_.lineno, assert_.col_offset) + return self.statements + + def visit_Name(self, name: ast.Name) -> Tuple[ast.Name, str]: + # Display the repr of the name if it's a local variable or + # _should_repr_global_name() thinks it's acceptable. + locs = ast.Call(self.builtin("locals"), [], []) + inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs]) + dorepr = self.helper("_should_repr_global_name", name) + test = ast.BoolOp(ast.Or(), [inlocs, dorepr]) + expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop: ast.BoolOp) -> Tuple[ast.Name, str]: + res_var = self.variable() + expl_list = self.assign(ast.List([], ast.Load())) + app = ast.Attribute(expl_list, "append", ast.Load()) + is_or = int(isinstance(boolop.op, ast.Or)) + body = save = self.statements + fail_save = self.expl_stmts + levels = len(boolop.values) - 1 + self.push_format_context() + # Process each operand, short-circuiting if needed. + for i, v in enumerate(boolop.values): + if i: + fail_inner: List[ast.stmt] = [] + # cond is set in a prior loop iteration below + self.expl_stmts.append(ast.If(cond, fail_inner, [])) # noqa + self.expl_stmts = fail_inner + self.push_format_context() + res, expl = self.visit(v) + body.append(ast.Assign([ast.Name(res_var, ast.Store())], res)) + expl_format = self.pop_format_context(ast.Str(expl)) + call = ast.Call(app, [expl_format], []) + self.expl_stmts.append(ast.Expr(call)) + if i < levels: + cond: ast.expr = res + if is_or: + cond = ast.UnaryOp(ast.Not(), cond) + inner: List[ast.stmt] = [] + self.statements.append(ast.If(cond, inner, [])) + self.statements = body = inner + self.statements = save + self.expl_stmts = fail_save + expl_template = self.helper("_format_boolop", expl_list, ast.Num(is_or)) + expl = self.pop_format_context(expl_template) + return ast.Name(res_var, ast.Load()), self.explanation_param(expl) + + def visit_UnaryOp(self, unary: ast.UnaryOp) -> Tuple[ast.Name, str]: + pattern = UNARY_MAP[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop: ast.BinOp) -> Tuple[ast.Name, str]: + symbol = BINOP_MAP[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = f"({left_expl} {symbol} {right_expl})" + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call: ast.Call) -> Tuple[ast.Name, str]: + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + for arg in call.args: + res, expl = self.visit(arg) + arg_expls.append(expl) + new_args.append(res) + for keyword in call.keywords: + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + if keyword.arg: + arg_expls.append(keyword.arg + "=" + expl) + else: # **args have `arg` keywords with an .arg of None + arg_expls.append("**" + expl) + + expl = "{}({})".format(func_expl, ", ".join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = f"{res_expl}\n{{{res_expl} = {expl}\n}}" + return res, outer_expl + + def visit_Starred(self, starred: ast.Starred) -> Tuple[ast.Starred, str]: + # A Starred node can appear in a function call. + res, expl = self.visit(starred.value) + new_starred = ast.Starred(res, starred.ctx) + return new_starred, "*" + expl + + def visit_Attribute(self, attr: ast.Attribute) -> Tuple[ast.Name, str]: + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp: ast.Compare) -> Tuple[ast.expr, str]: + self.push_format_context() + left_res, left_expl = self.visit(comp.left) + if isinstance(comp.left, (ast.Compare, ast.BoolOp)): + left_expl = f"({left_expl})" + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + next_res, next_expl = self.visit(next_operand) + if isinstance(next_operand, (ast.Compare, ast.BoolOp)): + next_expl = f"({next_expl})" + results.append(next_res) + sym = BINOP_MAP[op.__class__] + syms.append(ast.Str(sym)) + expl = f"{left_expl} {sym} {next_expl}" + expls.append(ast.Str(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use pytest.assertion.util._reprcompare if that's available. + expl_call = self.helper( + "_call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load()), + ) + if len(comp.ops) > 1: + res: ast.expr = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + return res, self.explanation_param(self.pop_format_context(expl_call)) + + +def try_makedirs(cache_dir: Path) -> bool: + """Attempt to create the given directory and sub-directories exist. + + Returns True if successful or if it already exists. + """ + try: + os.makedirs(os.fspath(cache_dir), exist_ok=True) + except (FileNotFoundError, NotADirectoryError, FileExistsError): + # One of the path components was not a directory: + # - we're in a zip file + # - it is a file + return False + except PermissionError: + return False + except OSError as e: + # as of now, EROFS doesn't have an equivalent OSError-subclass + if e.errno == errno.EROFS: + return False + raise + return True + + +def get_cache_dir(file_path: Path) -> Path: + """Return the cache directory to write .pyc files for the given .py file path.""" + if sys.version_info >= (3, 8) and sys.pycache_prefix: + # given: + # prefix = '/tmp/pycs' + # path = '/home/user/proj/test_app.py' + # we want: + # '/tmp/pycs/home/user/proj' + return Path(sys.pycache_prefix) / Path(*file_path.parts[1:-1]) + else: + # classic pycache directory + return file_path.parent / "__pycache__" diff --git a/myenv/lib/python3.9/site-packages/_pytest/assertion/truncate.py b/myenv/lib/python3.9/site-packages/_pytest/assertion/truncate.py new file mode 100644 index 0000000..5ba9ddc --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/assertion/truncate.py @@ -0,0 +1,100 @@ +"""Utilities for truncating assertion output. + +Current default behaviour is to truncate assertion explanations at +~8 terminal lines, unless running in "-vv" mode or running on CI. +""" +import os +from typing import List +from typing import Optional + +from _pytest.nodes import Item + + +DEFAULT_MAX_LINES = 8 +DEFAULT_MAX_CHARS = 8 * 80 +USAGE_MSG = "use '-vv' to show" + + +def truncate_if_required( + explanation: List[str], item: Item, max_length: Optional[int] = None +) -> List[str]: + """Truncate this assertion explanation if the given test item is eligible.""" + if _should_truncate_item(item): + return _truncate_explanation(explanation) + return explanation + + +def _should_truncate_item(item: Item) -> bool: + """Whether or not this test item is eligible for truncation.""" + verbose = item.config.option.verbose + return verbose < 2 and not _running_on_ci() + + +def _running_on_ci() -> bool: + """Check if we're currently running on a CI system.""" + env_vars = ["CI", "BUILD_NUMBER"] + return any(var in os.environ for var in env_vars) + + +def _truncate_explanation( + input_lines: List[str], + max_lines: Optional[int] = None, + max_chars: Optional[int] = None, +) -> List[str]: + """Truncate given list of strings that makes up the assertion explanation. + + Truncates to either 8 lines, or 640 characters - whichever the input reaches + first. The remaining lines will be replaced by a usage message. + """ + + if max_lines is None: + max_lines = DEFAULT_MAX_LINES + if max_chars is None: + max_chars = DEFAULT_MAX_CHARS + + # Check if truncation required + input_char_count = len("".join(input_lines)) + if len(input_lines) <= max_lines and input_char_count <= max_chars: + return input_lines + + # Truncate first to max_lines, and then truncate to max_chars if max_chars + # is exceeded. + truncated_explanation = input_lines[:max_lines] + truncated_explanation = _truncate_by_char_count(truncated_explanation, max_chars) + + # Add ellipsis to final line + truncated_explanation[-1] = truncated_explanation[-1] + "..." + + # Append useful message to explanation + truncated_line_count = len(input_lines) - len(truncated_explanation) + truncated_line_count += 1 # Account for the part-truncated final line + msg = "...Full output truncated" + if truncated_line_count == 1: + msg += f" ({truncated_line_count} line hidden)" + else: + msg += f" ({truncated_line_count} lines hidden)" + msg += f", {USAGE_MSG}" + truncated_explanation.extend(["", str(msg)]) + return truncated_explanation + + +def _truncate_by_char_count(input_lines: List[str], max_chars: int) -> List[str]: + # Check if truncation required + if len("".join(input_lines)) <= max_chars: + return input_lines + + # Find point at which input length exceeds total allowed length + iterated_char_count = 0 + for iterated_index, input_line in enumerate(input_lines): + if iterated_char_count + len(input_line) > max_chars: + break + iterated_char_count += len(input_line) + + # Create truncated explanation with modified final line + truncated_result = input_lines[:iterated_index] + final_line = input_lines[iterated_index] + if final_line: + final_line_truncate_point = max_chars - iterated_char_count + final_line = final_line[:final_line_truncate_point] + truncated_result.append(final_line) + return truncated_result diff --git a/myenv/lib/python3.9/site-packages/_pytest/assertion/util.py b/myenv/lib/python3.9/site-packages/_pytest/assertion/util.py new file mode 100644 index 0000000..da1ffd1 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/assertion/util.py @@ -0,0 +1,477 @@ +"""Utilities for assertion debugging.""" +import collections.abc +import pprint +from typing import AbstractSet +from typing import Any +from typing import Callable +from typing import Iterable +from typing import List +from typing import Mapping +from typing import Optional +from typing import Sequence + +import _pytest._code +from _pytest import outcomes +from _pytest._io.saferepr import _pformat_dispatch +from _pytest._io.saferepr import safeformat +from _pytest._io.saferepr import saferepr + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare: Optional[Callable[[str, object, object], Optional[str]]] = None + +# Works similarly as _reprcompare attribute. Is populated with the hook call +# when pytest_runtest_setup is called. +_assertion_pass: Optional[Callable[[int, str, str], None]] = None + + +def format_explanation(explanation: str) -> str: + r"""Format an explanation. + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + lines = _split_explanation(explanation) + result = _format_lines(lines) + return "\n".join(result) + + +def _split_explanation(explanation: str) -> List[str]: + r"""Return a list of individual lines in the explanation. + + This will return a list of lines split on '\n{', '\n}' and '\n~'. + Any other newlines will be escaped and appear in the line as the + literal '\n' characters. + """ + raw_lines = (explanation or "").split("\n") + lines = [raw_lines[0]] + for values in raw_lines[1:]: + if values and values[0] in ["{", "}", "~", ">"]: + lines.append(values) + else: + lines[-1] += "\\n" + values + return lines + + +def _format_lines(lines: Sequence[str]) -> List[str]: + """Format the individual lines. + + This will replace the '{', '}' and '~' characters of our mini formatting + language with the proper 'where ...', 'and ...' and ' + ...' text, taking + care of indentation along the way. + + Return a list of formatted lines. + """ + result = list(lines[:1]) + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith("{"): + if stackcnt[-1]: + s = "and " + else: + s = "where " + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(" +" + " " * (len(stack) - 1) + s + line[1:]) + elif line.startswith("}"): + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line[0] in ["~", ">"] + stack[-1] += 1 + indent = len(stack) if line.startswith("~") else len(stack) - 1 + result.append(" " * indent + line[1:]) + assert len(stack) == 1 + return result + + +def issequence(x: Any) -> bool: + return isinstance(x, collections.abc.Sequence) and not isinstance(x, str) + + +def istext(x: Any) -> bool: + return isinstance(x, str) + + +def isdict(x: Any) -> bool: + return isinstance(x, dict) + + +def isset(x: Any) -> bool: + return isinstance(x, (set, frozenset)) + + +def isnamedtuple(obj: Any) -> bool: + return isinstance(obj, tuple) and getattr(obj, "_fields", None) is not None + + +def isdatacls(obj: Any) -> bool: + return getattr(obj, "__dataclass_fields__", None) is not None + + +def isattrs(obj: Any) -> bool: + return getattr(obj, "__attrs_attrs__", None) is not None + + +def isiterable(obj: Any) -> bool: + try: + iter(obj) + return not istext(obj) + except TypeError: + return False + + +def assertrepr_compare(config, op: str, left: Any, right: Any) -> Optional[List[str]]: + """Return specialised explanations for some operators/operands.""" + verbose = config.getoption("verbose") + if verbose > 1: + left_repr = safeformat(left) + right_repr = safeformat(right) + else: + # XXX: "15 chars indentation" is wrong + # ("E AssertionError: assert "); should use term width. + maxsize = ( + 80 - 15 - len(op) - 2 + ) // 2 # 15 chars indentation, 1 space around op + left_repr = saferepr(left, maxsize=maxsize) + right_repr = saferepr(right, maxsize=maxsize) + + summary = f"{left_repr} {op} {right_repr}" + + explanation = None + try: + if op == "==": + explanation = _compare_eq_any(left, right, verbose) + elif op == "not in": + if istext(left) and istext(right): + explanation = _notin_text(left, right, verbose) + except outcomes.Exit: + raise + except Exception: + explanation = [ + "(pytest_assertion plugin: representation of details failed: {}.".format( + _pytest._code.ExceptionInfo.from_current()._getreprcrash() + ), + " Probably an object has a faulty __repr__.)", + ] + + if not explanation: + return None + + return [summary] + explanation + + +def _compare_eq_any(left: Any, right: Any, verbose: int = 0) -> List[str]: + explanation = [] + if istext(left) and istext(right): + explanation = _diff_text(left, right, verbose) + else: + if type(left) == type(right) and ( + isdatacls(left) or isattrs(left) or isnamedtuple(left) + ): + # Note: unlike dataclasses/attrs, namedtuples compare only the + # field values, not the type or field names. But this branch + # intentionally only handles the same-type case, which was often + # used in older code bases before dataclasses/attrs were available. + explanation = _compare_eq_cls(left, right, verbose) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right, verbose) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right, verbose) + elif isdict(left) and isdict(right): + explanation = _compare_eq_dict(left, right, verbose) + elif verbose > 0: + explanation = _compare_eq_verbose(left, right) + if isiterable(left) and isiterable(right): + expl = _compare_eq_iterable(left, right, verbose) + explanation.extend(expl) + return explanation + + +def _diff_text(left: str, right: str, verbose: int = 0) -> List[str]: + """Return the explanation for the diff between text. + + Unless --verbose is used this will skip leading and trailing + characters which are identical to keep the diff minimal. + """ + from difflib import ndiff + + explanation: List[str] = [] + + if verbose < 1: + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = [ + "Skipping %s identical leading characters in diff, use -v to show" % i + ] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += [ + "Skipping {} identical trailing " + "characters in diff, use -v to show".format(i) + ] + left = left[:-i] + right = right[:-i] + keepends = True + if left.isspace() or right.isspace(): + left = repr(str(left)) + right = repr(str(right)) + explanation += ["Strings contain only whitespace, escaping them using repr()"] + # "right" is the expected base against which we compare "left", + # see https://github.com/pytest-dev/pytest/issues/3333 + explanation += [ + line.strip("\n") + for line in ndiff(right.splitlines(keepends), left.splitlines(keepends)) + ] + return explanation + + +def _compare_eq_verbose(left: Any, right: Any) -> List[str]: + keepends = True + left_lines = repr(left).splitlines(keepends) + right_lines = repr(right).splitlines(keepends) + + explanation: List[str] = [] + explanation += ["+" + line for line in left_lines] + explanation += ["-" + line for line in right_lines] + + return explanation + + +def _surrounding_parens_on_own_lines(lines: List[str]) -> None: + """Move opening/closing parenthesis/bracket to own lines.""" + opening = lines[0][:1] + if opening in ["(", "[", "{"]: + lines[0] = " " + lines[0][1:] + lines[:] = [opening] + lines + closing = lines[-1][-1:] + if closing in [")", "]", "}"]: + lines[-1] = lines[-1][:-1] + "," + lines[:] = lines + [closing] + + +def _compare_eq_iterable( + left: Iterable[Any], right: Iterable[Any], verbose: int = 0 +) -> List[str]: + if not verbose: + return ["Use -v to get the full diff"] + # dynamic import to speedup pytest + import difflib + + left_formatting = pprint.pformat(left).splitlines() + right_formatting = pprint.pformat(right).splitlines() + + # Re-format for different output lengths. + lines_left = len(left_formatting) + lines_right = len(right_formatting) + if lines_left != lines_right: + left_formatting = _pformat_dispatch(left).splitlines() + right_formatting = _pformat_dispatch(right).splitlines() + + if lines_left > 1 or lines_right > 1: + _surrounding_parens_on_own_lines(left_formatting) + _surrounding_parens_on_own_lines(right_formatting) + + explanation = ["Full diff:"] + # "right" is the expected base against which we compare "left", + # see https://github.com/pytest-dev/pytest/issues/3333 + explanation.extend( + line.rstrip() for line in difflib.ndiff(right_formatting, left_formatting) + ) + return explanation + + +def _compare_eq_sequence( + left: Sequence[Any], right: Sequence[Any], verbose: int = 0 +) -> List[str]: + comparing_bytes = isinstance(left, bytes) and isinstance(right, bytes) + explanation: List[str] = [] + len_left = len(left) + len_right = len(right) + for i in range(min(len_left, len_right)): + if left[i] != right[i]: + if comparing_bytes: + # when comparing bytes, we want to see their ascii representation + # instead of their numeric values (#5260) + # using a slice gives us the ascii representation: + # >>> s = b'foo' + # >>> s[0] + # 102 + # >>> s[0:1] + # b'f' + left_value = left[i : i + 1] + right_value = right[i : i + 1] + else: + left_value = left[i] + right_value = right[i] + + explanation += [f"At index {i} diff: {left_value!r} != {right_value!r}"] + break + + if comparing_bytes: + # when comparing bytes, it doesn't help to show the "sides contain one or more + # items" longer explanation, so skip it + + return explanation + + len_diff = len_left - len_right + if len_diff: + if len_diff > 0: + dir_with_more = "Left" + extra = saferepr(left[len_right]) + else: + len_diff = 0 - len_diff + dir_with_more = "Right" + extra = saferepr(right[len_left]) + + if len_diff == 1: + explanation += [f"{dir_with_more} contains one more item: {extra}"] + else: + explanation += [ + "%s contains %d more items, first extra item: %s" + % (dir_with_more, len_diff, extra) + ] + return explanation + + +def _compare_eq_set( + left: AbstractSet[Any], right: AbstractSet[Any], verbose: int = 0 +) -> List[str]: + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append("Extra items in the left set:") + for item in diff_left: + explanation.append(saferepr(item)) + if diff_right: + explanation.append("Extra items in the right set:") + for item in diff_right: + explanation.append(saferepr(item)) + return explanation + + +def _compare_eq_dict( + left: Mapping[Any, Any], right: Mapping[Any, Any], verbose: int = 0 +) -> List[str]: + explanation: List[str] = [] + set_left = set(left) + set_right = set(right) + common = set_left.intersection(set_right) + same = {k: left[k] for k in common if left[k] == right[k]} + if same and verbose < 2: + explanation += ["Omitting %s identical items, use -vv to show" % len(same)] + elif same: + explanation += ["Common items:"] + explanation += pprint.pformat(same).splitlines() + diff = {k for k in common if left[k] != right[k]} + if diff: + explanation += ["Differing items:"] + for k in diff: + explanation += [saferepr({k: left[k]}) + " != " + saferepr({k: right[k]})] + extra_left = set_left - set_right + len_extra_left = len(extra_left) + if len_extra_left: + explanation.append( + "Left contains %d more item%s:" + % (len_extra_left, "" if len_extra_left == 1 else "s") + ) + explanation.extend( + pprint.pformat({k: left[k] for k in extra_left}).splitlines() + ) + extra_right = set_right - set_left + len_extra_right = len(extra_right) + if len_extra_right: + explanation.append( + "Right contains %d more item%s:" + % (len_extra_right, "" if len_extra_right == 1 else "s") + ) + explanation.extend( + pprint.pformat({k: right[k] for k in extra_right}).splitlines() + ) + return explanation + + +def _compare_eq_cls(left: Any, right: Any, verbose: int) -> List[str]: + if isdatacls(left): + all_fields = left.__dataclass_fields__ + fields_to_check = [field for field, info in all_fields.items() if info.compare] + elif isattrs(left): + all_fields = left.__attrs_attrs__ + fields_to_check = [field.name for field in all_fields if getattr(field, "eq")] + elif isnamedtuple(left): + fields_to_check = left._fields + else: + assert False + + indent = " " + same = [] + diff = [] + for field in fields_to_check: + if getattr(left, field) == getattr(right, field): + same.append(field) + else: + diff.append(field) + + explanation = [] + if same or diff: + explanation += [""] + if same and verbose < 2: + explanation.append("Omitting %s identical items, use -vv to show" % len(same)) + elif same: + explanation += ["Matching attributes:"] + explanation += pprint.pformat(same).splitlines() + if diff: + explanation += ["Differing attributes:"] + explanation += pprint.pformat(diff).splitlines() + for field in diff: + field_left = getattr(left, field) + field_right = getattr(right, field) + explanation += [ + "", + "Drill down into differing attribute %s:" % field, + ("%s%s: %r != %r") % (indent, field, field_left, field_right), + ] + explanation += [ + indent + line + for line in _compare_eq_any(field_left, field_right, verbose) + ] + return explanation + + +def _notin_text(term: str, text: str, verbose: int = 0) -> List[str]: + index = text.find(term) + head = text[:index] + tail = text[index + len(term) :] + correct_text = head + tail + diff = _diff_text(text, correct_text, verbose) + newdiff = ["%s is contained here:" % saferepr(term, maxsize=42)] + for line in diff: + if line.startswith("Skipping"): + continue + if line.startswith("- "): + continue + if line.startswith("+ "): + newdiff.append(" " + line[2:]) + else: + newdiff.append(line) + return newdiff diff --git a/myenv/lib/python3.9/site-packages/_pytest/cacheprovider.py b/myenv/lib/python3.9/site-packages/_pytest/cacheprovider.py new file mode 100644 index 0000000..03acd03 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/cacheprovider.py @@ -0,0 +1,575 @@ +"""Implementation of the cache provider.""" +# This plugin was not named "cache" to avoid conflicts with the external +# pytest-cache version. +import json +import os +from pathlib import Path +from typing import Dict +from typing import Generator +from typing import Iterable +from typing import List +from typing import Optional +from typing import Set +from typing import Union + +import attr +import py + +from .pathlib import resolve_from_str +from .pathlib import rm_rf +from .reports import CollectReport +from _pytest import nodes +from _pytest._io import TerminalWriter +from _pytest.compat import final +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.main import Session +from _pytest.python import Module +from _pytest.python import Package +from _pytest.reports import TestReport + + +README_CONTENT = """\ +# pytest cache directory # + +This directory contains data from the pytest's cache plugin, +which provides the `--lf` and `--ff` options, as well as the `cache` fixture. + +**Do not** commit this to version control. + +See [the docs](https://docs.pytest.org/en/stable/cache.html) for more information. +""" + +CACHEDIR_TAG_CONTENT = b"""\ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by pytest. +# For information about cache directory tags, see: +# http://www.bford.info/cachedir/spec.html +""" + + +@final +@attr.s(init=False) +class Cache: + _cachedir = attr.ib(type=Path, repr=False) + _config = attr.ib(type=Config, repr=False) + + # sub-directory under cache-dir for directories created by "makedir" + _CACHE_PREFIX_DIRS = "d" + + # sub-directory under cache-dir for values created by "set" + _CACHE_PREFIX_VALUES = "v" + + def __init__( + self, cachedir: Path, config: Config, *, _ispytest: bool = False + ) -> None: + check_ispytest(_ispytest) + self._cachedir = cachedir + self._config = config + + @classmethod + def for_config(cls, config: Config, *, _ispytest: bool = False) -> "Cache": + """Create the Cache instance for a Config. + + :meta private: + """ + check_ispytest(_ispytest) + cachedir = cls.cache_dir_from_config(config, _ispytest=True) + if config.getoption("cacheclear") and cachedir.is_dir(): + cls.clear_cache(cachedir, _ispytest=True) + return cls(cachedir, config, _ispytest=True) + + @classmethod + def clear_cache(cls, cachedir: Path, _ispytest: bool = False) -> None: + """Clear the sub-directories used to hold cached directories and values. + + :meta private: + """ + check_ispytest(_ispytest) + for prefix in (cls._CACHE_PREFIX_DIRS, cls._CACHE_PREFIX_VALUES): + d = cachedir / prefix + if d.is_dir(): + rm_rf(d) + + @staticmethod + def cache_dir_from_config(config: Config, *, _ispytest: bool = False) -> Path: + """Get the path to the cache directory for a Config. + + :meta private: + """ + check_ispytest(_ispytest) + return resolve_from_str(config.getini("cache_dir"), config.rootpath) + + def warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None: + """Issue a cache warning. + + :meta private: + """ + check_ispytest(_ispytest) + import warnings + from _pytest.warning_types import PytestCacheWarning + + warnings.warn( + PytestCacheWarning(fmt.format(**args) if args else fmt), + self._config.hook, + stacklevel=3, + ) + + def makedir(self, name: str) -> py.path.local: + """Return a directory path object with the given name. + + If the directory does not yet exist, it will be created. You can use + it to manage files to e.g. store/retrieve database dumps across test + sessions. + + :param name: + Must be a string not containing a ``/`` separator. + Make sure the name contains your plugin or application + identifiers to prevent clashes with other cache users. + """ + path = Path(name) + if len(path.parts) > 1: + raise ValueError("name is not allowed to contain path separators") + res = self._cachedir.joinpath(self._CACHE_PREFIX_DIRS, path) + res.mkdir(exist_ok=True, parents=True) + return py.path.local(res) + + def _getvaluepath(self, key: str) -> Path: + return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key)) + + def get(self, key: str, default): + """Return the cached value for the given key. + + If no value was yet cached or the value cannot be read, the specified + default is returned. + + :param key: + Must be a ``/`` separated value. Usually the first + name is the name of your plugin or your application. + :param default: + The value to return in case of a cache-miss or invalid cache value. + """ + path = self._getvaluepath(key) + try: + with path.open("r") as f: + return json.load(f) + except (ValueError, OSError): + return default + + def set(self, key: str, value: object) -> None: + """Save value for the given key. + + :param key: + Must be a ``/`` separated value. Usually the first + name is the name of your plugin or your application. + :param value: + Must be of any combination of basic python types, + including nested types like lists of dictionaries. + """ + path = self._getvaluepath(key) + try: + if path.parent.is_dir(): + cache_dir_exists_already = True + else: + cache_dir_exists_already = self._cachedir.exists() + path.parent.mkdir(exist_ok=True, parents=True) + except OSError: + self.warn("could not create cache path {path}", path=path, _ispytest=True) + return + if not cache_dir_exists_already: + self._ensure_supporting_files() + data = json.dumps(value, indent=2, sort_keys=True) + try: + f = path.open("w") + except OSError: + self.warn("cache could not write path {path}", path=path, _ispytest=True) + else: + with f: + f.write(data) + + def _ensure_supporting_files(self) -> None: + """Create supporting files in the cache dir that are not really part of the cache.""" + readme_path = self._cachedir / "README.md" + readme_path.write_text(README_CONTENT) + + gitignore_path = self._cachedir.joinpath(".gitignore") + msg = "# Created by pytest automatically.\n*\n" + gitignore_path.write_text(msg, encoding="UTF-8") + + cachedir_tag_path = self._cachedir.joinpath("CACHEDIR.TAG") + cachedir_tag_path.write_bytes(CACHEDIR_TAG_CONTENT) + + +class LFPluginCollWrapper: + def __init__(self, lfplugin: "LFPlugin") -> None: + self.lfplugin = lfplugin + self._collected_at_least_one_failure = False + + @hookimpl(hookwrapper=True) + def pytest_make_collect_report(self, collector: nodes.Collector): + if isinstance(collector, Session): + out = yield + res: CollectReport = out.get_result() + + # Sort any lf-paths to the beginning. + lf_paths = self.lfplugin._last_failed_paths + res.result = sorted( + res.result, key=lambda x: 0 if Path(str(x.fspath)) in lf_paths else 1, + ) + return + + elif isinstance(collector, Module): + if Path(str(collector.fspath)) in self.lfplugin._last_failed_paths: + out = yield + res = out.get_result() + result = res.result + lastfailed = self.lfplugin.lastfailed + + # Only filter with known failures. + if not self._collected_at_least_one_failure: + if not any(x.nodeid in lastfailed for x in result): + return + self.lfplugin.config.pluginmanager.register( + LFPluginCollSkipfiles(self.lfplugin), "lfplugin-collskip" + ) + self._collected_at_least_one_failure = True + + session = collector.session + result[:] = [ + x + for x in result + if x.nodeid in lastfailed + # Include any passed arguments (not trivial to filter). + or session.isinitpath(x.fspath) + # Keep all sub-collectors. + or isinstance(x, nodes.Collector) + ] + return + yield + + +class LFPluginCollSkipfiles: + def __init__(self, lfplugin: "LFPlugin") -> None: + self.lfplugin = lfplugin + + @hookimpl + def pytest_make_collect_report( + self, collector: nodes.Collector + ) -> Optional[CollectReport]: + # Packages are Modules, but _last_failed_paths only contains + # test-bearing paths and doesn't try to include the paths of their + # packages, so don't filter them. + if isinstance(collector, Module) and not isinstance(collector, Package): + if Path(str(collector.fspath)) not in self.lfplugin._last_failed_paths: + self.lfplugin._skipped_files += 1 + + return CollectReport( + collector.nodeid, "passed", longrepr=None, result=[] + ) + return None + + +class LFPlugin: + """Plugin which implements the --lf (run last-failing) option.""" + + def __init__(self, config: Config) -> None: + self.config = config + active_keys = "lf", "failedfirst" + self.active = any(config.getoption(key) for key in active_keys) + assert config.cache + self.lastfailed: Dict[str, bool] = config.cache.get("cache/lastfailed", {}) + self._previously_failed_count: Optional[int] = None + self._report_status: Optional[str] = None + self._skipped_files = 0 # count skipped files during collection due to --lf + + if config.getoption("lf"): + self._last_failed_paths = self.get_last_failed_paths() + config.pluginmanager.register( + LFPluginCollWrapper(self), "lfplugin-collwrapper" + ) + + def get_last_failed_paths(self) -> Set[Path]: + """Return a set with all Paths()s of the previously failed nodeids.""" + rootpath = self.config.rootpath + result = {rootpath / nodeid.split("::")[0] for nodeid in self.lastfailed} + return {x for x in result if x.exists()} + + def pytest_report_collectionfinish(self) -> Optional[str]: + if self.active and self.config.getoption("verbose") >= 0: + return "run-last-failure: %s" % self._report_status + return None + + def pytest_runtest_logreport(self, report: TestReport) -> None: + if (report.when == "call" and report.passed) or report.skipped: + self.lastfailed.pop(report.nodeid, None) + elif report.failed: + self.lastfailed[report.nodeid] = True + + def pytest_collectreport(self, report: CollectReport) -> None: + passed = report.outcome in ("passed", "skipped") + if passed: + if report.nodeid in self.lastfailed: + self.lastfailed.pop(report.nodeid) + self.lastfailed.update((item.nodeid, True) for item in report.result) + else: + self.lastfailed[report.nodeid] = True + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_collection_modifyitems( + self, config: Config, items: List[nodes.Item] + ) -> Generator[None, None, None]: + yield + + if not self.active: + return + + if self.lastfailed: + previously_failed = [] + previously_passed = [] + for item in items: + if item.nodeid in self.lastfailed: + previously_failed.append(item) + else: + previously_passed.append(item) + self._previously_failed_count = len(previously_failed) + + if not previously_failed: + # Running a subset of all tests with recorded failures + # only outside of it. + self._report_status = "%d known failures not in selected tests" % ( + len(self.lastfailed), + ) + else: + if self.config.getoption("lf"): + items[:] = previously_failed + config.hook.pytest_deselected(items=previously_passed) + else: # --failedfirst + items[:] = previously_failed + previously_passed + + noun = "failure" if self._previously_failed_count == 1 else "failures" + suffix = " first" if self.config.getoption("failedfirst") else "" + self._report_status = "rerun previous {count} {noun}{suffix}".format( + count=self._previously_failed_count, suffix=suffix, noun=noun + ) + + if self._skipped_files > 0: + files_noun = "file" if self._skipped_files == 1 else "files" + self._report_status += " (skipped {files} {files_noun})".format( + files=self._skipped_files, files_noun=files_noun + ) + else: + self._report_status = "no previously failed tests, " + if self.config.getoption("last_failed_no_failures") == "none": + self._report_status += "deselecting all items." + config.hook.pytest_deselected(items=items[:]) + items[:] = [] + else: + self._report_status += "not deselecting items." + + def pytest_sessionfinish(self, session: Session) -> None: + config = self.config + if config.getoption("cacheshow") or hasattr(config, "workerinput"): + return + + assert config.cache is not None + saved_lastfailed = config.cache.get("cache/lastfailed", {}) + if saved_lastfailed != self.lastfailed: + config.cache.set("cache/lastfailed", self.lastfailed) + + +class NFPlugin: + """Plugin which implements the --nf (run new-first) option.""" + + def __init__(self, config: Config) -> None: + self.config = config + self.active = config.option.newfirst + assert config.cache is not None + self.cached_nodeids = set(config.cache.get("cache/nodeids", [])) + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_collection_modifyitems( + self, items: List[nodes.Item] + ) -> Generator[None, None, None]: + yield + + if self.active: + new_items: Dict[str, nodes.Item] = {} + other_items: Dict[str, nodes.Item] = {} + for item in items: + if item.nodeid not in self.cached_nodeids: + new_items[item.nodeid] = item + else: + other_items[item.nodeid] = item + + items[:] = self._get_increasing_order( + new_items.values() + ) + self._get_increasing_order(other_items.values()) + self.cached_nodeids.update(new_items) + else: + self.cached_nodeids.update(item.nodeid for item in items) + + def _get_increasing_order(self, items: Iterable[nodes.Item]) -> List[nodes.Item]: + return sorted(items, key=lambda item: item.fspath.mtime(), reverse=True) # type: ignore[no-any-return] + + def pytest_sessionfinish(self) -> None: + config = self.config + if config.getoption("cacheshow") or hasattr(config, "workerinput"): + return + + if config.getoption("collectonly"): + return + + assert config.cache is not None + config.cache.set("cache/nodeids", sorted(self.cached_nodeids)) + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--lf", + "--last-failed", + action="store_true", + dest="lf", + help="rerun only the tests that failed " + "at the last run (or all if none failed)", + ) + group.addoption( + "--ff", + "--failed-first", + action="store_true", + dest="failedfirst", + help="run all tests, but run the last failures first.\n" + "This may re-order tests and thus lead to " + "repeated fixture setup/teardown.", + ) + group.addoption( + "--nf", + "--new-first", + action="store_true", + dest="newfirst", + help="run tests from new files first, then the rest of the tests " + "sorted by file mtime", + ) + group.addoption( + "--cache-show", + action="append", + nargs="?", + dest="cacheshow", + help=( + "show cache contents, don't perform collection or tests. " + "Optional argument: glob (default: '*')." + ), + ) + group.addoption( + "--cache-clear", + action="store_true", + dest="cacheclear", + help="remove all cache contents at start of test run.", + ) + cache_dir_default = ".pytest_cache" + if "TOX_ENV_DIR" in os.environ: + cache_dir_default = os.path.join(os.environ["TOX_ENV_DIR"], cache_dir_default) + parser.addini("cache_dir", default=cache_dir_default, help="cache directory path.") + group.addoption( + "--lfnf", + "--last-failed-no-failures", + action="store", + dest="last_failed_no_failures", + choices=("all", "none"), + default="all", + help="which tests to run with no previously (known) failures.", + ) + + +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.cacheshow: + from _pytest.main import wrap_session + + return wrap_session(config, cacheshow) + return None + + +@hookimpl(tryfirst=True) +def pytest_configure(config: Config) -> None: + config.cache = Cache.for_config(config, _ispytest=True) + config.pluginmanager.register(LFPlugin(config), "lfplugin") + config.pluginmanager.register(NFPlugin(config), "nfplugin") + + +@fixture +def cache(request: FixtureRequest) -> Cache: + """Return a cache object that can persist state between testing sessions. + + cache.get(key, default) + cache.set(key, value) + + Keys must be ``/`` separated strings, where the first part is usually the + name of your plugin or application to avoid clashes with other cache users. + + Values can be any object handled by the json stdlib module. + """ + assert request.config.cache is not None + return request.config.cache + + +def pytest_report_header(config: Config) -> Optional[str]: + """Display cachedir with --cache-show and if non-default.""" + if config.option.verbose > 0 or config.getini("cache_dir") != ".pytest_cache": + assert config.cache is not None + cachedir = config.cache._cachedir + # TODO: evaluate generating upward relative paths + # starting with .., ../.. if sensible + + try: + displaypath = cachedir.relative_to(config.rootpath) + except ValueError: + displaypath = cachedir + return f"cachedir: {displaypath}" + return None + + +def cacheshow(config: Config, session: Session) -> int: + from pprint import pformat + + assert config.cache is not None + + tw = TerminalWriter() + tw.line("cachedir: " + str(config.cache._cachedir)) + if not config.cache._cachedir.is_dir(): + tw.line("cache is empty") + return 0 + + glob = config.option.cacheshow[0] + if glob is None: + glob = "*" + + dummy = object() + basedir = config.cache._cachedir + vdir = basedir / Cache._CACHE_PREFIX_VALUES + tw.sep("-", "cache values for %r" % glob) + for valpath in sorted(x for x in vdir.rglob(glob) if x.is_file()): + key = str(valpath.relative_to(vdir)) + val = config.cache.get(key, dummy) + if val is dummy: + tw.line("%s contains unreadable content, will be ignored" % key) + else: + tw.line("%s contains:" % key) + for line in pformat(val).splitlines(): + tw.line(" " + line) + + ddir = basedir / Cache._CACHE_PREFIX_DIRS + if ddir.is_dir(): + contents = sorted(ddir.rglob(glob)) + tw.sep("-", "cache directories for %r" % glob) + for p in contents: + # if p.check(dir=1): + # print("%s/" % p.relto(basedir)) + if p.is_file(): + key = str(p.relative_to(basedir)) + tw.line(f"{key} is a file of length {p.stat().st_size:d}") + return 0 diff --git a/myenv/lib/python3.9/site-packages/_pytest/capture.py b/myenv/lib/python3.9/site-packages/_pytest/capture.py new file mode 100644 index 0000000..0863026 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/capture.py @@ -0,0 +1,967 @@ +"""Per-test stdout/stderr capturing mechanism.""" +import contextlib +import functools +import io +import os +import sys +from io import UnsupportedOperation +from tempfile import TemporaryFile +from typing import Any +from typing import AnyStr +from typing import Generator +from typing import Generic +from typing import Iterator +from typing import Optional +from typing import TextIO +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +from _pytest.compat import final +from _pytest.config import Config +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import SubRequest +from _pytest.nodes import Collector +from _pytest.nodes import File +from _pytest.nodes import Item + +if TYPE_CHECKING: + from typing_extensions import Literal + + _CaptureMethod = Literal["fd", "sys", "no", "tee-sys"] + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group._addoption( + "--capture", + action="store", + default="fd", + metavar="method", + choices=["fd", "sys", "no", "tee-sys"], + help="per-test capturing method: one of fd|sys|no|tee-sys.", + ) + group._addoption( + "-s", + action="store_const", + const="no", + dest="capture", + help="shortcut for --capture=no.", + ) + + +def _colorama_workaround() -> None: + """Ensure colorama is imported so that it attaches to the correct stdio + handles on Windows. + + colorama uses the terminal on import time. So if something does the + first import of colorama while I/O capture is active, colorama will + fail in various ways. + """ + if sys.platform.startswith("win32"): + try: + import colorama # noqa: F401 + except ImportError: + pass + + +def _readline_workaround() -> None: + """Ensure readline is imported so that it attaches to the correct stdio + handles on Windows. + + Pdb uses readline support where available--when not running from the Python + prompt, the readline module is not imported until running the pdb REPL. If + running pytest with the --pdb option this means the readline module is not + imported until after I/O capture has been started. + + This is a problem for pyreadline, which is often used to implement readline + support on Windows, as it does not attach to the correct handles for stdout + and/or stdin if they have been redirected by the FDCapture mechanism. This + workaround ensures that readline is imported before I/O capture is setup so + that it can attach to the actual stdin/out for the console. + + See https://github.com/pytest-dev/pytest/pull/1281. + """ + if sys.platform.startswith("win32"): + try: + import readline # noqa: F401 + except ImportError: + pass + + +def _py36_windowsconsoleio_workaround(stream: TextIO) -> None: + """Workaround for Windows Unicode console handling on Python>=3.6. + + Python 3.6 implemented Unicode console handling for Windows. This works + by reading/writing to the raw console handle using + ``{Read,Write}ConsoleW``. + + The problem is that we are going to ``dup2`` over the stdio file + descriptors when doing ``FDCapture`` and this will ``CloseHandle`` the + handles used by Python to write to the console. Though there is still some + weirdness and the console handle seems to only be closed randomly and not + on the first call to ``CloseHandle``, or maybe it gets reopened with the + same handle value when we suspend capturing. + + The workaround in this case will reopen stdio with a different fd which + also means a different handle by replicating the logic in + "Py_lifecycle.c:initstdio/create_stdio". + + :param stream: + In practice ``sys.stdout`` or ``sys.stderr``, but given + here as parameter for unittesting purposes. + + See https://github.com/pytest-dev/py/issues/103. + """ + if not sys.platform.startswith("win32") or hasattr(sys, "pypy_version_info"): + return + + # Bail out if ``stream`` doesn't seem like a proper ``io`` stream (#2666). + if not hasattr(stream, "buffer"): # type: ignore[unreachable] + return + + buffered = hasattr(stream.buffer, "raw") + raw_stdout = stream.buffer.raw if buffered else stream.buffer # type: ignore[attr-defined] + + if not isinstance(raw_stdout, io._WindowsConsoleIO): # type: ignore[attr-defined] + return + + def _reopen_stdio(f, mode): + if not buffered and mode[0] == "w": + buffering = 0 + else: + buffering = -1 + + return io.TextIOWrapper( + open(os.dup(f.fileno()), mode, buffering), # type: ignore[arg-type] + f.encoding, + f.errors, + f.newlines, + f.line_buffering, + ) + + sys.stdin = _reopen_stdio(sys.stdin, "rb") + sys.stdout = _reopen_stdio(sys.stdout, "wb") + sys.stderr = _reopen_stdio(sys.stderr, "wb") + + +@hookimpl(hookwrapper=True) +def pytest_load_initial_conftests(early_config: Config): + ns = early_config.known_args_namespace + if ns.capture == "fd": + _py36_windowsconsoleio_workaround(sys.stdout) + _colorama_workaround() + _readline_workaround() + pluginmanager = early_config.pluginmanager + capman = CaptureManager(ns.capture) + pluginmanager.register(capman, "capturemanager") + + # Make sure that capturemanager is properly reset at final shutdown. + early_config.add_cleanup(capman.stop_global_capturing) + + # Finally trigger conftest loading but while capturing (issue #93). + capman.start_global_capturing() + outcome = yield + capman.suspend_global_capture() + if outcome.excinfo is not None: + out, err = capman.read_global_capture() + sys.stdout.write(out) + sys.stderr.write(err) + + +# IO Helpers. + + +class EncodedFile(io.TextIOWrapper): + __slots__ = () + + @property + def name(self) -> str: + # Ensure that file.name is a string. Workaround for a Python bug + # fixed in >=3.7.4: https://bugs.python.org/issue36015 + return repr(self.buffer) + + @property + def mode(self) -> str: + # TextIOWrapper doesn't expose a mode, but at least some of our + # tests check it. + return self.buffer.mode.replace("b", "") + + +class CaptureIO(io.TextIOWrapper): + def __init__(self) -> None: + super().__init__(io.BytesIO(), encoding="UTF-8", newline="", write_through=True) + + def getvalue(self) -> str: + assert isinstance(self.buffer, io.BytesIO) + return self.buffer.getvalue().decode("UTF-8") + + +class TeeCaptureIO(CaptureIO): + def __init__(self, other: TextIO) -> None: + self._other = other + super().__init__() + + def write(self, s: str) -> int: + super().write(s) + return self._other.write(s) + + +class DontReadFromInput: + encoding = None + + def read(self, *args): + raise OSError( + "pytest: reading from stdin while output is captured! Consider using `-s`." + ) + + readline = read + readlines = read + __next__ = read + + def __iter__(self): + return self + + def fileno(self) -> int: + raise UnsupportedOperation("redirected stdin is pseudofile, has no fileno()") + + def isatty(self) -> bool: + return False + + def close(self) -> None: + pass + + @property + def buffer(self): + return self + + +# Capture classes. + + +patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"} + + +class NoCapture: + EMPTY_BUFFER = None + __init__ = start = done = suspend = resume = lambda *args: None + + +class SysCaptureBinary: + + EMPTY_BUFFER = b"" + + def __init__(self, fd: int, tmpfile=None, *, tee: bool = False) -> None: + name = patchsysdict[fd] + self._old = getattr(sys, name) + self.name = name + if tmpfile is None: + if name == "stdin": + tmpfile = DontReadFromInput() + else: + tmpfile = CaptureIO() if not tee else TeeCaptureIO(self._old) + self.tmpfile = tmpfile + self._state = "initialized" + + def repr(self, class_name: str) -> str: + return "<{} {} _old={} _state={!r} tmpfile={!r}>".format( + class_name, + self.name, + hasattr(self, "_old") and repr(self._old) or "", + self._state, + self.tmpfile, + ) + + def __repr__(self) -> str: + return "<{} {} _old={} _state={!r} tmpfile={!r}>".format( + self.__class__.__name__, + self.name, + hasattr(self, "_old") and repr(self._old) or "", + self._state, + self.tmpfile, + ) + + def _assert_state(self, op: str, states: Tuple[str, ...]) -> None: + assert ( + self._state in states + ), "cannot {} in state {!r}: expected one of {}".format( + op, self._state, ", ".join(states) + ) + + def start(self) -> None: + self._assert_state("start", ("initialized",)) + setattr(sys, self.name, self.tmpfile) + self._state = "started" + + def snap(self): + self._assert_state("snap", ("started", "suspended")) + self.tmpfile.seek(0) + res = self.tmpfile.buffer.read() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def done(self) -> None: + self._assert_state("done", ("initialized", "started", "suspended", "done")) + if self._state == "done": + return + setattr(sys, self.name, self._old) + del self._old + self.tmpfile.close() + self._state = "done" + + def suspend(self) -> None: + self._assert_state("suspend", ("started", "suspended")) + setattr(sys, self.name, self._old) + self._state = "suspended" + + def resume(self) -> None: + self._assert_state("resume", ("started", "suspended")) + if self._state == "started": + return + setattr(sys, self.name, self.tmpfile) + self._state = "started" + + def writeorg(self, data) -> None: + self._assert_state("writeorg", ("started", "suspended")) + self._old.flush() + self._old.buffer.write(data) + self._old.buffer.flush() + + +class SysCapture(SysCaptureBinary): + EMPTY_BUFFER = "" # type: ignore[assignment] + + def snap(self): + res = self.tmpfile.getvalue() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def writeorg(self, data): + self._assert_state("writeorg", ("started", "suspended")) + self._old.write(data) + self._old.flush() + + +class FDCaptureBinary: + """Capture IO to/from a given OS-level file descriptor. + + snap() produces `bytes`. + """ + + EMPTY_BUFFER = b"" + + def __init__(self, targetfd: int) -> None: + self.targetfd = targetfd + + try: + os.fstat(targetfd) + except OSError: + # FD capturing is conceptually simple -- create a temporary file, + # redirect the FD to it, redirect back when done. But when the + # target FD is invalid it throws a wrench into this loveley scheme. + # + # Tests themselves shouldn't care if the FD is valid, FD capturing + # should work regardless of external circumstances. So falling back + # to just sys capturing is not a good option. + # + # Further complications are the need to support suspend() and the + # possibility of FD reuse (e.g. the tmpfile getting the very same + # target FD). The following approach is robust, I believe. + self.targetfd_invalid: Optional[int] = os.open(os.devnull, os.O_RDWR) + os.dup2(self.targetfd_invalid, targetfd) + else: + self.targetfd_invalid = None + self.targetfd_save = os.dup(targetfd) + + if targetfd == 0: + self.tmpfile = open(os.devnull) + self.syscapture = SysCapture(targetfd) + else: + self.tmpfile = EncodedFile( + TemporaryFile(buffering=0), + encoding="utf-8", + errors="replace", + newline="", + write_through=True, + ) + if targetfd in patchsysdict: + self.syscapture = SysCapture(targetfd, self.tmpfile) + else: + self.syscapture = NoCapture() + + self._state = "initialized" + + def __repr__(self) -> str: + return "<{} {} oldfd={} _state={!r} tmpfile={!r}>".format( + self.__class__.__name__, + self.targetfd, + self.targetfd_save, + self._state, + self.tmpfile, + ) + + def _assert_state(self, op: str, states: Tuple[str, ...]) -> None: + assert ( + self._state in states + ), "cannot {} in state {!r}: expected one of {}".format( + op, self._state, ", ".join(states) + ) + + def start(self) -> None: + """Start capturing on targetfd using memorized tmpfile.""" + self._assert_state("start", ("initialized",)) + os.dup2(self.tmpfile.fileno(), self.targetfd) + self.syscapture.start() + self._state = "started" + + def snap(self): + self._assert_state("snap", ("started", "suspended")) + self.tmpfile.seek(0) + res = self.tmpfile.buffer.read() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def done(self) -> None: + """Stop capturing, restore streams, return original capture file, + seeked to position zero.""" + self._assert_state("done", ("initialized", "started", "suspended", "done")) + if self._state == "done": + return + os.dup2(self.targetfd_save, self.targetfd) + os.close(self.targetfd_save) + if self.targetfd_invalid is not None: + if self.targetfd_invalid != self.targetfd: + os.close(self.targetfd) + os.close(self.targetfd_invalid) + self.syscapture.done() + self.tmpfile.close() + self._state = "done" + + def suspend(self) -> None: + self._assert_state("suspend", ("started", "suspended")) + if self._state == "suspended": + return + self.syscapture.suspend() + os.dup2(self.targetfd_save, self.targetfd) + self._state = "suspended" + + def resume(self) -> None: + self._assert_state("resume", ("started", "suspended")) + if self._state == "started": + return + self.syscapture.resume() + os.dup2(self.tmpfile.fileno(), self.targetfd) + self._state = "started" + + def writeorg(self, data): + """Write to original file descriptor.""" + self._assert_state("writeorg", ("started", "suspended")) + os.write(self.targetfd_save, data) + + +class FDCapture(FDCaptureBinary): + """Capture IO to/from a given OS-level file descriptor. + + snap() produces text. + """ + + # Ignore type because it doesn't match the type in the superclass (bytes). + EMPTY_BUFFER = "" # type: ignore + + def snap(self): + self._assert_state("snap", ("started", "suspended")) + self.tmpfile.seek(0) + res = self.tmpfile.read() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def writeorg(self, data): + """Write to original file descriptor.""" + super().writeorg(data.encode("utf-8")) # XXX use encoding of original stream + + +# MultiCapture + + +# This class was a namedtuple, but due to mypy limitation[0] it could not be +# made generic, so was replaced by a regular class which tries to emulate the +# pertinent parts of a namedtuple. If the mypy limitation is ever lifted, can +# make it a namedtuple again. +# [0]: https://github.com/python/mypy/issues/685 +@final +@functools.total_ordering +class CaptureResult(Generic[AnyStr]): + """The result of :method:`CaptureFixture.readouterr`.""" + + __slots__ = ("out", "err") + + def __init__(self, out: AnyStr, err: AnyStr) -> None: + self.out: AnyStr = out + self.err: AnyStr = err + + def __len__(self) -> int: + return 2 + + def __iter__(self) -> Iterator[AnyStr]: + return iter((self.out, self.err)) + + def __getitem__(self, item: int) -> AnyStr: + return tuple(self)[item] + + def _replace( + self, *, out: Optional[AnyStr] = None, err: Optional[AnyStr] = None + ) -> "CaptureResult[AnyStr]": + return CaptureResult( + out=self.out if out is None else out, err=self.err if err is None else err + ) + + def count(self, value: AnyStr) -> int: + return tuple(self).count(value) + + def index(self, value) -> int: + return tuple(self).index(value) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, (CaptureResult, tuple)): + return NotImplemented + return tuple(self) == tuple(other) + + def __hash__(self) -> int: + return hash(tuple(self)) + + def __lt__(self, other: object) -> bool: + if not isinstance(other, (CaptureResult, tuple)): + return NotImplemented + return tuple(self) < tuple(other) + + def __repr__(self) -> str: + return f"CaptureResult(out={self.out!r}, err={self.err!r})" + + +class MultiCapture(Generic[AnyStr]): + _state = None + _in_suspended = False + + def __init__(self, in_, out, err) -> None: + self.in_ = in_ + self.out = out + self.err = err + + def __repr__(self) -> str: + return "".format( + self.out, self.err, self.in_, self._state, self._in_suspended, + ) + + def start_capturing(self) -> None: + self._state = "started" + if self.in_: + self.in_.start() + if self.out: + self.out.start() + if self.err: + self.err.start() + + def pop_outerr_to_orig(self) -> Tuple[AnyStr, AnyStr]: + """Pop current snapshot out/err capture and flush to orig streams.""" + out, err = self.readouterr() + if out: + self.out.writeorg(out) + if err: + self.err.writeorg(err) + return out, err + + def suspend_capturing(self, in_: bool = False) -> None: + self._state = "suspended" + if self.out: + self.out.suspend() + if self.err: + self.err.suspend() + if in_ and self.in_: + self.in_.suspend() + self._in_suspended = True + + def resume_capturing(self) -> None: + self._state = "started" + if self.out: + self.out.resume() + if self.err: + self.err.resume() + if self._in_suspended: + self.in_.resume() + self._in_suspended = False + + def stop_capturing(self) -> None: + """Stop capturing and reset capturing streams.""" + if self._state == "stopped": + raise ValueError("was already stopped") + self._state = "stopped" + if self.out: + self.out.done() + if self.err: + self.err.done() + if self.in_: + self.in_.done() + + def is_started(self) -> bool: + """Whether actively capturing -- not suspended or stopped.""" + return self._state == "started" + + def readouterr(self) -> CaptureResult[AnyStr]: + if self.out: + out = self.out.snap() + else: + out = "" + if self.err: + err = self.err.snap() + else: + err = "" + return CaptureResult(out, err) + + +def _get_multicapture(method: "_CaptureMethod") -> MultiCapture[str]: + if method == "fd": + return MultiCapture(in_=FDCapture(0), out=FDCapture(1), err=FDCapture(2)) + elif method == "sys": + return MultiCapture(in_=SysCapture(0), out=SysCapture(1), err=SysCapture(2)) + elif method == "no": + return MultiCapture(in_=None, out=None, err=None) + elif method == "tee-sys": + return MultiCapture( + in_=None, out=SysCapture(1, tee=True), err=SysCapture(2, tee=True) + ) + raise ValueError(f"unknown capturing method: {method!r}") + + +# CaptureManager and CaptureFixture + + +class CaptureManager: + """The capture plugin. + + Manages that the appropriate capture method is enabled/disabled during + collection and each test phase (setup, call, teardown). After each of + those points, the captured output is obtained and attached to the + collection/runtest report. + + There are two levels of capture: + + * global: enabled by default and can be suppressed by the ``-s`` + option. This is always enabled/disabled during collection and each test + phase. + + * fixture: when a test function or one of its fixture depend on the + ``capsys`` or ``capfd`` fixtures. In this case special handling is + needed to ensure the fixtures take precedence over the global capture. + """ + + def __init__(self, method: "_CaptureMethod") -> None: + self._method = method + self._global_capturing: Optional[MultiCapture[str]] = None + self._capture_fixture: Optional[CaptureFixture[Any]] = None + + def __repr__(self) -> str: + return "".format( + self._method, self._global_capturing, self._capture_fixture + ) + + def is_capturing(self) -> Union[str, bool]: + if self.is_globally_capturing(): + return "global" + if self._capture_fixture: + return "fixture %s" % self._capture_fixture.request.fixturename + return False + + # Global capturing control + + def is_globally_capturing(self) -> bool: + return self._method != "no" + + def start_global_capturing(self) -> None: + assert self._global_capturing is None + self._global_capturing = _get_multicapture(self._method) + self._global_capturing.start_capturing() + + def stop_global_capturing(self) -> None: + if self._global_capturing is not None: + self._global_capturing.pop_outerr_to_orig() + self._global_capturing.stop_capturing() + self._global_capturing = None + + def resume_global_capture(self) -> None: + # During teardown of the python process, and on rare occasions, capture + # attributes can be `None` while trying to resume global capture. + if self._global_capturing is not None: + self._global_capturing.resume_capturing() + + def suspend_global_capture(self, in_: bool = False) -> None: + if self._global_capturing is not None: + self._global_capturing.suspend_capturing(in_=in_) + + def suspend(self, in_: bool = False) -> None: + # Need to undo local capsys-et-al if it exists before disabling global capture. + self.suspend_fixture() + self.suspend_global_capture(in_) + + def resume(self) -> None: + self.resume_global_capture() + self.resume_fixture() + + def read_global_capture(self) -> CaptureResult[str]: + assert self._global_capturing is not None + return self._global_capturing.readouterr() + + # Fixture Control + + def set_fixture(self, capture_fixture: "CaptureFixture[Any]") -> None: + if self._capture_fixture: + current_fixture = self._capture_fixture.request.fixturename + requested_fixture = capture_fixture.request.fixturename + capture_fixture.request.raiseerror( + "cannot use {} and {} at the same time".format( + requested_fixture, current_fixture + ) + ) + self._capture_fixture = capture_fixture + + def unset_fixture(self) -> None: + self._capture_fixture = None + + def activate_fixture(self) -> None: + """If the current item is using ``capsys`` or ``capfd``, activate + them so they take precedence over the global capture.""" + if self._capture_fixture: + self._capture_fixture._start() + + def deactivate_fixture(self) -> None: + """Deactivate the ``capsys`` or ``capfd`` fixture of this item, if any.""" + if self._capture_fixture: + self._capture_fixture.close() + + def suspend_fixture(self) -> None: + if self._capture_fixture: + self._capture_fixture._suspend() + + def resume_fixture(self) -> None: + if self._capture_fixture: + self._capture_fixture._resume() + + # Helper context managers + + @contextlib.contextmanager + def global_and_fixture_disabled(self) -> Generator[None, None, None]: + """Context manager to temporarily disable global and current fixture capturing.""" + do_fixture = self._capture_fixture and self._capture_fixture._is_started() + if do_fixture: + self.suspend_fixture() + do_global = self._global_capturing and self._global_capturing.is_started() + if do_global: + self.suspend_global_capture() + try: + yield + finally: + if do_global: + self.resume_global_capture() + if do_fixture: + self.resume_fixture() + + @contextlib.contextmanager + def item_capture(self, when: str, item: Item) -> Generator[None, None, None]: + self.resume_global_capture() + self.activate_fixture() + try: + yield + finally: + self.deactivate_fixture() + self.suspend_global_capture(in_=False) + + out, err = self.read_global_capture() + item.add_report_section(when, "stdout", out) + item.add_report_section(when, "stderr", err) + + # Hooks + + @hookimpl(hookwrapper=True) + def pytest_make_collect_report(self, collector: Collector): + if isinstance(collector, File): + self.resume_global_capture() + outcome = yield + self.suspend_global_capture() + out, err = self.read_global_capture() + rep = outcome.get_result() + if out: + rep.sections.append(("Captured stdout", out)) + if err: + rep.sections.append(("Captured stderr", err)) + else: + yield + + @hookimpl(hookwrapper=True) + def pytest_runtest_setup(self, item: Item) -> Generator[None, None, None]: + with self.item_capture("setup", item): + yield + + @hookimpl(hookwrapper=True) + def pytest_runtest_call(self, item: Item) -> Generator[None, None, None]: + with self.item_capture("call", item): + yield + + @hookimpl(hookwrapper=True) + def pytest_runtest_teardown(self, item: Item) -> Generator[None, None, None]: + with self.item_capture("teardown", item): + yield + + @hookimpl(tryfirst=True) + def pytest_keyboard_interrupt(self) -> None: + self.stop_global_capturing() + + @hookimpl(tryfirst=True) + def pytest_internalerror(self) -> None: + self.stop_global_capturing() + + +class CaptureFixture(Generic[AnyStr]): + """Object returned by the :fixture:`capsys`, :fixture:`capsysbinary`, + :fixture:`capfd` and :fixture:`capfdbinary` fixtures.""" + + def __init__( + self, captureclass, request: SubRequest, *, _ispytest: bool = False + ) -> None: + check_ispytest(_ispytest) + self.captureclass = captureclass + self.request = request + self._capture: Optional[MultiCapture[AnyStr]] = None + self._captured_out = self.captureclass.EMPTY_BUFFER + self._captured_err = self.captureclass.EMPTY_BUFFER + + def _start(self) -> None: + if self._capture is None: + self._capture = MultiCapture( + in_=None, out=self.captureclass(1), err=self.captureclass(2), + ) + self._capture.start_capturing() + + def close(self) -> None: + if self._capture is not None: + out, err = self._capture.pop_outerr_to_orig() + self._captured_out += out + self._captured_err += err + self._capture.stop_capturing() + self._capture = None + + def readouterr(self) -> CaptureResult[AnyStr]: + """Read and return the captured output so far, resetting the internal + buffer. + + :returns: + The captured content as a namedtuple with ``out`` and ``err`` + string attributes. + """ + captured_out, captured_err = self._captured_out, self._captured_err + if self._capture is not None: + out, err = self._capture.readouterr() + captured_out += out + captured_err += err + self._captured_out = self.captureclass.EMPTY_BUFFER + self._captured_err = self.captureclass.EMPTY_BUFFER + return CaptureResult(captured_out, captured_err) + + def _suspend(self) -> None: + """Suspend this fixture's own capturing temporarily.""" + if self._capture is not None: + self._capture.suspend_capturing() + + def _resume(self) -> None: + """Resume this fixture's own capturing temporarily.""" + if self._capture is not None: + self._capture.resume_capturing() + + def _is_started(self) -> bool: + """Whether actively capturing -- not disabled or closed.""" + if self._capture is not None: + return self._capture.is_started() + return False + + @contextlib.contextmanager + def disabled(self) -> Generator[None, None, None]: + """Temporarily disable capturing while inside the ``with`` block.""" + capmanager = self.request.config.pluginmanager.getplugin("capturemanager") + with capmanager.global_and_fixture_disabled(): + yield + + +# The fixtures. + + +@fixture +def capsys(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: + """Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``. + + The captured output is made available via ``capsys.readouterr()`` method + calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``text`` objects. + """ + capman = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture[str](SysCapture, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() + + +@fixture +def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]: + """Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``. + + The captured output is made available via ``capsysbinary.readouterr()`` + method calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``bytes`` objects. + """ + capman = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture[bytes](SysCaptureBinary, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() + + +@fixture +def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: + """Enable text capturing of writes to file descriptors ``1`` and ``2``. + + The captured output is made available via ``capfd.readouterr()`` method + calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``text`` objects. + """ + capman = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture[str](FDCapture, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() + + +@fixture +def capfdbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]: + """Enable bytes capturing of writes to file descriptors ``1`` and ``2``. + + The captured output is made available via ``capfd.readouterr()`` method + calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``byte`` objects. + """ + capman = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture[bytes](FDCaptureBinary, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() diff --git a/myenv/lib/python3.9/site-packages/_pytest/compat.py b/myenv/lib/python3.9/site-packages/_pytest/compat.py new file mode 100644 index 0000000..c7f86ea --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/compat.py @@ -0,0 +1,400 @@ +"""Python version compatibility code.""" +import enum +import functools +import inspect +import re +import sys +from contextlib import contextmanager +from inspect import Parameter +from inspect import signature +from pathlib import Path +from typing import Any +from typing import Callable +from typing import Generic +from typing import Optional +from typing import Tuple +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import attr + +from _pytest.outcomes import fail +from _pytest.outcomes import TEST_OUTCOME + +if TYPE_CHECKING: + from typing import NoReturn + from typing_extensions import Final + + +_T = TypeVar("_T") +_S = TypeVar("_S") + + +# fmt: off +# Singleton type for NOTSET, as described in: +# https://www.python.org/dev/peps/pep-0484/#support-for-singleton-types-in-unions +class NotSetType(enum.Enum): + token = 0 +NOTSET: "Final" = NotSetType.token # noqa: E305 +# fmt: on + +if sys.version_info >= (3, 8): + from importlib import metadata as importlib_metadata +else: + import importlib_metadata # noqa: F401 + + +def _format_args(func: Callable[..., Any]) -> str: + return str(signature(func)) + + +# The type of re.compile objects is not exposed in Python. +REGEX_TYPE = type(re.compile("")) + + +def is_generator(func: object) -> bool: + genfunc = inspect.isgeneratorfunction(func) + return genfunc and not iscoroutinefunction(func) + + +def iscoroutinefunction(func: object) -> bool: + """Return True if func is a coroutine function (a function defined with async + def syntax, and doesn't contain yield), or a function decorated with + @asyncio.coroutine. + + Note: copied and modified from Python 3.5's builtin couroutines.py to avoid + importing asyncio directly, which in turns also initializes the "logging" + module as a side-effect (see issue #8). + """ + return inspect.iscoroutinefunction(func) or getattr(func, "_is_coroutine", False) + + +def is_async_function(func: object) -> bool: + """Return True if the given function seems to be an async function or + an async generator.""" + return iscoroutinefunction(func) or inspect.isasyncgenfunction(func) + + +def getlocation(function, curdir: Optional[str] = None) -> str: + function = get_real_func(function) + fn = Path(inspect.getfile(function)) + lineno = function.__code__.co_firstlineno + if curdir is not None: + try: + relfn = fn.relative_to(curdir) + except ValueError: + pass + else: + return "%s:%d" % (relfn, lineno + 1) + return "%s:%d" % (fn, lineno + 1) + + +def num_mock_patch_args(function) -> int: + """Return number of arguments used up by mock arguments (if any).""" + patchings = getattr(function, "patchings", None) + if not patchings: + return 0 + + mock_sentinel = getattr(sys.modules.get("mock"), "DEFAULT", object()) + ut_mock_sentinel = getattr(sys.modules.get("unittest.mock"), "DEFAULT", object()) + + return len( + [ + p + for p in patchings + if not p.attribute_name + and (p.new is mock_sentinel or p.new is ut_mock_sentinel) + ] + ) + + +def getfuncargnames( + function: Callable[..., Any], + *, + name: str = "", + is_method: bool = False, + cls: Optional[type] = None, +) -> Tuple[str, ...]: + """Return the names of a function's mandatory arguments. + + Should return the names of all function arguments that: + * Aren't bound to an instance or type as in instance or class methods. + * Don't have default values. + * Aren't bound with functools.partial. + * Aren't replaced with mocks. + + The is_method and cls arguments indicate that the function should + be treated as a bound method even though it's not unless, only in + the case of cls, the function is a static method. + + The name parameter should be the original name in which the function was collected. + """ + # TODO(RonnyPfannschmidt): This function should be refactored when we + # revisit fixtures. The fixture mechanism should ask the node for + # the fixture names, and not try to obtain directly from the + # function object well after collection has occurred. + + # The parameters attribute of a Signature object contains an + # ordered mapping of parameter names to Parameter instances. This + # creates a tuple of the names of the parameters that don't have + # defaults. + try: + parameters = signature(function).parameters + except (ValueError, TypeError) as e: + fail( + f"Could not determine arguments of {function!r}: {e}", pytrace=False, + ) + + arg_names = tuple( + p.name + for p in parameters.values() + if ( + p.kind is Parameter.POSITIONAL_OR_KEYWORD + or p.kind is Parameter.KEYWORD_ONLY + ) + and p.default is Parameter.empty + ) + if not name: + name = function.__name__ + + # If this function should be treated as a bound method even though + # it's passed as an unbound method or function, remove the first + # parameter name. + if is_method or ( + cls and not isinstance(cls.__dict__.get(name, None), staticmethod) + ): + arg_names = arg_names[1:] + # Remove any names that will be replaced with mocks. + if hasattr(function, "__wrapped__"): + arg_names = arg_names[num_mock_patch_args(function) :] + return arg_names + + +if sys.version_info < (3, 7): + + @contextmanager + def nullcontext(): + yield + + +else: + from contextlib import nullcontext as nullcontext # noqa: F401 + + +def get_default_arg_names(function: Callable[..., Any]) -> Tuple[str, ...]: + # Note: this code intentionally mirrors the code at the beginning of + # getfuncargnames, to get the arguments which were excluded from its result + # because they had default values. + return tuple( + p.name + for p in signature(function).parameters.values() + if p.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) + and p.default is not Parameter.empty + ) + + +_non_printable_ascii_translate_table = { + i: f"\\x{i:02x}" for i in range(128) if i not in range(32, 127) +} +_non_printable_ascii_translate_table.update( + {ord("\t"): "\\t", ord("\r"): "\\r", ord("\n"): "\\n"} +) + + +def _translate_non_printable(s: str) -> str: + return s.translate(_non_printable_ascii_translate_table) + + +STRING_TYPES = bytes, str + + +def _bytes_to_ascii(val: bytes) -> str: + return val.decode("ascii", "backslashreplace") + + +def ascii_escaped(val: Union[bytes, str]) -> str: + r"""If val is pure ASCII, return it as an str, otherwise, escape + bytes objects into a sequence of escaped bytes: + + b'\xc3\xb4\xc5\xd6' -> r'\xc3\xb4\xc5\xd6' + + and escapes unicode objects into a sequence of escaped unicode + ids, e.g.: + + r'4\nV\U00043efa\x0eMXWB\x1e\u3028\u15fd\xcd\U0007d944' + + Note: + The obvious "v.decode('unicode-escape')" will return + valid UTF-8 unicode if it finds them in bytes, but we + want to return escaped bytes for any byte, even if they match + a UTF-8 string. + """ + if isinstance(val, bytes): + ret = _bytes_to_ascii(val) + else: + ret = val.encode("unicode_escape").decode("ascii") + return _translate_non_printable(ret) + + +@attr.s +class _PytestWrapper: + """Dummy wrapper around a function object for internal use only. + + Used to correctly unwrap the underlying function object when we are + creating fixtures, because we wrap the function object ourselves with a + decorator to issue warnings when the fixture function is called directly. + """ + + obj = attr.ib() + + +def get_real_func(obj): + """Get the real function object of the (possibly) wrapped object by + functools.wraps or functools.partial.""" + start_obj = obj + for i in range(100): + # __pytest_wrapped__ is set by @pytest.fixture when wrapping the fixture function + # to trigger a warning if it gets called directly instead of by pytest: we don't + # want to unwrap further than this otherwise we lose useful wrappings like @mock.patch (#3774) + new_obj = getattr(obj, "__pytest_wrapped__", None) + if isinstance(new_obj, _PytestWrapper): + obj = new_obj.obj + break + new_obj = getattr(obj, "__wrapped__", None) + if new_obj is None: + break + obj = new_obj + else: + from _pytest._io.saferepr import saferepr + + raise ValueError( + ("could not find real function of {start}\nstopped at {current}").format( + start=saferepr(start_obj), current=saferepr(obj) + ) + ) + if isinstance(obj, functools.partial): + obj = obj.func + return obj + + +def get_real_method(obj, holder): + """Attempt to obtain the real function object that might be wrapping + ``obj``, while at the same time returning a bound method to ``holder`` if + the original object was a bound method.""" + try: + is_method = hasattr(obj, "__func__") + obj = get_real_func(obj) + except Exception: # pragma: no cover + return obj + if is_method and hasattr(obj, "__get__") and callable(obj.__get__): + obj = obj.__get__(holder) + return obj + + +def getimfunc(func): + try: + return func.__func__ + except AttributeError: + return func + + +def safe_getattr(object: Any, name: str, default: Any) -> Any: + """Like getattr but return default upon any Exception or any OutcomeException. + + Attribute access can potentially fail for 'evil' Python objects. + See issue #214. + It catches OutcomeException because of #2490 (issue #580), new outcomes + are derived from BaseException instead of Exception (for more details + check #2707). + """ + try: + return getattr(object, name, default) + except TEST_OUTCOME: + return default + + +def safe_isclass(obj: object) -> bool: + """Ignore any exception via isinstance on Python 3.""" + try: + return inspect.isclass(obj) + except Exception: + return False + + +if TYPE_CHECKING: + if sys.version_info >= (3, 8): + from typing import final as final + else: + from typing_extensions import final as final +elif sys.version_info >= (3, 8): + from typing import final as final +else: + + def final(f): + return f + + +if sys.version_info >= (3, 8): + from functools import cached_property as cached_property +else: + from typing import overload + from typing import Type + + class cached_property(Generic[_S, _T]): + __slots__ = ("func", "__doc__") + + def __init__(self, func: Callable[[_S], _T]) -> None: + self.func = func + self.__doc__ = func.__doc__ + + @overload + def __get__( + self, instance: None, owner: Optional[Type[_S]] = ... + ) -> "cached_property[_S, _T]": + ... + + @overload + def __get__(self, instance: _S, owner: Optional[Type[_S]] = ...) -> _T: + ... + + def __get__(self, instance, owner=None): + if instance is None: + return self + value = instance.__dict__[self.func.__name__] = self.func(instance) + return value + + +# Perform exhaustiveness checking. +# +# Consider this example: +# +# MyUnion = Union[int, str] +# +# def handle(x: MyUnion) -> int { +# if isinstance(x, int): +# return 1 +# elif isinstance(x, str): +# return 2 +# else: +# raise Exception('unreachable') +# +# Now suppose we add a new variant: +# +# MyUnion = Union[int, str, bytes] +# +# After doing this, we must remember ourselves to go and update the handle +# function to handle the new variant. +# +# With `assert_never` we can do better: +# +# // raise Exception('unreachable') +# return assert_never(x) +# +# Now, if we forget to handle the new variant, the type-checker will emit a +# compile-time error, instead of the runtime error we would have gotten +# previously. +# +# This also work for Enums (if you use `is` to compare) and Literals. +def assert_never(value: "NoReturn") -> "NoReturn": + assert False, "Unhandled value: {} ({})".format(value, type(value).__name__) diff --git a/myenv/lib/python3.9/site-packages/_pytest/config/__init__.py b/myenv/lib/python3.9/site-packages/_pytest/config/__init__.py new file mode 100644 index 0000000..bd9e288 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/config/__init__.py @@ -0,0 +1,1606 @@ +"""Command line options, ini-file and conftest.py processing.""" +import argparse +import collections.abc +import contextlib +import copy +import enum +import inspect +import os +import re +import shlex +import sys +import types +import warnings +from functools import lru_cache +from pathlib import Path +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generator +from typing import IO +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import Sequence +from typing import Set +from typing import TextIO +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +import attr +import py +from pluggy import HookimplMarker +from pluggy import HookspecMarker +from pluggy import PluginManager + +import _pytest._code +import _pytest.deprecated +import _pytest.hookspec +from .exceptions import PrintHelp as PrintHelp +from .exceptions import UsageError as UsageError +from .findpaths import determine_setup +from _pytest._code import ExceptionInfo +from _pytest._code import filter_traceback +from _pytest._io import TerminalWriter +from _pytest.compat import final +from _pytest.compat import importlib_metadata +from _pytest.outcomes import fail +from _pytest.outcomes import Skipped +from _pytest.pathlib import bestrelpath +from _pytest.pathlib import import_path +from _pytest.pathlib import ImportMode +from _pytest.store import Store +from _pytest.warning_types import PytestConfigWarning + +if TYPE_CHECKING: + + from _pytest._code.code import _TracebackStyle + from _pytest.terminal import TerminalReporter + from .argparsing import Argument + + +_PluggyPlugin = object +"""A type to represent plugin objects. + +Plugins can be any namespace, so we can't narrow it down much, but we use an +alias to make the intent clear. + +Ideally this type would be provided by pluggy itself. +""" + + +hookimpl = HookimplMarker("pytest") +hookspec = HookspecMarker("pytest") + + +@final +class ExitCode(enum.IntEnum): + """Encodes the valid exit codes by pytest. + + Currently users and plugins may supply other exit codes as well. + + .. versionadded:: 5.0 + """ + + #: Tests passed. + OK = 0 + #: Tests failed. + TESTS_FAILED = 1 + #: pytest was interrupted. + INTERRUPTED = 2 + #: An internal error got in the way. + INTERNAL_ERROR = 3 + #: pytest was misused. + USAGE_ERROR = 4 + #: pytest couldn't find tests. + NO_TESTS_COLLECTED = 5 + + +class ConftestImportFailure(Exception): + def __init__( + self, + path: py.path.local, + excinfo: Tuple[Type[Exception], Exception, TracebackType], + ) -> None: + super().__init__(path, excinfo) + self.path = path + self.excinfo = excinfo + + def __str__(self) -> str: + return "{}: {} (from {})".format( + self.excinfo[0].__name__, self.excinfo[1], self.path + ) + + +def filter_traceback_for_conftest_import_failure( + entry: _pytest._code.TracebackEntry, +) -> bool: + """Filter tracebacks entries which point to pytest internals or importlib. + + Make a special case for importlib because we use it to import test modules and conftest files + in _pytest.pathlib.import_path. + """ + return filter_traceback(entry) and "importlib" not in str(entry.path).split(os.sep) + + +def main( + args: Optional[Union[List[str], py.path.local]] = None, + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, +) -> Union[int, ExitCode]: + """Perform an in-process test run. + + :param args: List of command line arguments. + :param plugins: List of plugin objects to be auto-registered during initialization. + + :returns: An exit code. + """ + try: + try: + config = _prepareconfig(args, plugins) + except ConftestImportFailure as e: + exc_info = ExceptionInfo(e.excinfo) + tw = TerminalWriter(sys.stderr) + tw.line(f"ImportError while loading conftest '{e.path}'.", red=True) + exc_info.traceback = exc_info.traceback.filter( + filter_traceback_for_conftest_import_failure + ) + exc_repr = ( + exc_info.getrepr(style="short", chain=False) + if exc_info.traceback + else exc_info.exconly() + ) + formatted_tb = str(exc_repr) + for line in formatted_tb.splitlines(): + tw.line(line.rstrip(), red=True) + return ExitCode.USAGE_ERROR + else: + try: + ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main( + config=config + ) + try: + return ExitCode(ret) + except ValueError: + return ret + finally: + config._ensure_unconfigure() + except UsageError as e: + tw = TerminalWriter(sys.stderr) + for msg in e.args: + tw.line(f"ERROR: {msg}\n", red=True) + return ExitCode.USAGE_ERROR + + +def console_main() -> int: + """The CLI entry point of pytest. + + This function is not meant for programmable use; use `main()` instead. + """ + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + try: + code = main() + sys.stdout.flush() + return code + except BrokenPipeError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another BrokenPipeError at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + return 1 # Python exits with error code 1 on EPIPE + + +class cmdline: # compatibility namespace + main = staticmethod(main) + + +def filename_arg(path: str, optname: str) -> str: + """Argparse type validator for filename arguments. + + :path: Path of filename. + :optname: Name of the option. + """ + if os.path.isdir(path): + raise UsageError(f"{optname} must be a filename, given: {path}") + return path + + +def directory_arg(path: str, optname: str) -> str: + """Argparse type validator for directory arguments. + + :path: Path of directory. + :optname: Name of the option. + """ + if not os.path.isdir(path): + raise UsageError(f"{optname} must be a directory, given: {path}") + return path + + +# Plugins that cannot be disabled via "-p no:X" currently. +essential_plugins = ( + "mark", + "main", + "runner", + "fixtures", + "helpconfig", # Provides -p. +) + +default_plugins = essential_plugins + ( + "python", + "terminal", + "debugging", + "unittest", + "capture", + "skipping", + "tmpdir", + "monkeypatch", + "recwarn", + "pastebin", + "nose", + "assertion", + "junitxml", + "doctest", + "cacheprovider", + "freeze_support", + "setuponly", + "setupplan", + "stepwise", + "warnings", + "logging", + "reports", + *(["unraisableexception", "threadexception"] if sys.version_info >= (3, 8) else []), + "faulthandler", +) + +builtin_plugins = set(default_plugins) +builtin_plugins.add("pytester") +builtin_plugins.add("pytester_assertions") + + +def get_config( + args: Optional[List[str]] = None, + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, +) -> "Config": + # subsequent calls to main will create a fresh instance + pluginmanager = PytestPluginManager() + config = Config( + pluginmanager, + invocation_params=Config.InvocationParams( + args=args or (), plugins=plugins, dir=Path.cwd(), + ), + ) + + if args is not None: + # Handle any "-p no:plugin" args. + pluginmanager.consider_preparse(args, exclude_only=True) + + for spec in default_plugins: + pluginmanager.import_plugin(spec) + + return config + + +def get_plugin_manager() -> "PytestPluginManager": + """Obtain a new instance of the + :py:class:`_pytest.config.PytestPluginManager`, with default plugins + already loaded. + + This function can be used by integration with other tools, like hooking + into pytest to run tests into an IDE. + """ + return get_config().pluginmanager + + +def _prepareconfig( + args: Optional[Union[py.path.local, List[str]]] = None, + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, +) -> "Config": + if args is None: + args = sys.argv[1:] + elif isinstance(args, py.path.local): + args = [str(args)] + elif not isinstance(args, list): + msg = "`args` parameter expected to be a list of strings, got: {!r} (type: {})" + raise TypeError(msg.format(args, type(args))) + + config = get_config(args, plugins) + pluginmanager = config.pluginmanager + try: + if plugins: + for plugin in plugins: + if isinstance(plugin, str): + pluginmanager.consider_pluginarg(plugin) + else: + pluginmanager.register(plugin) + config = pluginmanager.hook.pytest_cmdline_parse( + pluginmanager=pluginmanager, args=args + ) + return config + except BaseException: + config._ensure_unconfigure() + raise + + +@final +class PytestPluginManager(PluginManager): + """A :py:class:`pluggy.PluginManager ` with + additional pytest-specific functionality: + + * Loading plugins from the command line, ``PYTEST_PLUGINS`` env variable and + ``pytest_plugins`` global variables found in plugins being loaded. + * ``conftest.py`` loading during start-up. + """ + + def __init__(self) -> None: + import _pytest.assertion + + super().__init__("pytest") + # The objects are module objects, only used generically. + self._conftest_plugins: Set[types.ModuleType] = set() + + # State related to local conftest plugins. + self._dirpath2confmods: Dict[py.path.local, List[types.ModuleType]] = {} + self._conftestpath2mod: Dict[Path, types.ModuleType] = {} + self._confcutdir: Optional[py.path.local] = None + self._noconftest = False + self._duplicatepaths: Set[py.path.local] = set() + + # plugins that were explicitly skipped with pytest.skip + # list of (module name, skip reason) + # previously we would issue a warning when a plugin was skipped, but + # since we refactored warnings as first citizens of Config, they are + # just stored here to be used later. + self.skipped_plugins: List[Tuple[str, str]] = [] + + self.add_hookspecs(_pytest.hookspec) + self.register(self) + if os.environ.get("PYTEST_DEBUG"): + err: IO[str] = sys.stderr + encoding: str = getattr(err, "encoding", "utf8") + try: + err = open( + os.dup(err.fileno()), mode=err.mode, buffering=1, encoding=encoding, + ) + except Exception: + pass + self.trace.root.setwriter(err.write) + self.enable_tracing() + + # Config._consider_importhook will set a real object if required. + self.rewrite_hook = _pytest.assertion.DummyRewriteHook() + # Used to know when we are importing conftests after the pytest_configure stage. + self._configured = False + + def parse_hookimpl_opts(self, plugin: _PluggyPlugin, name: str): + # pytest hooks are always prefixed with "pytest_", + # so we avoid accessing possibly non-readable attributes + # (see issue #1073). + if not name.startswith("pytest_"): + return + # Ignore names which can not be hooks. + if name == "pytest_plugins": + return + + method = getattr(plugin, name) + opts = super().parse_hookimpl_opts(plugin, name) + + # Consider only actual functions for hooks (#3775). + if not inspect.isroutine(method): + return + + # Collect unmarked hooks as long as they have the `pytest_' prefix. + if opts is None and name.startswith("pytest_"): + opts = {} + if opts is not None: + # TODO: DeprecationWarning, people should use hookimpl + # https://github.com/pytest-dev/pytest/issues/4562 + known_marks = {m.name for m in getattr(method, "pytestmark", [])} + + for name in ("tryfirst", "trylast", "optionalhook", "hookwrapper"): + opts.setdefault(name, hasattr(method, name) or name in known_marks) + return opts + + def parse_hookspec_opts(self, module_or_class, name: str): + opts = super().parse_hookspec_opts(module_or_class, name) + if opts is None: + method = getattr(module_or_class, name) + + if name.startswith("pytest_"): + # todo: deprecate hookspec hacks + # https://github.com/pytest-dev/pytest/issues/4562 + known_marks = {m.name for m in getattr(method, "pytestmark", [])} + opts = { + "firstresult": hasattr(method, "firstresult") + or "firstresult" in known_marks, + "historic": hasattr(method, "historic") + or "historic" in known_marks, + } + return opts + + def register( + self, plugin: _PluggyPlugin, name: Optional[str] = None + ) -> Optional[str]: + if name in _pytest.deprecated.DEPRECATED_EXTERNAL_PLUGINS: + warnings.warn( + PytestConfigWarning( + "{} plugin has been merged into the core, " + "please remove it from your requirements.".format( + name.replace("_", "-") + ) + ) + ) + return None + ret: Optional[str] = super().register(plugin, name) + if ret: + self.hook.pytest_plugin_registered.call_historic( + kwargs=dict(plugin=plugin, manager=self) + ) + + if isinstance(plugin, types.ModuleType): + self.consider_module(plugin) + return ret + + def getplugin(self, name: str): + # Support deprecated naming because plugins (xdist e.g.) use it. + plugin: Optional[_PluggyPlugin] = self.get_plugin(name) + return plugin + + def hasplugin(self, name: str) -> bool: + """Return whether a plugin with the given name is registered.""" + return bool(self.get_plugin(name)) + + def pytest_configure(self, config: "Config") -> None: + """:meta private:""" + # XXX now that the pluginmanager exposes hookimpl(tryfirst...) + # we should remove tryfirst/trylast as markers. + config.addinivalue_line( + "markers", + "tryfirst: mark a hook implementation function such that the " + "plugin machinery will try to call it first/as early as possible.", + ) + config.addinivalue_line( + "markers", + "trylast: mark a hook implementation function such that the " + "plugin machinery will try to call it last/as late as possible.", + ) + self._configured = True + + # + # Internal API for local conftest plugin handling. + # + def _set_initial_conftests(self, namespace: argparse.Namespace) -> None: + """Load initial conftest files given a preparsed "namespace". + + As conftest files may add their own command line options which have + arguments ('--my-opt somepath') we might get some false positives. + All builtin and 3rd party plugins will have been loaded, however, so + common options will not confuse our logic here. + """ + current = py.path.local() + self._confcutdir = ( + current.join(namespace.confcutdir, abs=True) + if namespace.confcutdir + else None + ) + self._noconftest = namespace.noconftest + self._using_pyargs = namespace.pyargs + testpaths = namespace.file_or_dir + foundanchor = False + for testpath in testpaths: + path = str(testpath) + # remove node-id syntax + i = path.find("::") + if i != -1: + path = path[:i] + anchor = current.join(path, abs=1) + if anchor.exists(): # we found some file object + self._try_load_conftest(anchor, namespace.importmode) + foundanchor = True + if not foundanchor: + self._try_load_conftest(current, namespace.importmode) + + def _try_load_conftest( + self, anchor: py.path.local, importmode: Union[str, ImportMode] + ) -> None: + self._getconftestmodules(anchor, importmode) + # let's also consider test* subdirs + if anchor.check(dir=1): + for x in anchor.listdir("test*"): + if x.check(dir=1): + self._getconftestmodules(x, importmode) + + @lru_cache(maxsize=128) + def _getconftestmodules( + self, path: py.path.local, importmode: Union[str, ImportMode], + ) -> List[types.ModuleType]: + if self._noconftest: + return [] + + if path.isfile(): + directory = path.dirpath() + else: + directory = path + + # XXX these days we may rather want to use config.rootpath + # and allow users to opt into looking into the rootdir parent + # directories instead of requiring to specify confcutdir. + clist = [] + for parent in directory.parts(): + if self._confcutdir and self._confcutdir.relto(parent): + continue + conftestpath = parent.join("conftest.py") + if conftestpath.isfile(): + mod = self._importconftest(conftestpath, importmode) + clist.append(mod) + self._dirpath2confmods[directory] = clist + return clist + + def _rget_with_confmod( + self, name: str, path: py.path.local, importmode: Union[str, ImportMode], + ) -> Tuple[types.ModuleType, Any]: + modules = self._getconftestmodules(path, importmode) + for mod in reversed(modules): + try: + return mod, getattr(mod, name) + except AttributeError: + continue + raise KeyError(name) + + def _importconftest( + self, conftestpath: py.path.local, importmode: Union[str, ImportMode], + ) -> types.ModuleType: + # Use a resolved Path object as key to avoid loading the same conftest + # twice with build systems that create build directories containing + # symlinks to actual files. + # Using Path().resolve() is better than py.path.realpath because + # it resolves to the correct path/drive in case-insensitive file systems (#5792) + key = Path(str(conftestpath)).resolve() + + with contextlib.suppress(KeyError): + return self._conftestpath2mod[key] + + pkgpath = conftestpath.pypkgpath() + if pkgpath is None: + _ensure_removed_sysmodule(conftestpath.purebasename) + + try: + mod = import_path(conftestpath, mode=importmode) + except Exception as e: + assert e.__traceback__ is not None + exc_info = (type(e), e, e.__traceback__) + raise ConftestImportFailure(conftestpath, exc_info) from e + + self._check_non_top_pytest_plugins(mod, conftestpath) + + self._conftest_plugins.add(mod) + self._conftestpath2mod[key] = mod + dirpath = conftestpath.dirpath() + if dirpath in self._dirpath2confmods: + for path, mods in self._dirpath2confmods.items(): + if path and path.relto(dirpath) or path == dirpath: + assert mod not in mods + mods.append(mod) + self.trace(f"loading conftestmodule {mod!r}") + self.consider_conftest(mod) + return mod + + def _check_non_top_pytest_plugins( + self, mod: types.ModuleType, conftestpath: py.path.local, + ) -> None: + if ( + hasattr(mod, "pytest_plugins") + and self._configured + and not self._using_pyargs + ): + msg = ( + "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported:\n" + "It affects the entire test suite instead of just below the conftest as expected.\n" + " {}\n" + "Please move it to a top level conftest file at the rootdir:\n" + " {}\n" + "For more information, visit:\n" + " https://docs.pytest.org/en/stable/deprecations.html#pytest-plugins-in-non-top-level-conftest-files" + ) + fail(msg.format(conftestpath, self._confcutdir), pytrace=False) + + # + # API for bootstrapping plugin loading + # + # + + def consider_preparse( + self, args: Sequence[str], *, exclude_only: bool = False + ) -> None: + i = 0 + n = len(args) + while i < n: + opt = args[i] + i += 1 + if isinstance(opt, str): + if opt == "-p": + try: + parg = args[i] + except IndexError: + return + i += 1 + elif opt.startswith("-p"): + parg = opt[2:] + else: + continue + if exclude_only and not parg.startswith("no:"): + continue + self.consider_pluginarg(parg) + + def consider_pluginarg(self, arg: str) -> None: + if arg.startswith("no:"): + name = arg[3:] + if name in essential_plugins: + raise UsageError("plugin %s cannot be disabled" % name) + + # PR #4304: remove stepwise if cacheprovider is blocked. + if name == "cacheprovider": + self.set_blocked("stepwise") + self.set_blocked("pytest_stepwise") + + self.set_blocked(name) + if not name.startswith("pytest_"): + self.set_blocked("pytest_" + name) + else: + name = arg + # Unblock the plugin. None indicates that it has been blocked. + # There is no interface with pluggy for this. + if self._name2plugin.get(name, -1) is None: + del self._name2plugin[name] + if not name.startswith("pytest_"): + if self._name2plugin.get("pytest_" + name, -1) is None: + del self._name2plugin["pytest_" + name] + self.import_plugin(arg, consider_entry_points=True) + + def consider_conftest(self, conftestmodule: types.ModuleType) -> None: + self.register(conftestmodule, name=conftestmodule.__file__) + + def consider_env(self) -> None: + self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS")) + + def consider_module(self, mod: types.ModuleType) -> None: + self._import_plugin_specs(getattr(mod, "pytest_plugins", [])) + + def _import_plugin_specs( + self, spec: Union[None, types.ModuleType, str, Sequence[str]] + ) -> None: + plugins = _get_plugin_specs_as_list(spec) + for import_spec in plugins: + self.import_plugin(import_spec) + + def import_plugin(self, modname: str, consider_entry_points: bool = False) -> None: + """Import a plugin with ``modname``. + + If ``consider_entry_points`` is True, entry point names are also + considered to find a plugin. + """ + # Most often modname refers to builtin modules, e.g. "pytester", + # "terminal" or "capture". Those plugins are registered under their + # basename for historic purposes but must be imported with the + # _pytest prefix. + assert isinstance(modname, str), ( + "module name as text required, got %r" % modname + ) + if self.is_blocked(modname) or self.get_plugin(modname) is not None: + return + + importspec = "_pytest." + modname if modname in builtin_plugins else modname + self.rewrite_hook.mark_rewrite(importspec) + + if consider_entry_points: + loaded = self.load_setuptools_entrypoints("pytest11", name=modname) + if loaded: + return + + try: + __import__(importspec) + except ImportError as e: + raise ImportError( + 'Error importing plugin "{}": {}'.format(modname, str(e.args[0])) + ).with_traceback(e.__traceback__) from e + + except Skipped as e: + self.skipped_plugins.append((modname, e.msg or "")) + else: + mod = sys.modules[importspec] + self.register(mod, modname) + + +def _get_plugin_specs_as_list( + specs: Union[None, types.ModuleType, str, Sequence[str]] +) -> List[str]: + """Parse a plugins specification into a list of plugin names.""" + # None means empty. + if specs is None: + return [] + # Workaround for #3899 - a submodule which happens to be called "pytest_plugins". + if isinstance(specs, types.ModuleType): + return [] + # Comma-separated list. + if isinstance(specs, str): + return specs.split(",") if specs else [] + # Direct specification. + if isinstance(specs, collections.abc.Sequence): + return list(specs) + raise UsageError( + "Plugins may be specified as a sequence or a ','-separated string of plugin names. Got: %r" + % specs + ) + + +def _ensure_removed_sysmodule(modname: str) -> None: + try: + del sys.modules[modname] + except KeyError: + pass + + +class Notset: + def __repr__(self): + return "" + + +notset = Notset() + + +def _iter_rewritable_modules(package_files: Iterable[str]) -> Iterator[str]: + """Given an iterable of file names in a source distribution, return the "names" that should + be marked for assertion rewrite. + + For example the package "pytest_mock/__init__.py" should be added as "pytest_mock" in + the assertion rewrite mechanism. + + This function has to deal with dist-info based distributions and egg based distributions + (which are still very much in use for "editable" installs). + + Here are the file names as seen in a dist-info based distribution: + + pytest_mock/__init__.py + pytest_mock/_version.py + pytest_mock/plugin.py + pytest_mock.egg-info/PKG-INFO + + Here are the file names as seen in an egg based distribution: + + src/pytest_mock/__init__.py + src/pytest_mock/_version.py + src/pytest_mock/plugin.py + src/pytest_mock.egg-info/PKG-INFO + LICENSE + setup.py + + We have to take in account those two distribution flavors in order to determine which + names should be considered for assertion rewriting. + + More information: + https://github.com/pytest-dev/pytest-mock/issues/167 + """ + package_files = list(package_files) + seen_some = False + for fn in package_files: + is_simple_module = "/" not in fn and fn.endswith(".py") + is_package = fn.count("/") == 1 and fn.endswith("__init__.py") + if is_simple_module: + module_name, _ = os.path.splitext(fn) + # we ignore "setup.py" at the root of the distribution + if module_name != "setup": + seen_some = True + yield module_name + elif is_package: + package_name = os.path.dirname(fn) + seen_some = True + yield package_name + + if not seen_some: + # At this point we did not find any packages or modules suitable for assertion + # rewriting, so we try again by stripping the first path component (to account for + # "src" based source trees for example). + # This approach lets us have the common case continue to be fast, as egg-distributions + # are rarer. + new_package_files = [] + for fn in package_files: + parts = fn.split("/") + new_fn = "/".join(parts[1:]) + if new_fn: + new_package_files.append(new_fn) + if new_package_files: + yield from _iter_rewritable_modules(new_package_files) + + +def _args_converter(args: Iterable[str]) -> Tuple[str, ...]: + return tuple(args) + + +@final +class Config: + """Access to configuration values, pluginmanager and plugin hooks. + + :param PytestPluginManager pluginmanager: + + :param InvocationParams invocation_params: + Object containing parameters regarding the :func:`pytest.main` + invocation. + """ + + @final + @attr.s(frozen=True) + class InvocationParams: + """Holds parameters passed during :func:`pytest.main`. + + The object attributes are read-only. + + .. versionadded:: 5.1 + + .. note:: + + Note that the environment variable ``PYTEST_ADDOPTS`` and the ``addopts`` + ini option are handled by pytest, not being included in the ``args`` attribute. + + Plugins accessing ``InvocationParams`` must be aware of that. + """ + + args = attr.ib(type=Tuple[str, ...], converter=_args_converter) + """The command-line arguments as passed to :func:`pytest.main`. + + :type: Tuple[str, ...] + """ + plugins = attr.ib(type=Optional[Sequence[Union[str, _PluggyPlugin]]]) + """Extra plugins, might be `None`. + + :type: Optional[Sequence[Union[str, plugin]]] + """ + dir = attr.ib(type=Path) + """The directory from which :func:`pytest.main` was invoked. + + :type: pathlib.Path + """ + + def __init__( + self, + pluginmanager: PytestPluginManager, + *, + invocation_params: Optional[InvocationParams] = None, + ) -> None: + from .argparsing import Parser, FILE_OR_DIR + + if invocation_params is None: + invocation_params = self.InvocationParams( + args=(), plugins=None, dir=Path.cwd() + ) + + self.option = argparse.Namespace() + """Access to command line option as attributes. + + :type: argparse.Namespace + """ + + self.invocation_params = invocation_params + """The parameters with which pytest was invoked. + + :type: InvocationParams + """ + + _a = FILE_OR_DIR + self._parser = Parser( + usage=f"%(prog)s [options] [{_a}] [{_a}] [...]", + processopt=self._processopt, + ) + self.pluginmanager = pluginmanager + """The plugin manager handles plugin registration and hook invocation. + + :type: PytestPluginManager + """ + + self.trace = self.pluginmanager.trace.root.get("config") + self.hook = self.pluginmanager.hook + self._inicache: Dict[str, Any] = {} + self._override_ini: Sequence[str] = () + self._opt2dest: Dict[str, str] = {} + self._cleanup: List[Callable[[], None]] = [] + # A place where plugins can store information on the config for their + # own use. Currently only intended for internal plugins. + self._store = Store() + self.pluginmanager.register(self, "pytestconfig") + self._configured = False + self.hook.pytest_addoption.call_historic( + kwargs=dict(parser=self._parser, pluginmanager=self.pluginmanager) + ) + + if TYPE_CHECKING: + from _pytest.cacheprovider import Cache + + self.cache: Optional[Cache] = None + + @property + def invocation_dir(self) -> py.path.local: + """The directory from which pytest was invoked. + + Prefer to use :attr:`invocation_params.dir `, + which is a :class:`pathlib.Path`. + + :type: py.path.local + """ + return py.path.local(str(self.invocation_params.dir)) + + @property + def rootpath(self) -> Path: + """The path to the :ref:`rootdir `. + + :type: pathlib.Path + + .. versionadded:: 6.1 + """ + return self._rootpath + + @property + def rootdir(self) -> py.path.local: + """The path to the :ref:`rootdir `. + + Prefer to use :attr:`rootpath`, which is a :class:`pathlib.Path`. + + :type: py.path.local + """ + return py.path.local(str(self.rootpath)) + + @property + def inipath(self) -> Optional[Path]: + """The path to the :ref:`configfile `. + + :type: Optional[pathlib.Path] + + .. versionadded:: 6.1 + """ + return self._inipath + + @property + def inifile(self) -> Optional[py.path.local]: + """The path to the :ref:`configfile `. + + Prefer to use :attr:`inipath`, which is a :class:`pathlib.Path`. + + :type: Optional[py.path.local] + """ + return py.path.local(str(self.inipath)) if self.inipath else None + + def add_cleanup(self, func: Callable[[], None]) -> None: + """Add a function to be called when the config object gets out of + use (usually coninciding with pytest_unconfigure).""" + self._cleanup.append(func) + + def _do_configure(self) -> None: + assert not self._configured + self._configured = True + with warnings.catch_warnings(): + warnings.simplefilter("default") + self.hook.pytest_configure.call_historic(kwargs=dict(config=self)) + + def _ensure_unconfigure(self) -> None: + if self._configured: + self._configured = False + self.hook.pytest_unconfigure(config=self) + self.hook.pytest_configure._call_history = [] + while self._cleanup: + fin = self._cleanup.pop() + fin() + + def get_terminal_writer(self) -> TerminalWriter: + terminalreporter: TerminalReporter = self.pluginmanager.get_plugin( + "terminalreporter" + ) + return terminalreporter._tw + + def pytest_cmdline_parse( + self, pluginmanager: PytestPluginManager, args: List[str] + ) -> "Config": + try: + self.parse(args) + except UsageError: + + # Handle --version and --help here in a minimal fashion. + # This gets done via helpconfig normally, but its + # pytest_cmdline_main is not called in case of errors. + if getattr(self.option, "version", False) or "--version" in args: + from _pytest.helpconfig import showversion + + showversion(self) + elif ( + getattr(self.option, "help", False) or "--help" in args or "-h" in args + ): + self._parser._getparser().print_help() + sys.stdout.write( + "\nNOTE: displaying only minimal help due to UsageError.\n\n" + ) + + raise + + return self + + def notify_exception( + self, + excinfo: ExceptionInfo[BaseException], + option: Optional[argparse.Namespace] = None, + ) -> None: + if option and getattr(option, "fulltrace", False): + style: _TracebackStyle = "long" + else: + style = "native" + excrepr = excinfo.getrepr( + funcargs=True, showlocals=getattr(option, "showlocals", False), style=style + ) + res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo) + if not any(res): + for line in str(excrepr).split("\n"): + sys.stderr.write("INTERNALERROR> %s\n" % line) + sys.stderr.flush() + + def cwd_relative_nodeid(self, nodeid: str) -> str: + # nodeid's are relative to the rootpath, compute relative to cwd. + if self.invocation_params.dir != self.rootpath: + fullpath = self.rootpath / nodeid + nodeid = bestrelpath(self.invocation_params.dir, fullpath) + return nodeid + + @classmethod + def fromdictargs(cls, option_dict, args) -> "Config": + """Constructor usable for subprocesses.""" + config = get_config(args) + config.option.__dict__.update(option_dict) + config.parse(args, addopts=False) + for x in config.option.plugins: + config.pluginmanager.consider_pluginarg(x) + return config + + def _processopt(self, opt: "Argument") -> None: + for name in opt._short_opts + opt._long_opts: + self._opt2dest[name] = opt.dest + + if hasattr(opt, "default"): + if not hasattr(self.option, opt.dest): + setattr(self.option, opt.dest, opt.default) + + @hookimpl(trylast=True) + def pytest_load_initial_conftests(self, early_config: "Config") -> None: + self.pluginmanager._set_initial_conftests(early_config.known_args_namespace) + + def _initini(self, args: Sequence[str]) -> None: + ns, unknown_args = self._parser.parse_known_and_unknown_args( + args, namespace=copy.copy(self.option) + ) + rootpath, inipath, inicfg = determine_setup( + ns.inifilename, + ns.file_or_dir + unknown_args, + rootdir_cmd_arg=ns.rootdir or None, + config=self, + ) + self._rootpath = rootpath + self._inipath = inipath + self.inicfg = inicfg + self._parser.extra_info["rootdir"] = str(self.rootpath) + self._parser.extra_info["inifile"] = str(self.inipath) + self._parser.addini("addopts", "extra command line options", "args") + self._parser.addini("minversion", "minimally required pytest version") + self._parser.addini( + "required_plugins", + "plugins that must be present for pytest to run", + type="args", + default=[], + ) + self._override_ini = ns.override_ini or () + + def _consider_importhook(self, args: Sequence[str]) -> None: + """Install the PEP 302 import hook if using assertion rewriting. + + Needs to parse the --assert= option from the commandline + and find all the installed plugins to mark them for rewriting + by the importhook. + """ + ns, unknown_args = self._parser.parse_known_and_unknown_args(args) + mode = getattr(ns, "assertmode", "plain") + if mode == "rewrite": + import _pytest.assertion + + try: + hook = _pytest.assertion.install_importhook(self) + except SystemError: + mode = "plain" + else: + self._mark_plugins_for_rewrite(hook) + self._warn_about_missing_assertion(mode) + + def _mark_plugins_for_rewrite(self, hook) -> None: + """Given an importhook, mark for rewrite any top-level + modules or packages in the distribution package for + all pytest plugins.""" + self.pluginmanager.rewrite_hook = hook + + if os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"): + # We don't autoload from setuptools entry points, no need to continue. + return + + package_files = ( + str(file) + for dist in importlib_metadata.distributions() + if any(ep.group == "pytest11" for ep in dist.entry_points) + for file in dist.files or [] + ) + + for name in _iter_rewritable_modules(package_files): + hook.mark_rewrite(name) + + def _validate_args(self, args: List[str], via: str) -> List[str]: + """Validate known args.""" + self._parser._config_source_hint = via # type: ignore + try: + self._parser.parse_known_and_unknown_args( + args, namespace=copy.copy(self.option) + ) + finally: + del self._parser._config_source_hint # type: ignore + + return args + + def _preparse(self, args: List[str], addopts: bool = True) -> None: + if addopts: + env_addopts = os.environ.get("PYTEST_ADDOPTS", "") + if len(env_addopts): + args[:] = ( + self._validate_args(shlex.split(env_addopts), "via PYTEST_ADDOPTS") + + args + ) + self._initini(args) + if addopts: + args[:] = ( + self._validate_args(self.getini("addopts"), "via addopts config") + args + ) + + self.known_args_namespace = self._parser.parse_known_args( + args, namespace=copy.copy(self.option) + ) + self._checkversion() + self._consider_importhook(args) + self.pluginmanager.consider_preparse(args, exclude_only=False) + if not os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"): + # Don't autoload from setuptools entry point. Only explicitly specified + # plugins are going to be loaded. + self.pluginmanager.load_setuptools_entrypoints("pytest11") + self.pluginmanager.consider_env() + + self.known_args_namespace = self._parser.parse_known_args( + args, namespace=copy.copy(self.known_args_namespace) + ) + + self._validate_plugins() + self._warn_about_skipped_plugins() + + if self.known_args_namespace.strict: + self.issue_config_time_warning( + _pytest.deprecated.STRICT_OPTION, stacklevel=2 + ) + + if self.known_args_namespace.confcutdir is None and self.inipath is not None: + confcutdir = str(self.inipath.parent) + self.known_args_namespace.confcutdir = confcutdir + try: + self.hook.pytest_load_initial_conftests( + early_config=self, args=args, parser=self._parser + ) + except ConftestImportFailure as e: + if self.known_args_namespace.help or self.known_args_namespace.version: + # we don't want to prevent --help/--version to work + # so just let is pass and print a warning at the end + self.issue_config_time_warning( + PytestConfigWarning(f"could not load initial conftests: {e.path}"), + stacklevel=2, + ) + else: + raise + + @hookimpl(hookwrapper=True) + def pytest_collection(self) -> Generator[None, None, None]: + """Validate invalid ini keys after collection is done so we take in account + options added by late-loading conftest files.""" + yield + self._validate_config_options() + + def _checkversion(self) -> None: + import pytest + + minver = self.inicfg.get("minversion", None) + if minver: + # Imported lazily to improve start-up time. + from packaging.version import Version + + if not isinstance(minver, str): + raise pytest.UsageError( + "%s: 'minversion' must be a single value" % self.inipath + ) + + if Version(minver) > Version(pytest.__version__): + raise pytest.UsageError( + "%s: 'minversion' requires pytest-%s, actual pytest-%s'" + % (self.inipath, minver, pytest.__version__,) + ) + + def _validate_config_options(self) -> None: + for key in sorted(self._get_unknown_ini_keys()): + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + + def _validate_plugins(self) -> None: + required_plugins = sorted(self.getini("required_plugins")) + if not required_plugins: + return + + # Imported lazily to improve start-up time. + from packaging.version import Version + from packaging.requirements import InvalidRequirement, Requirement + + plugin_info = self.pluginmanager.list_plugin_distinfo() + plugin_dist_info = {dist.project_name: dist.version for _, dist in plugin_info} + + missing_plugins = [] + for required_plugin in required_plugins: + try: + spec = Requirement(required_plugin) + except InvalidRequirement: + missing_plugins.append(required_plugin) + continue + + if spec.name not in plugin_dist_info: + missing_plugins.append(required_plugin) + elif Version(plugin_dist_info[spec.name]) not in spec.specifier: + missing_plugins.append(required_plugin) + + if missing_plugins: + raise UsageError( + "Missing required plugins: {}".format(", ".join(missing_plugins)), + ) + + def _warn_or_fail_if_strict(self, message: str) -> None: + if self.known_args_namespace.strict_config: + raise UsageError(message) + + self.issue_config_time_warning(PytestConfigWarning(message), stacklevel=3) + + def _get_unknown_ini_keys(self) -> List[str]: + parser_inicfg = self._parser._inidict + return [name for name in self.inicfg if name not in parser_inicfg] + + def parse(self, args: List[str], addopts: bool = True) -> None: + # Parse given cmdline arguments into this config object. + assert not hasattr( + self, "args" + ), "can only parse cmdline args at most once per Config object" + self.hook.pytest_addhooks.call_historic( + kwargs=dict(pluginmanager=self.pluginmanager) + ) + self._preparse(args, addopts=addopts) + # XXX deprecated hook: + self.hook.pytest_cmdline_preparse(config=self, args=args) + self._parser.after_preparse = True # type: ignore + try: + args = self._parser.parse_setoption( + args, self.option, namespace=self.option + ) + if not args: + if self.invocation_params.dir == self.rootpath: + args = self.getini("testpaths") + if not args: + args = [str(self.invocation_params.dir)] + self.args = args + except PrintHelp: + pass + + def issue_config_time_warning(self, warning: Warning, stacklevel: int) -> None: + """Issue and handle a warning during the "configure" stage. + + During ``pytest_configure`` we can't capture warnings using the ``catch_warnings_for_item`` + function because it is not possible to have hookwrappers around ``pytest_configure``. + + This function is mainly intended for plugins that need to issue warnings during + ``pytest_configure`` (or similar stages). + + :param warning: The warning instance. + :param stacklevel: stacklevel forwarded to warnings.warn. + """ + if self.pluginmanager.is_blocked("warnings"): + return + + cmdline_filters = self.known_args_namespace.pythonwarnings or [] + config_filters = self.getini("filterwarnings") + + with warnings.catch_warnings(record=True) as records: + warnings.simplefilter("always", type(warning)) + apply_warning_filters(config_filters, cmdline_filters) + warnings.warn(warning, stacklevel=stacklevel) + + if records: + frame = sys._getframe(stacklevel - 1) + location = frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name + self.hook.pytest_warning_captured.call_historic( + kwargs=dict( + warning_message=records[0], + when="config", + item=None, + location=location, + ) + ) + self.hook.pytest_warning_recorded.call_historic( + kwargs=dict( + warning_message=records[0], + when="config", + nodeid="", + location=location, + ) + ) + + def addinivalue_line(self, name: str, line: str) -> None: + """Add a line to an ini-file option. The option must have been + declared but might not yet be set in which case the line becomes + the first line in its value.""" + x = self.getini(name) + assert isinstance(x, list) + x.append(line) # modifies the cached list inline + + def getini(self, name: str): + """Return configuration value from an :ref:`ini file `. + + If the specified name hasn't been registered through a prior + :py:func:`parser.addini <_pytest.config.argparsing.Parser.addini>` + call (usually from a plugin), a ValueError is raised. + """ + try: + return self._inicache[name] + except KeyError: + self._inicache[name] = val = self._getini(name) + return val + + def _getini(self, name: str): + try: + description, type, default = self._parser._inidict[name] + except KeyError as e: + raise ValueError(f"unknown configuration value: {name!r}") from e + override_value = self._get_override_ini_value(name) + if override_value is None: + try: + value = self.inicfg[name] + except KeyError: + if default is not None: + return default + if type is None: + return "" + return [] + else: + value = override_value + # Coerce the values based on types. + # + # Note: some coercions are only required if we are reading from .ini files, because + # the file format doesn't contain type information, but when reading from toml we will + # get either str or list of str values (see _parse_ini_config_from_pyproject_toml). + # For example: + # + # ini: + # a_line_list = "tests acceptance" + # in this case, we need to split the string to obtain a list of strings. + # + # toml: + # a_line_list = ["tests", "acceptance"] + # in this case, we already have a list ready to use. + # + if type == "pathlist": + # TODO: This assert is probably not valid in all cases. + assert self.inipath is not None + dp = self.inipath.parent + input_values = shlex.split(value) if isinstance(value, str) else value + return [py.path.local(str(dp / x)) for x in input_values] + elif type == "args": + return shlex.split(value) if isinstance(value, str) else value + elif type == "linelist": + if isinstance(value, str): + return [t for t in map(lambda x: x.strip(), value.split("\n")) if t] + else: + return value + elif type == "bool": + return _strtobool(str(value).strip()) + else: + assert type in [None, "string"] + return value + + def _getconftest_pathlist( + self, name: str, path: py.path.local + ) -> Optional[List[py.path.local]]: + try: + mod, relroots = self.pluginmanager._rget_with_confmod( + name, path, self.getoption("importmode") + ) + except KeyError: + return None + modpath = py.path.local(mod.__file__).dirpath() + values: List[py.path.local] = [] + for relroot in relroots: + if not isinstance(relroot, py.path.local): + relroot = relroot.replace("/", os.sep) + relroot = modpath.join(relroot, abs=True) + values.append(relroot) + return values + + def _get_override_ini_value(self, name: str) -> Optional[str]: + value = None + # override_ini is a list of "ini=value" options. + # Always use the last item if multiple values are set for same ini-name, + # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2. + for ini_config in self._override_ini: + try: + key, user_ini_value = ini_config.split("=", 1) + except ValueError as e: + raise UsageError( + "-o/--override-ini expects option=value style (got: {!r}).".format( + ini_config + ) + ) from e + else: + if key == name: + value = user_ini_value + return value + + def getoption(self, name: str, default=notset, skip: bool = False): + """Return command line option value. + + :param name: Name of the option. You may also specify + the literal ``--OPT`` option instead of the "dest" option name. + :param default: Default value if no option of that name exists. + :param skip: If True, raise pytest.skip if option does not exists + or has a None value. + """ + name = self._opt2dest.get(name, name) + try: + val = getattr(self.option, name) + if val is None and skip: + raise AttributeError(name) + return val + except AttributeError as e: + if default is not notset: + return default + if skip: + import pytest + + pytest.skip(f"no {name!r} option found") + raise ValueError(f"no option named {name!r}") from e + + def getvalue(self, name: str, path=None): + """Deprecated, use getoption() instead.""" + return self.getoption(name) + + def getvalueorskip(self, name: str, path=None): + """Deprecated, use getoption(skip=True) instead.""" + return self.getoption(name, skip=True) + + def _warn_about_missing_assertion(self, mode: str) -> None: + if not _assertion_supported(): + if mode == "plain": + warning_text = ( + "ASSERTIONS ARE NOT EXECUTED" + " and FAILING TESTS WILL PASS. Are you" + " using python -O?" + ) + else: + warning_text = ( + "assertions not in test modules or" + " plugins will be ignored" + " because assert statements are not executed " + "by the underlying Python interpreter " + "(are you using python -O?)\n" + ) + self.issue_config_time_warning( + PytestConfigWarning(warning_text), stacklevel=3, + ) + + def _warn_about_skipped_plugins(self) -> None: + for module_name, msg in self.pluginmanager.skipped_plugins: + self.issue_config_time_warning( + PytestConfigWarning(f"skipped plugin {module_name!r}: {msg}"), + stacklevel=2, + ) + + +def _assertion_supported() -> bool: + try: + assert False + except AssertionError: + return True + else: + return False # type: ignore[unreachable] + + +def create_terminal_writer( + config: Config, file: Optional[TextIO] = None +) -> TerminalWriter: + """Create a TerminalWriter instance configured according to the options + in the config object. + + Every code which requires a TerminalWriter object and has access to a + config object should use this function. + """ + tw = TerminalWriter(file=file) + + if config.option.color == "yes": + tw.hasmarkup = True + elif config.option.color == "no": + tw.hasmarkup = False + + if config.option.code_highlight == "yes": + tw.code_highlight = True + elif config.option.code_highlight == "no": + tw.code_highlight = False + + return tw + + +def _strtobool(val: str) -> bool: + """Convert a string representation of truth to True or False. + + True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values + are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if + 'val' is anything else. + + .. note:: Copied from distutils.util. + """ + val = val.lower() + if val in ("y", "yes", "t", "true", "on", "1"): + return True + elif val in ("n", "no", "f", "false", "off", "0"): + return False + else: + raise ValueError(f"invalid truth value {val!r}") + + +@lru_cache(maxsize=50) +def parse_warning_filter( + arg: str, *, escape: bool +) -> Tuple[str, str, Type[Warning], str, int]: + """Parse a warnings filter string. + + This is copied from warnings._setoption, but does not apply the filter, + only parses it, and makes the escaping optional. + """ + parts = arg.split(":") + if len(parts) > 5: + raise warnings._OptionError(f"too many fields (max 5): {arg!r}") + while len(parts) < 5: + parts.append("") + action_, message, category_, module, lineno_ = [s.strip() for s in parts] + action: str = warnings._getaction(action_) # type: ignore[attr-defined] + category: Type[Warning] = warnings._getcategory(category_) # type: ignore[attr-defined] + if message and escape: + message = re.escape(message) + if module and escape: + module = re.escape(module) + r"\Z" + if lineno_: + try: + lineno = int(lineno_) + if lineno < 0: + raise ValueError + except (ValueError, OverflowError) as e: + raise warnings._OptionError(f"invalid lineno {lineno_!r}") from e + else: + lineno = 0 + return action, message, category, module, lineno + + +def apply_warning_filters( + config_filters: Iterable[str], cmdline_filters: Iterable[str] +) -> None: + """Applies pytest-configured filters to the warnings module""" + # Filters should have this precedence: cmdline options, config. + # Filters should be applied in the inverse order of precedence. + for arg in config_filters: + warnings.filterwarnings(*parse_warning_filter(arg, escape=False)) + + for arg in cmdline_filters: + warnings.filterwarnings(*parse_warning_filter(arg, escape=True)) diff --git a/myenv/lib/python3.9/site-packages/_pytest/config/argparsing.py b/myenv/lib/python3.9/site-packages/_pytest/config/argparsing.py new file mode 100644 index 0000000..9a48196 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/config/argparsing.py @@ -0,0 +1,522 @@ +import argparse +import sys +import warnings +from gettext import gettext +from typing import Any +from typing import Callable +from typing import cast +from typing import Dict +from typing import List +from typing import Mapping +from typing import Optional +from typing import Sequence +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import py + +import _pytest._io +from _pytest.compat import final +from _pytest.config.exceptions import UsageError + +if TYPE_CHECKING: + from typing import NoReturn + from typing_extensions import Literal + +FILE_OR_DIR = "file_or_dir" + + +@final +class Parser: + """Parser for command line arguments and ini-file values. + + :ivar extra_info: Dict of generic param -> value to display in case + there's an error processing the command line arguments. + """ + + prog: Optional[str] = None + + def __init__( + self, + usage: Optional[str] = None, + processopt: Optional[Callable[["Argument"], None]] = None, + ) -> None: + self._anonymous = OptionGroup("custom options", parser=self) + self._groups: List[OptionGroup] = [] + self._processopt = processopt + self._usage = usage + self._inidict: Dict[str, Tuple[str, Optional[str], Any]] = {} + self._ininames: List[str] = [] + self.extra_info: Dict[str, Any] = {} + + def processoption(self, option: "Argument") -> None: + if self._processopt: + if option.dest: + self._processopt(option) + + def getgroup( + self, name: str, description: str = "", after: Optional[str] = None + ) -> "OptionGroup": + """Get (or create) a named option Group. + + :name: Name of the option group. + :description: Long description for --help output. + :after: Name of another group, used for ordering --help output. + + The returned group object has an ``addoption`` method with the same + signature as :py:func:`parser.addoption + <_pytest.config.argparsing.Parser.addoption>` but will be shown in the + respective group in the output of ``pytest. --help``. + """ + for group in self._groups: + if group.name == name: + return group + group = OptionGroup(name, description, parser=self) + i = 0 + for i, grp in enumerate(self._groups): + if grp.name == after: + break + self._groups.insert(i + 1, group) + return group + + def addoption(self, *opts: str, **attrs: Any) -> None: + """Register a command line option. + + :opts: Option names, can be short or long options. + :attrs: Same attributes which the ``add_argument()`` function of the + `argparse library `_ + accepts. + + After command line parsing, options are available on the pytest config + object via ``config.option.NAME`` where ``NAME`` is usually set + by passing a ``dest`` attribute, for example + ``addoption("--long", dest="NAME", ...)``. + """ + self._anonymous.addoption(*opts, **attrs) + + def parse( + self, + args: Sequence[Union[str, py.path.local]], + namespace: Optional[argparse.Namespace] = None, + ) -> argparse.Namespace: + from _pytest._argcomplete import try_argcomplete + + self.optparser = self._getparser() + try_argcomplete(self.optparser) + strargs = [str(x) if isinstance(x, py.path.local) else x for x in args] + return self.optparser.parse_args(strargs, namespace=namespace) + + def _getparser(self) -> "MyOptionParser": + from _pytest._argcomplete import filescompleter + + optparser = MyOptionParser(self, self.extra_info, prog=self.prog) + groups = self._groups + [self._anonymous] + for group in groups: + if group.options: + desc = group.description or group.name + arggroup = optparser.add_argument_group(desc) + for option in group.options: + n = option.names() + a = option.attrs() + arggroup.add_argument(*n, **a) + file_or_dir_arg = optparser.add_argument(FILE_OR_DIR, nargs="*") + # bash like autocompletion for dirs (appending '/') + # Type ignored because typeshed doesn't know about argcomplete. + file_or_dir_arg.completer = filescompleter # type: ignore + return optparser + + def parse_setoption( + self, + args: Sequence[Union[str, py.path.local]], + option: argparse.Namespace, + namespace: Optional[argparse.Namespace] = None, + ) -> List[str]: + parsedoption = self.parse(args, namespace=namespace) + for name, value in parsedoption.__dict__.items(): + setattr(option, name, value) + return cast(List[str], getattr(parsedoption, FILE_OR_DIR)) + + def parse_known_args( + self, + args: Sequence[Union[str, py.path.local]], + namespace: Optional[argparse.Namespace] = None, + ) -> argparse.Namespace: + """Parse and return a namespace object with known arguments at this point.""" + return self.parse_known_and_unknown_args(args, namespace=namespace)[0] + + def parse_known_and_unknown_args( + self, + args: Sequence[Union[str, py.path.local]], + namespace: Optional[argparse.Namespace] = None, + ) -> Tuple[argparse.Namespace, List[str]]: + """Parse and return a namespace object with known arguments, and + the remaining arguments unknown at this point.""" + optparser = self._getparser() + strargs = [str(x) if isinstance(x, py.path.local) else x for x in args] + return optparser.parse_known_args(strargs, namespace=namespace) + + def addini( + self, + name: str, + help: str, + type: Optional[ + "Literal['string', 'pathlist', 'args', 'linelist', 'bool']" + ] = None, + default=None, + ) -> None: + """Register an ini-file option. + + :name: Name of the ini-variable. + :type: Type of the variable, can be ``string``, ``pathlist``, ``args``, + ``linelist`` or ``bool``. Defaults to ``string`` if ``None`` or + not passed. + :default: Default value if no ini-file option exists but is queried. + + The value of ini-variables can be retrieved via a call to + :py:func:`config.getini(name) <_pytest.config.Config.getini>`. + """ + assert type in (None, "string", "pathlist", "args", "linelist", "bool") + self._inidict[name] = (help, type, default) + self._ininames.append(name) + + +class ArgumentError(Exception): + """Raised if an Argument instance is created with invalid or + inconsistent arguments.""" + + def __init__(self, msg: str, option: Union["Argument", str]) -> None: + self.msg = msg + self.option_id = str(option) + + def __str__(self) -> str: + if self.option_id: + return f"option {self.option_id}: {self.msg}" + else: + return self.msg + + +class Argument: + """Class that mimics the necessary behaviour of optparse.Option. + + It's currently a least effort implementation and ignoring choices + and integer prefixes. + + https://docs.python.org/3/library/optparse.html#optparse-standard-option-types + """ + + _typ_map = {"int": int, "string": str, "float": float, "complex": complex} + + def __init__(self, *names: str, **attrs: Any) -> None: + """Store parms in private vars for use in add_argument.""" + self._attrs = attrs + self._short_opts: List[str] = [] + self._long_opts: List[str] = [] + if "%default" in (attrs.get("help") or ""): + warnings.warn( + 'pytest now uses argparse. "%default" should be' + ' changed to "%(default)s" ', + DeprecationWarning, + stacklevel=3, + ) + try: + typ = attrs["type"] + except KeyError: + pass + else: + # This might raise a keyerror as well, don't want to catch that. + if isinstance(typ, str): + if typ == "choice": + warnings.warn( + "`type` argument to addoption() is the string %r." + " For choices this is optional and can be omitted, " + " but when supplied should be a type (for example `str` or `int`)." + " (options: %s)" % (typ, names), + DeprecationWarning, + stacklevel=4, + ) + # argparse expects a type here take it from + # the type of the first element + attrs["type"] = type(attrs["choices"][0]) + else: + warnings.warn( + "`type` argument to addoption() is the string %r, " + " but when supplied should be a type (for example `str` or `int`)." + " (options: %s)" % (typ, names), + DeprecationWarning, + stacklevel=4, + ) + attrs["type"] = Argument._typ_map[typ] + # Used in test_parseopt -> test_parse_defaultgetter. + self.type = attrs["type"] + else: + self.type = typ + try: + # Attribute existence is tested in Config._processopt. + self.default = attrs["default"] + except KeyError: + pass + self._set_opt_strings(names) + dest: Optional[str] = attrs.get("dest") + if dest: + self.dest = dest + elif self._long_opts: + self.dest = self._long_opts[0][2:].replace("-", "_") + else: + try: + self.dest = self._short_opts[0][1:] + except IndexError as e: + self.dest = "???" # Needed for the error repr. + raise ArgumentError("need a long or short option", self) from e + + def names(self) -> List[str]: + return self._short_opts + self._long_opts + + def attrs(self) -> Mapping[str, Any]: + # Update any attributes set by processopt. + attrs = "default dest help".split() + attrs.append(self.dest) + for attr in attrs: + try: + self._attrs[attr] = getattr(self, attr) + except AttributeError: + pass + if self._attrs.get("help"): + a = self._attrs["help"] + a = a.replace("%default", "%(default)s") + # a = a.replace('%prog', '%(prog)s') + self._attrs["help"] = a + return self._attrs + + def _set_opt_strings(self, opts: Sequence[str]) -> None: + """Directly from optparse. + + Might not be necessary as this is passed to argparse later on. + """ + for opt in opts: + if len(opt) < 2: + raise ArgumentError( + "invalid option string %r: " + "must be at least two characters long" % opt, + self, + ) + elif len(opt) == 2: + if not (opt[0] == "-" and opt[1] != "-"): + raise ArgumentError( + "invalid short option string %r: " + "must be of the form -x, (x any non-dash char)" % opt, + self, + ) + self._short_opts.append(opt) + else: + if not (opt[0:2] == "--" and opt[2] != "-"): + raise ArgumentError( + "invalid long option string %r: " + "must start with --, followed by non-dash" % opt, + self, + ) + self._long_opts.append(opt) + + def __repr__(self) -> str: + args: List[str] = [] + if self._short_opts: + args += ["_short_opts: " + repr(self._short_opts)] + if self._long_opts: + args += ["_long_opts: " + repr(self._long_opts)] + args += ["dest: " + repr(self.dest)] + if hasattr(self, "type"): + args += ["type: " + repr(self.type)] + if hasattr(self, "default"): + args += ["default: " + repr(self.default)] + return "Argument({})".format(", ".join(args)) + + +class OptionGroup: + def __init__( + self, name: str, description: str = "", parser: Optional[Parser] = None + ) -> None: + self.name = name + self.description = description + self.options: List[Argument] = [] + self.parser = parser + + def addoption(self, *optnames: str, **attrs: Any) -> None: + """Add an option to this group. + + If a shortened version of a long option is specified, it will + be suppressed in the help. addoption('--twowords', '--two-words') + results in help showing '--two-words' only, but --twowords gets + accepted **and** the automatic destination is in args.twowords. + """ + conflict = set(optnames).intersection( + name for opt in self.options for name in opt.names() + ) + if conflict: + raise ValueError("option names %s already added" % conflict) + option = Argument(*optnames, **attrs) + self._addoption_instance(option, shortupper=False) + + def _addoption(self, *optnames: str, **attrs: Any) -> None: + option = Argument(*optnames, **attrs) + self._addoption_instance(option, shortupper=True) + + def _addoption_instance(self, option: "Argument", shortupper: bool = False) -> None: + if not shortupper: + for opt in option._short_opts: + if opt[0] == "-" and opt[1].islower(): + raise ValueError("lowercase shortoptions reserved") + if self.parser: + self.parser.processoption(option) + self.options.append(option) + + +class MyOptionParser(argparse.ArgumentParser): + def __init__( + self, + parser: Parser, + extra_info: Optional[Dict[str, Any]] = None, + prog: Optional[str] = None, + ) -> None: + self._parser = parser + argparse.ArgumentParser.__init__( + self, + prog=prog, + usage=parser._usage, + add_help=False, + formatter_class=DropShorterLongHelpFormatter, + allow_abbrev=False, + ) + # extra_info is a dict of (param -> value) to display if there's + # an usage error to provide more contextual information to the user. + self.extra_info = extra_info if extra_info else {} + + def error(self, message: str) -> "NoReturn": + """Transform argparse error message into UsageError.""" + msg = f"{self.prog}: error: {message}" + + if hasattr(self._parser, "_config_source_hint"): + # Type ignored because the attribute is set dynamically. + msg = f"{msg} ({self._parser._config_source_hint})" # type: ignore + + raise UsageError(self.format_usage() + msg) + + # Type ignored because typeshed has a very complex type in the superclass. + def parse_args( # type: ignore + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[argparse.Namespace] = None, + ) -> argparse.Namespace: + """Allow splitting of positional arguments.""" + parsed, unrecognized = self.parse_known_args(args, namespace) + if unrecognized: + for arg in unrecognized: + if arg and arg[0] == "-": + lines = ["unrecognized arguments: %s" % (" ".join(unrecognized))] + for k, v in sorted(self.extra_info.items()): + lines.append(f" {k}: {v}") + self.error("\n".join(lines)) + getattr(parsed, FILE_OR_DIR).extend(unrecognized) + return parsed + + if sys.version_info[:2] < (3, 9): # pragma: no cover + # Backport of https://github.com/python/cpython/pull/14316 so we can + # disable long --argument abbreviations without breaking short flags. + def _parse_optional( + self, arg_string: str + ) -> Optional[Tuple[Optional[argparse.Action], str, Optional[str]]]: + if not arg_string: + return None + if not arg_string[0] in self.prefix_chars: + return None + if arg_string in self._option_string_actions: + action = self._option_string_actions[arg_string] + return action, arg_string, None + if len(arg_string) == 1: + return None + if "=" in arg_string: + option_string, explicit_arg = arg_string.split("=", 1) + if option_string in self._option_string_actions: + action = self._option_string_actions[option_string] + return action, option_string, explicit_arg + if self.allow_abbrev or not arg_string.startswith("--"): + option_tuples = self._get_option_tuples(arg_string) + if len(option_tuples) > 1: + msg = gettext( + "ambiguous option: %(option)s could match %(matches)s" + ) + options = ", ".join(option for _, option, _ in option_tuples) + self.error(msg % {"option": arg_string, "matches": options}) + elif len(option_tuples) == 1: + (option_tuple,) = option_tuples + return option_tuple + if self._negative_number_matcher.match(arg_string): + if not self._has_negative_number_optionals: + return None + if " " in arg_string: + return None + return None, arg_string, None + + +class DropShorterLongHelpFormatter(argparse.HelpFormatter): + """Shorten help for long options that differ only in extra hyphens. + + - Collapse **long** options that are the same except for extra hyphens. + - Shortcut if there are only two options and one of them is a short one. + - Cache result on the action object as this is called at least 2 times. + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + # Use more accurate terminal width. + if "width" not in kwargs: + kwargs["width"] = _pytest._io.get_terminal_width() + super().__init__(*args, **kwargs) + + def _format_action_invocation(self, action: argparse.Action) -> str: + orgstr = argparse.HelpFormatter._format_action_invocation(self, action) + if orgstr and orgstr[0] != "-": # only optional arguments + return orgstr + res: Optional[str] = getattr(action, "_formatted_action_invocation", None) + if res: + return res + options = orgstr.split(", ") + if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2): + # a shortcut for '-h, --help' or '--abc', '-a' + action._formatted_action_invocation = orgstr # type: ignore + return orgstr + return_list = [] + short_long: Dict[str, str] = {} + for option in options: + if len(option) == 2 or option[2] == " ": + continue + if not option.startswith("--"): + raise ArgumentError( + 'long optional argument without "--": [%s]' % (option), option + ) + xxoption = option[2:] + shortened = xxoption.replace("-", "") + if shortened not in short_long or len(short_long[shortened]) < len( + xxoption + ): + short_long[shortened] = xxoption + # now short_long has been filled out to the longest with dashes + # **and** we keep the right option ordering from add_argument + for option in options: + if len(option) == 2 or option[2] == " ": + return_list.append(option) + if option[2:] == short_long.get(option.replace("-", "")): + return_list.append(option.replace(" ", "=", 1)) + formatted_action_invocation = ", ".join(return_list) + action._formatted_action_invocation = formatted_action_invocation # type: ignore + return formatted_action_invocation + + def _split_lines(self, text, width): + """Wrap lines after splitting on original newlines. + + This allows to have explicit line breaks in the help text. + """ + import textwrap + + lines = [] + for line in text.splitlines(): + lines.extend(textwrap.wrap(line.strip(), width)) + return lines diff --git a/myenv/lib/python3.9/site-packages/_pytest/config/exceptions.py b/myenv/lib/python3.9/site-packages/_pytest/config/exceptions.py new file mode 100644 index 0000000..4f1320e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/config/exceptions.py @@ -0,0 +1,11 @@ +from _pytest.compat import final + + +@final +class UsageError(Exception): + """Error in pytest usage or invocation.""" + + +class PrintHelp(Exception): + """Raised when pytest should print its help to skip the rest of the + argument parsing and validation.""" diff --git a/myenv/lib/python3.9/site-packages/_pytest/config/findpaths.py b/myenv/lib/python3.9/site-packages/_pytest/config/findpaths.py new file mode 100644 index 0000000..2edf545 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/config/findpaths.py @@ -0,0 +1,211 @@ +import os +from pathlib import Path +from typing import Dict +from typing import Iterable +from typing import List +from typing import Optional +from typing import Sequence +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import iniconfig + +from .exceptions import UsageError +from _pytest.outcomes import fail +from _pytest.pathlib import absolutepath +from _pytest.pathlib import commonpath + +if TYPE_CHECKING: + from . import Config + + +def _parse_ini_config(path: Path) -> iniconfig.IniConfig: + """Parse the given generic '.ini' file using legacy IniConfig parser, returning + the parsed object. + + Raise UsageError if the file cannot be parsed. + """ + try: + return iniconfig.IniConfig(str(path)) + except iniconfig.ParseError as exc: + raise UsageError(str(exc)) from exc + + +def load_config_dict_from_file( + filepath: Path, +) -> Optional[Dict[str, Union[str, List[str]]]]: + """Load pytest configuration from the given file path, if supported. + + Return None if the file does not contain valid pytest configuration. + """ + + # Configuration from ini files are obtained from the [pytest] section, if present. + if filepath.suffix == ".ini": + iniconfig = _parse_ini_config(filepath) + + if "pytest" in iniconfig: + return dict(iniconfig["pytest"].items()) + else: + # "pytest.ini" files are always the source of configuration, even if empty. + if filepath.name == "pytest.ini": + return {} + + # '.cfg' files are considered if they contain a "[tool:pytest]" section. + elif filepath.suffix == ".cfg": + iniconfig = _parse_ini_config(filepath) + + if "tool:pytest" in iniconfig.sections: + return dict(iniconfig["tool:pytest"].items()) + elif "pytest" in iniconfig.sections: + # If a setup.cfg contains a "[pytest]" section, we raise a failure to indicate users that + # plain "[pytest]" sections in setup.cfg files is no longer supported (#3086). + fail(CFG_PYTEST_SECTION.format(filename="setup.cfg"), pytrace=False) + + # '.toml' files are considered if they contain a [tool.pytest.ini_options] table. + elif filepath.suffix == ".toml": + import toml + + config = toml.load(str(filepath)) + + result = config.get("tool", {}).get("pytest", {}).get("ini_options", None) + if result is not None: + # TOML supports richer data types than ini files (strings, arrays, floats, ints, etc), + # however we need to convert all scalar values to str for compatibility with the rest + # of the configuration system, which expects strings only. + def make_scalar(v: object) -> Union[str, List[str]]: + return v if isinstance(v, list) else str(v) + + return {k: make_scalar(v) for k, v in result.items()} + + return None + + +def locate_config( + args: Iterable[Path], +) -> Tuple[ + Optional[Path], Optional[Path], Dict[str, Union[str, List[str]]], +]: + """Search in the list of arguments for a valid ini-file for pytest, + and return a tuple of (rootdir, inifile, cfg-dict).""" + config_names = [ + "pytest.ini", + "pyproject.toml", + "tox.ini", + "setup.cfg", + ] + args = [x for x in args if not str(x).startswith("-")] + if not args: + args = [Path.cwd()] + for arg in args: + argpath = absolutepath(arg) + for base in (argpath, *argpath.parents): + for config_name in config_names: + p = base / config_name + if p.is_file(): + ini_config = load_config_dict_from_file(p) + if ini_config is not None: + return base, p, ini_config + return None, None, {} + + +def get_common_ancestor(paths: Iterable[Path]) -> Path: + common_ancestor: Optional[Path] = None + for path in paths: + if not path.exists(): + continue + if common_ancestor is None: + common_ancestor = path + else: + if common_ancestor in path.parents or path == common_ancestor: + continue + elif path in common_ancestor.parents: + common_ancestor = path + else: + shared = commonpath(path, common_ancestor) + if shared is not None: + common_ancestor = shared + if common_ancestor is None: + common_ancestor = Path.cwd() + elif common_ancestor.is_file(): + common_ancestor = common_ancestor.parent + return common_ancestor + + +def get_dirs_from_args(args: Iterable[str]) -> List[Path]: + def is_option(x: str) -> bool: + return x.startswith("-") + + def get_file_part_from_node_id(x: str) -> str: + return x.split("::")[0] + + def get_dir_from_path(path: Path) -> Path: + if path.is_dir(): + return path + return path.parent + + def safe_exists(path: Path) -> bool: + # This can throw on paths that contain characters unrepresentable at the OS level, + # or with invalid syntax on Windows (https://bugs.python.org/issue35306) + try: + return path.exists() + except OSError: + return False + + # These look like paths but may not exist + possible_paths = ( + absolutepath(get_file_part_from_node_id(arg)) + for arg in args + if not is_option(arg) + ) + + return [get_dir_from_path(path) for path in possible_paths if safe_exists(path)] + + +CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supported, change to [tool:pytest] instead." + + +def determine_setup( + inifile: Optional[str], + args: Sequence[str], + rootdir_cmd_arg: Optional[str] = None, + config: Optional["Config"] = None, +) -> Tuple[Path, Optional[Path], Dict[str, Union[str, List[str]]]]: + rootdir = None + dirs = get_dirs_from_args(args) + if inifile: + inipath_ = absolutepath(inifile) + inipath: Optional[Path] = inipath_ + inicfg = load_config_dict_from_file(inipath_) or {} + if rootdir_cmd_arg is None: + rootdir = get_common_ancestor(dirs) + else: + ancestor = get_common_ancestor(dirs) + rootdir, inipath, inicfg = locate_config([ancestor]) + if rootdir is None and rootdir_cmd_arg is None: + for possible_rootdir in (ancestor, *ancestor.parents): + if (possible_rootdir / "setup.py").is_file(): + rootdir = possible_rootdir + break + else: + if dirs != [ancestor]: + rootdir, inipath, inicfg = locate_config(dirs) + if rootdir is None: + if config is not None: + cwd = config.invocation_params.dir + else: + cwd = Path.cwd() + rootdir = get_common_ancestor([cwd, ancestor]) + is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/" + if is_fs_root: + rootdir = ancestor + if rootdir_cmd_arg: + rootdir = absolutepath(os.path.expandvars(rootdir_cmd_arg)) + if not rootdir.is_dir(): + raise UsageError( + "Directory '{}' not found. Check your '--rootdir' option.".format( + rootdir + ) + ) + assert rootdir is not None + return rootdir, inipath, inicfg or {} diff --git a/myenv/lib/python3.9/site-packages/_pytest/debugging.py b/myenv/lib/python3.9/site-packages/_pytest/debugging.py new file mode 100644 index 0000000..d3a5c61 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/debugging.py @@ -0,0 +1,388 @@ +"""Interactive debugging with PDB, the Python Debugger.""" +import argparse +import functools +import sys +import types +from typing import Any +from typing import Callable +from typing import Generator +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +from _pytest import outcomes +from _pytest._code import ExceptionInfo +from _pytest.config import Config +from _pytest.config import ConftestImportFailure +from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager +from _pytest.config.argparsing import Parser +from _pytest.config.exceptions import UsageError +from _pytest.nodes import Node +from _pytest.reports import BaseReport + +if TYPE_CHECKING: + from _pytest.capture import CaptureManager + from _pytest.runner import CallInfo + + +def _validate_usepdb_cls(value: str) -> Tuple[str, str]: + """Validate syntax of --pdbcls option.""" + try: + modname, classname = value.split(":") + except ValueError as e: + raise argparse.ArgumentTypeError( + f"{value!r} is not in the format 'modname:classname'" + ) from e + return (modname, classname) + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group._addoption( + "--pdb", + dest="usepdb", + action="store_true", + help="start the interactive Python debugger on errors or KeyboardInterrupt.", + ) + group._addoption( + "--pdbcls", + dest="usepdb_cls", + metavar="modulename:classname", + type=_validate_usepdb_cls, + help="start a custom interactive Python debugger on errors. " + "For example: --pdbcls=IPython.terminal.debugger:TerminalPdb", + ) + group._addoption( + "--trace", + dest="trace", + action="store_true", + help="Immediately break when running each test.", + ) + + +def pytest_configure(config: Config) -> None: + import pdb + + if config.getvalue("trace"): + config.pluginmanager.register(PdbTrace(), "pdbtrace") + if config.getvalue("usepdb"): + config.pluginmanager.register(PdbInvoke(), "pdbinvoke") + + pytestPDB._saved.append( + (pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config) + ) + pdb.set_trace = pytestPDB.set_trace + pytestPDB._pluginmanager = config.pluginmanager + pytestPDB._config = config + + # NOTE: not using pytest_unconfigure, since it might get called although + # pytest_configure was not (if another plugin raises UsageError). + def fin() -> None: + ( + pdb.set_trace, + pytestPDB._pluginmanager, + pytestPDB._config, + ) = pytestPDB._saved.pop() + + config._cleanup.append(fin) + + +class pytestPDB: + """Pseudo PDB that defers to the real pdb.""" + + _pluginmanager: Optional[PytestPluginManager] = None + _config: Optional[Config] = None + _saved: List[ + Tuple[Callable[..., None], Optional[PytestPluginManager], Optional[Config]] + ] = [] + _recursive_debug = 0 + _wrapped_pdb_cls: Optional[Tuple[Type[Any], Type[Any]]] = None + + @classmethod + def _is_capturing(cls, capman: Optional["CaptureManager"]) -> Union[str, bool]: + if capman: + return capman.is_capturing() + return False + + @classmethod + def _import_pdb_cls(cls, capman: Optional["CaptureManager"]): + if not cls._config: + import pdb + + # Happens when using pytest.set_trace outside of a test. + return pdb.Pdb + + usepdb_cls = cls._config.getvalue("usepdb_cls") + + if cls._wrapped_pdb_cls and cls._wrapped_pdb_cls[0] == usepdb_cls: + return cls._wrapped_pdb_cls[1] + + if usepdb_cls: + modname, classname = usepdb_cls + + try: + __import__(modname) + mod = sys.modules[modname] + + # Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp). + parts = classname.split(".") + pdb_cls = getattr(mod, parts[0]) + for part in parts[1:]: + pdb_cls = getattr(pdb_cls, part) + except Exception as exc: + value = ":".join((modname, classname)) + raise UsageError( + f"--pdbcls: could not import {value!r}: {exc}" + ) from exc + else: + import pdb + + pdb_cls = pdb.Pdb + + wrapped_cls = cls._get_pdb_wrapper_class(pdb_cls, capman) + cls._wrapped_pdb_cls = (usepdb_cls, wrapped_cls) + return wrapped_cls + + @classmethod + def _get_pdb_wrapper_class(cls, pdb_cls, capman: Optional["CaptureManager"]): + import _pytest.config + + # Type ignored because mypy doesn't support "dynamic" + # inheritance like this. + class PytestPdbWrapper(pdb_cls): # type: ignore[valid-type,misc] + _pytest_capman = capman + _continued = False + + def do_debug(self, arg): + cls._recursive_debug += 1 + ret = super().do_debug(arg) + cls._recursive_debug -= 1 + return ret + + def do_continue(self, arg): + ret = super().do_continue(arg) + if cls._recursive_debug == 0: + assert cls._config is not None + tw = _pytest.config.create_terminal_writer(cls._config) + tw.line() + + capman = self._pytest_capman + capturing = pytestPDB._is_capturing(capman) + if capturing: + if capturing == "global": + tw.sep(">", "PDB continue (IO-capturing resumed)") + else: + tw.sep( + ">", + "PDB continue (IO-capturing resumed for %s)" + % capturing, + ) + assert capman is not None + capman.resume() + else: + tw.sep(">", "PDB continue") + assert cls._pluginmanager is not None + cls._pluginmanager.hook.pytest_leave_pdb(config=cls._config, pdb=self) + self._continued = True + return ret + + do_c = do_cont = do_continue + + def do_quit(self, arg): + """Raise Exit outcome when quit command is used in pdb. + + This is a bit of a hack - it would be better if BdbQuit + could be handled, but this would require to wrap the + whole pytest run, and adjust the report etc. + """ + ret = super().do_quit(arg) + + if cls._recursive_debug == 0: + outcomes.exit("Quitting debugger") + + return ret + + do_q = do_quit + do_exit = do_quit + + def setup(self, f, tb): + """Suspend on setup(). + + Needed after do_continue resumed, and entering another + breakpoint again. + """ + ret = super().setup(f, tb) + if not ret and self._continued: + # pdb.setup() returns True if the command wants to exit + # from the interaction: do not suspend capturing then. + if self._pytest_capman: + self._pytest_capman.suspend_global_capture(in_=True) + return ret + + def get_stack(self, f, t): + stack, i = super().get_stack(f, t) + if f is None: + # Find last non-hidden frame. + i = max(0, len(stack) - 1) + while i and stack[i][0].f_locals.get("__tracebackhide__", False): + i -= 1 + return stack, i + + return PytestPdbWrapper + + @classmethod + def _init_pdb(cls, method, *args, **kwargs): + """Initialize PDB debugging, dropping any IO capturing.""" + import _pytest.config + + if cls._pluginmanager is None: + capman: Optional[CaptureManager] = None + else: + capman = cls._pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend(in_=True) + + if cls._config: + tw = _pytest.config.create_terminal_writer(cls._config) + tw.line() + + if cls._recursive_debug == 0: + # Handle header similar to pdb.set_trace in py37+. + header = kwargs.pop("header", None) + if header is not None: + tw.sep(">", header) + else: + capturing = cls._is_capturing(capman) + if capturing == "global": + tw.sep(">", f"PDB {method} (IO-capturing turned off)") + elif capturing: + tw.sep( + ">", + "PDB %s (IO-capturing turned off for %s)" + % (method, capturing), + ) + else: + tw.sep(">", f"PDB {method}") + + _pdb = cls._import_pdb_cls(capman)(**kwargs) + + if cls._pluginmanager: + cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config, pdb=_pdb) + return _pdb + + @classmethod + def set_trace(cls, *args, **kwargs) -> None: + """Invoke debugging via ``Pdb.set_trace``, dropping any IO capturing.""" + frame = sys._getframe().f_back + _pdb = cls._init_pdb("set_trace", *args, **kwargs) + _pdb.set_trace(frame) + + +class PdbInvoke: + def pytest_exception_interact( + self, node: Node, call: "CallInfo[Any]", report: BaseReport + ) -> None: + capman = node.config.pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend_global_capture(in_=True) + out, err = capman.read_global_capture() + sys.stdout.write(out) + sys.stdout.write(err) + assert call.excinfo is not None + _enter_pdb(node, call.excinfo, report) + + def pytest_internalerror(self, excinfo: ExceptionInfo[BaseException]) -> None: + tb = _postmortem_traceback(excinfo) + post_mortem(tb) + + +class PdbTrace: + @hookimpl(hookwrapper=True) + def pytest_pyfunc_call(self, pyfuncitem) -> Generator[None, None, None]: + wrap_pytest_function_for_tracing(pyfuncitem) + yield + + +def wrap_pytest_function_for_tracing(pyfuncitem): + """Change the Python function object of the given Function item by a + wrapper which actually enters pdb before calling the python function + itself, effectively leaving the user in the pdb prompt in the first + statement of the function.""" + _pdb = pytestPDB._init_pdb("runcall") + testfunction = pyfuncitem.obj + + # we can't just return `partial(pdb.runcall, testfunction)` because (on + # python < 3.7.4) runcall's first param is `func`, which means we'd get + # an exception if one of the kwargs to testfunction was called `func`. + @functools.wraps(testfunction) + def wrapper(*args, **kwargs): + func = functools.partial(testfunction, *args, **kwargs) + _pdb.runcall(func) + + pyfuncitem.obj = wrapper + + +def maybe_wrap_pytest_function_for_tracing(pyfuncitem): + """Wrap the given pytestfunct item for tracing support if --trace was given in + the command line.""" + if pyfuncitem.config.getvalue("trace"): + wrap_pytest_function_for_tracing(pyfuncitem) + + +def _enter_pdb( + node: Node, excinfo: ExceptionInfo[BaseException], rep: BaseReport +) -> BaseReport: + # XXX we re-use the TerminalReporter's terminalwriter + # because this seems to avoid some encoding related troubles + # for not completely clear reasons. + tw = node.config.pluginmanager.getplugin("terminalreporter")._tw + tw.line() + + showcapture = node.config.option.showcapture + + for sectionname, content in ( + ("stdout", rep.capstdout), + ("stderr", rep.capstderr), + ("log", rep.caplog), + ): + if showcapture in (sectionname, "all") and content: + tw.sep(">", "captured " + sectionname) + if content[-1:] == "\n": + content = content[:-1] + tw.line(content) + + tw.sep(">", "traceback") + rep.toterminal(tw) + tw.sep(">", "entering PDB") + tb = _postmortem_traceback(excinfo) + rep._pdbshown = True # type: ignore[attr-defined] + post_mortem(tb) + return rep + + +def _postmortem_traceback(excinfo: ExceptionInfo[BaseException]) -> types.TracebackType: + from doctest import UnexpectedException + + if isinstance(excinfo.value, UnexpectedException): + # A doctest.UnexpectedException is not useful for post_mortem. + # Use the underlying exception instead: + return excinfo.value.exc_info[2] + elif isinstance(excinfo.value, ConftestImportFailure): + # A config.ConftestImportFailure is not useful for post_mortem. + # Use the underlying exception instead: + return excinfo.value.excinfo[2] + else: + assert excinfo._excinfo is not None + return excinfo._excinfo[2] + + +def post_mortem(t: types.TracebackType) -> None: + p = pytestPDB._init_pdb("post_mortem") + p.reset() + p.interaction(None, t) + if p.quitting: + outcomes.exit("Quitting debugger") diff --git a/myenv/lib/python3.9/site-packages/_pytest/deprecated.py b/myenv/lib/python3.9/site-packages/_pytest/deprecated.py new file mode 100644 index 0000000..19b31d6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/deprecated.py @@ -0,0 +1,87 @@ +"""Deprecation messages and bits of code used elsewhere in the codebase that +is planned to be removed in the next pytest release. + +Keeping it in a central location makes it easy to track what is deprecated and should +be removed when the time comes. + +All constants defined in this module should be either instances of +:class:`PytestWarning`, or :class:`UnformattedWarning` +in case of warnings which need to format their messages. +""" +from warnings import warn + +from _pytest.warning_types import PytestDeprecationWarning +from _pytest.warning_types import UnformattedWarning + +# set of plugins which have been integrated into the core; we use this list to ignore +# them during registration to avoid conflicts +DEPRECATED_EXTERNAL_PLUGINS = { + "pytest_catchlog", + "pytest_capturelog", + "pytest_faulthandler", +} + + +FILLFUNCARGS = UnformattedWarning( + PytestDeprecationWarning, + "{name} is deprecated, use " + "function._request._fillfixtures() instead if you cannot avoid reaching into internals.", +) + +PYTEST_COLLECT_MODULE = UnformattedWarning( + PytestDeprecationWarning, + "pytest.collect.{name} was moved to pytest.{name}\n" + "Please update to the new name.", +) + +YIELD_FIXTURE = PytestDeprecationWarning( + "@pytest.yield_fixture is deprecated.\n" + "Use @pytest.fixture instead; they are the same." +) + +MINUS_K_DASH = PytestDeprecationWarning( + "The `-k '-expr'` syntax to -k is deprecated.\nUse `-k 'not expr'` instead." +) + +MINUS_K_COLON = PytestDeprecationWarning( + "The `-k 'expr:'` syntax to -k is deprecated.\n" + "Please open an issue if you use this and want a replacement." +) + +WARNING_CAPTURED_HOOK = PytestDeprecationWarning( + "The pytest_warning_captured is deprecated and will be removed in a future release.\n" + "Please use pytest_warning_recorded instead." +) + +FSCOLLECTOR_GETHOOKPROXY_ISINITPATH = PytestDeprecationWarning( + "The gethookproxy() and isinitpath() methods of FSCollector and Package are deprecated; " + "use self.session.gethookproxy() and self.session.isinitpath() instead. " +) + +STRICT_OPTION = PytestDeprecationWarning( + "The --strict option is deprecated, use --strict-markers instead." +) + +PRIVATE = PytestDeprecationWarning("A private pytest class or function was used.") + + +# You want to make some `__init__` or function "private". +# +# def my_private_function(some, args): +# ... +# +# Do this: +# +# def my_private_function(some, args, *, _ispytest: bool = False): +# check_ispytest(_ispytest) +# ... +# +# Change all internal/allowed calls to +# +# my_private_function(some, args, _ispytest=True) +# +# All other calls will get the default _ispytest=False and trigger +# the warning (possibly error in the future). +def check_ispytest(ispytest: bool) -> None: + if not ispytest: + warn(PRIVATE, stacklevel=3) diff --git a/myenv/lib/python3.9/site-packages/_pytest/doctest.py b/myenv/lib/python3.9/site-packages/_pytest/doctest.py new file mode 100644 index 0000000..64e8f0e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/doctest.py @@ -0,0 +1,724 @@ +"""Discover and run doctests in modules and test files.""" +import bdb +import inspect +import platform +import sys +import traceback +import types +import warnings +from contextlib import contextmanager +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generator +from typing import Iterable +from typing import List +from typing import Optional +from typing import Pattern +from typing import Sequence +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +import py.path + +import pytest +from _pytest import outcomes +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import ReprFileLocation +from _pytest._code.code import TerminalRepr +from _pytest._io import TerminalWriter +from _pytest.compat import safe_getattr +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureRequest +from _pytest.nodes import Collector +from _pytest.outcomes import OutcomeException +from _pytest.pathlib import import_path +from _pytest.python_api import approx +from _pytest.warning_types import PytestWarning + +if TYPE_CHECKING: + import doctest + +DOCTEST_REPORT_CHOICE_NONE = "none" +DOCTEST_REPORT_CHOICE_CDIFF = "cdiff" +DOCTEST_REPORT_CHOICE_NDIFF = "ndiff" +DOCTEST_REPORT_CHOICE_UDIFF = "udiff" +DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = "only_first_failure" + +DOCTEST_REPORT_CHOICES = ( + DOCTEST_REPORT_CHOICE_NONE, + DOCTEST_REPORT_CHOICE_CDIFF, + DOCTEST_REPORT_CHOICE_NDIFF, + DOCTEST_REPORT_CHOICE_UDIFF, + DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE, +) + +# Lazy definition of runner class +RUNNER_CLASS = None +# Lazy definition of output checker class +CHECKER_CLASS: Optional[Type["doctest.OutputChecker"]] = None + + +def pytest_addoption(parser: Parser) -> None: + parser.addini( + "doctest_optionflags", + "option flags for doctests", + type="args", + default=["ELLIPSIS"], + ) + parser.addini( + "doctest_encoding", "encoding used for doctest files", default="utf-8" + ) + group = parser.getgroup("collect") + group.addoption( + "--doctest-modules", + action="store_true", + default=False, + help="run doctests in all .py modules", + dest="doctestmodules", + ) + group.addoption( + "--doctest-report", + type=str.lower, + default="udiff", + help="choose another output format for diffs on doctest failure", + choices=DOCTEST_REPORT_CHOICES, + dest="doctestreport", + ) + group.addoption( + "--doctest-glob", + action="append", + default=[], + metavar="pat", + help="doctests file matching pattern, default: test*.txt", + dest="doctestglob", + ) + group.addoption( + "--doctest-ignore-import-errors", + action="store_true", + default=False, + help="ignore doctest ImportErrors", + dest="doctest_ignore_import_errors", + ) + group.addoption( + "--doctest-continue-on-failure", + action="store_true", + default=False, + help="for a given doctest, continue to run after the first failure", + dest="doctest_continue_on_failure", + ) + + +def pytest_unconfigure() -> None: + global RUNNER_CLASS + + RUNNER_CLASS = None + + +def pytest_collect_file( + path: py.path.local, parent: Collector, +) -> Optional[Union["DoctestModule", "DoctestTextfile"]]: + config = parent.config + if path.ext == ".py": + if config.option.doctestmodules and not _is_setup_py(path): + mod: DoctestModule = DoctestModule.from_parent(parent, fspath=path) + return mod + elif _is_doctest(config, path, parent): + txt: DoctestTextfile = DoctestTextfile.from_parent(parent, fspath=path) + return txt + return None + + +def _is_setup_py(path: py.path.local) -> bool: + if path.basename != "setup.py": + return False + contents = path.read_binary() + return b"setuptools" in contents or b"distutils" in contents + + +def _is_doctest(config: Config, path: py.path.local, parent) -> bool: + if path.ext in (".txt", ".rst") and parent.session.isinitpath(path): + return True + globs = config.getoption("doctestglob") or ["test*.txt"] + for glob in globs: + if path.check(fnmatch=glob): + return True + return False + + +class ReprFailDoctest(TerminalRepr): + def __init__( + self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]] + ) -> None: + self.reprlocation_lines = reprlocation_lines + + def toterminal(self, tw: TerminalWriter) -> None: + for reprlocation, lines in self.reprlocation_lines: + for line in lines: + tw.line(line) + reprlocation.toterminal(tw) + + +class MultipleDoctestFailures(Exception): + def __init__(self, failures: Sequence["doctest.DocTestFailure"]) -> None: + super().__init__() + self.failures = failures + + +def _init_runner_class() -> Type["doctest.DocTestRunner"]: + import doctest + + class PytestDoctestRunner(doctest.DebugRunner): + """Runner to collect failures. + + Note that the out variable in this case is a list instead of a + stdout-like object. + """ + + def __init__( + self, + checker: Optional["doctest.OutputChecker"] = None, + verbose: Optional[bool] = None, + optionflags: int = 0, + continue_on_failure: bool = True, + ) -> None: + doctest.DebugRunner.__init__( + self, checker=checker, verbose=verbose, optionflags=optionflags + ) + self.continue_on_failure = continue_on_failure + + def report_failure( + self, out, test: "doctest.DocTest", example: "doctest.Example", got: str, + ) -> None: + failure = doctest.DocTestFailure(test, example, got) + if self.continue_on_failure: + out.append(failure) + else: + raise failure + + def report_unexpected_exception( + self, + out, + test: "doctest.DocTest", + example: "doctest.Example", + exc_info: Tuple[Type[BaseException], BaseException, types.TracebackType], + ) -> None: + if isinstance(exc_info[1], OutcomeException): + raise exc_info[1] + if isinstance(exc_info[1], bdb.BdbQuit): + outcomes.exit("Quitting debugger") + failure = doctest.UnexpectedException(test, example, exc_info) + if self.continue_on_failure: + out.append(failure) + else: + raise failure + + return PytestDoctestRunner + + +def _get_runner( + checker: Optional["doctest.OutputChecker"] = None, + verbose: Optional[bool] = None, + optionflags: int = 0, + continue_on_failure: bool = True, +) -> "doctest.DocTestRunner": + # We need this in order to do a lazy import on doctest + global RUNNER_CLASS + if RUNNER_CLASS is None: + RUNNER_CLASS = _init_runner_class() + # Type ignored because the continue_on_failure argument is only defined on + # PytestDoctestRunner, which is lazily defined so can't be used as a type. + return RUNNER_CLASS( # type: ignore + checker=checker, + verbose=verbose, + optionflags=optionflags, + continue_on_failure=continue_on_failure, + ) + + +class DoctestItem(pytest.Item): + def __init__( + self, + name: str, + parent: "Union[DoctestTextfile, DoctestModule]", + runner: Optional["doctest.DocTestRunner"] = None, + dtest: Optional["doctest.DocTest"] = None, + ) -> None: + super().__init__(name, parent) + self.runner = runner + self.dtest = dtest + self.obj = None + self.fixture_request: Optional[FixtureRequest] = None + + @classmethod + def from_parent( # type: ignore + cls, + parent: "Union[DoctestTextfile, DoctestModule]", + *, + name: str, + runner: "doctest.DocTestRunner", + dtest: "doctest.DocTest", + ): + # incompatible signature due to to imposed limits on sublcass + """The public named constructor.""" + return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest) + + def setup(self) -> None: + if self.dtest is not None: + self.fixture_request = _setup_fixtures(self) + globs = dict(getfixture=self.fixture_request.getfixturevalue) + for name, value in self.fixture_request.getfixturevalue( + "doctest_namespace" + ).items(): + globs[name] = value + self.dtest.globs.update(globs) + + def runtest(self) -> None: + assert self.dtest is not None + assert self.runner is not None + _check_all_skipped(self.dtest) + self._disable_output_capturing_for_darwin() + failures: List["doctest.DocTestFailure"] = [] + # Type ignored because we change the type of `out` from what + # doctest expects. + self.runner.run(self.dtest, out=failures) # type: ignore[arg-type] + if failures: + raise MultipleDoctestFailures(failures) + + def _disable_output_capturing_for_darwin(self) -> None: + """Disable output capturing. Otherwise, stdout is lost to doctest (#985).""" + if platform.system() != "Darwin": + return + capman = self.config.pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend_global_capture(in_=True) + out, err = capman.read_global_capture() + sys.stdout.write(out) + sys.stderr.write(err) + + # TODO: Type ignored -- breaks Liskov Substitution. + def repr_failure( # type: ignore[override] + self, excinfo: ExceptionInfo[BaseException], + ) -> Union[str, TerminalRepr]: + import doctest + + failures: Optional[ + Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]] + ] = (None) + if isinstance( + excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException) + ): + failures = [excinfo.value] + elif isinstance(excinfo.value, MultipleDoctestFailures): + failures = excinfo.value.failures + + if failures is not None: + reprlocation_lines = [] + for failure in failures: + example = failure.example + test = failure.test + filename = test.filename + if test.lineno is None: + lineno = None + else: + lineno = test.lineno + example.lineno + 1 + message = type(failure).__name__ + # TODO: ReprFileLocation doesn't expect a None lineno. + reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type] + checker = _get_checker() + report_choice = _get_report_choice( + self.config.getoption("doctestreport") + ) + if lineno is not None: + assert failure.test.docstring is not None + lines = failure.test.docstring.splitlines(False) + # add line numbers to the left of the error message + assert test.lineno is not None + lines = [ + "%03d %s" % (i + test.lineno + 1, x) + for (i, x) in enumerate(lines) + ] + # trim docstring error lines to 10 + lines = lines[max(example.lineno - 9, 0) : example.lineno + 1] + else: + lines = [ + "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example" + ] + indent = ">>>" + for line in example.source.splitlines(): + lines.append(f"??? {indent} {line}") + indent = "..." + if isinstance(failure, doctest.DocTestFailure): + lines += checker.output_difference( + example, failure.got, report_choice + ).split("\n") + else: + inner_excinfo = ExceptionInfo(failure.exc_info) + lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] + lines += [ + x.strip("\n") + for x in traceback.format_exception(*failure.exc_info) + ] + reprlocation_lines.append((reprlocation, lines)) + return ReprFailDoctest(reprlocation_lines) + else: + return super().repr_failure(excinfo) + + def reportinfo(self): + assert self.dtest is not None + return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name + + +def _get_flag_lookup() -> Dict[str, int]: + import doctest + + return dict( + DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1, + DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE, + NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE, + ELLIPSIS=doctest.ELLIPSIS, + IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL, + COMPARISON_FLAGS=doctest.COMPARISON_FLAGS, + ALLOW_UNICODE=_get_allow_unicode_flag(), + ALLOW_BYTES=_get_allow_bytes_flag(), + NUMBER=_get_number_flag(), + ) + + +def get_optionflags(parent): + optionflags_str = parent.config.getini("doctest_optionflags") + flag_lookup_table = _get_flag_lookup() + flag_acc = 0 + for flag in optionflags_str: + flag_acc |= flag_lookup_table[flag] + return flag_acc + + +def _get_continue_on_failure(config): + continue_on_failure = config.getvalue("doctest_continue_on_failure") + if continue_on_failure: + # We need to turn off this if we use pdb since we should stop at + # the first failure. + if config.getvalue("usepdb"): + continue_on_failure = False + return continue_on_failure + + +class DoctestTextfile(pytest.Module): + obj = None + + def collect(self) -> Iterable[DoctestItem]: + import doctest + + # Inspired by doctest.testfile; ideally we would use it directly, + # but it doesn't support passing a custom checker. + encoding = self.config.getini("doctest_encoding") + text = self.fspath.read_text(encoding) + filename = str(self.fspath) + name = self.fspath.basename + globs = {"__name__": "__main__"} + + optionflags = get_optionflags(self) + + runner = _get_runner( + verbose=False, + optionflags=optionflags, + checker=_get_checker(), + continue_on_failure=_get_continue_on_failure(self.config), + ) + + parser = doctest.DocTestParser() + test = parser.get_doctest(text, globs, name, filename, 0) + if test.examples: + yield DoctestItem.from_parent( + self, name=test.name, runner=runner, dtest=test + ) + + +def _check_all_skipped(test: "doctest.DocTest") -> None: + """Raise pytest.skip() if all examples in the given DocTest have the SKIP + option set.""" + import doctest + + all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples) + if all_skipped: + pytest.skip("all tests skipped by +SKIP option") + + +def _is_mocked(obj: object) -> bool: + """Return if an object is possibly a mock object by checking the + existence of a highly improbable attribute.""" + return ( + safe_getattr(obj, "pytest_mock_example_attribute_that_shouldnt_exist", None) + is not None + ) + + +@contextmanager +def _patch_unwrap_mock_aware() -> Generator[None, None, None]: + """Context manager which replaces ``inspect.unwrap`` with a version + that's aware of mock objects and doesn't recurse into them.""" + real_unwrap = inspect.unwrap + + def _mock_aware_unwrap( + func: Callable[..., Any], *, stop: Optional[Callable[[Any], Any]] = None + ) -> Any: + try: + if stop is None or stop is _is_mocked: + return real_unwrap(func, stop=_is_mocked) + _stop = stop + return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func)) + except Exception as e: + warnings.warn( + "Got %r when unwrapping %r. This is usually caused " + "by a violation of Python's object protocol; see e.g. " + "https://github.com/pytest-dev/pytest/issues/5080" % (e, func), + PytestWarning, + ) + raise + + inspect.unwrap = _mock_aware_unwrap + try: + yield + finally: + inspect.unwrap = real_unwrap + + +class DoctestModule(pytest.Module): + def collect(self) -> Iterable[DoctestItem]: + import doctest + + class MockAwareDocTestFinder(doctest.DocTestFinder): + """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug. + + https://github.com/pytest-dev/pytest/issues/3456 + https://bugs.python.org/issue25532 + """ + + def _find_lineno(self, obj, source_lines): + """Doctest code does not take into account `@property`, this + is a hackish way to fix it. + + https://bugs.python.org/issue17446 + """ + if isinstance(obj, property): + obj = getattr(obj, "fget", obj) + # Type ignored because this is a private function. + return doctest.DocTestFinder._find_lineno( # type: ignore + self, obj, source_lines, + ) + + def _find( + self, tests, obj, name, module, source_lines, globs, seen + ) -> None: + if _is_mocked(obj): + return + with _patch_unwrap_mock_aware(): + + # Type ignored because this is a private function. + doctest.DocTestFinder._find( # type: ignore + self, tests, obj, name, module, source_lines, globs, seen + ) + + if self.fspath.basename == "conftest.py": + module = self.config.pluginmanager._importconftest( + self.fspath, self.config.getoption("importmode") + ) + else: + try: + module = import_path(self.fspath) + except ImportError: + if self.config.getvalue("doctest_ignore_import_errors"): + pytest.skip("unable to import module %r" % self.fspath) + else: + raise + # Uses internal doctest module parsing mechanism. + finder = MockAwareDocTestFinder() + optionflags = get_optionflags(self) + runner = _get_runner( + verbose=False, + optionflags=optionflags, + checker=_get_checker(), + continue_on_failure=_get_continue_on_failure(self.config), + ) + + for test in finder.find(module, module.__name__): + if test.examples: # skip empty doctests + yield DoctestItem.from_parent( + self, name=test.name, runner=runner, dtest=test + ) + + +def _setup_fixtures(doctest_item: DoctestItem) -> FixtureRequest: + """Used by DoctestTextfile and DoctestItem to setup fixture information.""" + + def func() -> None: + pass + + doctest_item.funcargs = {} # type: ignore[attr-defined] + fm = doctest_item.session._fixturemanager + doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined] + node=doctest_item, func=func, cls=None, funcargs=False + ) + fixture_request = FixtureRequest(doctest_item, _ispytest=True) + fixture_request._fillfixtures() + return fixture_request + + +def _init_checker_class() -> Type["doctest.OutputChecker"]: + import doctest + import re + + class LiteralsOutputChecker(doctest.OutputChecker): + # Based on doctest_nose_plugin.py from the nltk project + # (https://github.com/nltk/nltk) and on the "numtest" doctest extension + # by Sebastien Boisgerault (https://github.com/boisgera/numtest). + + _unicode_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE) + _bytes_literal_re = re.compile(r"(\W|^)[bB]([rR]?[\'\"])", re.UNICODE) + _number_re = re.compile( + r""" + (?P + (?P + (?P [+-]?\d*)\.(?P\d+) + | + (?P [+-]?\d+)\. + ) + (?: + [Ee] + (?P [+-]?\d+) + )? + | + (?P [+-]?\d+) + (?: + [Ee] + (?P [+-]?\d+) + ) + ) + """, + re.VERBOSE, + ) + + def check_output(self, want: str, got: str, optionflags: int) -> bool: + if doctest.OutputChecker.check_output(self, want, got, optionflags): + return True + + allow_unicode = optionflags & _get_allow_unicode_flag() + allow_bytes = optionflags & _get_allow_bytes_flag() + allow_number = optionflags & _get_number_flag() + + if not allow_unicode and not allow_bytes and not allow_number: + return False + + def remove_prefixes(regex: Pattern[str], txt: str) -> str: + return re.sub(regex, r"\1\2", txt) + + if allow_unicode: + want = remove_prefixes(self._unicode_literal_re, want) + got = remove_prefixes(self._unicode_literal_re, got) + + if allow_bytes: + want = remove_prefixes(self._bytes_literal_re, want) + got = remove_prefixes(self._bytes_literal_re, got) + + if allow_number: + got = self._remove_unwanted_precision(want, got) + + return doctest.OutputChecker.check_output(self, want, got, optionflags) + + def _remove_unwanted_precision(self, want: str, got: str) -> str: + wants = list(self._number_re.finditer(want)) + gots = list(self._number_re.finditer(got)) + if len(wants) != len(gots): + return got + offset = 0 + for w, g in zip(wants, gots): + fraction: Optional[str] = w.group("fraction") + exponent: Optional[str] = w.group("exponent1") + if exponent is None: + exponent = w.group("exponent2") + if fraction is None: + precision = 0 + else: + precision = len(fraction) + if exponent is not None: + precision -= int(exponent) + if float(w.group()) == approx(float(g.group()), abs=10 ** -precision): + # They're close enough. Replace the text we actually + # got with the text we want, so that it will match when we + # check the string literally. + got = ( + got[: g.start() + offset] + w.group() + got[g.end() + offset :] + ) + offset += w.end() - w.start() - (g.end() - g.start()) + return got + + return LiteralsOutputChecker + + +def _get_checker() -> "doctest.OutputChecker": + """Return a doctest.OutputChecker subclass that supports some + additional options: + + * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b'' + prefixes (respectively) in string literals. Useful when the same + doctest should run in Python 2 and Python 3. + + * NUMBER to ignore floating-point differences smaller than the + precision of the literal number in the doctest. + + An inner class is used to avoid importing "doctest" at the module + level. + """ + global CHECKER_CLASS + if CHECKER_CLASS is None: + CHECKER_CLASS = _init_checker_class() + return CHECKER_CLASS() + + +def _get_allow_unicode_flag() -> int: + """Register and return the ALLOW_UNICODE flag.""" + import doctest + + return doctest.register_optionflag("ALLOW_UNICODE") + + +def _get_allow_bytes_flag() -> int: + """Register and return the ALLOW_BYTES flag.""" + import doctest + + return doctest.register_optionflag("ALLOW_BYTES") + + +def _get_number_flag() -> int: + """Register and return the NUMBER flag.""" + import doctest + + return doctest.register_optionflag("NUMBER") + + +def _get_report_choice(key: str) -> int: + """Return the actual `doctest` module flag value. + + We want to do it as late as possible to avoid importing `doctest` and all + its dependencies when parsing options, as it adds overhead and breaks tests. + """ + import doctest + + return { + DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF, + DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF, + DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF, + DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE, + DOCTEST_REPORT_CHOICE_NONE: 0, + }[key] + + +@pytest.fixture(scope="session") +def doctest_namespace() -> Dict[str, Any]: + """Fixture that returns a :py:class:`dict` that will be injected into the + namespace of doctests.""" + return dict() diff --git a/myenv/lib/python3.9/site-packages/_pytest/faulthandler.py b/myenv/lib/python3.9/site-packages/_pytest/faulthandler.py new file mode 100644 index 0000000..ff673b5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/faulthandler.py @@ -0,0 +1,116 @@ +import io +import os +import sys +from typing import Generator +from typing import TextIO + +import pytest +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.nodes import Item +from _pytest.store import StoreKey + + +fault_handler_stderr_key = StoreKey[TextIO]() + + +def pytest_addoption(parser: Parser) -> None: + help = ( + "Dump the traceback of all threads if a test takes " + "more than TIMEOUT seconds to finish." + ) + parser.addini("faulthandler_timeout", help, default=0.0) + + +def pytest_configure(config: Config) -> None: + import faulthandler + + if not faulthandler.is_enabled(): + # faulthhandler is not enabled, so install plugin that does the actual work + # of enabling faulthandler before each test executes. + config.pluginmanager.register(FaultHandlerHooks(), "faulthandler-hooks") + else: + # Do not handle dumping to stderr if faulthandler is already enabled, so warn + # users that the option is being ignored. + timeout = FaultHandlerHooks.get_timeout_config_value(config) + if timeout > 0: + config.issue_config_time_warning( + pytest.PytestConfigWarning( + "faulthandler module enabled before pytest configuration step, " + "'faulthandler_timeout' option ignored" + ), + stacklevel=2, + ) + + +class FaultHandlerHooks: + """Implements hooks that will actually install fault handler before tests execute, + as well as correctly handle pdb and internal errors.""" + + def pytest_configure(self, config: Config) -> None: + import faulthandler + + stderr_fd_copy = os.dup(self._get_stderr_fileno()) + config._store[fault_handler_stderr_key] = open(stderr_fd_copy, "w") + faulthandler.enable(file=config._store[fault_handler_stderr_key]) + + def pytest_unconfigure(self, config: Config) -> None: + import faulthandler + + faulthandler.disable() + # close our dup file installed during pytest_configure + # re-enable the faulthandler, attaching it to the default sys.stderr + # so we can see crashes after pytest has finished, usually during + # garbage collection during interpreter shutdown + config._store[fault_handler_stderr_key].close() + del config._store[fault_handler_stderr_key] + faulthandler.enable(file=self._get_stderr_fileno()) + + @staticmethod + def _get_stderr_fileno(): + try: + fileno = sys.stderr.fileno() + # The Twisted Logger will return an invalid file descriptor since it is not backed + # by an FD. So, let's also forward this to the same code path as with pytest-xdist. + if fileno == -1: + raise AttributeError() + return fileno + except (AttributeError, io.UnsupportedOperation): + # pytest-xdist monkeypatches sys.stderr with an object that is not an actual file. + # https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors + # This is potentially dangerous, but the best we can do. + return sys.__stderr__.fileno() + + @staticmethod + def get_timeout_config_value(config): + return float(config.getini("faulthandler_timeout") or 0.0) + + @pytest.hookimpl(hookwrapper=True, trylast=True) + def pytest_runtest_protocol(self, item: Item) -> Generator[None, None, None]: + timeout = self.get_timeout_config_value(item.config) + stderr = item.config._store[fault_handler_stderr_key] + if timeout > 0 and stderr is not None: + import faulthandler + + faulthandler.dump_traceback_later(timeout, file=stderr) + try: + yield + finally: + faulthandler.cancel_dump_traceback_later() + else: + yield + + @pytest.hookimpl(tryfirst=True) + def pytest_enter_pdb(self) -> None: + """Cancel any traceback dumping due to timeout before entering pdb.""" + import faulthandler + + faulthandler.cancel_dump_traceback_later() + + @pytest.hookimpl(tryfirst=True) + def pytest_exception_interact(self) -> None: + """Cancel any traceback dumping due to an interactive exception being + raised.""" + import faulthandler + + faulthandler.cancel_dump_traceback_later() diff --git a/myenv/lib/python3.9/site-packages/_pytest/fixtures.py b/myenv/lib/python3.9/site-packages/_pytest/fixtures.py new file mode 100644 index 0000000..273bcaf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/fixtures.py @@ -0,0 +1,1680 @@ +import functools +import inspect +import os +import sys +import warnings +from collections import defaultdict +from collections import deque +from types import TracebackType +from typing import Any +from typing import Callable +from typing import cast +from typing import Dict +from typing import Generator +from typing import Generic +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import overload +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import attr +import py + +import _pytest +from _pytest import nodes +from _pytest._code import getfslineno +from _pytest._code.code import FormattedExcinfo +from _pytest._code.code import TerminalRepr +from _pytest._io import TerminalWriter +from _pytest.compat import _format_args +from _pytest.compat import _PytestWrapper +from _pytest.compat import assert_never +from _pytest.compat import final +from _pytest.compat import get_real_func +from _pytest.compat import get_real_method +from _pytest.compat import getfuncargnames +from _pytest.compat import getimfunc +from _pytest.compat import getlocation +from _pytest.compat import is_generator +from _pytest.compat import NOTSET +from _pytest.compat import safe_getattr +from _pytest.config import _PluggyPlugin +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.deprecated import FILLFUNCARGS +from _pytest.deprecated import YIELD_FIXTURE +from _pytest.mark import Mark +from _pytest.mark import ParameterSet +from _pytest.mark.structures import MarkDecorator +from _pytest.outcomes import fail +from _pytest.outcomes import TEST_OUTCOME +from _pytest.pathlib import absolutepath +from _pytest.store import StoreKey + +if TYPE_CHECKING: + from typing import Deque + from typing import NoReturn + from typing_extensions import Literal + + from _pytest.main import Session + from _pytest.python import CallSpec2 + from _pytest.python import Function + from _pytest.python import Metafunc + + _Scope = Literal["session", "package", "module", "class", "function"] + + +# The value of the fixture -- return/yield of the fixture function (type variable). +_FixtureValue = TypeVar("_FixtureValue") +# The type of the fixture function (type variable). +_FixtureFunction = TypeVar("_FixtureFunction", bound=Callable[..., object]) +# The type of a fixture function (type alias generic in fixture value). +_FixtureFunc = Union[ + Callable[..., _FixtureValue], Callable[..., Generator[_FixtureValue, None, None]] +] +# The type of FixtureDef.cached_result (type alias generic in fixture value). +_FixtureCachedResult = Union[ + Tuple[ + # The result. + _FixtureValue, + # Cache key. + object, + None, + ], + Tuple[ + None, + # Cache key. + object, + # Exc info if raised. + Tuple[Type[BaseException], BaseException, TracebackType], + ], +] + + +@attr.s(frozen=True) +class PseudoFixtureDef(Generic[_FixtureValue]): + cached_result = attr.ib(type="_FixtureCachedResult[_FixtureValue]") + scope = attr.ib(type="_Scope") + + +def pytest_sessionstart(session: "Session") -> None: + session._fixturemanager = FixtureManager(session) + + +def get_scope_package(node, fixturedef: "FixtureDef[object]"): + import pytest + + cls = pytest.Package + current = node + fixture_package_name = "{}/{}".format(fixturedef.baseid, "__init__.py") + while current and ( + type(current) is not cls or fixture_package_name != current.nodeid + ): + current = current.parent + if current is None: + return node.session + return current + + +def get_scope_node( + node: nodes.Node, scope: "_Scope" +) -> Optional[Union[nodes.Item, nodes.Collector]]: + import _pytest.python + + if scope == "function": + return node.getparent(nodes.Item) + elif scope == "class": + return node.getparent(_pytest.python.Class) + elif scope == "module": + return node.getparent(_pytest.python.Module) + elif scope == "package": + return node.getparent(_pytest.python.Package) + elif scope == "session": + return node.getparent(_pytest.main.Session) + else: + assert_never(scope) + + +# Used for storing artificial fixturedefs for direct parametrization. +name2pseudofixturedef_key = StoreKey[Dict[str, "FixtureDef[Any]"]]() + + +def add_funcarg_pseudo_fixture_def( + collector: nodes.Collector, metafunc: "Metafunc", fixturemanager: "FixtureManager" +) -> None: + # This function will transform all collected calls to functions + # if they use direct funcargs (i.e. direct parametrization) + # because we want later test execution to be able to rely on + # an existing FixtureDef structure for all arguments. + # XXX we can probably avoid this algorithm if we modify CallSpec2 + # to directly care for creating the fixturedefs within its methods. + if not metafunc._calls[0].funcargs: + # This function call does not have direct parametrization. + return + # Collect funcargs of all callspecs into a list of values. + arg2params: Dict[str, List[object]] = {} + arg2scope: Dict[str, _Scope] = {} + for callspec in metafunc._calls: + for argname, argvalue in callspec.funcargs.items(): + assert argname not in callspec.params + callspec.params[argname] = argvalue + arg2params_list = arg2params.setdefault(argname, []) + callspec.indices[argname] = len(arg2params_list) + arg2params_list.append(argvalue) + if argname not in arg2scope: + scopenum = callspec._arg2scopenum.get(argname, scopenum_function) + arg2scope[argname] = scopes[scopenum] + callspec.funcargs.clear() + + # Register artificial FixtureDef's so that later at test execution + # time we can rely on a proper FixtureDef to exist for fixture setup. + arg2fixturedefs = metafunc._arg2fixturedefs + for argname, valuelist in arg2params.items(): + # If we have a scope that is higher than function, we need + # to make sure we only ever create an according fixturedef on + # a per-scope basis. We thus store and cache the fixturedef on the + # node related to the scope. + scope = arg2scope[argname] + node = None + if scope != "function": + node = get_scope_node(collector, scope) + if node is None: + assert scope == "class" and isinstance(collector, _pytest.python.Module) + # Use module-level collector for class-scope (for now). + node = collector + if node is None: + name2pseudofixturedef = None + else: + default: Dict[str, FixtureDef[Any]] = {} + name2pseudofixturedef = node._store.setdefault( + name2pseudofixturedef_key, default + ) + if name2pseudofixturedef is not None and argname in name2pseudofixturedef: + arg2fixturedefs[argname] = [name2pseudofixturedef[argname]] + else: + fixturedef = FixtureDef( + fixturemanager=fixturemanager, + baseid="", + argname=argname, + func=get_direct_param_fixture_func, + scope=arg2scope[argname], + params=valuelist, + unittest=False, + ids=None, + ) + arg2fixturedefs[argname] = [fixturedef] + if name2pseudofixturedef is not None: + name2pseudofixturedef[argname] = fixturedef + + +def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]: + """Return fixturemarker or None if it doesn't exist or raised + exceptions.""" + try: + fixturemarker: Optional[FixtureFunctionMarker] = getattr( + obj, "_pytestfixturefunction", None + ) + except TEST_OUTCOME: + # some objects raise errors like request (from flask import request) + # we don't expect them to be fixture functions + return None + return fixturemarker + + +# Parametrized fixture key, helper alias for code below. +_Key = Tuple[object, ...] + + +def get_parametrized_fixture_keys(item: nodes.Item, scopenum: int) -> Iterator[_Key]: + """Return list of keys for all parametrized arguments which match + the specified scope. """ + assert scopenum < scopenum_function # function + try: + callspec = item.callspec # type: ignore[attr-defined] + except AttributeError: + pass + else: + cs: CallSpec2 = callspec + # cs.indices.items() is random order of argnames. Need to + # sort this so that different calls to + # get_parametrized_fixture_keys will be deterministic. + for argname, param_index in sorted(cs.indices.items()): + if cs._arg2scopenum[argname] != scopenum: + continue + if scopenum == 0: # session + key: _Key = (argname, param_index) + elif scopenum == 1: # package + key = (argname, param_index, item.fspath.dirpath()) + elif scopenum == 2: # module + key = (argname, param_index, item.fspath) + elif scopenum == 3: # class + item_cls = item.cls # type: ignore[attr-defined] + key = (argname, param_index, item.fspath, item_cls) + yield key + + +# Algorithm for sorting on a per-parametrized resource setup basis. +# It is called for scopenum==0 (session) first and performs sorting +# down to the lower scopes such as to minimize number of "high scope" +# setups and teardowns. + + +def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]: + argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]] = {} + items_by_argkey: Dict[int, Dict[_Key, Deque[nodes.Item]]] = {} + for scopenum in range(0, scopenum_function): + d: Dict[nodes.Item, Dict[_Key, None]] = {} + argkeys_cache[scopenum] = d + item_d: Dict[_Key, Deque[nodes.Item]] = defaultdict(deque) + items_by_argkey[scopenum] = item_d + for item in items: + keys = dict.fromkeys(get_parametrized_fixture_keys(item, scopenum), None) + if keys: + d[item] = keys + for key in keys: + item_d[key].append(item) + items_dict = dict.fromkeys(items, None) + return list(reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, 0)) + + +def fix_cache_order( + item: nodes.Item, + argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]], + items_by_argkey: Dict[int, Dict[_Key, "Deque[nodes.Item]"]], +) -> None: + for scopenum in range(0, scopenum_function): + for key in argkeys_cache[scopenum].get(item, []): + items_by_argkey[scopenum][key].appendleft(item) + + +def reorder_items_atscope( + items: Dict[nodes.Item, None], + argkeys_cache: Dict[int, Dict[nodes.Item, Dict[_Key, None]]], + items_by_argkey: Dict[int, Dict[_Key, "Deque[nodes.Item]"]], + scopenum: int, +) -> Dict[nodes.Item, None]: + if scopenum >= scopenum_function or len(items) < 3: + return items + ignore: Set[Optional[_Key]] = set() + items_deque = deque(items) + items_done: Dict[nodes.Item, None] = {} + scoped_items_by_argkey = items_by_argkey[scopenum] + scoped_argkeys_cache = argkeys_cache[scopenum] + while items_deque: + no_argkey_group: Dict[nodes.Item, None] = {} + slicing_argkey = None + while items_deque: + item = items_deque.popleft() + if item in items_done or item in no_argkey_group: + continue + argkeys = dict.fromkeys( + (k for k in scoped_argkeys_cache.get(item, []) if k not in ignore), None + ) + if not argkeys: + no_argkey_group[item] = None + else: + slicing_argkey, _ = argkeys.popitem() + # We don't have to remove relevant items from later in the + # deque because they'll just be ignored. + matching_items = [ + i for i in scoped_items_by_argkey[slicing_argkey] if i in items + ] + for i in reversed(matching_items): + fix_cache_order(i, argkeys_cache, items_by_argkey) + items_deque.appendleft(i) + break + if no_argkey_group: + no_argkey_group = reorder_items_atscope( + no_argkey_group, argkeys_cache, items_by_argkey, scopenum + 1 + ) + for item in no_argkey_group: + items_done[item] = None + ignore.add(slicing_argkey) + return items_done + + +def _fillfuncargs(function: "Function") -> None: + """Fill missing fixtures for a test function, old public API (deprecated).""" + warnings.warn(FILLFUNCARGS.format(name="pytest._fillfuncargs()"), stacklevel=2) + _fill_fixtures_impl(function) + + +def fillfixtures(function: "Function") -> None: + """Fill missing fixtures for a test function (deprecated).""" + warnings.warn( + FILLFUNCARGS.format(name="_pytest.fixtures.fillfixtures()"), stacklevel=2 + ) + _fill_fixtures_impl(function) + + +def _fill_fixtures_impl(function: "Function") -> None: + """Internal implementation to fill fixtures on the given function object.""" + try: + request = function._request + except AttributeError: + # XXX this special code path is only expected to execute + # with the oejskit plugin. It uses classes with funcargs + # and we thus have to work a bit to allow this. + fm = function.session._fixturemanager + assert function.parent is not None + fi = fm.getfixtureinfo(function.parent, function.obj, None) + function._fixtureinfo = fi + request = function._request = FixtureRequest(function, _ispytest=True) + request._fillfixtures() + # Prune out funcargs for jstests. + newfuncargs = {} + for name in fi.argnames: + newfuncargs[name] = function.funcargs[name] + function.funcargs = newfuncargs + else: + request._fillfixtures() + + +def get_direct_param_fixture_func(request): + return request.param + + +@attr.s(slots=True) +class FuncFixtureInfo: + # Original function argument names. + argnames = attr.ib(type=Tuple[str, ...]) + # Argnames that function immediately requires. These include argnames + + # fixture names specified via usefixtures and via autouse=True in fixture + # definitions. + initialnames = attr.ib(type=Tuple[str, ...]) + names_closure = attr.ib(type=List[str]) + name2fixturedefs = attr.ib(type=Dict[str, Sequence["FixtureDef[Any]"]]) + + def prune_dependency_tree(self) -> None: + """Recompute names_closure from initialnames and name2fixturedefs. + + Can only reduce names_closure, which means that the new closure will + always be a subset of the old one. The order is preserved. + + This method is needed because direct parametrization may shadow some + of the fixtures that were included in the originally built dependency + tree. In this way the dependency tree can get pruned, and the closure + of argnames may get reduced. + """ + closure: Set[str] = set() + working_set = set(self.initialnames) + while working_set: + argname = working_set.pop() + # Argname may be smth not included in the original names_closure, + # in which case we ignore it. This currently happens with pseudo + # FixtureDefs which wrap 'get_direct_param_fixture_func(request)'. + # So they introduce the new dependency 'request' which might have + # been missing in the original tree (closure). + if argname not in closure and argname in self.names_closure: + closure.add(argname) + if argname in self.name2fixturedefs: + working_set.update(self.name2fixturedefs[argname][-1].argnames) + + self.names_closure[:] = sorted(closure, key=self.names_closure.index) + + +class FixtureRequest: + """A request for a fixture from a test or fixture function. + + A request object gives access to the requesting test context and has + an optional ``param`` attribute in case the fixture is parametrized + indirectly. + """ + + def __init__(self, pyfuncitem, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + self._pyfuncitem = pyfuncitem + #: Fixture for which this request is being performed. + self.fixturename: Optional[str] = None + #: Scope string, one of "function", "class", "module", "session". + self.scope: _Scope = "function" + self._fixture_defs: Dict[str, FixtureDef[Any]] = {} + fixtureinfo: FuncFixtureInfo = pyfuncitem._fixtureinfo + self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() + self._arg2index: Dict[str, int] = {} + self._fixturemanager: FixtureManager = (pyfuncitem.session._fixturemanager) + + @property + def fixturenames(self) -> List[str]: + """Names of all active fixtures in this request.""" + result = list(self._pyfuncitem._fixtureinfo.names_closure) + result.extend(set(self._fixture_defs).difference(result)) + return result + + @property + def node(self): + """Underlying collection node (depends on current request scope).""" + return self._getscopeitem(self.scope) + + def _getnextfixturedef(self, argname: str) -> "FixtureDef[Any]": + fixturedefs = self._arg2fixturedefs.get(argname, None) + if fixturedefs is None: + # We arrive here because of a dynamic call to + # getfixturevalue(argname) usage which was naturally + # not known at parsing/collection time. + assert self._pyfuncitem.parent is not None + parentid = self._pyfuncitem.parent.nodeid + fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid) + # TODO: Fix this type ignore. Either add assert or adjust types. + # Can this be None here? + self._arg2fixturedefs[argname] = fixturedefs # type: ignore[assignment] + # fixturedefs list is immutable so we maintain a decreasing index. + index = self._arg2index.get(argname, 0) - 1 + if fixturedefs is None or (-index > len(fixturedefs)): + raise FixtureLookupError(argname, self) + self._arg2index[argname] = index + return fixturedefs[index] + + @property + def config(self) -> Config: + """The pytest config object associated with this request.""" + return self._pyfuncitem.config # type: ignore[no-any-return] + + @property + def function(self): + """Test function object if the request has a per-function scope.""" + if self.scope != "function": + raise AttributeError( + f"function not available in {self.scope}-scoped context" + ) + return self._pyfuncitem.obj + + @property + def cls(self): + """Class (can be None) where the test function was collected.""" + if self.scope not in ("class", "function"): + raise AttributeError(f"cls not available in {self.scope}-scoped context") + clscol = self._pyfuncitem.getparent(_pytest.python.Class) + if clscol: + return clscol.obj + + @property + def instance(self): + """Instance (can be None) on which test function was collected.""" + # unittest support hack, see _pytest.unittest.TestCaseFunction. + try: + return self._pyfuncitem._testcase + except AttributeError: + function = getattr(self, "function", None) + return getattr(function, "__self__", None) + + @property + def module(self): + """Python module object where the test function was collected.""" + if self.scope not in ("function", "class", "module"): + raise AttributeError(f"module not available in {self.scope}-scoped context") + return self._pyfuncitem.getparent(_pytest.python.Module).obj + + @property + def fspath(self) -> py.path.local: + """The file system path of the test module which collected this test.""" + if self.scope not in ("function", "class", "module", "package"): + raise AttributeError(f"module not available in {self.scope}-scoped context") + # TODO: Remove ignore once _pyfuncitem is properly typed. + return self._pyfuncitem.fspath # type: ignore + + @property + def keywords(self): + """Keywords/markers dictionary for the underlying node.""" + return self.node.keywords + + @property + def session(self) -> "Session": + """Pytest session object.""" + return self._pyfuncitem.session # type: ignore[no-any-return] + + def addfinalizer(self, finalizer: Callable[[], object]) -> None: + """Add finalizer/teardown function to be called after the last test + within the requesting test context finished execution.""" + # XXX usually this method is shadowed by fixturedef specific ones. + self._addfinalizer(finalizer, scope=self.scope) + + def _addfinalizer(self, finalizer: Callable[[], object], scope) -> None: + colitem = self._getscopeitem(scope) + self._pyfuncitem.session._setupstate.addfinalizer( + finalizer=finalizer, colitem=colitem + ) + + def applymarker(self, marker: Union[str, MarkDecorator]) -> None: + """Apply a marker to a single test function invocation. + + This method is useful if you don't want to have a keyword/marker + on all function invocations. + + :param marker: + A :py:class:`_pytest.mark.MarkDecorator` object created by a call + to ``pytest.mark.NAME(...)``. + """ + self.node.add_marker(marker) + + def raiseerror(self, msg: Optional[str]) -> "NoReturn": + """Raise a FixtureLookupError with the given message.""" + raise self._fixturemanager.FixtureLookupError(None, self, msg) + + def _fillfixtures(self) -> None: + item = self._pyfuncitem + fixturenames = getattr(item, "fixturenames", self.fixturenames) + for argname in fixturenames: + if argname not in item.funcargs: + item.funcargs[argname] = self.getfixturevalue(argname) + + def getfixturevalue(self, argname: str) -> Any: + """Dynamically run a named fixture function. + + Declaring fixtures via function argument is recommended where possible. + But if you can only decide whether to use another fixture at test + setup time, you may use this function to retrieve it inside a fixture + or test function body. + + :raises pytest.FixtureLookupError: + If the given fixture could not be found. + """ + fixturedef = self._get_active_fixturedef(argname) + assert fixturedef.cached_result is not None + return fixturedef.cached_result[0] + + def _get_active_fixturedef( + self, argname: str + ) -> Union["FixtureDef[object]", PseudoFixtureDef[object]]: + try: + return self._fixture_defs[argname] + except KeyError: + try: + fixturedef = self._getnextfixturedef(argname) + except FixtureLookupError: + if argname == "request": + cached_result = (self, [0], None) + scope: _Scope = "function" + return PseudoFixtureDef(cached_result, scope) + raise + # Remove indent to prevent the python3 exception + # from leaking into the call. + self._compute_fixture_value(fixturedef) + self._fixture_defs[argname] = fixturedef + return fixturedef + + def _get_fixturestack(self) -> List["FixtureDef[Any]"]: + current = self + values: List[FixtureDef[Any]] = [] + while 1: + fixturedef = getattr(current, "_fixturedef", None) + if fixturedef is None: + values.reverse() + return values + values.append(fixturedef) + assert isinstance(current, SubRequest) + current = current._parent_request + + def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None: + """Create a SubRequest based on "self" and call the execute method + of the given FixtureDef object. + + This will force the FixtureDef object to throw away any previous + results and compute a new fixture value, which will be stored into + the FixtureDef object itself. + """ + # prepare a subrequest object before calling fixture function + # (latter managed by fixturedef) + argname = fixturedef.argname + funcitem = self._pyfuncitem + scope = fixturedef.scope + try: + param = funcitem.callspec.getparam(argname) + except (AttributeError, ValueError): + param = NOTSET + param_index = 0 + has_params = fixturedef.params is not None + fixtures_not_supported = getattr(funcitem, "nofuncargs", False) + if has_params and fixtures_not_supported: + msg = ( + "{name} does not support fixtures, maybe unittest.TestCase subclass?\n" + "Node id: {nodeid}\n" + "Function type: {typename}" + ).format( + name=funcitem.name, + nodeid=funcitem.nodeid, + typename=type(funcitem).__name__, + ) + fail(msg, pytrace=False) + if has_params: + frame = inspect.stack()[3] + frameinfo = inspect.getframeinfo(frame[0]) + source_path = py.path.local(frameinfo.filename) + source_lineno = frameinfo.lineno + rel_source_path = source_path.relto(funcitem.config.rootdir) + if rel_source_path: + source_path_str = rel_source_path + else: + source_path_str = str(source_path) + msg = ( + "The requested fixture has no parameter defined for test:\n" + " {}\n\n" + "Requested fixture '{}' defined in:\n{}" + "\n\nRequested here:\n{}:{}".format( + funcitem.nodeid, + fixturedef.argname, + getlocation(fixturedef.func, funcitem.config.rootdir), + source_path_str, + source_lineno, + ) + ) + fail(msg, pytrace=False) + else: + param_index = funcitem.callspec.indices[argname] + # If a parametrize invocation set a scope it will override + # the static scope defined with the fixture function. + paramscopenum = funcitem.callspec._arg2scopenum.get(argname) + if paramscopenum is not None: + scope = scopes[paramscopenum] + + subrequest = SubRequest( + self, scope, param, param_index, fixturedef, _ispytest=True + ) + + # Check if a higher-level scoped fixture accesses a lower level one. + subrequest._check_scope(argname, self.scope, scope) + try: + # Call the fixture function. + fixturedef.execute(request=subrequest) + finally: + self._schedule_finalizers(fixturedef, subrequest) + + def _schedule_finalizers( + self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest" + ) -> None: + # If fixture function failed it might have registered finalizers. + self.session._setupstate.addfinalizer( + functools.partial(fixturedef.finish, request=subrequest), subrequest.node + ) + + def _check_scope( + self, argname: str, invoking_scope: "_Scope", requested_scope: "_Scope", + ) -> None: + if argname == "request": + return + if scopemismatch(invoking_scope, requested_scope): + # Try to report something helpful. + lines = self._factorytraceback() + fail( + "ScopeMismatch: You tried to access the %r scoped " + "fixture %r with a %r scoped request object, " + "involved factories\n%s" + % ((requested_scope, argname, invoking_scope, "\n".join(lines))), + pytrace=False, + ) + + def _factorytraceback(self) -> List[str]: + lines = [] + for fixturedef in self._get_fixturestack(): + factory = fixturedef.func + fs, lineno = getfslineno(factory) + p = self._pyfuncitem.session.fspath.bestrelpath(fs) + args = _format_args(factory) + lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args)) + return lines + + def _getscopeitem(self, scope: "_Scope") -> Union[nodes.Item, nodes.Collector]: + if scope == "function": + # This might also be a non-function Item despite its attribute name. + node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem + elif scope == "package": + # FIXME: _fixturedef is not defined on FixtureRequest (this class), + # but on FixtureRequest (a subclass). + node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined] + else: + node = get_scope_node(self._pyfuncitem, scope) + if node is None and scope == "class": + # Fallback to function item itself. + node = self._pyfuncitem + assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format( + scope, self._pyfuncitem + ) + return node + + def __repr__(self) -> str: + return "" % (self.node) + + +@final +class SubRequest(FixtureRequest): + """A sub request for handling getting a fixture from a test function/fixture.""" + + def __init__( + self, + request: "FixtureRequest", + scope: "_Scope", + param, + param_index: int, + fixturedef: "FixtureDef[object]", + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._parent_request = request + self.fixturename = fixturedef.argname + if param is not NOTSET: + self.param = param + self.param_index = param_index + self.scope = scope + self._fixturedef = fixturedef + self._pyfuncitem = request._pyfuncitem + self._fixture_defs = request._fixture_defs + self._arg2fixturedefs = request._arg2fixturedefs + self._arg2index = request._arg2index + self._fixturemanager = request._fixturemanager + + def __repr__(self) -> str: + return f"" + + def addfinalizer(self, finalizer: Callable[[], object]) -> None: + """Add finalizer/teardown function to be called after the last test + within the requesting test context finished execution.""" + self._fixturedef.addfinalizer(finalizer) + + def _schedule_finalizers( + self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest" + ) -> None: + # If the executing fixturedef was not explicitly requested in the argument list (via + # getfixturevalue inside the fixture call) then ensure this fixture def will be finished + # first. + if fixturedef.argname not in self.fixturenames: + fixturedef.addfinalizer( + functools.partial(self._fixturedef.finish, request=self) + ) + super()._schedule_finalizers(fixturedef, subrequest) + + +scopes: List["_Scope"] = ["session", "package", "module", "class", "function"] +scopenum_function = scopes.index("function") + + +def scopemismatch(currentscope: "_Scope", newscope: "_Scope") -> bool: + return scopes.index(newscope) > scopes.index(currentscope) + + +def scope2index(scope: str, descr: str, where: Optional[str] = None) -> int: + """Look up the index of ``scope`` and raise a descriptive value error + if not defined.""" + strscopes: Sequence[str] = scopes + try: + return strscopes.index(scope) + except ValueError: + fail( + "{} {}got an unexpected scope value '{}'".format( + descr, f"from {where} " if where else "", scope + ), + pytrace=False, + ) + + +@final +class FixtureLookupError(LookupError): + """Could not return a requested fixture (missing or invalid).""" + + def __init__( + self, argname: Optional[str], request: FixtureRequest, msg: Optional[str] = None + ) -> None: + self.argname = argname + self.request = request + self.fixturestack = request._get_fixturestack() + self.msg = msg + + def formatrepr(self) -> "FixtureLookupErrorRepr": + tblines: List[str] = [] + addline = tblines.append + stack = [self.request._pyfuncitem.obj] + stack.extend(map(lambda x: x.func, self.fixturestack)) + msg = self.msg + if msg is not None: + # The last fixture raise an error, let's present + # it at the requesting side. + stack = stack[:-1] + for function in stack: + fspath, lineno = getfslineno(function) + try: + lines, _ = inspect.getsourcelines(get_real_func(function)) + except (OSError, IndexError, TypeError): + error_msg = "file %s, line %s: source code not available" + addline(error_msg % (fspath, lineno + 1)) + else: + addline("file {}, line {}".format(fspath, lineno + 1)) + for i, line in enumerate(lines): + line = line.rstrip() + addline(" " + line) + if line.lstrip().startswith("def"): + break + + if msg is None: + fm = self.request._fixturemanager + available = set() + parentid = self.request._pyfuncitem.parent.nodeid + for name, fixturedefs in fm._arg2fixturedefs.items(): + faclist = list(fm._matchfactories(fixturedefs, parentid)) + if faclist: + available.add(name) + if self.argname in available: + msg = " recursive dependency involving fixture '{}' detected".format( + self.argname + ) + else: + msg = f"fixture '{self.argname}' not found" + msg += "\n available fixtures: {}".format(", ".join(sorted(available))) + msg += "\n use 'pytest --fixtures [testpath]' for help on them." + + return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) + + +class FixtureLookupErrorRepr(TerminalRepr): + def __init__( + self, + filename: Union[str, py.path.local], + firstlineno: int, + tblines: Sequence[str], + errorstring: str, + argname: Optional[str], + ) -> None: + self.tblines = tblines + self.errorstring = errorstring + self.filename = filename + self.firstlineno = firstlineno + self.argname = argname + + def toterminal(self, tw: TerminalWriter) -> None: + # tw.line("FixtureLookupError: %s" %(self.argname), red=True) + for tbline in self.tblines: + tw.line(tbline.rstrip()) + lines = self.errorstring.split("\n") + if lines: + tw.line( + "{} {}".format(FormattedExcinfo.fail_marker, lines[0].strip()), + red=True, + ) + for line in lines[1:]: + tw.line( + f"{FormattedExcinfo.flow_marker} {line.strip()}", red=True, + ) + tw.line() + tw.line("%s:%d" % (self.filename, self.firstlineno + 1)) + + +def fail_fixturefunc(fixturefunc, msg: str) -> "NoReturn": + fs, lineno = getfslineno(fixturefunc) + location = "{}:{}".format(fs, lineno + 1) + source = _pytest._code.Source(fixturefunc) + fail(msg + ":\n\n" + str(source.indent()) + "\n" + location, pytrace=False) + + +def call_fixture_func( + fixturefunc: "_FixtureFunc[_FixtureValue]", request: FixtureRequest, kwargs +) -> _FixtureValue: + if is_generator(fixturefunc): + fixturefunc = cast( + Callable[..., Generator[_FixtureValue, None, None]], fixturefunc + ) + generator = fixturefunc(**kwargs) + try: + fixture_result = next(generator) + except StopIteration: + raise ValueError(f"{request.fixturename} did not yield a value") from None + finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator) + request.addfinalizer(finalizer) + else: + fixturefunc = cast(Callable[..., _FixtureValue], fixturefunc) + fixture_result = fixturefunc(**kwargs) + return fixture_result + + +def _teardown_yield_fixture(fixturefunc, it) -> None: + """Execute the teardown of a fixture function by advancing the iterator + after the yield and ensure the iteration ends (if not it means there is + more than one yield in the function).""" + try: + next(it) + except StopIteration: + pass + else: + fail_fixturefunc(fixturefunc, "fixture function has more than one 'yield'") + + +def _eval_scope_callable( + scope_callable: "Callable[[str, Config], _Scope]", + fixture_name: str, + config: Config, +) -> "_Scope": + try: + # Type ignored because there is no typing mechanism to specify + # keyword arguments, currently. + result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg] + except Exception as e: + raise TypeError( + "Error evaluating {} while defining fixture '{}'.\n" + "Expected a function with the signature (*, fixture_name, config)".format( + scope_callable, fixture_name + ) + ) from e + if not isinstance(result, str): + fail( + "Expected {} to return a 'str' while defining fixture '{}', but it returned:\n" + "{!r}".format(scope_callable, fixture_name, result), + pytrace=False, + ) + return result + + +@final +class FixtureDef(Generic[_FixtureValue]): + """A container for a factory definition.""" + + def __init__( + self, + fixturemanager: "FixtureManager", + baseid: Optional[str], + argname: str, + func: "_FixtureFunc[_FixtureValue]", + scope: "Union[_Scope, Callable[[str, Config], _Scope]]", + params: Optional[Sequence[object]], + unittest: bool = False, + ids: Optional[ + Union[ + Tuple[Union[None, str, float, int, bool], ...], + Callable[[Any], Optional[object]], + ] + ] = None, + ) -> None: + self._fixturemanager = fixturemanager + self.baseid = baseid or "" + self.has_location = baseid is not None + self.func = func + self.argname = argname + if callable(scope): + scope_ = _eval_scope_callable(scope, argname, fixturemanager.config) + else: + scope_ = scope + self.scopenum = scope2index( + # TODO: Check if the `or` here is really necessary. + scope_ or "function", # type: ignore[unreachable] + descr=f"Fixture '{func.__name__}'", + where=baseid, + ) + self.scope = scope_ + self.params: Optional[Sequence[object]] = params + self.argnames: Tuple[str, ...] = getfuncargnames( + func, name=argname, is_method=unittest + ) + self.unittest = unittest + self.ids = ids + self.cached_result: Optional[_FixtureCachedResult[_FixtureValue]] = None + self._finalizers: List[Callable[[], object]] = [] + + def addfinalizer(self, finalizer: Callable[[], object]) -> None: + self._finalizers.append(finalizer) + + def finish(self, request: SubRequest) -> None: + exc = None + try: + while self._finalizers: + try: + func = self._finalizers.pop() + func() + except BaseException as e: + # XXX Only first exception will be seen by user, + # ideally all should be reported. + if exc is None: + exc = e + if exc: + raise exc + finally: + hook = self._fixturemanager.session.gethookproxy(request.node.fspath) + hook.pytest_fixture_post_finalizer(fixturedef=self, request=request) + # Even if finalization fails, we invalidate the cached fixture + # value and remove all finalizers because they may be bound methods + # which will keep instances alive. + self.cached_result = None + self._finalizers = [] + + def execute(self, request: SubRequest) -> _FixtureValue: + # Get required arguments and register our own finish() + # with their finalization. + for argname in self.argnames: + fixturedef = request._get_active_fixturedef(argname) + if argname != "request": + # PseudoFixtureDef is only for "request". + assert isinstance(fixturedef, FixtureDef) + fixturedef.addfinalizer(functools.partial(self.finish, request=request)) + + my_cache_key = self.cache_key(request) + if self.cached_result is not None: + # note: comparison with `==` can fail (or be expensive) for e.g. + # numpy arrays (#6497). + cache_key = self.cached_result[1] + if my_cache_key is cache_key: + if self.cached_result[2] is not None: + _, val, tb = self.cached_result[2] + raise val.with_traceback(tb) + else: + result = self.cached_result[0] + return result + # We have a previous but differently parametrized fixture instance + # so we need to tear it down before creating a new one. + self.finish(request) + assert self.cached_result is None + + hook = self._fixturemanager.session.gethookproxy(request.node.fspath) + result = hook.pytest_fixture_setup(fixturedef=self, request=request) + return result + + def cache_key(self, request: SubRequest) -> object: + return request.param_index if not hasattr(request, "param") else request.param + + def __repr__(self) -> str: + return "".format( + self.argname, self.scope, self.baseid + ) + + +def resolve_fixture_function( + fixturedef: FixtureDef[_FixtureValue], request: FixtureRequest +) -> "_FixtureFunc[_FixtureValue]": + """Get the actual callable that can be called to obtain the fixture + value, dealing with unittest-specific instances and bound methods.""" + fixturefunc = fixturedef.func + if fixturedef.unittest: + if request.instance is not None: + # Bind the unbound method to the TestCase instance. + fixturefunc = fixturedef.func.__get__(request.instance) # type: ignore[union-attr] + else: + # The fixture function needs to be bound to the actual + # request.instance so that code working with "fixturedef" behaves + # as expected. + if request.instance is not None: + # Handle the case where fixture is defined not in a test class, but some other class + # (for example a plugin class with a fixture), see #2270. + if hasattr(fixturefunc, "__self__") and not isinstance( + request.instance, fixturefunc.__self__.__class__ # type: ignore[union-attr] + ): + return fixturefunc + fixturefunc = getimfunc(fixturedef.func) + if fixturefunc != fixturedef.func: + fixturefunc = fixturefunc.__get__(request.instance) # type: ignore[union-attr] + return fixturefunc + + +def pytest_fixture_setup( + fixturedef: FixtureDef[_FixtureValue], request: SubRequest +) -> _FixtureValue: + """Execution of fixture setup.""" + kwargs = {} + for argname in fixturedef.argnames: + fixdef = request._get_active_fixturedef(argname) + assert fixdef.cached_result is not None + result, arg_cache_key, exc = fixdef.cached_result + request._check_scope(argname, request.scope, fixdef.scope) + kwargs[argname] = result + + fixturefunc = resolve_fixture_function(fixturedef, request) + my_cache_key = fixturedef.cache_key(request) + try: + result = call_fixture_func(fixturefunc, request, kwargs) + except TEST_OUTCOME: + exc_info = sys.exc_info() + assert exc_info[0] is not None + fixturedef.cached_result = (None, my_cache_key, exc_info) + raise + fixturedef.cached_result = (result, my_cache_key, None) + return result + + +def _ensure_immutable_ids( + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ], +) -> Optional[ + Union[ + Tuple[Union[None, str, float, int, bool], ...], + Callable[[Any], Optional[object]], + ] +]: + if ids is None: + return None + if callable(ids): + return ids + return tuple(ids) + + +def _params_converter( + params: Optional[Iterable[object]], +) -> Optional[Tuple[object, ...]]: + return tuple(params) if params is not None else None + + +def wrap_function_to_error_out_if_called_directly( + function: _FixtureFunction, fixture_marker: "FixtureFunctionMarker", +) -> _FixtureFunction: + """Wrap the given fixture function so we can raise an error about it being called directly, + instead of used as an argument in a test function.""" + message = ( + 'Fixture "{name}" called directly. Fixtures are not meant to be called directly,\n' + "but are created automatically when test functions request them as parameters.\n" + "See https://docs.pytest.org/en/stable/fixture.html for more information about fixtures, and\n" + "https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code." + ).format(name=fixture_marker.name or function.__name__) + + @functools.wraps(function) + def result(*args, **kwargs): + fail(message, pytrace=False) + + # Keep reference to the original function in our own custom attribute so we don't unwrap + # further than this point and lose useful wrappings like @mock.patch (#3774). + result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined] + + return cast(_FixtureFunction, result) + + +@final +@attr.s(frozen=True) +class FixtureFunctionMarker: + scope = attr.ib(type="Union[_Scope, Callable[[str, Config], _Scope]]") + params = attr.ib(type=Optional[Tuple[object, ...]], converter=_params_converter) + autouse = attr.ib(type=bool, default=False) + ids = attr.ib( + type=Union[ + Tuple[Union[None, str, float, int, bool], ...], + Callable[[Any], Optional[object]], + ], + default=None, + converter=_ensure_immutable_ids, + ) + name = attr.ib(type=Optional[str], default=None) + + def __call__(self, function: _FixtureFunction) -> _FixtureFunction: + if inspect.isclass(function): + raise ValueError("class fixtures not supported (maybe in the future)") + + if getattr(function, "_pytestfixturefunction", False): + raise ValueError( + "fixture is being applied more than once to the same function" + ) + + function = wrap_function_to_error_out_if_called_directly(function, self) + + name = self.name or function.__name__ + if name == "request": + location = getlocation(function) + fail( + "'request' is a reserved word for fixtures, use another name:\n {}".format( + location + ), + pytrace=False, + ) + + # Type ignored because https://github.com/python/mypy/issues/2087. + function._pytestfixturefunction = self # type: ignore[attr-defined] + return function + + +@overload +def fixture( + fixture_function: _FixtureFunction, + *, + scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = ..., + params: Optional[Iterable[object]] = ..., + autouse: bool = ..., + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = ..., + name: Optional[str] = ..., +) -> _FixtureFunction: + ... + + +@overload +def fixture( + fixture_function: None = ..., + *, + scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = ..., + params: Optional[Iterable[object]] = ..., + autouse: bool = ..., + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = ..., + name: Optional[str] = None, +) -> FixtureFunctionMarker: + ... + + +def fixture( + fixture_function: Optional[_FixtureFunction] = None, + *, + scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = "function", + params: Optional[Iterable[object]] = None, + autouse: bool = False, + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = None, + name: Optional[str] = None, +) -> Union[FixtureFunctionMarker, _FixtureFunction]: + """Decorator to mark a fixture factory function. + + This decorator can be used, with or without parameters, to define a + fixture function. + + The name of the fixture function can later be referenced to cause its + invocation ahead of running tests: test modules or classes can use the + ``pytest.mark.usefixtures(fixturename)`` marker. + + Test functions can directly use fixture names as input arguments in which + case the fixture instance returned from the fixture function will be + injected. + + Fixtures can provide their values to test functions using ``return`` or + ``yield`` statements. When using ``yield`` the code block after the + ``yield`` statement is executed as teardown code regardless of the test + outcome, and must yield exactly once. + + :param scope: + The scope for which this fixture is shared; one of ``"function"`` + (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``. + + This parameter may also be a callable which receives ``(fixture_name, config)`` + as parameters, and must return a ``str`` with one of the values mentioned above. + + See :ref:`dynamic scope` in the docs for more information. + + :param params: + An optional list of parameters which will cause multiple invocations + of the fixture function and all of the tests using it. The current + parameter is available in ``request.param``. + + :param autouse: + If True, the fixture func is activated for all tests that can see it. + If False (the default), an explicit reference is needed to activate + the fixture. + + :param ids: + List of string ids each corresponding to the params so that they are + part of the test id. If no ids are provided they will be generated + automatically from the params. + + :param name: + The name of the fixture. This defaults to the name of the decorated + function. If a fixture is used in the same module in which it is + defined, the function name of the fixture will be shadowed by the + function arg that requests the fixture; one way to resolve this is to + name the decorated function ``fixture_`` and then use + ``@pytest.fixture(name='')``. + """ + fixture_marker = FixtureFunctionMarker( + scope=scope, params=params, autouse=autouse, ids=ids, name=name, + ) + + # Direct decoration. + if fixture_function: + return fixture_marker(fixture_function) + + return fixture_marker + + +def yield_fixture( + fixture_function=None, + *args, + scope="function", + params=None, + autouse=False, + ids=None, + name=None, +): + """(Return a) decorator to mark a yield-fixture factory function. + + .. deprecated:: 3.0 + Use :py:func:`pytest.fixture` directly instead. + """ + warnings.warn(YIELD_FIXTURE, stacklevel=2) + return fixture( + fixture_function, + *args, + scope=scope, + params=params, + autouse=autouse, + ids=ids, + name=name, + ) + + +@fixture(scope="session") +def pytestconfig(request: FixtureRequest) -> Config: + """Session-scoped fixture that returns the :class:`_pytest.config.Config` object. + + Example:: + + def test_foo(pytestconfig): + if pytestconfig.getoption("verbose") > 0: + ... + + """ + return request.config + + +def pytest_addoption(parser: Parser) -> None: + parser.addini( + "usefixtures", + type="args", + default=[], + help="list of default fixtures to be used with this project", + ) + + +class FixtureManager: + """pytest fixture definitions and information is stored and managed + from this class. + + During collection fm.parsefactories() is called multiple times to parse + fixture function definitions into FixtureDef objects and internal + data structures. + + During collection of test functions, metafunc-mechanics instantiate + a FuncFixtureInfo object which is cached per node/func-name. + This FuncFixtureInfo object is later retrieved by Function nodes + which themselves offer a fixturenames attribute. + + The FuncFixtureInfo object holds information about fixtures and FixtureDefs + relevant for a particular function. An initial list of fixtures is + assembled like this: + + - ini-defined usefixtures + - autouse-marked fixtures along the collection chain up from the function + - usefixtures markers at module/class/function level + - test function funcargs + + Subsequently the funcfixtureinfo.fixturenames attribute is computed + as the closure of the fixtures needed to setup the initial fixtures, + i.e. fixtures needed by fixture functions themselves are appended + to the fixturenames list. + + Upon the test-setup phases all fixturenames are instantiated, retrieved + by a lookup of their FuncFixtureInfo. + """ + + FixtureLookupError = FixtureLookupError + FixtureLookupErrorRepr = FixtureLookupErrorRepr + + def __init__(self, session: "Session") -> None: + self.session = session + self.config: Config = session.config + self._arg2fixturedefs: Dict[str, List[FixtureDef[Any]]] = {} + self._holderobjseen: Set[object] = set() + # A mapping from a nodeid to a list of autouse fixtures it defines. + self._nodeid_autousenames: Dict[str, List[str]] = { + "": self.config.getini("usefixtures"), + } + session.config.pluginmanager.register(self, "funcmanage") + + def _get_direct_parametrize_args(self, node: nodes.Node) -> List[str]: + """Return all direct parametrization arguments of a node, so we don't + mistake them for fixtures. + + Check https://github.com/pytest-dev/pytest/issues/5036. + + These things are done later as well when dealing with parametrization + so this could be improved. + """ + parametrize_argnames: List[str] = [] + for marker in node.iter_markers(name="parametrize"): + if not marker.kwargs.get("indirect", False): + p_argnames, _ = ParameterSet._parse_parametrize_args( + *marker.args, **marker.kwargs + ) + parametrize_argnames.extend(p_argnames) + + return parametrize_argnames + + def getfixtureinfo( + self, node: nodes.Node, func, cls, funcargs: bool = True + ) -> FuncFixtureInfo: + if funcargs and not getattr(node, "nofuncargs", False): + argnames = getfuncargnames(func, name=node.name, cls=cls) + else: + argnames = () + + usefixtures = tuple( + arg for mark in node.iter_markers(name="usefixtures") for arg in mark.args + ) + initialnames = usefixtures + argnames + fm = node.session._fixturemanager + initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure( + initialnames, node, ignore_args=self._get_direct_parametrize_args(node) + ) + return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs) + + def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None: + nodeid = None + try: + p = absolutepath(plugin.__file__) # type: ignore[attr-defined] + except AttributeError: + pass + else: + # Construct the base nodeid which is later used to check + # what fixtures are visible for particular tests (as denoted + # by their test id). + if p.name.startswith("conftest.py"): + try: + nodeid = str(p.parent.relative_to(self.config.rootpath)) + except ValueError: + nodeid = "" + if nodeid == ".": + nodeid = "" + if os.sep != nodes.SEP: + nodeid = nodeid.replace(os.sep, nodes.SEP) + + self.parsefactories(plugin, nodeid) + + def _getautousenames(self, nodeid: str) -> Iterator[str]: + """Return the names of autouse fixtures applicable to nodeid.""" + for parentnodeid in nodes.iterparentnodeids(nodeid): + basenames = self._nodeid_autousenames.get(parentnodeid) + if basenames: + yield from basenames + + def getfixtureclosure( + self, + fixturenames: Tuple[str, ...], + parentnode: nodes.Node, + ignore_args: Sequence[str] = (), + ) -> Tuple[Tuple[str, ...], List[str], Dict[str, Sequence[FixtureDef[Any]]]]: + # Collect the closure of all fixtures, starting with the given + # fixturenames as the initial set. As we have to visit all + # factory definitions anyway, we also return an arg2fixturedefs + # mapping so that the caller can reuse it and does not have + # to re-discover fixturedefs again for each fixturename + # (discovering matching fixtures for a given name/node is expensive). + + parentid = parentnode.nodeid + fixturenames_closure = list(self._getautousenames(parentid)) + + def merge(otherlist: Iterable[str]) -> None: + for arg in otherlist: + if arg not in fixturenames_closure: + fixturenames_closure.append(arg) + + merge(fixturenames) + + # At this point, fixturenames_closure contains what we call "initialnames", + # which is a set of fixturenames the function immediately requests. We + # need to return it as well, so save this. + initialnames = tuple(fixturenames_closure) + + arg2fixturedefs: Dict[str, Sequence[FixtureDef[Any]]] = {} + lastlen = -1 + while lastlen != len(fixturenames_closure): + lastlen = len(fixturenames_closure) + for argname in fixturenames_closure: + if argname in ignore_args: + continue + if argname in arg2fixturedefs: + continue + fixturedefs = self.getfixturedefs(argname, parentid) + if fixturedefs: + arg2fixturedefs[argname] = fixturedefs + merge(fixturedefs[-1].argnames) + + def sort_by_scope(arg_name: str) -> int: + try: + fixturedefs = arg2fixturedefs[arg_name] + except KeyError: + return scopes.index("function") + else: + return fixturedefs[-1].scopenum + + fixturenames_closure.sort(key=sort_by_scope) + return initialnames, fixturenames_closure, arg2fixturedefs + + def pytest_generate_tests(self, metafunc: "Metafunc") -> None: + """Generate new tests based on parametrized fixtures used by the given metafunc""" + + def get_parametrize_mark_argnames(mark: Mark) -> Sequence[str]: + args, _ = ParameterSet._parse_parametrize_args(*mark.args, **mark.kwargs) + return args + + for argname in metafunc.fixturenames: + # Get the FixtureDefs for the argname. + fixture_defs = metafunc._arg2fixturedefs.get(argname) + if not fixture_defs: + # Will raise FixtureLookupError at setup time if not parametrized somewhere + # else (e.g @pytest.mark.parametrize) + continue + + # If the test itself parametrizes using this argname, give it + # precedence. + if any( + argname in get_parametrize_mark_argnames(mark) + for mark in metafunc.definition.iter_markers("parametrize") + ): + continue + + # In the common case we only look at the fixture def with the + # closest scope (last in the list). But if the fixture overrides + # another fixture, while requesting the super fixture, keep going + # in case the super fixture is parametrized (#1953). + for fixturedef in reversed(fixture_defs): + # Fixture is parametrized, apply it and stop. + if fixturedef.params is not None: + metafunc.parametrize( + argname, + fixturedef.params, + indirect=True, + scope=fixturedef.scope, + ids=fixturedef.ids, + ) + break + + # Not requesting the overridden super fixture, stop. + if argname not in fixturedef.argnames: + break + + # Try next super fixture, if any. + + def pytest_collection_modifyitems(self, items: List[nodes.Item]) -> None: + # Separate parametrized setups. + items[:] = reorder_items(items) + + def parsefactories( + self, node_or_obj, nodeid=NOTSET, unittest: bool = False + ) -> None: + if nodeid is not NOTSET: + holderobj = node_or_obj + else: + holderobj = node_or_obj.obj + nodeid = node_or_obj.nodeid + if holderobj in self._holderobjseen: + return + + self._holderobjseen.add(holderobj) + autousenames = [] + for name in dir(holderobj): + # The attribute can be an arbitrary descriptor, so the attribute + # access below can raise. safe_getatt() ignores such exceptions. + obj = safe_getattr(holderobj, name, None) + marker = getfixturemarker(obj) + if not isinstance(marker, FixtureFunctionMarker): + # Magic globals with __getattr__ might have got us a wrong + # fixture attribute. + continue + + if marker.name: + name = marker.name + + # During fixture definition we wrap the original fixture function + # to issue a warning if called directly, so here we unwrap it in + # order to not emit the warning when pytest itself calls the + # fixture function. + obj = get_real_method(obj, holderobj) + + fixture_def = FixtureDef( + fixturemanager=self, + baseid=nodeid, + argname=name, + func=obj, + scope=marker.scope, + params=marker.params, + unittest=unittest, + ids=marker.ids, + ) + + faclist = self._arg2fixturedefs.setdefault(name, []) + if fixture_def.has_location: + faclist.append(fixture_def) + else: + # fixturedefs with no location are at the front + # so this inserts the current fixturedef after the + # existing fixturedefs from external plugins but + # before the fixturedefs provided in conftests. + i = len([f for f in faclist if not f.has_location]) + faclist.insert(i, fixture_def) + if marker.autouse: + autousenames.append(name) + + if autousenames: + self._nodeid_autousenames.setdefault(nodeid or "", []).extend(autousenames) + + def getfixturedefs( + self, argname: str, nodeid: str + ) -> Optional[Sequence[FixtureDef[Any]]]: + """Get a list of fixtures which are applicable to the given node id. + + :param str argname: Name of the fixture to search for. + :param str nodeid: Full node id of the requesting test. + :rtype: Sequence[FixtureDef] + """ + try: + fixturedefs = self._arg2fixturedefs[argname] + except KeyError: + return None + return tuple(self._matchfactories(fixturedefs, nodeid)) + + def _matchfactories( + self, fixturedefs: Iterable[FixtureDef[Any]], nodeid: str + ) -> Iterator[FixtureDef[Any]]: + parentnodeids = set(nodes.iterparentnodeids(nodeid)) + for fixturedef in fixturedefs: + if fixturedef.baseid in parentnodeids: + yield fixturedef diff --git a/myenv/lib/python3.9/site-packages/_pytest/freeze_support.py b/myenv/lib/python3.9/site-packages/_pytest/freeze_support.py new file mode 100644 index 0000000..8b93ed5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/freeze_support.py @@ -0,0 +1,45 @@ +"""Provides a function to report all internal modules for using freezing +tools.""" +import types +from typing import Iterator +from typing import List +from typing import Union + + +def freeze_includes() -> List[str]: + """Return a list of module names used by pytest that should be + included by cx_freeze.""" + import py + import _pytest + + result = list(_iter_all_modules(py)) + result += list(_iter_all_modules(_pytest)) + return result + + +def _iter_all_modules( + package: Union[str, types.ModuleType], prefix: str = "", +) -> Iterator[str]: + """Iterate over the names of all modules that can be found in the given + package, recursively. + + >>> import _pytest + >>> list(_iter_all_modules(_pytest)) + ['_pytest._argcomplete', '_pytest._code.code', ...] + """ + import os + import pkgutil + + if isinstance(package, str): + path = package + else: + # Type ignored because typeshed doesn't define ModuleType.__path__ + # (only defined on packages). + package_path = package.__path__ # type: ignore[attr-defined] + path, prefix = package_path[0], package.__name__ + "." + for _, name, is_package in pkgutil.iter_modules([path]): + if is_package: + for m in _iter_all_modules(os.path.join(path, name), prefix=name + "."): + yield prefix + m + else: + yield prefix + name diff --git a/myenv/lib/python3.9/site-packages/_pytest/helpconfig.py b/myenv/lib/python3.9/site-packages/_pytest/helpconfig.py new file mode 100644 index 0000000..4384d07 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/helpconfig.py @@ -0,0 +1,261 @@ +"""Version info, help messages, tracing configuration.""" +import os +import sys +from argparse import Action +from typing import List +from typing import Optional +from typing import Union + +import py + +import pytest +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import PrintHelp +from _pytest.config.argparsing import Parser + + +class HelpAction(Action): + """An argparse Action that will raise an exception in order to skip the + rest of the argument parsing when --help is passed. + + This prevents argparse from quitting due to missing required arguments + when any are defined, for example by ``pytest_addoption``. + This is similar to the way that the builtin argparse --help option is + implemented by raising SystemExit. + """ + + def __init__(self, option_strings, dest=None, default=False, help=None): + super().__init__( + option_strings=option_strings, + dest=dest, + const=True, + default=default, + nargs=0, + help=help, + ) + + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, self.const) + + # We should only skip the rest of the parsing after preparse is done. + if getattr(parser._parser, "after_preparse", False): + raise PrintHelp + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--version", + "-V", + action="count", + default=0, + dest="version", + help="display pytest version and information about plugins." + "When given twice, also display information about plugins.", + ) + group._addoption( + "-h", + "--help", + action=HelpAction, + dest="help", + help="show help message and configuration info", + ) + group._addoption( + "-p", + action="append", + dest="plugins", + default=[], + metavar="name", + help="early-load given plugin module name or entry point (multi-allowed).\n" + "To avoid loading of plugins, use the `no:` prefix, e.g. " + "`no:doctest`.", + ) + group.addoption( + "--traceconfig", + "--trace-config", + action="store_true", + default=False, + help="trace considerations of conftest.py files.", + ) + group.addoption( + "--debug", + action="store_true", + dest="debug", + default=False, + help="store internal tracing debug information in 'pytestdebug.log'.", + ) + group._addoption( + "-o", + "--override-ini", + dest="override_ini", + action="append", + help='override ini option with "option=value" style, e.g. `-o xfail_strict=True -o cache_dir=cache`.', + ) + + +@pytest.hookimpl(hookwrapper=True) +def pytest_cmdline_parse(): + outcome = yield + config: Config = outcome.get_result() + if config.option.debug: + path = os.path.abspath("pytestdebug.log") + debugfile = open(path, "w") + debugfile.write( + "versions pytest-%s, py-%s, " + "python-%s\ncwd=%s\nargs=%s\n\n" + % ( + pytest.__version__, + py.__version__, + ".".join(map(str, sys.version_info)), + os.getcwd(), + config.invocation_params.args, + ) + ) + config.trace.root.setwriter(debugfile.write) + undo_tracing = config.pluginmanager.enable_tracing() + sys.stderr.write("writing pytestdebug information to %s\n" % path) + + def unset_tracing() -> None: + debugfile.close() + sys.stderr.write("wrote pytestdebug information to %s\n" % debugfile.name) + config.trace.root.setwriter(None) + undo_tracing() + + config.add_cleanup(unset_tracing) + + +def showversion(config: Config) -> None: + if config.option.version > 1: + sys.stderr.write( + "This is pytest version {}, imported from {}\n".format( + pytest.__version__, pytest.__file__ + ) + ) + plugininfo = getpluginversioninfo(config) + if plugininfo: + for line in plugininfo: + sys.stderr.write(line + "\n") + else: + sys.stderr.write(f"pytest {pytest.__version__}\n") + + +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.version > 0: + showversion(config) + return 0 + elif config.option.help: + config._do_configure() + showhelp(config) + config._ensure_unconfigure() + return 0 + return None + + +def showhelp(config: Config) -> None: + import textwrap + + reporter = config.pluginmanager.get_plugin("terminalreporter") + tw = reporter._tw + tw.write(config._parser.optparser.format_help()) + tw.line() + tw.line( + "[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:" + ) + tw.line() + + columns = tw.fullwidth # costly call + indent_len = 24 # based on argparse's max_help_position=24 + indent = " " * indent_len + for name in config._parser._ininames: + help, type, default = config._parser._inidict[name] + if type is None: + type = "string" + if help is None: + raise TypeError(f"help argument cannot be None for {name}") + spec = f"{name} ({type}):" + tw.write(" %s" % spec) + spec_len = len(spec) + if spec_len > (indent_len - 3): + # Display help starting at a new line. + tw.line() + helplines = textwrap.wrap( + help, + columns, + initial_indent=indent, + subsequent_indent=indent, + break_on_hyphens=False, + ) + + for line in helplines: + tw.line(line) + else: + # Display help starting after the spec, following lines indented. + tw.write(" " * (indent_len - spec_len - 2)) + wrapped = textwrap.wrap(help, columns - indent_len, break_on_hyphens=False) + + if wrapped: + tw.line(wrapped[0]) + for line in wrapped[1:]: + tw.line(indent + line) + + tw.line() + tw.line("environment variables:") + vars = [ + ("PYTEST_ADDOPTS", "extra command line options"), + ("PYTEST_PLUGINS", "comma-separated plugins to load during startup"), + ("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "set to disable plugin auto-loading"), + ("PYTEST_DEBUG", "set to enable debug tracing of pytest's internals"), + ] + for name, help in vars: + tw.line(f" {name:<24} {help}") + tw.line() + tw.line() + + tw.line("to see available markers type: pytest --markers") + tw.line("to see available fixtures type: pytest --fixtures") + tw.line( + "(shown according to specified file_or_dir or current dir " + "if not specified; fixtures with leading '_' are only shown " + "with the '-v' option" + ) + + for warningreport in reporter.stats.get("warnings", []): + tw.line("warning : " + warningreport.message, red=True) + return + + +conftest_options = [("pytest_plugins", "list of plugin names to load")] + + +def getpluginversioninfo(config: Config) -> List[str]: + lines = [] + plugininfo = config.pluginmanager.list_plugin_distinfo() + if plugininfo: + lines.append("setuptools registered plugins:") + for plugin, dist in plugininfo: + loc = getattr(plugin, "__file__", repr(plugin)) + content = f"{dist.project_name}-{dist.version} at {loc}" + lines.append(" " + content) + return lines + + +def pytest_report_header(config: Config) -> List[str]: + lines = [] + if config.option.debug or config.option.traceconfig: + lines.append(f"using: pytest-{pytest.__version__} pylib-{py.__version__}") + + verinfo = getpluginversioninfo(config) + if verinfo: + lines.extend(verinfo) + + if config.option.traceconfig: + lines.append("active plugins:") + items = config.pluginmanager.list_name_plugin() + for name, plugin in items: + if hasattr(plugin, "__file__"): + r = plugin.__file__ + else: + r = repr(plugin) + lines.append(f" {name:<20}: {r}") + return lines diff --git a/myenv/lib/python3.9/site-packages/_pytest/hookspec.py b/myenv/lib/python3.9/site-packages/_pytest/hookspec.py new file mode 100644 index 0000000..e499b74 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/hookspec.py @@ -0,0 +1,891 @@ +"""Hook specifications for pytest plugins which are invoked by pytest itself +and by builtin plugins.""" +from typing import Any +from typing import Dict +from typing import List +from typing import Mapping +from typing import Optional +from typing import Sequence +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import py.path +from pluggy import HookspecMarker + +from _pytest.deprecated import WARNING_CAPTURED_HOOK + +if TYPE_CHECKING: + import pdb + import warnings + from typing_extensions import Literal + + from _pytest._code.code import ExceptionRepr + from _pytest.code import ExceptionInfo + from _pytest.config import Config + from _pytest.config import ExitCode + from _pytest.config import PytestPluginManager + from _pytest.config import _PluggyPlugin + from _pytest.config.argparsing import Parser + from _pytest.fixtures import FixtureDef + from _pytest.fixtures import SubRequest + from _pytest.main import Session + from _pytest.nodes import Collector + from _pytest.nodes import Item + from _pytest.outcomes import Exit + from _pytest.python import Function + from _pytest.python import Metafunc + from _pytest.python import Module + from _pytest.python import PyCollector + from _pytest.reports import CollectReport + from _pytest.reports import TestReport + from _pytest.runner import CallInfo + from _pytest.terminal import TerminalReporter + + +hookspec = HookspecMarker("pytest") + +# ------------------------------------------------------------------------- +# Initialization hooks called for every plugin +# ------------------------------------------------------------------------- + + +@hookspec(historic=True) +def pytest_addhooks(pluginmanager: "PytestPluginManager") -> None: + """Called at plugin registration time to allow adding new hooks via a call to + ``pluginmanager.add_hookspecs(module_or_class, prefix)``. + + :param _pytest.config.PytestPluginManager pluginmanager: pytest plugin manager. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + """ + + +@hookspec(historic=True) +def pytest_plugin_registered( + plugin: "_PluggyPlugin", manager: "PytestPluginManager" +) -> None: + """A new pytest plugin got registered. + + :param plugin: The plugin module or instance. + :param _pytest.config.PytestPluginManager manager: pytest plugin manager. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + """ + + +@hookspec(historic=True) +def pytest_addoption(parser: "Parser", pluginmanager: "PytestPluginManager") -> None: + """Register argparse-style options and ini-style config values, + called once at the beginning of a test run. + + .. note:: + + This function should be implemented only in plugins or ``conftest.py`` + files situated at the tests root directory due to how pytest + :ref:`discovers plugins during startup `. + + :param _pytest.config.argparsing.Parser parser: + To add command line options, call + :py:func:`parser.addoption(...) <_pytest.config.argparsing.Parser.addoption>`. + To add ini-file values call :py:func:`parser.addini(...) + <_pytest.config.argparsing.Parser.addini>`. + + :param _pytest.config.PytestPluginManager pluginmanager: + pytest plugin manager, which can be used to install :py:func:`hookspec`'s + or :py:func:`hookimpl`'s and allow one plugin to call another plugin's hooks + to change how command line options are added. + + Options can later be accessed through the + :py:class:`config <_pytest.config.Config>` object, respectively: + + - :py:func:`config.getoption(name) <_pytest.config.Config.getoption>` to + retrieve the value of a command line option. + + - :py:func:`config.getini(name) <_pytest.config.Config.getini>` to retrieve + a value read from an ini-style file. + + The config object is passed around on many internal objects via the ``.config`` + attribute or can be retrieved as the ``pytestconfig`` fixture. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + """ + + +@hookspec(historic=True) +def pytest_configure(config: "Config") -> None: + """Allow plugins and conftest files to perform initial configuration. + + This hook is called for every plugin and initial conftest file + after command line options have been parsed. + + After that, the hook is called for other conftest files as they are + imported. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + + :param _pytest.config.Config config: The pytest config object. + """ + + +# ------------------------------------------------------------------------- +# Bootstrapping hooks called for plugins registered early enough: +# internal and 3rd party plugins. +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_cmdline_parse( + pluginmanager: "PytestPluginManager", args: List[str] +) -> Optional["Config"]: + """Return an initialized config object, parsing the specified args. + + Stops at first non-None result, see :ref:`firstresult`. + + .. note:: + This hook will only be called for plugin classes passed to the + ``plugins`` arg when using `pytest.main`_ to perform an in-process + test run. + + :param _pytest.config.PytestPluginManager pluginmanager: Pytest plugin manager. + :param List[str] args: List of arguments passed on the command line. + """ + + +def pytest_cmdline_preparse(config: "Config", args: List[str]) -> None: + """(**Deprecated**) modify command line arguments before option parsing. + + This hook is considered deprecated and will be removed in a future pytest version. Consider + using :func:`pytest_load_initial_conftests` instead. + + .. note:: + This hook will not be called for ``conftest.py`` files, only for setuptools plugins. + + :param _pytest.config.Config config: The pytest config object. + :param List[str] args: Arguments passed on the command line. + """ + + +@hookspec(firstresult=True) +def pytest_cmdline_main(config: "Config") -> Optional[Union["ExitCode", int]]: + """Called for performing the main command line action. The default + implementation will invoke the configure hooks and runtest_mainloop. + + .. note:: + This hook will not be called for ``conftest.py`` files, only for setuptools plugins. + + Stops at first non-None result, see :ref:`firstresult`. + + :param _pytest.config.Config config: The pytest config object. + """ + + +def pytest_load_initial_conftests( + early_config: "Config", parser: "Parser", args: List[str] +) -> None: + """Called to implement the loading of initial conftest files ahead + of command line option parsing. + + .. note:: + This hook will not be called for ``conftest.py`` files, only for setuptools plugins. + + :param _pytest.config.Config early_config: The pytest config object. + :param List[str] args: Arguments passed on the command line. + :param _pytest.config.argparsing.Parser parser: To add command line options. + """ + + +# ------------------------------------------------------------------------- +# collection hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_collection(session: "Session") -> Optional[object]: + """Perform the collection phase for the given session. + + Stops at first non-None result, see :ref:`firstresult`. + The return value is not used, but only stops further processing. + + The default collection phase is this (see individual hooks for full details): + + 1. Starting from ``session`` as the initial collector: + + 1. ``pytest_collectstart(collector)`` + 2. ``report = pytest_make_collect_report(collector)`` + 3. ``pytest_exception_interact(collector, call, report)`` if an interactive exception occurred + 4. For each collected node: + + 1. If an item, ``pytest_itemcollected(item)`` + 2. If a collector, recurse into it. + + 5. ``pytest_collectreport(report)`` + + 2. ``pytest_collection_modifyitems(session, config, items)`` + + 1. ``pytest_deselected(items)`` for any deselected items (may be called multiple times) + + 3. ``pytest_collection_finish(session)`` + 4. Set ``session.items`` to the list of collected items + 5. Set ``session.testscollected`` to the number of collected items + + You can implement this hook to only perform some action before collection, + for example the terminal plugin uses it to start displaying the collection + counter (and returns `None`). + + :param pytest.Session session: The pytest session object. + """ + + +def pytest_collection_modifyitems( + session: "Session", config: "Config", items: List["Item"] +) -> None: + """Called after collection has been performed. May filter or re-order + the items in-place. + + :param pytest.Session session: The pytest session object. + :param _pytest.config.Config config: The pytest config object. + :param List[pytest.Item] items: List of item objects. + """ + + +def pytest_collection_finish(session: "Session") -> None: + """Called after collection has been performed and modified. + + :param pytest.Session session: The pytest session object. + """ + + +@hookspec(firstresult=True) +def pytest_ignore_collect(path: py.path.local, config: "Config") -> Optional[bool]: + """Return True to prevent considering this path for collection. + + This hook is consulted for all files and directories prior to calling + more specific hooks. + + Stops at first non-None result, see :ref:`firstresult`. + + :param py.path.local path: The path to analyze. + :param _pytest.config.Config config: The pytest config object. + """ + + +def pytest_collect_file( + path: py.path.local, parent: "Collector" +) -> "Optional[Collector]": + """Create a Collector for the given path, or None if not relevant. + + The new node needs to have the specified ``parent`` as a parent. + + :param py.path.local path: The path to collect. + """ + + +# logging hooks for collection + + +def pytest_collectstart(collector: "Collector") -> None: + """Collector starts collecting.""" + + +def pytest_itemcollected(item: "Item") -> None: + """We just collected a test item.""" + + +def pytest_collectreport(report: "CollectReport") -> None: + """Collector finished collecting.""" + + +def pytest_deselected(items: Sequence["Item"]) -> None: + """Called for deselected test items, e.g. by keyword. + + May be called multiple times. + """ + + +@hookspec(firstresult=True) +def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectReport]": + """Perform ``collector.collect()`` and return a CollectReport. + + Stops at first non-None result, see :ref:`firstresult`. + """ + + +# ------------------------------------------------------------------------- +# Python test function related hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_pycollect_makemodule(path: py.path.local, parent) -> Optional["Module"]: + """Return a Module collector or None for the given path. + + This hook will be called for each matching test module path. + The pytest_collect_file hook needs to be used if you want to + create test modules for files that do not match as a test module. + + Stops at first non-None result, see :ref:`firstresult`. + + :param py.path.local path: The path of module to collect. + """ + + +@hookspec(firstresult=True) +def pytest_pycollect_makeitem( + collector: "PyCollector", name: str, obj: object +) -> Union[None, "Item", "Collector", List[Union["Item", "Collector"]]]: + """Return a custom item/collector for a Python object in a module, or None. + + Stops at first non-None result, see :ref:`firstresult`. + """ + + +@hookspec(firstresult=True) +def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: + """Call underlying test function. + + Stops at first non-None result, see :ref:`firstresult`. + """ + + +def pytest_generate_tests(metafunc: "Metafunc") -> None: + """Generate (multiple) parametrized calls to a test function.""" + + +@hookspec(firstresult=True) +def pytest_make_parametrize_id( + config: "Config", val: object, argname: str +) -> Optional[str]: + """Return a user-friendly string representation of the given ``val`` + that will be used by @pytest.mark.parametrize calls, or None if the hook + doesn't know about ``val``. + + The parameter name is available as ``argname``, if required. + + Stops at first non-None result, see :ref:`firstresult`. + + :param _pytest.config.Config config: The pytest config object. + :param val: The parametrized value. + :param str argname: The automatic parameter name produced by pytest. + """ + + +# ------------------------------------------------------------------------- +# runtest related hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_runtestloop(session: "Session") -> Optional[object]: + """Perform the main runtest loop (after collection finished). + + The default hook implementation performs the runtest protocol for all items + collected in the session (``session.items``), unless the collection failed + or the ``collectonly`` pytest option is set. + + If at any point :py:func:`pytest.exit` is called, the loop is + terminated immediately. + + If at any point ``session.shouldfail`` or ``session.shouldstop`` are set, the + loop is terminated after the runtest protocol for the current item is finished. + + :param pytest.Session session: The pytest session object. + + Stops at first non-None result, see :ref:`firstresult`. + The return value is not used, but only stops further processing. + """ + + +@hookspec(firstresult=True) +def pytest_runtest_protocol( + item: "Item", nextitem: "Optional[Item]" +) -> Optional[object]: + """Perform the runtest protocol for a single test item. + + The default runtest protocol is this (see individual hooks for full details): + + - ``pytest_runtest_logstart(nodeid, location)`` + + - Setup phase: + - ``call = pytest_runtest_setup(item)`` (wrapped in ``CallInfo(when="setup")``) + - ``report = pytest_runtest_makereport(item, call)`` + - ``pytest_runtest_logreport(report)`` + - ``pytest_exception_interact(call, report)`` if an interactive exception occurred + + - Call phase, if the the setup passed and the ``setuponly`` pytest option is not set: + - ``call = pytest_runtest_call(item)`` (wrapped in ``CallInfo(when="call")``) + - ``report = pytest_runtest_makereport(item, call)`` + - ``pytest_runtest_logreport(report)`` + - ``pytest_exception_interact(call, report)`` if an interactive exception occurred + + - Teardown phase: + - ``call = pytest_runtest_teardown(item, nextitem)`` (wrapped in ``CallInfo(when="teardown")``) + - ``report = pytest_runtest_makereport(item, call)`` + - ``pytest_runtest_logreport(report)`` + - ``pytest_exception_interact(call, report)`` if an interactive exception occurred + + - ``pytest_runtest_logfinish(nodeid, location)`` + + :param item: Test item for which the runtest protocol is performed. + :param nextitem: The scheduled-to-be-next test item (or None if this is the end my friend). + + Stops at first non-None result, see :ref:`firstresult`. + The return value is not used, but only stops further processing. + """ + + +def pytest_runtest_logstart( + nodeid: str, location: Tuple[str, Optional[int], str] +) -> None: + """Called at the start of running the runtest protocol for a single item. + + See :func:`pytest_runtest_protocol` for a description of the runtest protocol. + + :param str nodeid: Full node ID of the item. + :param location: A tuple of ``(filename, lineno, testname)``. + """ + + +def pytest_runtest_logfinish( + nodeid: str, location: Tuple[str, Optional[int], str] +) -> None: + """Called at the end of running the runtest protocol for a single item. + + See :func:`pytest_runtest_protocol` for a description of the runtest protocol. + + :param str nodeid: Full node ID of the item. + :param location: A tuple of ``(filename, lineno, testname)``. + """ + + +def pytest_runtest_setup(item: "Item") -> None: + """Called to perform the setup phase for a test item. + + The default implementation runs ``setup()`` on ``item`` and all of its + parents (which haven't been setup yet). This includes obtaining the + values of fixtures required by the item (which haven't been obtained + yet). + """ + + +def pytest_runtest_call(item: "Item") -> None: + """Called to run the test for test item (the call phase). + + The default implementation calls ``item.runtest()``. + """ + + +def pytest_runtest_teardown(item: "Item", nextitem: Optional["Item"]) -> None: + """Called to perform the teardown phase for a test item. + + The default implementation runs the finalizers and calls ``teardown()`` + on ``item`` and all of its parents (which need to be torn down). This + includes running the teardown phase of fixtures required by the item (if + they go out of scope). + + :param nextitem: + The scheduled-to-be-next test item (None if no further test item is + scheduled). This argument can be used to perform exact teardowns, + i.e. calling just enough finalizers so that nextitem only needs to + call setup-functions. + """ + + +@hookspec(firstresult=True) +def pytest_runtest_makereport( + item: "Item", call: "CallInfo[None]" +) -> Optional["TestReport"]: + """Called to create a :py:class:`_pytest.reports.TestReport` for each of + the setup, call and teardown runtest phases of a test item. + + See :func:`pytest_runtest_protocol` for a description of the runtest protocol. + + :param CallInfo[None] call: The ``CallInfo`` for the phase. + + Stops at first non-None result, see :ref:`firstresult`. + """ + + +def pytest_runtest_logreport(report: "TestReport") -> None: + """Process the :py:class:`_pytest.reports.TestReport` produced for each + of the setup, call and teardown runtest phases of an item. + + See :func:`pytest_runtest_protocol` for a description of the runtest protocol. + """ + + +@hookspec(firstresult=True) +def pytest_report_to_serializable( + config: "Config", report: Union["CollectReport", "TestReport"], +) -> Optional[Dict[str, Any]]: + """Serialize the given report object into a data structure suitable for + sending over the wire, e.g. converted to JSON.""" + + +@hookspec(firstresult=True) +def pytest_report_from_serializable( + config: "Config", data: Dict[str, Any], +) -> Optional[Union["CollectReport", "TestReport"]]: + """Restore a report object previously serialized with pytest_report_to_serializable().""" + + +# ------------------------------------------------------------------------- +# Fixture related hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_fixture_setup( + fixturedef: "FixtureDef[Any]", request: "SubRequest" +) -> Optional[object]: + """Perform fixture setup execution. + + :returns: The return value of the call to the fixture function. + + Stops at first non-None result, see :ref:`firstresult`. + + .. note:: + If the fixture function returns None, other implementations of + this hook function will continue to be called, according to the + behavior of the :ref:`firstresult` option. + """ + + +def pytest_fixture_post_finalizer( + fixturedef: "FixtureDef[Any]", request: "SubRequest" +) -> None: + """Called after fixture teardown, but before the cache is cleared, so + the fixture result ``fixturedef.cached_result`` is still available (not + ``None``).""" + + +# ------------------------------------------------------------------------- +# test session related hooks +# ------------------------------------------------------------------------- + + +def pytest_sessionstart(session: "Session") -> None: + """Called after the ``Session`` object has been created and before performing collection + and entering the run test loop. + + :param pytest.Session session: The pytest session object. + """ + + +def pytest_sessionfinish( + session: "Session", exitstatus: Union[int, "ExitCode"], +) -> None: + """Called after whole test run finished, right before returning the exit status to the system. + + :param pytest.Session session: The pytest session object. + :param int exitstatus: The status which pytest will return to the system. + """ + + +def pytest_unconfigure(config: "Config") -> None: + """Called before test process is exited. + + :param _pytest.config.Config config: The pytest config object. + """ + + +# ------------------------------------------------------------------------- +# hooks for customizing the assert methods +# ------------------------------------------------------------------------- + + +def pytest_assertrepr_compare( + config: "Config", op: str, left: object, right: object +) -> Optional[List[str]]: + """Return explanation for comparisons in failing assert expressions. + + Return None for no custom explanation, otherwise return a list + of strings. The strings will be joined by newlines but any newlines + *in* a string will be escaped. Note that all but the first line will + be indented slightly, the intention is for the first line to be a summary. + + :param _pytest.config.Config config: The pytest config object. + """ + + +def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> None: + """**(Experimental)** Called whenever an assertion passes. + + .. versionadded:: 5.0 + + Use this hook to do some processing after a passing assertion. + The original assertion information is available in the `orig` string + and the pytest introspected assertion information is available in the + `expl` string. + + This hook must be explicitly enabled by the ``enable_assertion_pass_hook`` + ini-file option: + + .. code-block:: ini + + [pytest] + enable_assertion_pass_hook=true + + You need to **clean the .pyc** files in your project directory and interpreter libraries + when enabling this option, as assertions will require to be re-written. + + :param pytest.Item item: pytest item object of current test. + :param int lineno: Line number of the assert statement. + :param str orig: String with the original assertion. + :param str expl: String with the assert explanation. + + .. note:: + + This hook is **experimental**, so its parameters or even the hook itself might + be changed/removed without warning in any future pytest release. + + If you find this hook useful, please share your feedback in an issue. + """ + + +# ------------------------------------------------------------------------- +# Hooks for influencing reporting (invoked from _pytest_terminal). +# ------------------------------------------------------------------------- + + +def pytest_report_header( + config: "Config", startdir: py.path.local +) -> Union[str, List[str]]: + """Return a string or list of strings to be displayed as header info for terminal reporting. + + :param _pytest.config.Config config: The pytest config object. + :param py.path.local startdir: The starting dir. + + .. note:: + + Lines returned by a plugin are displayed before those of plugins which + ran before it. + If you want to have your line(s) displayed first, use + :ref:`trylast=True `. + + .. note:: + + This function should be implemented only in plugins or ``conftest.py`` + files situated at the tests root directory due to how pytest + :ref:`discovers plugins during startup `. + """ + + +def pytest_report_collectionfinish( + config: "Config", startdir: py.path.local, items: Sequence["Item"], +) -> Union[str, List[str]]: + """Return a string or list of strings to be displayed after collection + has finished successfully. + + These strings will be displayed after the standard "collected X items" message. + + .. versionadded:: 3.2 + + :param _pytest.config.Config config: The pytest config object. + :param py.path.local startdir: The starting dir. + :param items: List of pytest items that are going to be executed; this list should not be modified. + + .. note:: + + Lines returned by a plugin are displayed before those of plugins which + ran before it. + If you want to have your line(s) displayed first, use + :ref:`trylast=True `. + """ + + +@hookspec(firstresult=True) +def pytest_report_teststatus( + report: Union["CollectReport", "TestReport"], config: "Config" +) -> Tuple[ + str, str, Union[str, Mapping[str, bool]], +]: + """Return result-category, shortletter and verbose word for status + reporting. + + The result-category is a category in which to count the result, for + example "passed", "skipped", "error" or the empty string. + + The shortletter is shown as testing progresses, for example ".", "s", + "E" or the empty string. + + The verbose word is shown as testing progresses in verbose mode, for + example "PASSED", "SKIPPED", "ERROR" or the empty string. + + pytest may style these implicitly according to the report outcome. + To provide explicit styling, return a tuple for the verbose word, + for example ``"rerun", "R", ("RERUN", {"yellow": True})``. + + :param report: The report object whose status is to be returned. + :param _pytest.config.Config config: The pytest config object. + + Stops at first non-None result, see :ref:`firstresult`. + """ + + +def pytest_terminal_summary( + terminalreporter: "TerminalReporter", exitstatus: "ExitCode", config: "Config", +) -> None: + """Add a section to terminal summary reporting. + + :param _pytest.terminal.TerminalReporter terminalreporter: The internal terminal reporter object. + :param int exitstatus: The exit status that will be reported back to the OS. + :param _pytest.config.Config config: The pytest config object. + + .. versionadded:: 4.2 + The ``config`` parameter. + """ + + +@hookspec(historic=True, warn_on_impl=WARNING_CAPTURED_HOOK) +def pytest_warning_captured( + warning_message: "warnings.WarningMessage", + when: "Literal['config', 'collect', 'runtest']", + item: Optional["Item"], + location: Optional[Tuple[str, int, str]], +) -> None: + """(**Deprecated**) Process a warning captured by the internal pytest warnings plugin. + + .. deprecated:: 6.0 + + This hook is considered deprecated and will be removed in a future pytest version. + Use :func:`pytest_warning_recorded` instead. + + :param warnings.WarningMessage warning_message: + The captured warning. This is the same object produced by :py:func:`warnings.catch_warnings`, and contains + the same attributes as the parameters of :py:func:`warnings.showwarning`. + + :param str when: + Indicates when the warning was captured. Possible values: + + * ``"config"``: during pytest configuration/initialization stage. + * ``"collect"``: during test collection. + * ``"runtest"``: during test execution. + + :param pytest.Item|None item: + The item being executed if ``when`` is ``"runtest"``, otherwise ``None``. + + :param tuple location: + When available, holds information about the execution context of the captured + warning (filename, linenumber, function). ``function`` evaluates to + when the execution context is at the module level. + """ + + +@hookspec(historic=True) +def pytest_warning_recorded( + warning_message: "warnings.WarningMessage", + when: "Literal['config', 'collect', 'runtest']", + nodeid: str, + location: Optional[Tuple[str, int, str]], +) -> None: + """Process a warning captured by the internal pytest warnings plugin. + + :param warnings.WarningMessage warning_message: + The captured warning. This is the same object produced by :py:func:`warnings.catch_warnings`, and contains + the same attributes as the parameters of :py:func:`warnings.showwarning`. + + :param str when: + Indicates when the warning was captured. Possible values: + + * ``"config"``: during pytest configuration/initialization stage. + * ``"collect"``: during test collection. + * ``"runtest"``: during test execution. + + :param str nodeid: + Full id of the item. + + :param tuple|None location: + When available, holds information about the execution context of the captured + warning (filename, linenumber, function). ``function`` evaluates to + when the execution context is at the module level. + + .. versionadded:: 6.0 + """ + + +# ------------------------------------------------------------------------- +# Hooks for influencing skipping +# ------------------------------------------------------------------------- + + +def pytest_markeval_namespace(config: "Config") -> Dict[str, Any]: + """Called when constructing the globals dictionary used for + evaluating string conditions in xfail/skipif markers. + + This is useful when the condition for a marker requires + objects that are expensive or impossible to obtain during + collection time, which is required by normal boolean + conditions. + + .. versionadded:: 6.2 + + :param _pytest.config.Config config: The pytest config object. + :returns: A dictionary of additional globals to add. + """ + + +# ------------------------------------------------------------------------- +# error handling and internal debugging hooks +# ------------------------------------------------------------------------- + + +def pytest_internalerror( + excrepr: "ExceptionRepr", excinfo: "ExceptionInfo[BaseException]", +) -> Optional[bool]: + """Called for internal errors. + + Return True to suppress the fallback handling of printing an + INTERNALERROR message directly to sys.stderr. + """ + + +def pytest_keyboard_interrupt( + excinfo: "ExceptionInfo[Union[KeyboardInterrupt, Exit]]", +) -> None: + """Called for keyboard interrupt.""" + + +def pytest_exception_interact( + node: Union["Item", "Collector"], + call: "CallInfo[Any]", + report: Union["CollectReport", "TestReport"], +) -> None: + """Called when an exception was raised which can potentially be + interactively handled. + + May be called during collection (see :py:func:`pytest_make_collect_report`), + in which case ``report`` is a :py:class:`_pytest.reports.CollectReport`. + + May be called during runtest of an item (see :py:func:`pytest_runtest_protocol`), + in which case ``report`` is a :py:class:`_pytest.reports.TestReport`. + + This hook is not called if the exception that was raised is an internal + exception like ``skip.Exception``. + """ + + +def pytest_enter_pdb(config: "Config", pdb: "pdb.Pdb") -> None: + """Called upon pdb.set_trace(). + + Can be used by plugins to take special action just before the python + debugger enters interactive mode. + + :param _pytest.config.Config config: The pytest config object. + :param pdb.Pdb pdb: The Pdb instance. + """ + + +def pytest_leave_pdb(config: "Config", pdb: "pdb.Pdb") -> None: + """Called when leaving pdb (e.g. with continue after pdb.set_trace()). + + Can be used by plugins to take special action just after the python + debugger leaves interactive mode. + + :param _pytest.config.Config config: The pytest config object. + :param pdb.Pdb pdb: The Pdb instance. + """ diff --git a/myenv/lib/python3.9/site-packages/_pytest/junitxml.py b/myenv/lib/python3.9/site-packages/_pytest/junitxml.py new file mode 100644 index 0000000..c4761cd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/junitxml.py @@ -0,0 +1,700 @@ +"""Report test results in JUnit-XML format, for use with Jenkins and build +integration servers. + +Based on initial code from Ross Lawley. + +Output conforms to +https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd +""" +import functools +import os +import platform +import re +import xml.etree.ElementTree as ET +from datetime import datetime +from typing import Callable +from typing import Dict +from typing import List +from typing import Match +from typing import Optional +from typing import Tuple +from typing import Union + +import pytest +from _pytest import nodes +from _pytest import timing +from _pytest._code.code import ExceptionRepr +from _pytest._code.code import ReprFileLocation +from _pytest.config import Config +from _pytest.config import filename_arg +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureRequest +from _pytest.reports import TestReport +from _pytest.store import StoreKey +from _pytest.terminal import TerminalReporter + + +xml_key = StoreKey["LogXML"]() + + +def bin_xml_escape(arg: object) -> str: + r"""Visually escape invalid XML characters. + + For example, transforms + 'hello\aworld\b' + into + 'hello#x07world#x08' + Note that the #xABs are *not* XML escapes - missing the ampersand «. + The idea is to escape visually for the user rather than for XML itself. + """ + + def repl(matchobj: Match[str]) -> str: + i = ord(matchobj.group()) + if i <= 0xFF: + return "#x%02X" % i + else: + return "#x%04X" % i + + # The spec range of valid chars is: + # Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + # For an unknown(?) reason, we disallow #x7F (DEL) as well. + illegal_xml_re = ( + "[^\u0009\u000A\u000D\u0020-\u007E\u0080-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]" + ) + return re.sub(illegal_xml_re, repl, str(arg)) + + +def merge_family(left, right) -> None: + result = {} + for kl, vl in left.items(): + for kr, vr in right.items(): + if not isinstance(vl, list): + raise TypeError(type(vl)) + result[kl] = vl + vr + left.update(result) + + +families = {} +families["_base"] = {"testcase": ["classname", "name"]} +families["_base_legacy"] = {"testcase": ["file", "line", "url"]} + +# xUnit 1.x inherits legacy attributes. +families["xunit1"] = families["_base"].copy() +merge_family(families["xunit1"], families["_base_legacy"]) + +# xUnit 2.x uses strict base attributes. +families["xunit2"] = families["_base"] + + +class _NodeReporter: + def __init__(self, nodeid: Union[str, TestReport], xml: "LogXML") -> None: + self.id = nodeid + self.xml = xml + self.add_stats = self.xml.add_stats + self.family = self.xml.family + self.duration = 0 + self.properties: List[Tuple[str, str]] = [] + self.nodes: List[ET.Element] = [] + self.attrs: Dict[str, str] = {} + + def append(self, node: ET.Element) -> None: + self.xml.add_stats(node.tag) + self.nodes.append(node) + + def add_property(self, name: str, value: object) -> None: + self.properties.append((str(name), bin_xml_escape(value))) + + def add_attribute(self, name: str, value: object) -> None: + self.attrs[str(name)] = bin_xml_escape(value) + + def make_properties_node(self) -> Optional[ET.Element]: + """Return a Junit node containing custom properties, if any.""" + if self.properties: + properties = ET.Element("properties") + for name, value in self.properties: + properties.append(ET.Element("property", name=name, value=value)) + return properties + return None + + def record_testreport(self, testreport: TestReport) -> None: + names = mangle_test_address(testreport.nodeid) + existing_attrs = self.attrs + classnames = names[:-1] + if self.xml.prefix: + classnames.insert(0, self.xml.prefix) + attrs: Dict[str, str] = { + "classname": ".".join(classnames), + "name": bin_xml_escape(names[-1]), + "file": testreport.location[0], + } + if testreport.location[1] is not None: + attrs["line"] = str(testreport.location[1]) + if hasattr(testreport, "url"): + attrs["url"] = testreport.url + self.attrs = attrs + self.attrs.update(existing_attrs) # Restore any user-defined attributes. + + # Preserve legacy testcase behavior. + if self.family == "xunit1": + return + + # Filter out attributes not permitted by this test family. + # Including custom attributes because they are not valid here. + temp_attrs = {} + for key in self.attrs.keys(): + if key in families[self.family]["testcase"]: + temp_attrs[key] = self.attrs[key] + self.attrs = temp_attrs + + def to_xml(self) -> ET.Element: + testcase = ET.Element("testcase", self.attrs, time="%.3f" % self.duration) + properties = self.make_properties_node() + if properties is not None: + testcase.append(properties) + testcase.extend(self.nodes) + return testcase + + def _add_simple(self, tag: str, message: str, data: Optional[str] = None) -> None: + node = ET.Element(tag, message=message) + node.text = bin_xml_escape(data) + self.append(node) + + def write_captured_output(self, report: TestReport) -> None: + if not self.xml.log_passing_tests and report.passed: + return + + content_out = report.capstdout + content_log = report.caplog + content_err = report.capstderr + if self.xml.logging == "no": + return + content_all = "" + if self.xml.logging in ["log", "all"]: + content_all = self._prepare_content(content_log, " Captured Log ") + if self.xml.logging in ["system-out", "out-err", "all"]: + content_all += self._prepare_content(content_out, " Captured Out ") + self._write_content(report, content_all, "system-out") + content_all = "" + if self.xml.logging in ["system-err", "out-err", "all"]: + content_all += self._prepare_content(content_err, " Captured Err ") + self._write_content(report, content_all, "system-err") + content_all = "" + if content_all: + self._write_content(report, content_all, "system-out") + + def _prepare_content(self, content: str, header: str) -> str: + return "\n".join([header.center(80, "-"), content, ""]) + + def _write_content(self, report: TestReport, content: str, jheader: str) -> None: + tag = ET.Element(jheader) + tag.text = bin_xml_escape(content) + self.append(tag) + + def append_pass(self, report: TestReport) -> None: + self.add_stats("passed") + + def append_failure(self, report: TestReport) -> None: + # msg = str(report.longrepr.reprtraceback.extraline) + if hasattr(report, "wasxfail"): + self._add_simple("skipped", "xfail-marked test passes unexpectedly") + else: + assert report.longrepr is not None + reprcrash: Optional[ReprFileLocation] = getattr( + report.longrepr, "reprcrash", None + ) + if reprcrash is not None: + message = reprcrash.message + else: + message = str(report.longrepr) + message = bin_xml_escape(message) + self._add_simple("failure", message, str(report.longrepr)) + + def append_collect_error(self, report: TestReport) -> None: + # msg = str(report.longrepr.reprtraceback.extraline) + assert report.longrepr is not None + self._add_simple("error", "collection failure", str(report.longrepr)) + + def append_collect_skipped(self, report: TestReport) -> None: + self._add_simple("skipped", "collection skipped", str(report.longrepr)) + + def append_error(self, report: TestReport) -> None: + assert report.longrepr is not None + reprcrash: Optional[ReprFileLocation] = getattr( + report.longrepr, "reprcrash", None + ) + if reprcrash is not None: + reason = reprcrash.message + else: + reason = str(report.longrepr) + + if report.when == "teardown": + msg = f'failed on teardown with "{reason}"' + else: + msg = f'failed on setup with "{reason}"' + self._add_simple("error", msg, str(report.longrepr)) + + def append_skipped(self, report: TestReport) -> None: + if hasattr(report, "wasxfail"): + xfailreason = report.wasxfail + if xfailreason.startswith("reason: "): + xfailreason = xfailreason[8:] + xfailreason = bin_xml_escape(xfailreason) + skipped = ET.Element("skipped", type="pytest.xfail", message=xfailreason) + self.append(skipped) + else: + assert isinstance(report.longrepr, tuple) + filename, lineno, skipreason = report.longrepr + if skipreason.startswith("Skipped: "): + skipreason = skipreason[9:] + details = f"{filename}:{lineno}: {skipreason}" + + skipped = ET.Element("skipped", type="pytest.skip", message=skipreason) + skipped.text = bin_xml_escape(details) + self.append(skipped) + self.write_captured_output(report) + + def finalize(self) -> None: + data = self.to_xml() + self.__dict__.clear() + # Type ignored becuase mypy doesn't like overriding a method. + # Also the return value doesn't match... + self.to_xml = lambda: data # type: ignore[assignment] + + +def _warn_incompatibility_with_xunit2( + request: FixtureRequest, fixture_name: str +) -> None: + """Emit a PytestWarning about the given fixture being incompatible with newer xunit revisions.""" + from _pytest.warning_types import PytestWarning + + xml = request.config._store.get(xml_key, None) + if xml is not None and xml.family not in ("xunit1", "legacy"): + request.node.warn( + PytestWarning( + "{fixture_name} is incompatible with junit_family '{family}' (use 'legacy' or 'xunit1')".format( + fixture_name=fixture_name, family=xml.family + ) + ) + ) + + +@pytest.fixture +def record_property(request: FixtureRequest) -> Callable[[str, object], None]: + """Add extra properties to the calling test. + + User properties become part of the test report and are available to the + configured reporters, like JUnit XML. + + The fixture is callable with ``name, value``. The value is automatically + XML-encoded. + + Example:: + + def test_function(record_property): + record_property("example_key", 1) + """ + _warn_incompatibility_with_xunit2(request, "record_property") + + def append_property(name: str, value: object) -> None: + request.node.user_properties.append((name, value)) + + return append_property + + +@pytest.fixture +def record_xml_attribute(request: FixtureRequest) -> Callable[[str, object], None]: + """Add extra xml attributes to the tag for the calling test. + + The fixture is callable with ``name, value``. The value is + automatically XML-encoded. + """ + from _pytest.warning_types import PytestExperimentalApiWarning + + request.node.warn( + PytestExperimentalApiWarning("record_xml_attribute is an experimental feature") + ) + + _warn_incompatibility_with_xunit2(request, "record_xml_attribute") + + # Declare noop + def add_attr_noop(name: str, value: object) -> None: + pass + + attr_func = add_attr_noop + + xml = request.config._store.get(xml_key, None) + if xml is not None: + node_reporter = xml.node_reporter(request.node.nodeid) + attr_func = node_reporter.add_attribute + + return attr_func + + +def _check_record_param_type(param: str, v: str) -> None: + """Used by record_testsuite_property to check that the given parameter name is of the proper + type.""" + __tracebackhide__ = True + if not isinstance(v, str): + msg = "{param} parameter needs to be a string, but {g} given" # type: ignore[unreachable] + raise TypeError(msg.format(param=param, g=type(v).__name__)) + + +@pytest.fixture(scope="session") +def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object], None]: + """Record a new ```` tag as child of the root ````. + + This is suitable to writing global information regarding the entire test + suite, and is compatible with ``xunit2`` JUnit family. + + This is a ``session``-scoped fixture which is called with ``(name, value)``. Example: + + .. code-block:: python + + def test_foo(record_testsuite_property): + record_testsuite_property("ARCH", "PPC") + record_testsuite_property("STORAGE_TYPE", "CEPH") + + ``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped. + + .. warning:: + + Currently this fixture **does not work** with the + `pytest-xdist `__ plugin. See issue + `#7767 `__ for details. + """ + + __tracebackhide__ = True + + def record_func(name: str, value: object) -> None: + """No-op function in case --junitxml was not passed in the command-line.""" + __tracebackhide__ = True + _check_record_param_type("name", name) + + xml = request.config._store.get(xml_key, None) + if xml is not None: + record_func = xml.add_global_property # noqa + return record_func + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting") + group.addoption( + "--junitxml", + "--junit-xml", + action="store", + dest="xmlpath", + metavar="path", + type=functools.partial(filename_arg, optname="--junitxml"), + default=None, + help="create junit-xml style report file at given path.", + ) + group.addoption( + "--junitprefix", + "--junit-prefix", + action="store", + metavar="str", + default=None, + help="prepend prefix to classnames in junit-xml output", + ) + parser.addini( + "junit_suite_name", "Test suite name for JUnit report", default="pytest" + ) + parser.addini( + "junit_logging", + "Write captured log messages to JUnit report: " + "one of no|log|system-out|system-err|out-err|all", + default="no", + ) + parser.addini( + "junit_log_passing_tests", + "Capture log information for passing tests to JUnit report: ", + type="bool", + default=True, + ) + parser.addini( + "junit_duration_report", + "Duration time to report: one of total|call", + default="total", + ) # choices=['total', 'call']) + parser.addini( + "junit_family", + "Emit XML for schema: one of legacy|xunit1|xunit2", + default="xunit2", + ) + + +def pytest_configure(config: Config) -> None: + xmlpath = config.option.xmlpath + # Prevent opening xmllog on worker nodes (xdist). + if xmlpath and not hasattr(config, "workerinput"): + junit_family = config.getini("junit_family") + config._store[xml_key] = LogXML( + xmlpath, + config.option.junitprefix, + config.getini("junit_suite_name"), + config.getini("junit_logging"), + config.getini("junit_duration_report"), + junit_family, + config.getini("junit_log_passing_tests"), + ) + config.pluginmanager.register(config._store[xml_key]) + + +def pytest_unconfigure(config: Config) -> None: + xml = config._store.get(xml_key, None) + if xml: + del config._store[xml_key] + config.pluginmanager.unregister(xml) + + +def mangle_test_address(address: str) -> List[str]: + path, possible_open_bracket, params = address.partition("[") + names = path.split("::") + try: + names.remove("()") + except ValueError: + pass + # Convert file path to dotted path. + names[0] = names[0].replace(nodes.SEP, ".") + names[0] = re.sub(r"\.py$", "", names[0]) + # Put any params back. + names[-1] += possible_open_bracket + params + return names + + +class LogXML: + def __init__( + self, + logfile, + prefix: Optional[str], + suite_name: str = "pytest", + logging: str = "no", + report_duration: str = "total", + family="xunit1", + log_passing_tests: bool = True, + ) -> None: + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(os.path.abspath(logfile)) + self.prefix = prefix + self.suite_name = suite_name + self.logging = logging + self.log_passing_tests = log_passing_tests + self.report_duration = report_duration + self.family = family + self.stats: Dict[str, int] = dict.fromkeys( + ["error", "passed", "failure", "skipped"], 0 + ) + self.node_reporters: Dict[ + Tuple[Union[str, TestReport], object], _NodeReporter + ] = ({}) + self.node_reporters_ordered: List[_NodeReporter] = [] + self.global_properties: List[Tuple[str, str]] = [] + + # List of reports that failed on call but teardown is pending. + self.open_reports: List[TestReport] = [] + self.cnt_double_fail_tests = 0 + + # Replaces convenience family with real family. + if self.family == "legacy": + self.family = "xunit1" + + def finalize(self, report: TestReport) -> None: + nodeid = getattr(report, "nodeid", report) + # Local hack to handle xdist report order. + workernode = getattr(report, "node", None) + reporter = self.node_reporters.pop((nodeid, workernode)) + if reporter is not None: + reporter.finalize() + + def node_reporter(self, report: Union[TestReport, str]) -> _NodeReporter: + nodeid: Union[str, TestReport] = getattr(report, "nodeid", report) + # Local hack to handle xdist report order. + workernode = getattr(report, "node", None) + + key = nodeid, workernode + + if key in self.node_reporters: + # TODO: breaks for --dist=each + return self.node_reporters[key] + + reporter = _NodeReporter(nodeid, self) + + self.node_reporters[key] = reporter + self.node_reporters_ordered.append(reporter) + + return reporter + + def add_stats(self, key: str) -> None: + if key in self.stats: + self.stats[key] += 1 + + def _opentestcase(self, report: TestReport) -> _NodeReporter: + reporter = self.node_reporter(report) + reporter.record_testreport(report) + return reporter + + def pytest_runtest_logreport(self, report: TestReport) -> None: + """Handle a setup/call/teardown report, generating the appropriate + XML tags as necessary. + + Note: due to plugins like xdist, this hook may be called in interlaced + order with reports from other nodes. For example: + + Usual call order: + -> setup node1 + -> call node1 + -> teardown node1 + -> setup node2 + -> call node2 + -> teardown node2 + + Possible call order in xdist: + -> setup node1 + -> call node1 + -> setup node2 + -> call node2 + -> teardown node2 + -> teardown node1 + """ + close_report = None + if report.passed: + if report.when == "call": # ignore setup/teardown + reporter = self._opentestcase(report) + reporter.append_pass(report) + elif report.failed: + if report.when == "teardown": + # The following vars are needed when xdist plugin is used. + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + ( + rep + for rep in self.open_reports + if ( + rep.nodeid == report.nodeid + and getattr(rep, "item_index", None) == report_ii + and getattr(rep, "worker_id", None) == report_wid + ) + ), + None, + ) + if close_report: + # We need to open new testcase in case we have failure in + # call and error in teardown in order to follow junit + # schema. + self.finalize(close_report) + self.cnt_double_fail_tests += 1 + reporter = self._opentestcase(report) + if report.when == "call": + reporter.append_failure(report) + self.open_reports.append(report) + if not self.log_passing_tests: + reporter.write_captured_output(report) + else: + reporter.append_error(report) + elif report.skipped: + reporter = self._opentestcase(report) + reporter.append_skipped(report) + self.update_testcase_duration(report) + if report.when == "teardown": + reporter = self._opentestcase(report) + reporter.write_captured_output(report) + + for propname, propvalue in report.user_properties: + reporter.add_property(propname, str(propvalue)) + + self.finalize(report) + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + ( + rep + for rep in self.open_reports + if ( + rep.nodeid == report.nodeid + and getattr(rep, "item_index", None) == report_ii + and getattr(rep, "worker_id", None) == report_wid + ) + ), + None, + ) + if close_report: + self.open_reports.remove(close_report) + + def update_testcase_duration(self, report: TestReport) -> None: + """Accumulate total duration for nodeid from given report and update + the Junit.testcase with the new total if already created.""" + if self.report_duration == "total" or report.when == self.report_duration: + reporter = self.node_reporter(report) + reporter.duration += getattr(report, "duration", 0.0) + + def pytest_collectreport(self, report: TestReport) -> None: + if not report.passed: + reporter = self._opentestcase(report) + if report.failed: + reporter.append_collect_error(report) + else: + reporter.append_collect_skipped(report) + + def pytest_internalerror(self, excrepr: ExceptionRepr) -> None: + reporter = self.node_reporter("internal") + reporter.attrs.update(classname="pytest", name="internal") + reporter._add_simple("error", "internal error", str(excrepr)) + + def pytest_sessionstart(self) -> None: + self.suite_start_time = timing.time() + + def pytest_sessionfinish(self) -> None: + dirname = os.path.dirname(os.path.abspath(self.logfile)) + if not os.path.isdir(dirname): + os.makedirs(dirname) + logfile = open(self.logfile, "w", encoding="utf-8") + suite_stop_time = timing.time() + suite_time_delta = suite_stop_time - self.suite_start_time + + numtests = ( + self.stats["passed"] + + self.stats["failure"] + + self.stats["skipped"] + + self.stats["error"] + - self.cnt_double_fail_tests + ) + logfile.write('') + + suite_node = ET.Element( + "testsuite", + name=self.suite_name, + errors=str(self.stats["error"]), + failures=str(self.stats["failure"]), + skipped=str(self.stats["skipped"]), + tests=str(numtests), + time="%.3f" % suite_time_delta, + timestamp=datetime.fromtimestamp(self.suite_start_time).isoformat(), + hostname=platform.node(), + ) + global_properties = self._get_global_properties_node() + if global_properties is not None: + suite_node.append(global_properties) + for node_reporter in self.node_reporters_ordered: + suite_node.append(node_reporter.to_xml()) + testsuites = ET.Element("testsuites") + testsuites.append(suite_node) + logfile.write(ET.tostring(testsuites, encoding="unicode")) + logfile.close() + + def pytest_terminal_summary(self, terminalreporter: TerminalReporter) -> None: + terminalreporter.write_sep("-", f"generated xml file: {self.logfile}") + + def add_global_property(self, name: str, value: object) -> None: + __tracebackhide__ = True + _check_record_param_type("name", name) + self.global_properties.append((name, bin_xml_escape(value))) + + def _get_global_properties_node(self) -> Optional[ET.Element]: + """Return a Junit node containing custom properties, if any.""" + if self.global_properties: + properties = ET.Element("properties") + for name, value in self.global_properties: + properties.append(ET.Element("property", name=name, value=value)) + return properties + return None diff --git a/myenv/lib/python3.9/site-packages/_pytest/logging.py b/myenv/lib/python3.9/site-packages/_pytest/logging.py new file mode 100644 index 0000000..2e48473 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/logging.py @@ -0,0 +1,821 @@ +"""Access and control log capturing.""" +import logging +import os +import re +import sys +from contextlib import contextmanager +from io import StringIO +from pathlib import Path +from typing import AbstractSet +from typing import Dict +from typing import Generator +from typing import List +from typing import Mapping +from typing import Optional +from typing import Tuple +from typing import TypeVar +from typing import Union + +from _pytest import nodes +from _pytest._io import TerminalWriter +from _pytest.capture import CaptureManager +from _pytest.compat import final +from _pytest.compat import nullcontext +from _pytest.config import _strtobool +from _pytest.config import Config +from _pytest.config import create_terminal_writer +from _pytest.config import hookimpl +from _pytest.config import UsageError +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.main import Session +from _pytest.store import StoreKey +from _pytest.terminal import TerminalReporter + + +DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s" +DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S" +_ANSI_ESCAPE_SEQ = re.compile(r"\x1b\[[\d;]+m") +caplog_handler_key = StoreKey["LogCaptureHandler"]() +caplog_records_key = StoreKey[Dict[str, List[logging.LogRecord]]]() + + +def _remove_ansi_escape_sequences(text: str) -> str: + return _ANSI_ESCAPE_SEQ.sub("", text) + + +class ColoredLevelFormatter(logging.Formatter): + """A logging formatter which colorizes the %(levelname)..s part of the + log format passed to __init__.""" + + LOGLEVEL_COLOROPTS: Mapping[int, AbstractSet[str]] = { + logging.CRITICAL: {"red"}, + logging.ERROR: {"red", "bold"}, + logging.WARNING: {"yellow"}, + logging.WARN: {"yellow"}, + logging.INFO: {"green"}, + logging.DEBUG: {"purple"}, + logging.NOTSET: set(), + } + LEVELNAME_FMT_REGEX = re.compile(r"%\(levelname\)([+-.]?\d*s)") + + def __init__(self, terminalwriter: TerminalWriter, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self._original_fmt = self._style._fmt + self._level_to_fmt_mapping: Dict[int, str] = {} + + assert self._fmt is not None + levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt) + if not levelname_fmt_match: + return + levelname_fmt = levelname_fmt_match.group() + + for level, color_opts in self.LOGLEVEL_COLOROPTS.items(): + formatted_levelname = levelname_fmt % { + "levelname": logging.getLevelName(level) + } + + # add ANSI escape sequences around the formatted levelname + color_kwargs = {name: True for name in color_opts} + colorized_formatted_levelname = terminalwriter.markup( + formatted_levelname, **color_kwargs + ) + self._level_to_fmt_mapping[level] = self.LEVELNAME_FMT_REGEX.sub( + colorized_formatted_levelname, self._fmt + ) + + def format(self, record: logging.LogRecord) -> str: + fmt = self._level_to_fmt_mapping.get(record.levelno, self._original_fmt) + self._style._fmt = fmt + return super().format(record) + + +class PercentStyleMultiline(logging.PercentStyle): + """A logging style with special support for multiline messages. + + If the message of a record consists of multiple lines, this style + formats the message as if each line were logged separately. + """ + + def __init__(self, fmt: str, auto_indent: Union[int, str, bool, None]) -> None: + super().__init__(fmt) + self._auto_indent = self._get_auto_indent(auto_indent) + + @staticmethod + def _update_message( + record_dict: Dict[str, object], message: str + ) -> Dict[str, object]: + tmp = record_dict.copy() + tmp["message"] = message + return tmp + + @staticmethod + def _get_auto_indent(auto_indent_option: Union[int, str, bool, None]) -> int: + """Determine the current auto indentation setting. + + Specify auto indent behavior (on/off/fixed) by passing in + extra={"auto_indent": [value]} to the call to logging.log() or + using a --log-auto-indent [value] command line or the + log_auto_indent [value] config option. + + Default behavior is auto-indent off. + + Using the string "True" or "on" or the boolean True as the value + turns auto indent on, using the string "False" or "off" or the + boolean False or the int 0 turns it off, and specifying a + positive integer fixes the indentation position to the value + specified. + + Any other values for the option are invalid, and will silently be + converted to the default. + + :param None|bool|int|str auto_indent_option: + User specified option for indentation from command line, config + or extra kwarg. Accepts int, bool or str. str option accepts the + same range of values as boolean config options, as well as + positive integers represented in str form. + + :returns: + Indentation value, which can be + -1 (automatically determine indentation) or + 0 (auto-indent turned off) or + >0 (explicitly set indentation position). + """ + + if auto_indent_option is None: + return 0 + elif isinstance(auto_indent_option, bool): + if auto_indent_option: + return -1 + else: + return 0 + elif isinstance(auto_indent_option, int): + return int(auto_indent_option) + elif isinstance(auto_indent_option, str): + try: + return int(auto_indent_option) + except ValueError: + pass + try: + if _strtobool(auto_indent_option): + return -1 + except ValueError: + return 0 + + return 0 + + def format(self, record: logging.LogRecord) -> str: + if "\n" in record.message: + if hasattr(record, "auto_indent"): + # Passed in from the "extra={}" kwarg on the call to logging.log(). + auto_indent = self._get_auto_indent(record.auto_indent) # type: ignore[attr-defined] + else: + auto_indent = self._auto_indent + + if auto_indent: + lines = record.message.splitlines() + formatted = self._fmt % self._update_message(record.__dict__, lines[0]) + + if auto_indent < 0: + indentation = _remove_ansi_escape_sequences(formatted).find( + lines[0] + ) + else: + # Optimizes logging by allowing a fixed indentation. + indentation = auto_indent + lines[0] = formatted + return ("\n" + " " * indentation).join(lines) + return self._fmt % record.__dict__ + + +def get_option_ini(config: Config, *names: str): + for name in names: + ret = config.getoption(name) # 'default' arg won't work as expected + if ret is None: + ret = config.getini(name) + if ret: + return ret + + +def pytest_addoption(parser: Parser) -> None: + """Add options to control log capturing.""" + group = parser.getgroup("logging") + + def add_option_ini(option, dest, default=None, type=None, **kwargs): + parser.addini( + dest, default=default, type=type, help="default value for " + option + ) + group.addoption(option, dest=dest, **kwargs) + + add_option_ini( + "--log-level", + dest="log_level", + default=None, + metavar="LEVEL", + help=( + "level of messages to catch/display.\n" + "Not set by default, so it depends on the root/parent log handler's" + ' effective level, where it is "WARNING" by default.' + ), + ) + add_option_ini( + "--log-format", + dest="log_format", + default=DEFAULT_LOG_FORMAT, + help="log format as used by the logging module.", + ) + add_option_ini( + "--log-date-format", + dest="log_date_format", + default=DEFAULT_LOG_DATE_FORMAT, + help="log date format as used by the logging module.", + ) + parser.addini( + "log_cli", + default=False, + type="bool", + help='enable log display during test run (also known as "live logging").', + ) + add_option_ini( + "--log-cli-level", dest="log_cli_level", default=None, help="cli logging level." + ) + add_option_ini( + "--log-cli-format", + dest="log_cli_format", + default=None, + help="log format as used by the logging module.", + ) + add_option_ini( + "--log-cli-date-format", + dest="log_cli_date_format", + default=None, + help="log date format as used by the logging module.", + ) + add_option_ini( + "--log-file", + dest="log_file", + default=None, + help="path to a file when logging will be written to.", + ) + add_option_ini( + "--log-file-level", + dest="log_file_level", + default=None, + help="log file logging level.", + ) + add_option_ini( + "--log-file-format", + dest="log_file_format", + default=DEFAULT_LOG_FORMAT, + help="log format as used by the logging module.", + ) + add_option_ini( + "--log-file-date-format", + dest="log_file_date_format", + default=DEFAULT_LOG_DATE_FORMAT, + help="log date format as used by the logging module.", + ) + add_option_ini( + "--log-auto-indent", + dest="log_auto_indent", + default=None, + help="Auto-indent multiline messages passed to the logging module. Accepts true|on, false|off or an integer.", + ) + + +_HandlerType = TypeVar("_HandlerType", bound=logging.Handler) + + +# Not using @contextmanager for performance reasons. +class catching_logs: + """Context manager that prepares the whole logging machinery properly.""" + + __slots__ = ("handler", "level", "orig_level") + + def __init__(self, handler: _HandlerType, level: Optional[int] = None) -> None: + self.handler = handler + self.level = level + + def __enter__(self): + root_logger = logging.getLogger() + if self.level is not None: + self.handler.setLevel(self.level) + root_logger.addHandler(self.handler) + if self.level is not None: + self.orig_level = root_logger.level + root_logger.setLevel(min(self.orig_level, self.level)) + return self.handler + + def __exit__(self, type, value, traceback): + root_logger = logging.getLogger() + if self.level is not None: + root_logger.setLevel(self.orig_level) + root_logger.removeHandler(self.handler) + + +class LogCaptureHandler(logging.StreamHandler): + """A logging handler that stores log records and the log text.""" + + stream: StringIO + + def __init__(self) -> None: + """Create a new log handler.""" + super().__init__(StringIO()) + self.records: List[logging.LogRecord] = [] + + def emit(self, record: logging.LogRecord) -> None: + """Keep the log records in a list in addition to the log text.""" + self.records.append(record) + super().emit(record) + + def reset(self) -> None: + self.records = [] + self.stream = StringIO() + + def handleError(self, record: logging.LogRecord) -> None: + if logging.raiseExceptions: + # Fail the test if the log message is bad (emit failed). + # The default behavior of logging is to print "Logging error" + # to stderr with the call stack and some extra details. + # pytest wants to make such mistakes visible during testing. + raise + + +@final +class LogCaptureFixture: + """Provides access and control of log capturing.""" + + def __init__(self, item: nodes.Node, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + self._item = item + self._initial_handler_level: Optional[int] = None + # Dict of log name -> log level. + self._initial_logger_levels: Dict[Optional[str], int] = {} + + def _finalize(self) -> None: + """Finalize the fixture. + + This restores the log levels changed by :meth:`set_level`. + """ + # Restore log levels. + if self._initial_handler_level is not None: + self.handler.setLevel(self._initial_handler_level) + for logger_name, level in self._initial_logger_levels.items(): + logger = logging.getLogger(logger_name) + logger.setLevel(level) + + @property + def handler(self) -> LogCaptureHandler: + """Get the logging handler used by the fixture. + + :rtype: LogCaptureHandler + """ + return self._item._store[caplog_handler_key] + + def get_records(self, when: str) -> List[logging.LogRecord]: + """Get the logging records for one of the possible test phases. + + :param str when: + Which test phase to obtain the records from. Valid values are: "setup", "call" and "teardown". + + :returns: The list of captured records at the given stage. + :rtype: List[logging.LogRecord] + + .. versionadded:: 3.4 + """ + return self._item._store[caplog_records_key].get(when, []) + + @property + def text(self) -> str: + """The formatted log text.""" + return _remove_ansi_escape_sequences(self.handler.stream.getvalue()) + + @property + def records(self) -> List[logging.LogRecord]: + """The list of log records.""" + return self.handler.records + + @property + def record_tuples(self) -> List[Tuple[str, int, str]]: + """A list of a stripped down version of log records intended + for use in assertion comparison. + + The format of the tuple is: + + (logger_name, log_level, message) + """ + return [(r.name, r.levelno, r.getMessage()) for r in self.records] + + @property + def messages(self) -> List[str]: + """A list of format-interpolated log messages. + + Unlike 'records', which contains the format string and parameters for + interpolation, log messages in this list are all interpolated. + + Unlike 'text', which contains the output from the handler, log + messages in this list are unadorned with levels, timestamps, etc, + making exact comparisons more reliable. + + Note that traceback or stack info (from :func:`logging.exception` or + the `exc_info` or `stack_info` arguments to the logging functions) is + not included, as this is added by the formatter in the handler. + + .. versionadded:: 3.7 + """ + return [r.getMessage() for r in self.records] + + def clear(self) -> None: + """Reset the list of log records and the captured log text.""" + self.handler.reset() + + def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> None: + """Set the level of a logger for the duration of a test. + + .. versionchanged:: 3.4 + The levels of the loggers changed by this function will be + restored to their initial values at the end of the test. + + :param int level: The level. + :param str logger: The logger to update. If not given, the root logger. + """ + logger_obj = logging.getLogger(logger) + # Save the original log-level to restore it during teardown. + self._initial_logger_levels.setdefault(logger, logger_obj.level) + logger_obj.setLevel(level) + if self._initial_handler_level is None: + self._initial_handler_level = self.handler.level + self.handler.setLevel(level) + + @contextmanager + def at_level( + self, level: int, logger: Optional[str] = None + ) -> Generator[None, None, None]: + """Context manager that sets the level for capturing of logs. After + the end of the 'with' statement the level is restored to its original + value. + + :param int level: The level. + :param str logger: The logger to update. If not given, the root logger. + """ + logger_obj = logging.getLogger(logger) + orig_level = logger_obj.level + logger_obj.setLevel(level) + handler_orig_level = self.handler.level + self.handler.setLevel(level) + try: + yield + finally: + logger_obj.setLevel(orig_level) + self.handler.setLevel(handler_orig_level) + + +@fixture +def caplog(request: FixtureRequest) -> Generator[LogCaptureFixture, None, None]: + """Access and control log capturing. + + Captured logs are available through the following properties/methods:: + + * caplog.messages -> list of format-interpolated log messages + * caplog.text -> string containing formatted log output + * caplog.records -> list of logging.LogRecord instances + * caplog.record_tuples -> list of (logger_name, level, message) tuples + * caplog.clear() -> clear captured records and formatted log output string + """ + result = LogCaptureFixture(request.node, _ispytest=True) + yield result + result._finalize() + + +def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[int]: + for setting_name in setting_names: + log_level = config.getoption(setting_name) + if log_level is None: + log_level = config.getini(setting_name) + if log_level: + break + else: + return None + + if isinstance(log_level, str): + log_level = log_level.upper() + try: + return int(getattr(logging, log_level, log_level)) + except ValueError as e: + # Python logging does not recognise this as a logging level + raise UsageError( + "'{}' is not recognized as a logging level name for " + "'{}'. Please consider passing the " + "logging level num instead.".format(log_level, setting_name) + ) from e + + +# run after terminalreporter/capturemanager are configured +@hookimpl(trylast=True) +def pytest_configure(config: Config) -> None: + config.pluginmanager.register(LoggingPlugin(config), "logging-plugin") + + +class LoggingPlugin: + """Attaches to the logging module and captures log messages for each test.""" + + def __init__(self, config: Config) -> None: + """Create a new plugin to capture log messages. + + The formatter can be safely shared across all handlers so + create a single one for the entire test session here. + """ + self._config = config + + # Report logging. + self.formatter = self._create_formatter( + get_option_ini(config, "log_format"), + get_option_ini(config, "log_date_format"), + get_option_ini(config, "log_auto_indent"), + ) + self.log_level = get_log_level_for_setting(config, "log_level") + self.caplog_handler = LogCaptureHandler() + self.caplog_handler.setFormatter(self.formatter) + self.report_handler = LogCaptureHandler() + self.report_handler.setFormatter(self.formatter) + + # File logging. + self.log_file_level = get_log_level_for_setting(config, "log_file_level") + log_file = get_option_ini(config, "log_file") or os.devnull + if log_file != os.devnull: + directory = os.path.dirname(os.path.abspath(log_file)) + if not os.path.isdir(directory): + os.makedirs(directory) + + self.log_file_handler = _FileHandler(log_file, mode="w", encoding="UTF-8") + log_file_format = get_option_ini(config, "log_file_format", "log_format") + log_file_date_format = get_option_ini( + config, "log_file_date_format", "log_date_format" + ) + + log_file_formatter = logging.Formatter( + log_file_format, datefmt=log_file_date_format + ) + self.log_file_handler.setFormatter(log_file_formatter) + + # CLI/live logging. + self.log_cli_level = get_log_level_for_setting( + config, "log_cli_level", "log_level" + ) + if self._log_cli_enabled(): + terminal_reporter = config.pluginmanager.get_plugin("terminalreporter") + capture_manager = config.pluginmanager.get_plugin("capturemanager") + # if capturemanager plugin is disabled, live logging still works. + self.log_cli_handler: Union[ + _LiveLoggingStreamHandler, _LiveLoggingNullHandler + ] = _LiveLoggingStreamHandler(terminal_reporter, capture_manager) + else: + self.log_cli_handler = _LiveLoggingNullHandler() + log_cli_formatter = self._create_formatter( + get_option_ini(config, "log_cli_format", "log_format"), + get_option_ini(config, "log_cli_date_format", "log_date_format"), + get_option_ini(config, "log_auto_indent"), + ) + self.log_cli_handler.setFormatter(log_cli_formatter) + + def _create_formatter(self, log_format, log_date_format, auto_indent): + # Color option doesn't exist if terminal plugin is disabled. + color = getattr(self._config.option, "color", "no") + if color != "no" and ColoredLevelFormatter.LEVELNAME_FMT_REGEX.search( + log_format + ): + formatter: logging.Formatter = ColoredLevelFormatter( + create_terminal_writer(self._config), log_format, log_date_format + ) + else: + formatter = logging.Formatter(log_format, log_date_format) + + formatter._style = PercentStyleMultiline( + formatter._style._fmt, auto_indent=auto_indent + ) + + return formatter + + def set_log_path(self, fname: str) -> None: + """Set the filename parameter for Logging.FileHandler(). + + Creates parent directory if it does not exist. + + .. warning:: + This is an experimental API. + """ + fpath = Path(fname) + + if not fpath.is_absolute(): + fpath = self._config.rootpath / fpath + + if not fpath.parent.exists(): + fpath.parent.mkdir(exist_ok=True, parents=True) + + stream = fpath.open(mode="w", encoding="UTF-8") + if sys.version_info >= (3, 7): + old_stream = self.log_file_handler.setStream(stream) + else: + old_stream = self.log_file_handler.stream + self.log_file_handler.acquire() + try: + self.log_file_handler.flush() + self.log_file_handler.stream = stream + finally: + self.log_file_handler.release() + if old_stream: + old_stream.close() + + def _log_cli_enabled(self): + """Return whether live logging is enabled.""" + enabled = self._config.getoption( + "--log-cli-level" + ) is not None or self._config.getini("log_cli") + if not enabled: + return False + + terminal_reporter = self._config.pluginmanager.get_plugin("terminalreporter") + if terminal_reporter is None: + # terminal reporter is disabled e.g. by pytest-xdist. + return False + + return True + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_sessionstart(self) -> Generator[None, None, None]: + self.log_cli_handler.set_when("sessionstart") + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_collection(self) -> Generator[None, None, None]: + self.log_cli_handler.set_when("collection") + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield + + @hookimpl(hookwrapper=True) + def pytest_runtestloop(self, session: Session) -> Generator[None, None, None]: + if session.config.option.collectonly: + yield + return + + if self._log_cli_enabled() and self._config.getoption("verbose") < 1: + # The verbose flag is needed to avoid messy test progress output. + self._config.option.verbose = 1 + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield # Run all the tests. + + @hookimpl + def pytest_runtest_logstart(self) -> None: + self.log_cli_handler.reset() + self.log_cli_handler.set_when("start") + + @hookimpl + def pytest_runtest_logreport(self) -> None: + self.log_cli_handler.set_when("logreport") + + def _runtest_for(self, item: nodes.Item, when: str) -> Generator[None, None, None]: + """Implement the internals of the pytest_runtest_xxx() hooks.""" + with catching_logs( + self.caplog_handler, level=self.log_level, + ) as caplog_handler, catching_logs( + self.report_handler, level=self.log_level, + ) as report_handler: + caplog_handler.reset() + report_handler.reset() + item._store[caplog_records_key][when] = caplog_handler.records + item._store[caplog_handler_key] = caplog_handler + + yield + + log = report_handler.stream.getvalue().strip() + item.add_report_section(when, "log", log) + + @hookimpl(hookwrapper=True) + def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]: + self.log_cli_handler.set_when("setup") + + empty: Dict[str, List[logging.LogRecord]] = {} + item._store[caplog_records_key] = empty + yield from self._runtest_for(item, "setup") + + @hookimpl(hookwrapper=True) + def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]: + self.log_cli_handler.set_when("call") + + yield from self._runtest_for(item, "call") + + @hookimpl(hookwrapper=True) + def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]: + self.log_cli_handler.set_when("teardown") + + yield from self._runtest_for(item, "teardown") + del item._store[caplog_records_key] + del item._store[caplog_handler_key] + + @hookimpl + def pytest_runtest_logfinish(self) -> None: + self.log_cli_handler.set_when("finish") + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_sessionfinish(self) -> Generator[None, None, None]: + self.log_cli_handler.set_when("sessionfinish") + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield + + @hookimpl + def pytest_unconfigure(self) -> None: + # Close the FileHandler explicitly. + # (logging.shutdown might have lost the weakref?!) + self.log_file_handler.close() + + +class _FileHandler(logging.FileHandler): + """A logging FileHandler with pytest tweaks.""" + + def handleError(self, record: logging.LogRecord) -> None: + # Handled by LogCaptureHandler. + pass + + +class _LiveLoggingStreamHandler(logging.StreamHandler): + """A logging StreamHandler used by the live logging feature: it will + write a newline before the first log message in each test. + + During live logging we must also explicitly disable stdout/stderr + capturing otherwise it will get captured and won't appear in the + terminal. + """ + + # Officially stream needs to be a IO[str], but TerminalReporter + # isn't. So force it. + stream: TerminalReporter = None # type: ignore + + def __init__( + self, + terminal_reporter: TerminalReporter, + capture_manager: Optional[CaptureManager], + ) -> None: + logging.StreamHandler.__init__(self, stream=terminal_reporter) # type: ignore[arg-type] + self.capture_manager = capture_manager + self.reset() + self.set_when(None) + self._test_outcome_written = False + + def reset(self) -> None: + """Reset the handler; should be called before the start of each test.""" + self._first_record_emitted = False + + def set_when(self, when: Optional[str]) -> None: + """Prepare for the given test phase (setup/call/teardown).""" + self._when = when + self._section_name_shown = False + if when == "start": + self._test_outcome_written = False + + def emit(self, record: logging.LogRecord) -> None: + ctx_manager = ( + self.capture_manager.global_and_fixture_disabled() + if self.capture_manager + else nullcontext() + ) + with ctx_manager: + if not self._first_record_emitted: + self.stream.write("\n") + self._first_record_emitted = True + elif self._when in ("teardown", "finish"): + if not self._test_outcome_written: + self._test_outcome_written = True + self.stream.write("\n") + if not self._section_name_shown and self._when: + self.stream.section("live log " + self._when, sep="-", bold=True) + self._section_name_shown = True + super().emit(record) + + def handleError(self, record: logging.LogRecord) -> None: + # Handled by LogCaptureHandler. + pass + + +class _LiveLoggingNullHandler(logging.NullHandler): + """A logging handler used when live logging is disabled.""" + + def reset(self) -> None: + pass + + def set_when(self, when: str) -> None: + pass + + def handleError(self, record: logging.LogRecord) -> None: + # Handled by LogCaptureHandler. + pass diff --git a/myenv/lib/python3.9/site-packages/_pytest/main.py b/myenv/lib/python3.9/site-packages/_pytest/main.py new file mode 100644 index 0000000..41a33d4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/main.py @@ -0,0 +1,876 @@ +"""Core implementation of the testing process: init, session, runtest loop.""" +import argparse +import fnmatch +import functools +import importlib +import os +import sys +from pathlib import Path +from typing import Callable +from typing import Dict +from typing import FrozenSet +from typing import Iterator +from typing import List +from typing import Optional +from typing import overload +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +import attr +import py + +import _pytest._code +from _pytest import nodes +from _pytest.compat import final +from _pytest.config import Config +from _pytest.config import directory_arg +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager +from _pytest.config import UsageError +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureManager +from _pytest.outcomes import exit +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath +from _pytest.pathlib import visit +from _pytest.reports import CollectReport +from _pytest.reports import TestReport +from _pytest.runner import collect_one_node +from _pytest.runner import SetupState + + +if TYPE_CHECKING: + from typing_extensions import Literal + + +def pytest_addoption(parser: Parser) -> None: + parser.addini( + "norecursedirs", + "directory patterns to avoid for recursion", + type="args", + default=[ + "*.egg", + ".*", + "_darcs", + "build", + "CVS", + "dist", + "node_modules", + "venv", + "{arch}", + ], + ) + parser.addini( + "testpaths", + "directories to search for tests when no files or directories are given in the " + "command line.", + type="args", + default=[], + ) + group = parser.getgroup("general", "running and selection options") + group._addoption( + "-x", + "--exitfirst", + action="store_const", + dest="maxfail", + const=1, + help="exit instantly on first error or failed test.", + ) + group = parser.getgroup("pytest-warnings") + group.addoption( + "-W", + "--pythonwarnings", + action="append", + help="set which warnings to report, see -W option of python itself.", + ) + parser.addini( + "filterwarnings", + type="linelist", + help="Each line specifies a pattern for " + "warnings.filterwarnings. " + "Processed after -W/--pythonwarnings.", + ) + group._addoption( + "--maxfail", + metavar="num", + action="store", + type=int, + dest="maxfail", + default=0, + help="exit after first num failures or errors.", + ) + group._addoption( + "--strict-config", + action="store_true", + help="any warnings encountered while parsing the `pytest` section of the configuration file raise errors.", + ) + group._addoption( + "--strict-markers", + action="store_true", + help="markers not registered in the `markers` section of the configuration file raise errors.", + ) + group._addoption( + "--strict", action="store_true", help="(deprecated) alias to --strict-markers.", + ) + group._addoption( + "-c", + metavar="file", + type=str, + dest="inifilename", + help="load configuration from `file` instead of trying to locate one of the implicit " + "configuration files.", + ) + group._addoption( + "--continue-on-collection-errors", + action="store_true", + default=False, + dest="continue_on_collection_errors", + help="Force test execution even if collection errors occur.", + ) + group._addoption( + "--rootdir", + action="store", + dest="rootdir", + help="Define root directory for tests. Can be relative path: 'root_dir', './root_dir', " + "'root_dir/another_dir/'; absolute path: '/home/user/root_dir'; path with variables: " + "'$HOME/root_dir'.", + ) + + group = parser.getgroup("collect", "collection") + group.addoption( + "--collectonly", + "--collect-only", + "--co", + action="store_true", + help="only collect tests, don't execute them.", + ) + group.addoption( + "--pyargs", + action="store_true", + help="try to interpret all arguments as python packages.", + ) + group.addoption( + "--ignore", + action="append", + metavar="path", + help="ignore path during collection (multi-allowed).", + ) + group.addoption( + "--ignore-glob", + action="append", + metavar="path", + help="ignore path pattern during collection (multi-allowed).", + ) + group.addoption( + "--deselect", + action="append", + metavar="nodeid_prefix", + help="deselect item (via node id prefix) during collection (multi-allowed).", + ) + group.addoption( + "--confcutdir", + dest="confcutdir", + default=None, + metavar="dir", + type=functools.partial(directory_arg, optname="--confcutdir"), + help="only load conftest.py's relative to specified dir.", + ) + group.addoption( + "--noconftest", + action="store_true", + dest="noconftest", + default=False, + help="Don't load any conftest.py files.", + ) + group.addoption( + "--keepduplicates", + "--keep-duplicates", + action="store_true", + dest="keepduplicates", + default=False, + help="Keep duplicate tests.", + ) + group.addoption( + "--collect-in-virtualenv", + action="store_true", + dest="collect_in_virtualenv", + default=False, + help="Don't ignore tests in a local virtualenv directory", + ) + group.addoption( + "--import-mode", + default="prepend", + choices=["prepend", "append", "importlib"], + dest="importmode", + help="prepend/append to sys.path when importing test modules and conftest files, " + "default is to prepend.", + ) + + group = parser.getgroup("debugconfig", "test session debugging and configuration") + group.addoption( + "--basetemp", + dest="basetemp", + default=None, + type=validate_basetemp, + metavar="dir", + help=( + "base temporary directory for this test run." + "(warning: this directory is removed if it exists)" + ), + ) + + +def validate_basetemp(path: str) -> str: + # GH 7119 + msg = "basetemp must not be empty, the current working directory or any parent directory of it" + + # empty path + if not path: + raise argparse.ArgumentTypeError(msg) + + def is_ancestor(base: Path, query: Path) -> bool: + """Return whether query is an ancestor of base.""" + if base == query: + return True + for parent in base.parents: + if parent == query: + return True + return False + + # check if path is an ancestor of cwd + if is_ancestor(Path.cwd(), Path(path).absolute()): + raise argparse.ArgumentTypeError(msg) + + # check symlinks for ancestors + if is_ancestor(Path.cwd().resolve(), Path(path).resolve()): + raise argparse.ArgumentTypeError(msg) + + return path + + +def wrap_session( + config: Config, doit: Callable[[Config, "Session"], Optional[Union[int, ExitCode]]] +) -> Union[int, ExitCode]: + """Skeleton command line program.""" + session = Session.from_config(config) + session.exitstatus = ExitCode.OK + initstate = 0 + try: + try: + config._do_configure() + initstate = 1 + config.hook.pytest_sessionstart(session=session) + initstate = 2 + session.exitstatus = doit(config, session) or 0 + except UsageError: + session.exitstatus = ExitCode.USAGE_ERROR + raise + except Failed: + session.exitstatus = ExitCode.TESTS_FAILED + except (KeyboardInterrupt, exit.Exception): + excinfo = _pytest._code.ExceptionInfo.from_current() + exitstatus: Union[int, ExitCode] = ExitCode.INTERRUPTED + if isinstance(excinfo.value, exit.Exception): + if excinfo.value.returncode is not None: + exitstatus = excinfo.value.returncode + if initstate < 2: + sys.stderr.write(f"{excinfo.typename}: {excinfo.value.msg}\n") + config.hook.pytest_keyboard_interrupt(excinfo=excinfo) + session.exitstatus = exitstatus + except BaseException: + session.exitstatus = ExitCode.INTERNAL_ERROR + excinfo = _pytest._code.ExceptionInfo.from_current() + try: + config.notify_exception(excinfo, config.option) + except exit.Exception as exc: + if exc.returncode is not None: + session.exitstatus = exc.returncode + sys.stderr.write("{}: {}\n".format(type(exc).__name__, exc)) + else: + if isinstance(excinfo.value, SystemExit): + sys.stderr.write("mainloop: caught unexpected SystemExit!\n") + + finally: + # Explicitly break reference cycle. + excinfo = None # type: ignore + session.startdir.chdir() + if initstate >= 2: + try: + config.hook.pytest_sessionfinish( + session=session, exitstatus=session.exitstatus + ) + except exit.Exception as exc: + if exc.returncode is not None: + session.exitstatus = exc.returncode + sys.stderr.write("{}: {}\n".format(type(exc).__name__, exc)) + config._ensure_unconfigure() + return session.exitstatus + + +def pytest_cmdline_main(config: Config) -> Union[int, ExitCode]: + return wrap_session(config, _main) + + +def _main(config: Config, session: "Session") -> Optional[Union[int, ExitCode]]: + """Default command line protocol for initialization, session, + running tests and reporting.""" + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + + if session.testsfailed: + return ExitCode.TESTS_FAILED + elif session.testscollected == 0: + return ExitCode.NO_TESTS_COLLECTED + return None + + +def pytest_collection(session: "Session") -> None: + session.perform_collect() + + +def pytest_runtestloop(session: "Session") -> bool: + if session.testsfailed and not session.config.option.continue_on_collection_errors: + raise session.Interrupted( + "%d error%s during collection" + % (session.testsfailed, "s" if session.testsfailed != 1 else "") + ) + + if session.config.option.collectonly: + return True + + for i, item in enumerate(session.items): + nextitem = session.items[i + 1] if i + 1 < len(session.items) else None + item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem) + if session.shouldfail: + raise session.Failed(session.shouldfail) + if session.shouldstop: + raise session.Interrupted(session.shouldstop) + return True + + +def _in_venv(path: py.path.local) -> bool: + """Attempt to detect if ``path`` is the root of a Virtual Environment by + checking for the existence of the appropriate activate script.""" + bindir = path.join("Scripts" if sys.platform.startswith("win") else "bin") + if not bindir.isdir(): + return False + activates = ( + "activate", + "activate.csh", + "activate.fish", + "Activate", + "Activate.bat", + "Activate.ps1", + ) + return any([fname.basename in activates for fname in bindir.listdir()]) + + +def pytest_ignore_collect(path: py.path.local, config: Config) -> Optional[bool]: + ignore_paths = config._getconftest_pathlist("collect_ignore", path=path.dirpath()) + ignore_paths = ignore_paths or [] + excludeopt = config.getoption("ignore") + if excludeopt: + ignore_paths.extend([py.path.local(x) for x in excludeopt]) + + if py.path.local(path) in ignore_paths: + return True + + ignore_globs = config._getconftest_pathlist( + "collect_ignore_glob", path=path.dirpath() + ) + ignore_globs = ignore_globs or [] + excludeglobopt = config.getoption("ignore_glob") + if excludeglobopt: + ignore_globs.extend([py.path.local(x) for x in excludeglobopt]) + + if any(fnmatch.fnmatch(str(path), str(glob)) for glob in ignore_globs): + return True + + allow_in_venv = config.getoption("collect_in_virtualenv") + if not allow_in_venv and _in_venv(path): + return True + return None + + +def pytest_collection_modifyitems(items: List[nodes.Item], config: Config) -> None: + deselect_prefixes = tuple(config.getoption("deselect") or []) + if not deselect_prefixes: + return + + remaining = [] + deselected = [] + for colitem in items: + if colitem.nodeid.startswith(deselect_prefixes): + deselected.append(colitem) + else: + remaining.append(colitem) + + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = remaining + + +class FSHookProxy: + def __init__(self, pm: PytestPluginManager, remove_mods) -> None: + self.pm = pm + self.remove_mods = remove_mods + + def __getattr__(self, name: str): + x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods) + self.__dict__[name] = x + return x + + +class Interrupted(KeyboardInterrupt): + """Signals that the test run was interrupted.""" + + __module__ = "builtins" # For py3. + + +class Failed(Exception): + """Signals a stop as failed test run.""" + + +@attr.s +class _bestrelpath_cache(Dict[Path, str]): + path = attr.ib(type=Path) + + def __missing__(self, path: Path) -> str: + r = bestrelpath(self.path, path) + self[path] = r + return r + + +@final +class Session(nodes.FSCollector): + Interrupted = Interrupted + Failed = Failed + # Set on the session by runner.pytest_sessionstart. + _setupstate: SetupState + # Set on the session by fixtures.pytest_sessionstart. + _fixturemanager: FixtureManager + exitstatus: Union[int, ExitCode] + + def __init__(self, config: Config) -> None: + super().__init__( + config.rootdir, parent=None, config=config, session=self, nodeid="" + ) + self.testsfailed = 0 + self.testscollected = 0 + self.shouldstop: Union[bool, str] = False + self.shouldfail: Union[bool, str] = False + self.trace = config.trace.root.get("collection") + self.startdir = config.invocation_dir + self._initialpaths: FrozenSet[py.path.local] = frozenset() + + self._bestrelpathcache: Dict[Path, str] = _bestrelpath_cache(config.rootpath) + + self.config.pluginmanager.register(self, name="session") + + @classmethod + def from_config(cls, config: Config) -> "Session": + session: Session = cls._create(config) + return session + + def __repr__(self) -> str: + return "<%s %s exitstatus=%r testsfailed=%d testscollected=%d>" % ( + self.__class__.__name__, + self.name, + getattr(self, "exitstatus", ""), + self.testsfailed, + self.testscollected, + ) + + def _node_location_to_relpath(self, node_path: Path) -> str: + # bestrelpath is a quite slow function. + return self._bestrelpathcache[node_path] + + @hookimpl(tryfirst=True) + def pytest_collectstart(self) -> None: + if self.shouldfail: + raise self.Failed(self.shouldfail) + if self.shouldstop: + raise self.Interrupted(self.shouldstop) + + @hookimpl(tryfirst=True) + def pytest_runtest_logreport( + self, report: Union[TestReport, CollectReport] + ) -> None: + if report.failed and not hasattr(report, "wasxfail"): + self.testsfailed += 1 + maxfail = self.config.getvalue("maxfail") + if maxfail and self.testsfailed >= maxfail: + self.shouldfail = "stopping after %d failures" % (self.testsfailed) + + pytest_collectreport = pytest_runtest_logreport + + def isinitpath(self, path: py.path.local) -> bool: + return path in self._initialpaths + + def gethookproxy(self, fspath: py.path.local): + # Check if we have the common case of running + # hooks with all conftest.py files. + pm = self.config.pluginmanager + my_conftestmodules = pm._getconftestmodules( + fspath, self.config.getoption("importmode") + ) + remove_mods = pm._conftest_plugins.difference(my_conftestmodules) + if remove_mods: + # One or more conftests are not in use at this fspath. + proxy = FSHookProxy(pm, remove_mods) + else: + # All plugins are active for this fspath. + proxy = self.config.hook + return proxy + + def _recurse(self, direntry: "os.DirEntry[str]") -> bool: + if direntry.name == "__pycache__": + return False + path = py.path.local(direntry.path) + ihook = self.gethookproxy(path.dirpath()) + if ihook.pytest_ignore_collect(path=path, config=self.config): + return False + norecursepatterns = self.config.getini("norecursedirs") + if any(path.check(fnmatch=pat) for pat in norecursepatterns): + return False + return True + + def _collectfile( + self, path: py.path.local, handle_dupes: bool = True + ) -> Sequence[nodes.Collector]: + assert ( + path.isfile() + ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( + path, path.isdir(), path.exists(), path.islink() + ) + ihook = self.gethookproxy(path) + if not self.isinitpath(path): + if ihook.pytest_ignore_collect(path=path, config=self.config): + return () + + if handle_dupes: + keepduplicates = self.config.getoption("keepduplicates") + if not keepduplicates: + duplicate_paths = self.config.pluginmanager._duplicatepaths + if path in duplicate_paths: + return () + else: + duplicate_paths.add(path) + + return ihook.pytest_collect_file(path=path, parent=self) # type: ignore[no-any-return] + + @overload + def perform_collect( + self, args: Optional[Sequence[str]] = ..., genitems: "Literal[True]" = ... + ) -> Sequence[nodes.Item]: + ... + + @overload + def perform_collect( + self, args: Optional[Sequence[str]] = ..., genitems: bool = ... + ) -> Sequence[Union[nodes.Item, nodes.Collector]]: + ... + + def perform_collect( + self, args: Optional[Sequence[str]] = None, genitems: bool = True + ) -> Sequence[Union[nodes.Item, nodes.Collector]]: + """Perform the collection phase for this session. + + This is called by the default + :func:`pytest_collection <_pytest.hookspec.pytest_collection>` hook + implementation; see the documentation of this hook for more details. + For testing purposes, it may also be called directly on a fresh + ``Session``. + + This function normally recursively expands any collectors collected + from the session to their items, and only items are returned. For + testing purposes, this may be suppressed by passing ``genitems=False``, + in which case the return value contains these collectors unexpanded, + and ``session.items`` is empty. + """ + if args is None: + args = self.config.args + + self.trace("perform_collect", self, args) + self.trace.root.indent += 1 + + self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = [] + self._initial_parts: List[Tuple[py.path.local, List[str]]] = [] + self.items: List[nodes.Item] = [] + + hook = self.config.hook + + items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items + try: + initialpaths: List[py.path.local] = [] + for arg in args: + fspath, parts = resolve_collection_argument( + self.config.invocation_params.dir, + arg, + as_pypath=self.config.option.pyargs, + ) + self._initial_parts.append((fspath, parts)) + initialpaths.append(fspath) + self._initialpaths = frozenset(initialpaths) + rep = collect_one_node(self) + self.ihook.pytest_collectreport(report=rep) + self.trace.root.indent -= 1 + if self._notfound: + errors = [] + for arg, cols in self._notfound: + line = f"(no name {arg!r} in any of {cols!r})" + errors.append(f"not found: {arg}\n{line}") + raise UsageError(*errors) + if not genitems: + items = rep.result + else: + if rep.passed: + for node in rep.result: + self.items.extend(self.genitems(node)) + + self.config.pluginmanager.check_pending() + hook.pytest_collection_modifyitems( + session=self, config=self.config, items=items + ) + finally: + hook.pytest_collection_finish(session=self) + + self.testscollected = len(items) + return items + + def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]: + from _pytest.python import Package + + # Keep track of any collected nodes in here, so we don't duplicate fixtures. + node_cache1: Dict[py.path.local, Sequence[nodes.Collector]] = {} + node_cache2: Dict[ + Tuple[Type[nodes.Collector], py.path.local], nodes.Collector + ] = ({}) + + # Keep track of any collected collectors in matchnodes paths, so they + # are not collected more than once. + matchnodes_cache: Dict[Tuple[Type[nodes.Collector], str], CollectReport] = ({}) + + # Dirnames of pkgs with dunder-init files. + pkg_roots: Dict[str, Package] = {} + + for argpath, names in self._initial_parts: + self.trace("processing argument", (argpath, names)) + self.trace.root.indent += 1 + + # Start with a Session root, and delve to argpath item (dir or file) + # and stack all Packages found on the way. + # No point in finding packages when collecting doctests. + if not self.config.getoption("doctestmodules", False): + pm = self.config.pluginmanager + for parent in reversed(argpath.parts()): + if pm._confcutdir and pm._confcutdir.relto(parent): + break + + if parent.isdir(): + pkginit = parent.join("__init__.py") + if pkginit.isfile() and pkginit not in node_cache1: + col = self._collectfile(pkginit, handle_dupes=False) + if col: + if isinstance(col[0], Package): + pkg_roots[str(parent)] = col[0] + node_cache1[col[0].fspath] = [col[0]] + + # If it's a directory argument, recurse and look for any Subpackages. + # Let the Package collector deal with subnodes, don't collect here. + if argpath.check(dir=1): + assert not names, "invalid arg {!r}".format((argpath, names)) + + seen_dirs: Set[py.path.local] = set() + for direntry in visit(str(argpath), self._recurse): + if not direntry.is_file(): + continue + + path = py.path.local(direntry.path) + dirpath = path.dirpath() + + if dirpath not in seen_dirs: + # Collect packages first. + seen_dirs.add(dirpath) + pkginit = dirpath.join("__init__.py") + if pkginit.exists(): + for x in self._collectfile(pkginit): + yield x + if isinstance(x, Package): + pkg_roots[str(dirpath)] = x + if str(dirpath) in pkg_roots: + # Do not collect packages here. + continue + + for x in self._collectfile(path): + key = (type(x), x.fspath) + if key in node_cache2: + yield node_cache2[key] + else: + node_cache2[key] = x + yield x + else: + assert argpath.check(file=1) + + if argpath in node_cache1: + col = node_cache1[argpath] + else: + collect_root = pkg_roots.get(argpath.dirname, self) + col = collect_root._collectfile(argpath, handle_dupes=False) + if col: + node_cache1[argpath] = col + + matching = [] + work: List[ + Tuple[Sequence[Union[nodes.Item, nodes.Collector]], Sequence[str]] + ] = [(col, names)] + while work: + self.trace("matchnodes", col, names) + self.trace.root.indent += 1 + + matchnodes, matchnames = work.pop() + for node in matchnodes: + if not matchnames: + matching.append(node) + continue + if not isinstance(node, nodes.Collector): + continue + key = (type(node), node.nodeid) + if key in matchnodes_cache: + rep = matchnodes_cache[key] + else: + rep = collect_one_node(node) + matchnodes_cache[key] = rep + if rep.passed: + submatchnodes = [] + for r in rep.result: + # TODO: Remove parametrized workaround once collection structure contains + # parametrization. + if ( + r.name == matchnames[0] + or r.name.split("[")[0] == matchnames[0] + ): + submatchnodes.append(r) + if submatchnodes: + work.append((submatchnodes, matchnames[1:])) + # XXX Accept IDs that don't have "()" for class instances. + elif len(rep.result) == 1 and rep.result[0].name == "()": + work.append((rep.result, matchnames)) + else: + # Report collection failures here to avoid failing to run some test + # specified in the command line because the module could not be + # imported (#134). + node.ihook.pytest_collectreport(report=rep) + + self.trace("matchnodes finished -> ", len(matching), "nodes") + self.trace.root.indent -= 1 + + if not matching: + report_arg = "::".join((str(argpath), *names)) + self._notfound.append((report_arg, col)) + continue + + # If __init__.py was the only file requested, then the matched + # node will be the corresponding Package (by default), and the + # first yielded item will be the __init__ Module itself, so + # just use that. If this special case isn't taken, then all the + # files in the package will be yielded. + if argpath.basename == "__init__.py" and isinstance( + matching[0], Package + ): + try: + yield next(iter(matching[0].collect())) + except StopIteration: + # The package collects nothing with only an __init__.py + # file in it, which gets ignored by the default + # "python_files" option. + pass + continue + + yield from matching + + self.trace.root.indent -= 1 + + def genitems( + self, node: Union[nodes.Item, nodes.Collector] + ) -> Iterator[nodes.Item]: + self.trace("genitems", node) + if isinstance(node, nodes.Item): + node.ihook.pytest_itemcollected(item=node) + yield node + else: + assert isinstance(node, nodes.Collector) + rep = collect_one_node(node) + if rep.passed: + for subnode in rep.result: + yield from self.genitems(subnode) + node.ihook.pytest_collectreport(report=rep) + + +def search_pypath(module_name: str) -> str: + """Search sys.path for the given a dotted module name, and return its file system path.""" + try: + spec = importlib.util.find_spec(module_name) + # AttributeError: looks like package module, but actually filename + # ImportError: module does not exist + # ValueError: not a module name + except (AttributeError, ImportError, ValueError): + return module_name + if spec is None or spec.origin is None or spec.origin == "namespace": + return module_name + elif spec.submodule_search_locations: + return os.path.dirname(spec.origin) + else: + return spec.origin + + +def resolve_collection_argument( + invocation_path: Path, arg: str, *, as_pypath: bool = False +) -> Tuple[py.path.local, List[str]]: + """Parse path arguments optionally containing selection parts and return (fspath, names). + + Command-line arguments can point to files and/or directories, and optionally contain + parts for specific tests selection, for example: + + "pkg/tests/test_foo.py::TestClass::test_foo" + + This function ensures the path exists, and returns a tuple: + + (py.path.path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"]) + + When as_pypath is True, expects that the command-line argument actually contains + module paths instead of file-system paths: + + "pkg.tests.test_foo::TestClass::test_foo" + + In which case we search sys.path for a matching module, and then return the *path* to the + found module. + + If the path doesn't exist, raise UsageError. + If the path is a directory and selection parts are present, raise UsageError. + """ + strpath, *parts = str(arg).split("::") + if as_pypath: + strpath = search_pypath(strpath) + fspath = invocation_path / strpath + fspath = absolutepath(fspath) + if not fspath.exists(): + msg = ( + "module or package not found: {arg} (missing __init__.py?)" + if as_pypath + else "file or directory not found: {arg}" + ) + raise UsageError(msg.format(arg=arg)) + if parts and fspath.is_dir(): + msg = ( + "package argument cannot contain :: selection parts: {arg}" + if as_pypath + else "directory argument cannot contain :: selection parts: {arg}" + ) + raise UsageError(msg.format(arg=arg)) + return py.path.local(str(fspath)), parts diff --git a/myenv/lib/python3.9/site-packages/_pytest/mark/__init__.py b/myenv/lib/python3.9/site-packages/_pytest/mark/__init__.py new file mode 100644 index 0000000..329a11c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/mark/__init__.py @@ -0,0 +1,282 @@ +"""Generic mechanism for marking and selecting python functions.""" +import warnings +from typing import AbstractSet +from typing import Collection +from typing import List +from typing import Optional +from typing import TYPE_CHECKING +from typing import Union + +import attr + +from .expression import Expression +from .expression import ParseError +from .structures import EMPTY_PARAMETERSET_OPTION +from .structures import get_empty_parameterset_mark +from .structures import Mark +from .structures import MARK_GEN +from .structures import MarkDecorator +from .structures import MarkGenerator +from .structures import ParameterSet +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config import UsageError +from _pytest.config.argparsing import Parser +from _pytest.deprecated import MINUS_K_COLON +from _pytest.deprecated import MINUS_K_DASH +from _pytest.store import StoreKey + +if TYPE_CHECKING: + from _pytest.nodes import Item + + +__all__ = [ + "MARK_GEN", + "Mark", + "MarkDecorator", + "MarkGenerator", + "ParameterSet", + "get_empty_parameterset_mark", +] + + +old_mark_config_key = StoreKey[Optional[Config]]() + + +def param( + *values: object, + marks: Union[MarkDecorator, Collection[Union[MarkDecorator, Mark]]] = (), + id: Optional[str] = None, +) -> ParameterSet: + """Specify a parameter in `pytest.mark.parametrize`_ calls or + :ref:`parametrized fixtures `. + + .. code-block:: python + + @pytest.mark.parametrize( + "test_input,expected", + [("3+5", 8), pytest.param("6*9", 42, marks=pytest.mark.xfail),], + ) + def test_eval(test_input, expected): + assert eval(test_input) == expected + + :param values: Variable args of the values of the parameter set, in order. + :keyword marks: A single mark or a list of marks to be applied to this parameter set. + :keyword str id: The id to attribute to this parameter set. + """ + return ParameterSet.param(*values, marks=marks, id=id) + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group._addoption( + "-k", + action="store", + dest="keyword", + default="", + metavar="EXPRESSION", + help="only run tests which match the given substring expression. " + "An expression is a python evaluatable expression " + "where all names are substring-matched against test names " + "and their parent classes. Example: -k 'test_method or test_" + "other' matches all test functions and classes whose name " + "contains 'test_method' or 'test_other', while -k 'not test_method' " + "matches those that don't contain 'test_method' in their names. " + "-k 'not test_method and not test_other' will eliminate the matches. " + "Additionally keywords are matched to classes and functions " + "containing extra names in their 'extra_keyword_matches' set, " + "as well as functions which have names assigned directly to them. " + "The matching is case-insensitive.", + ) + + group._addoption( + "-m", + action="store", + dest="markexpr", + default="", + metavar="MARKEXPR", + help="only run tests matching given mark expression.\n" + "For example: -m 'mark1 and not mark2'.", + ) + + group.addoption( + "--markers", + action="store_true", + help="show markers (builtin, plugin and per-project ones).", + ) + + parser.addini("markers", "markers for test functions", "linelist") + parser.addini(EMPTY_PARAMETERSET_OPTION, "default marker for empty parametersets") + + +@hookimpl(tryfirst=True) +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + import _pytest.config + + if config.option.markers: + config._do_configure() + tw = _pytest.config.create_terminal_writer(config) + for line in config.getini("markers"): + parts = line.split(":", 1) + name = parts[0] + rest = parts[1] if len(parts) == 2 else "" + tw.write("@pytest.mark.%s:" % name, bold=True) + tw.line(rest) + tw.line() + config._ensure_unconfigure() + return 0 + + return None + + +@attr.s(slots=True) +class KeywordMatcher: + """A matcher for keywords. + + Given a list of names, matches any substring of one of these names. The + string inclusion check is case-insensitive. + + Will match on the name of colitem, including the names of its parents. + Only matches names of items which are either a :class:`Class` or a + :class:`Function`. + + Additionally, matches on names in the 'extra_keyword_matches' set of + any item, as well as names directly assigned to test functions. + """ + + _names = attr.ib(type=AbstractSet[str]) + + @classmethod + def from_item(cls, item: "Item") -> "KeywordMatcher": + mapped_names = set() + + # Add the names of the current item and any parent items. + import pytest + + for node in item.listchain(): + if not isinstance(node, (pytest.Instance, pytest.Session)): + mapped_names.add(node.name) + + # Add the names added as extra keywords to current or parent items. + mapped_names.update(item.listextrakeywords()) + + # Add the names attached to the current function through direct assignment. + function_obj = getattr(item, "function", None) + if function_obj: + mapped_names.update(function_obj.__dict__) + + # Add the markers to the keywords as we no longer handle them correctly. + mapped_names.update(mark.name for mark in item.iter_markers()) + + return cls(mapped_names) + + def __call__(self, subname: str) -> bool: + subname = subname.lower() + names = (name.lower() for name in self._names) + + for name in names: + if subname in name: + return True + return False + + +def deselect_by_keyword(items: "List[Item]", config: Config) -> None: + keywordexpr = config.option.keyword.lstrip() + if not keywordexpr: + return + + if keywordexpr.startswith("-"): + # To be removed in pytest 7.0.0. + warnings.warn(MINUS_K_DASH, stacklevel=2) + keywordexpr = "not " + keywordexpr[1:] + selectuntil = False + if keywordexpr[-1:] == ":": + # To be removed in pytest 7.0.0. + warnings.warn(MINUS_K_COLON, stacklevel=2) + selectuntil = True + keywordexpr = keywordexpr[:-1] + + try: + expression = Expression.compile(keywordexpr) + except ParseError as e: + raise UsageError( + f"Wrong expression passed to '-k': {keywordexpr}: {e}" + ) from None + + remaining = [] + deselected = [] + for colitem in items: + if keywordexpr and not expression.evaluate(KeywordMatcher.from_item(colitem)): + deselected.append(colitem) + else: + if selectuntil: + keywordexpr = None + remaining.append(colitem) + + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = remaining + + +@attr.s(slots=True) +class MarkMatcher: + """A matcher for markers which are present. + + Tries to match on any marker names, attached to the given colitem. + """ + + own_mark_names = attr.ib() + + @classmethod + def from_item(cls, item) -> "MarkMatcher": + mark_names = {mark.name for mark in item.iter_markers()} + return cls(mark_names) + + def __call__(self, name: str) -> bool: + return name in self.own_mark_names + + +def deselect_by_mark(items: "List[Item]", config: Config) -> None: + matchexpr = config.option.markexpr + if not matchexpr: + return + + try: + expression = Expression.compile(matchexpr) + except ParseError as e: + raise UsageError(f"Wrong expression passed to '-m': {matchexpr}: {e}") from None + + remaining = [] + deselected = [] + for item in items: + if expression.evaluate(MarkMatcher.from_item(item)): + remaining.append(item) + else: + deselected.append(item) + + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = remaining + + +def pytest_collection_modifyitems(items: "List[Item]", config: Config) -> None: + deselect_by_keyword(items, config) + deselect_by_mark(items, config) + + +def pytest_configure(config: Config) -> None: + config._store[old_mark_config_key] = MARK_GEN._config + MARK_GEN._config = config + + empty_parameterset = config.getini(EMPTY_PARAMETERSET_OPTION) + + if empty_parameterset not in ("skip", "xfail", "fail_at_collect", None, ""): + raise UsageError( + "{!s} must be one of skip, xfail or fail_at_collect" + " but it is {!r}".format(EMPTY_PARAMETERSET_OPTION, empty_parameterset) + ) + + +def pytest_unconfigure(config: Config) -> None: + MARK_GEN._config = config._store.get(old_mark_config_key, None) diff --git a/myenv/lib/python3.9/site-packages/_pytest/mark/expression.py b/myenv/lib/python3.9/site-packages/_pytest/mark/expression.py new file mode 100644 index 0000000..dc3991b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/mark/expression.py @@ -0,0 +1,221 @@ +r"""Evaluate match expressions, as used by `-k` and `-m`. + +The grammar is: + +expression: expr? EOF +expr: and_expr ('or' and_expr)* +and_expr: not_expr ('and' not_expr)* +not_expr: 'not' not_expr | '(' expr ')' | ident +ident: (\w|:|\+|-|\.|\[|\])+ + +The semantics are: + +- Empty expression evaluates to False. +- ident evaluates to True of False according to a provided matcher function. +- or/and/not evaluate according to the usual boolean semantics. +""" +import ast +import enum +import re +import types +from typing import Callable +from typing import Iterator +from typing import Mapping +from typing import Optional +from typing import Sequence +from typing import TYPE_CHECKING + +import attr + +if TYPE_CHECKING: + from typing import NoReturn + + +__all__ = [ + "Expression", + "ParseError", +] + + +class TokenType(enum.Enum): + LPAREN = "left parenthesis" + RPAREN = "right parenthesis" + OR = "or" + AND = "and" + NOT = "not" + IDENT = "identifier" + EOF = "end of input" + + +@attr.s(frozen=True, slots=True) +class Token: + type = attr.ib(type=TokenType) + value = attr.ib(type=str) + pos = attr.ib(type=int) + + +class ParseError(Exception): + """The expression contains invalid syntax. + + :param column: The column in the line where the error occurred (1-based). + :param message: A description of the error. + """ + + def __init__(self, column: int, message: str) -> None: + self.column = column + self.message = message + + def __str__(self) -> str: + return f"at column {self.column}: {self.message}" + + +class Scanner: + __slots__ = ("tokens", "current") + + def __init__(self, input: str) -> None: + self.tokens = self.lex(input) + self.current = next(self.tokens) + + def lex(self, input: str) -> Iterator[Token]: + pos = 0 + while pos < len(input): + if input[pos] in (" ", "\t"): + pos += 1 + elif input[pos] == "(": + yield Token(TokenType.LPAREN, "(", pos) + pos += 1 + elif input[pos] == ")": + yield Token(TokenType.RPAREN, ")", pos) + pos += 1 + else: + match = re.match(r"(:?\w|:|\+|-|\.|\[|\])+", input[pos:]) + if match: + value = match.group(0) + if value == "or": + yield Token(TokenType.OR, value, pos) + elif value == "and": + yield Token(TokenType.AND, value, pos) + elif value == "not": + yield Token(TokenType.NOT, value, pos) + else: + yield Token(TokenType.IDENT, value, pos) + pos += len(value) + else: + raise ParseError( + pos + 1, 'unexpected character "{}"'.format(input[pos]), + ) + yield Token(TokenType.EOF, "", pos) + + def accept(self, type: TokenType, *, reject: bool = False) -> Optional[Token]: + if self.current.type is type: + token = self.current + if token.type is not TokenType.EOF: + self.current = next(self.tokens) + return token + if reject: + self.reject((type,)) + return None + + def reject(self, expected: Sequence[TokenType]) -> "NoReturn": + raise ParseError( + self.current.pos + 1, + "expected {}; got {}".format( + " OR ".join(type.value for type in expected), self.current.type.value, + ), + ) + + +# True, False and None are legal match expression identifiers, +# but illegal as Python identifiers. To fix this, this prefix +# is added to identifiers in the conversion to Python AST. +IDENT_PREFIX = "$" + + +def expression(s: Scanner) -> ast.Expression: + if s.accept(TokenType.EOF): + ret: ast.expr = ast.NameConstant(False) + else: + ret = expr(s) + s.accept(TokenType.EOF, reject=True) + return ast.fix_missing_locations(ast.Expression(ret)) + + +def expr(s: Scanner) -> ast.expr: + ret = and_expr(s) + while s.accept(TokenType.OR): + rhs = and_expr(s) + ret = ast.BoolOp(ast.Or(), [ret, rhs]) + return ret + + +def and_expr(s: Scanner) -> ast.expr: + ret = not_expr(s) + while s.accept(TokenType.AND): + rhs = not_expr(s) + ret = ast.BoolOp(ast.And(), [ret, rhs]) + return ret + + +def not_expr(s: Scanner) -> ast.expr: + if s.accept(TokenType.NOT): + return ast.UnaryOp(ast.Not(), not_expr(s)) + if s.accept(TokenType.LPAREN): + ret = expr(s) + s.accept(TokenType.RPAREN, reject=True) + return ret + ident = s.accept(TokenType.IDENT) + if ident: + return ast.Name(IDENT_PREFIX + ident.value, ast.Load()) + s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT)) + + +class MatcherAdapter(Mapping[str, bool]): + """Adapts a matcher function to a locals mapping as required by eval().""" + + def __init__(self, matcher: Callable[[str], bool]) -> None: + self.matcher = matcher + + def __getitem__(self, key: str) -> bool: + return self.matcher(key[len(IDENT_PREFIX) :]) + + def __iter__(self) -> Iterator[str]: + raise NotImplementedError() + + def __len__(self) -> int: + raise NotImplementedError() + + +class Expression: + """A compiled match expression as used by -k and -m. + + The expression can be evaulated against different matchers. + """ + + __slots__ = ("code",) + + def __init__(self, code: types.CodeType) -> None: + self.code = code + + @classmethod + def compile(self, input: str) -> "Expression": + """Compile a match expression. + + :param input: The input expression - one line. + """ + astexpr = expression(Scanner(input)) + code: types.CodeType = compile( + astexpr, filename="", mode="eval", + ) + return Expression(code) + + def evaluate(self, matcher: Callable[[str], bool]) -> bool: + """Evaluate the match expression. + + :param matcher: + Given an identifier, should return whether it matches or not. + Should be prepared to handle arbitrary strings as input. + + :returns: Whether the expression matches or not. + """ + ret: bool = eval(self.code, {"__builtins__": {}}, MatcherAdapter(matcher)) + return ret diff --git a/myenv/lib/python3.9/site-packages/_pytest/mark/structures.py b/myenv/lib/python3.9/site-packages/_pytest/mark/structures.py new file mode 100644 index 0000000..6c126cf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/mark/structures.py @@ -0,0 +1,559 @@ +import collections.abc +import inspect +import warnings +from typing import Any +from typing import Callable +from typing import Collection +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Mapping +from typing import MutableMapping +from typing import NamedTuple +from typing import Optional +from typing import overload +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import attr + +from .._code import getfslineno +from ..compat import ascii_escaped +from ..compat import final +from ..compat import NOTSET +from ..compat import NotSetType +from _pytest.config import Config +from _pytest.outcomes import fail +from _pytest.warning_types import PytestUnknownMarkWarning + +if TYPE_CHECKING: + from ..nodes import Node + + +EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark" + + +def istestfunc(func) -> bool: + return ( + hasattr(func, "__call__") + and getattr(func, "__name__", "") != "" + ) + + +def get_empty_parameterset_mark( + config: Config, argnames: Sequence[str], func +) -> "MarkDecorator": + from ..nodes import Collector + + fs, lineno = getfslineno(func) + reason = "got empty parameter set %r, function %s at %s:%d" % ( + argnames, + func.__name__, + fs, + lineno, + ) + + requested_mark = config.getini(EMPTY_PARAMETERSET_OPTION) + if requested_mark in ("", None, "skip"): + mark = MARK_GEN.skip(reason=reason) + elif requested_mark == "xfail": + mark = MARK_GEN.xfail(reason=reason, run=False) + elif requested_mark == "fail_at_collect": + f_name = func.__name__ + _, lineno = getfslineno(func) + raise Collector.CollectError( + "Empty parameter set in '%s' at line %d" % (f_name, lineno + 1) + ) + else: + raise LookupError(requested_mark) + return mark + + +class ParameterSet( + NamedTuple( + "ParameterSet", + [ + ("values", Sequence[Union[object, NotSetType]]), + ("marks", Collection[Union["MarkDecorator", "Mark"]]), + ("id", Optional[str]), + ], + ) +): + @classmethod + def param( + cls, + *values: object, + marks: Union["MarkDecorator", Collection[Union["MarkDecorator", "Mark"]]] = (), + id: Optional[str] = None, + ) -> "ParameterSet": + if isinstance(marks, MarkDecorator): + marks = (marks,) + else: + assert isinstance(marks, collections.abc.Collection) + + if id is not None: + if not isinstance(id, str): + raise TypeError( + "Expected id to be a string, got {}: {!r}".format(type(id), id) + ) + id = ascii_escaped(id) + return cls(values, marks, id) + + @classmethod + def extract_from( + cls, + parameterset: Union["ParameterSet", Sequence[object], object], + force_tuple: bool = False, + ) -> "ParameterSet": + """Extract from an object or objects. + + :param parameterset: + A legacy style parameterset that may or may not be a tuple, + and may or may not be wrapped into a mess of mark objects. + + :param force_tuple: + Enforce tuple wrapping so single argument tuple values + don't get decomposed and break tests. + """ + + if isinstance(parameterset, cls): + return parameterset + if force_tuple: + return cls.param(parameterset) + else: + # TODO: Refactor to fix this type-ignore. Currently the following + # passes type-checking but crashes: + # + # @pytest.mark.parametrize(('x', 'y'), [1, 2]) + # def test_foo(x, y): pass + return cls(parameterset, marks=[], id=None) # type: ignore[arg-type] + + @staticmethod + def _parse_parametrize_args( + argnames: Union[str, List[str], Tuple[str, ...]], + argvalues: Iterable[Union["ParameterSet", Sequence[object], object]], + *args, + **kwargs, + ) -> Tuple[Union[List[str], Tuple[str, ...]], bool]: + if not isinstance(argnames, (tuple, list)): + argnames = [x.strip() for x in argnames.split(",") if x.strip()] + force_tuple = len(argnames) == 1 + else: + force_tuple = False + return argnames, force_tuple + + @staticmethod + def _parse_parametrize_parameters( + argvalues: Iterable[Union["ParameterSet", Sequence[object], object]], + force_tuple: bool, + ) -> List["ParameterSet"]: + return [ + ParameterSet.extract_from(x, force_tuple=force_tuple) for x in argvalues + ] + + @classmethod + def _for_parametrize( + cls, + argnames: Union[str, List[str], Tuple[str, ...]], + argvalues: Iterable[Union["ParameterSet", Sequence[object], object]], + func, + config: Config, + nodeid: str, + ) -> Tuple[Union[List[str], Tuple[str, ...]], List["ParameterSet"]]: + argnames, force_tuple = cls._parse_parametrize_args(argnames, argvalues) + parameters = cls._parse_parametrize_parameters(argvalues, force_tuple) + del argvalues + + if parameters: + # Check all parameter sets have the correct number of values. + for param in parameters: + if len(param.values) != len(argnames): + msg = ( + '{nodeid}: in "parametrize" the number of names ({names_len}):\n' + " {names}\n" + "must be equal to the number of values ({values_len}):\n" + " {values}" + ) + fail( + msg.format( + nodeid=nodeid, + values=param.values, + names=argnames, + names_len=len(argnames), + values_len=len(param.values), + ), + pytrace=False, + ) + else: + # Empty parameter set (likely computed at runtime): create a single + # parameter set with NOTSET values, with the "empty parameter set" mark applied to it. + mark = get_empty_parameterset_mark(config, argnames, func) + parameters.append( + ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None) + ) + return argnames, parameters + + +@final +@attr.s(frozen=True) +class Mark: + #: Name of the mark. + name = attr.ib(type=str) + #: Positional arguments of the mark decorator. + args = attr.ib(type=Tuple[Any, ...]) + #: Keyword arguments of the mark decorator. + kwargs = attr.ib(type=Mapping[str, Any]) + + #: Source Mark for ids with parametrize Marks. + _param_ids_from = attr.ib(type=Optional["Mark"], default=None, repr=False) + #: Resolved/generated ids with parametrize Marks. + _param_ids_generated = attr.ib( + type=Optional[Sequence[str]], default=None, repr=False + ) + + def _has_param_ids(self) -> bool: + return "ids" in self.kwargs or len(self.args) >= 4 + + def combined_with(self, other: "Mark") -> "Mark": + """Return a new Mark which is a combination of this + Mark and another Mark. + + Combines by appending args and merging kwargs. + + :param Mark other: The mark to combine with. + :rtype: Mark + """ + assert self.name == other.name + + # Remember source of ids with parametrize Marks. + param_ids_from: Optional[Mark] = None + if self.name == "parametrize": + if other._has_param_ids(): + param_ids_from = other + elif self._has_param_ids(): + param_ids_from = self + + return Mark( + self.name, + self.args + other.args, + dict(self.kwargs, **other.kwargs), + param_ids_from=param_ids_from, + ) + + +# A generic parameter designating an object to which a Mark may +# be applied -- a test function (callable) or class. +# Note: a lambda is not allowed, but this can't be represented. +_Markable = TypeVar("_Markable", bound=Union[Callable[..., object], type]) + + +@attr.s +class MarkDecorator: + """A decorator for applying a mark on test functions and classes. + + MarkDecorators are created with ``pytest.mark``:: + + mark1 = pytest.mark.NAME # Simple MarkDecorator + mark2 = pytest.mark.NAME(name1=value) # Parametrized MarkDecorator + + and can then be applied as decorators to test functions:: + + @mark2 + def test_function(): + pass + + When a MarkDecorator is called it does the following: + + 1. If called with a single class as its only positional argument and no + additional keyword arguments, it attaches the mark to the class so it + gets applied automatically to all test cases found in that class. + + 2. If called with a single function as its only positional argument and + no additional keyword arguments, it attaches the mark to the function, + containing all the arguments already stored internally in the + MarkDecorator. + + 3. When called in any other case, it returns a new MarkDecorator instance + with the original MarkDecorator's content updated with the arguments + passed to this call. + + Note: The rules above prevent MarkDecorators from storing only a single + function or class reference as their positional argument with no + additional keyword or positional arguments. You can work around this by + using `with_args()`. + """ + + mark = attr.ib(type=Mark, validator=attr.validators.instance_of(Mark)) + + @property + def name(self) -> str: + """Alias for mark.name.""" + return self.mark.name + + @property + def args(self) -> Tuple[Any, ...]: + """Alias for mark.args.""" + return self.mark.args + + @property + def kwargs(self) -> Mapping[str, Any]: + """Alias for mark.kwargs.""" + return self.mark.kwargs + + @property + def markname(self) -> str: + return self.name # for backward-compat (2.4.1 had this attr) + + def __repr__(self) -> str: + return f"" + + def with_args(self, *args: object, **kwargs: object) -> "MarkDecorator": + """Return a MarkDecorator with extra arguments added. + + Unlike calling the MarkDecorator, with_args() can be used even + if the sole argument is a callable/class. + + :rtype: MarkDecorator + """ + mark = Mark(self.name, args, kwargs) + return self.__class__(self.mark.combined_with(mark)) + + # Type ignored because the overloads overlap with an incompatible + # return type. Not much we can do about that. Thankfully mypy picks + # the first match so it works out even if we break the rules. + @overload + def __call__(self, arg: _Markable) -> _Markable: # type: ignore[misc] + pass + + @overload + def __call__(self, *args: object, **kwargs: object) -> "MarkDecorator": + pass + + def __call__(self, *args: object, **kwargs: object): + """Call the MarkDecorator.""" + if args and not kwargs: + func = args[0] + is_class = inspect.isclass(func) + if len(args) == 1 and (istestfunc(func) or is_class): + store_mark(func, self.mark) + return func + return self.with_args(*args, **kwargs) + + +def get_unpacked_marks(obj) -> List[Mark]: + """Obtain the unpacked marks that are stored on an object.""" + mark_list = getattr(obj, "pytestmark", []) + if not isinstance(mark_list, list): + mark_list = [mark_list] + return normalize_mark_list(mark_list) + + +def normalize_mark_list(mark_list: Iterable[Union[Mark, MarkDecorator]]) -> List[Mark]: + """Normalize marker decorating helpers to mark objects. + + :type List[Union[Mark, Markdecorator]] mark_list: + :rtype: List[Mark] + """ + extracted = [ + getattr(mark, "mark", mark) for mark in mark_list + ] # unpack MarkDecorator + for mark in extracted: + if not isinstance(mark, Mark): + raise TypeError(f"got {mark!r} instead of Mark") + return [x for x in extracted if isinstance(x, Mark)] + + +def store_mark(obj, mark: Mark) -> None: + """Store a Mark on an object. + + This is used to implement the Mark declarations/decorators correctly. + """ + assert isinstance(mark, Mark), mark + # Always reassign name to avoid updating pytestmark in a reference that + # was only borrowed. + obj.pytestmark = get_unpacked_marks(obj) + [mark] + + +# Typing for builtin pytest marks. This is cheating; it gives builtin marks +# special privilege, and breaks modularity. But practicality beats purity... +if TYPE_CHECKING: + from _pytest.fixtures import _Scope + + class _SkipMarkDecorator(MarkDecorator): + @overload # type: ignore[override,misc] + def __call__(self, arg: _Markable) -> _Markable: + ... + + @overload + def __call__(self, reason: str = ...) -> "MarkDecorator": + ... + + class _SkipifMarkDecorator(MarkDecorator): + def __call__( # type: ignore[override] + self, + condition: Union[str, bool] = ..., + *conditions: Union[str, bool], + reason: str = ..., + ) -> MarkDecorator: + ... + + class _XfailMarkDecorator(MarkDecorator): + @overload # type: ignore[override,misc] + def __call__(self, arg: _Markable) -> _Markable: + ... + + @overload + def __call__( + self, + condition: Union[str, bool] = ..., + *conditions: Union[str, bool], + reason: str = ..., + run: bool = ..., + raises: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = ..., + strict: bool = ..., + ) -> MarkDecorator: + ... + + class _ParametrizeMarkDecorator(MarkDecorator): + def __call__( # type: ignore[override] + self, + argnames: Union[str, List[str], Tuple[str, ...]], + argvalues: Iterable[Union[ParameterSet, Sequence[object], object]], + *, + indirect: Union[bool, Sequence[str]] = ..., + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = ..., + scope: Optional[_Scope] = ..., + ) -> MarkDecorator: + ... + + class _UsefixturesMarkDecorator(MarkDecorator): + def __call__( # type: ignore[override] + self, *fixtures: str + ) -> MarkDecorator: + ... + + class _FilterwarningsMarkDecorator(MarkDecorator): + def __call__( # type: ignore[override] + self, *filters: str + ) -> MarkDecorator: + ... + + +@final +class MarkGenerator: + """Factory for :class:`MarkDecorator` objects - exposed as + a ``pytest.mark`` singleton instance. + + Example:: + + import pytest + + @pytest.mark.slowtest + def test_function(): + pass + + applies a 'slowtest' :class:`Mark` on ``test_function``. + """ + + _config: Optional[Config] = None + _markers: Set[str] = set() + + # See TYPE_CHECKING above. + if TYPE_CHECKING: + skip: _SkipMarkDecorator + skipif: _SkipifMarkDecorator + xfail: _XfailMarkDecorator + parametrize: _ParametrizeMarkDecorator + usefixtures: _UsefixturesMarkDecorator + filterwarnings: _FilterwarningsMarkDecorator + + def __getattr__(self, name: str) -> MarkDecorator: + if name[0] == "_": + raise AttributeError("Marker name must NOT start with underscore") + + if self._config is not None: + # We store a set of markers as a performance optimisation - if a mark + # name is in the set we definitely know it, but a mark may be known and + # not in the set. We therefore start by updating the set! + if name not in self._markers: + for line in self._config.getini("markers"): + # example lines: "skipif(condition): skip the given test if..." + # or "hypothesis: tests which use Hypothesis", so to get the + # marker name we split on both `:` and `(`. + marker = line.split(":")[0].split("(")[0].strip() + self._markers.add(marker) + + # If the name is not in the set of known marks after updating, + # then it really is time to issue a warning or an error. + if name not in self._markers: + if self._config.option.strict_markers or self._config.option.strict: + fail( + f"{name!r} not found in `markers` configuration option", + pytrace=False, + ) + + # Raise a specific error for common misspellings of "parametrize". + if name in ["parameterize", "parametrise", "parameterise"]: + __tracebackhide__ = True + fail(f"Unknown '{name}' mark, did you mean 'parametrize'?") + + warnings.warn( + "Unknown pytest.mark.%s - is this a typo? You can register " + "custom marks to avoid this warning - for details, see " + "https://docs.pytest.org/en/stable/mark.html" % name, + PytestUnknownMarkWarning, + 2, + ) + + return MarkDecorator(Mark(name, (), {})) + + +MARK_GEN = MarkGenerator() + + +@final +class NodeKeywords(MutableMapping[str, Any]): + def __init__(self, node: "Node") -> None: + self.node = node + self.parent = node.parent + self._markers = {node.name: True} + + def __getitem__(self, key: str) -> Any: + try: + return self._markers[key] + except KeyError: + if self.parent is None: + raise + return self.parent.keywords[key] + + def __setitem__(self, key: str, value: Any) -> None: + self._markers[key] = value + + def __delitem__(self, key: str) -> None: + raise ValueError("cannot delete key in keywords dict") + + def __iter__(self) -> Iterator[str]: + seen = self._seen() + return iter(seen) + + def _seen(self) -> Set[str]: + seen = set(self._markers) + if self.parent is not None: + seen.update(self.parent.keywords) + return seen + + def __len__(self) -> int: + return len(self._seen()) + + def __repr__(self) -> str: + return f"" diff --git a/myenv/lib/python3.9/site-packages/_pytest/monkeypatch.py b/myenv/lib/python3.9/site-packages/_pytest/monkeypatch.py new file mode 100644 index 0000000..a052f69 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/monkeypatch.py @@ -0,0 +1,379 @@ +"""Monkeypatching and mocking functionality.""" +import os +import re +import sys +import warnings +from contextlib import contextmanager +from pathlib import Path +from typing import Any +from typing import Generator +from typing import List +from typing import MutableMapping +from typing import Optional +from typing import overload +from typing import Tuple +from typing import TypeVar +from typing import Union + +from _pytest.compat import final +from _pytest.fixtures import fixture +from _pytest.warning_types import PytestWarning + +RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$") + + +K = TypeVar("K") +V = TypeVar("V") + + +@fixture +def monkeypatch() -> Generator["MonkeyPatch", None, None]: + """A convenient fixture for monkey-patching. + + The fixture provides these methods to modify objects, dictionaries or + os.environ:: + + monkeypatch.setattr(obj, name, value, raising=True) + monkeypatch.delattr(obj, name, raising=True) + monkeypatch.setitem(mapping, name, value) + monkeypatch.delitem(obj, name, raising=True) + monkeypatch.setenv(name, value, prepend=False) + monkeypatch.delenv(name, raising=True) + monkeypatch.syspath_prepend(path) + monkeypatch.chdir(path) + + All modifications will be undone after the requesting test function or + fixture has finished. The ``raising`` parameter determines if a KeyError + or AttributeError will be raised if the set/deletion operation has no target. + """ + mpatch = MonkeyPatch() + yield mpatch + mpatch.undo() + + +def resolve(name: str) -> object: + # Simplified from zope.dottedname. + parts = name.split(".") + + used = parts.pop(0) + found = __import__(used) + for part in parts: + used += "." + part + try: + found = getattr(found, part) + except AttributeError: + pass + else: + continue + # We use explicit un-nesting of the handling block in order + # to avoid nested exceptions. + try: + __import__(used) + except ImportError as ex: + expected = str(ex).split()[-1] + if expected == used: + raise + else: + raise ImportError(f"import error in {used}: {ex}") from ex + found = annotated_getattr(found, part, used) + return found + + +def annotated_getattr(obj: object, name: str, ann: str) -> object: + try: + obj = getattr(obj, name) + except AttributeError as e: + raise AttributeError( + "{!r} object at {} has no attribute {!r}".format( + type(obj).__name__, ann, name + ) + ) from e + return obj + + +def derive_importpath(import_path: str, raising: bool) -> Tuple[str, object]: + if not isinstance(import_path, str) or "." not in import_path: # type: ignore[unreachable] + raise TypeError(f"must be absolute import path string, not {import_path!r}") + module, attr = import_path.rsplit(".", 1) + target = resolve(module) + if raising: + annotated_getattr(target, attr, ann=module) + return attr, target + + +class Notset: + def __repr__(self) -> str: + return "" + + +notset = Notset() + + +@final +class MonkeyPatch: + """Helper to conveniently monkeypatch attributes/items/environment + variables/syspath. + + Returned by the :fixture:`monkeypatch` fixture. + + :versionchanged:: 6.2 + Can now also be used directly as `pytest.MonkeyPatch()`, for when + the fixture is not available. In this case, use + :meth:`with MonkeyPatch.context() as mp: ` or remember to call + :meth:`undo` explicitly. + """ + + def __init__(self) -> None: + self._setattr: List[Tuple[object, str, object]] = [] + self._setitem: List[Tuple[MutableMapping[Any, Any], object, object]] = ([]) + self._cwd: Optional[str] = None + self._savesyspath: Optional[List[str]] = None + + @classmethod + @contextmanager + def context(cls) -> Generator["MonkeyPatch", None, None]: + """Context manager that returns a new :class:`MonkeyPatch` object + which undoes any patching done inside the ``with`` block upon exit. + + Example: + + .. code-block:: python + + import functools + + + def test_partial(monkeypatch): + with monkeypatch.context() as m: + m.setattr(functools, "partial", 3) + + Useful in situations where it is desired to undo some patches before the test ends, + such as mocking ``stdlib`` functions that might break pytest itself if mocked (for examples + of this see `#3290 `_. + """ + m = cls() + try: + yield m + finally: + m.undo() + + @overload + def setattr( + self, target: str, name: object, value: Notset = ..., raising: bool = ..., + ) -> None: + ... + + @overload + def setattr( + self, target: object, name: str, value: object, raising: bool = ..., + ) -> None: + ... + + def setattr( + self, + target: Union[str, object], + name: Union[object, str], + value: object = notset, + raising: bool = True, + ) -> None: + """Set attribute value on target, memorizing the old value. + + For convenience you can specify a string as ``target`` which + will be interpreted as a dotted import path, with the last part + being the attribute name. For example, + ``monkeypatch.setattr("os.getcwd", lambda: "/")`` + would set the ``getcwd`` function of the ``os`` module. + + Raises AttributeError if the attribute does not exist, unless + ``raising`` is set to False. + """ + __tracebackhide__ = True + import inspect + + if isinstance(value, Notset): + if not isinstance(target, str): + raise TypeError( + "use setattr(target, name, value) or " + "setattr(target, value) with target being a dotted " + "import string" + ) + value = name + name, target = derive_importpath(target, raising) + else: + if not isinstance(name, str): + raise TypeError( + "use setattr(target, name, value) with name being a string or " + "setattr(target, value) with target being a dotted " + "import string" + ) + + oldval = getattr(target, name, notset) + if raising and oldval is notset: + raise AttributeError(f"{target!r} has no attribute {name!r}") + + # avoid class descriptors like staticmethod/classmethod + if inspect.isclass(target): + oldval = target.__dict__.get(name, notset) + self._setattr.append((target, name, oldval)) + setattr(target, name, value) + + def delattr( + self, + target: Union[object, str], + name: Union[str, Notset] = notset, + raising: bool = True, + ) -> None: + """Delete attribute ``name`` from ``target``. + + If no ``name`` is specified and ``target`` is a string + it will be interpreted as a dotted import path with the + last part being the attribute name. + + Raises AttributeError it the attribute does not exist, unless + ``raising`` is set to False. + """ + __tracebackhide__ = True + import inspect + + if isinstance(name, Notset): + if not isinstance(target, str): + raise TypeError( + "use delattr(target, name) or " + "delattr(target) with target being a dotted " + "import string" + ) + name, target = derive_importpath(target, raising) + + if not hasattr(target, name): + if raising: + raise AttributeError(name) + else: + oldval = getattr(target, name, notset) + # Avoid class descriptors like staticmethod/classmethod. + if inspect.isclass(target): + oldval = target.__dict__.get(name, notset) + self._setattr.append((target, name, oldval)) + delattr(target, name) + + def setitem(self, dic: MutableMapping[K, V], name: K, value: V) -> None: + """Set dictionary entry ``name`` to value.""" + self._setitem.append((dic, name, dic.get(name, notset))) + dic[name] = value + + def delitem(self, dic: MutableMapping[K, V], name: K, raising: bool = True) -> None: + """Delete ``name`` from dict. + + Raises ``KeyError`` if it doesn't exist, unless ``raising`` is set to + False. + """ + if name not in dic: + if raising: + raise KeyError(name) + else: + self._setitem.append((dic, name, dic.get(name, notset))) + del dic[name] + + def setenv(self, name: str, value: str, prepend: Optional[str] = None) -> None: + """Set environment variable ``name`` to ``value``. + + If ``prepend`` is a character, read the current environment variable + value and prepend the ``value`` adjoined with the ``prepend`` + character. + """ + if not isinstance(value, str): + warnings.warn( # type: ignore[unreachable] + PytestWarning( + "Value of environment variable {name} type should be str, but got " + "{value!r} (type: {type}); converted to str implicitly".format( + name=name, value=value, type=type(value).__name__ + ) + ), + stacklevel=2, + ) + value = str(value) + if prepend and name in os.environ: + value = value + prepend + os.environ[name] + self.setitem(os.environ, name, value) + + def delenv(self, name: str, raising: bool = True) -> None: + """Delete ``name`` from the environment. + + Raises ``KeyError`` if it does not exist, unless ``raising`` is set to + False. + """ + environ: MutableMapping[str, str] = os.environ + self.delitem(environ, name, raising=raising) + + def syspath_prepend(self, path) -> None: + """Prepend ``path`` to ``sys.path`` list of import locations.""" + from pkg_resources import fixup_namespace_packages + + if self._savesyspath is None: + self._savesyspath = sys.path[:] + sys.path.insert(0, str(path)) + + # https://github.com/pypa/setuptools/blob/d8b901bc/docs/pkg_resources.txt#L162-L171 + fixup_namespace_packages(str(path)) + + # A call to syspathinsert() usually means that the caller wants to + # import some dynamically created files, thus with python3 we + # invalidate its import caches. + # This is especially important when any namespace package is in use, + # since then the mtime based FileFinder cache (that gets created in + # this case already) gets not invalidated when writing the new files + # quickly afterwards. + from importlib import invalidate_caches + + invalidate_caches() + + def chdir(self, path) -> None: + """Change the current working directory to the specified path. + + Path can be a string or a py.path.local object. + """ + if self._cwd is None: + self._cwd = os.getcwd() + if hasattr(path, "chdir"): + path.chdir() + elif isinstance(path, Path): + # Modern python uses the fspath protocol here LEGACY + os.chdir(str(path)) + else: + os.chdir(path) + + def undo(self) -> None: + """Undo previous changes. + + This call consumes the undo stack. Calling it a second time has no + effect unless you do more monkeypatching after the undo call. + + There is generally no need to call `undo()`, since it is + called automatically during tear-down. + + Note that the same `monkeypatch` fixture is used across a + single test function invocation. If `monkeypatch` is used both by + the test function itself and one of the test fixtures, + calling `undo()` will undo all of the changes made in + both functions. + """ + for obj, name, value in reversed(self._setattr): + if value is not notset: + setattr(obj, name, value) + else: + delattr(obj, name) + self._setattr[:] = [] + for dictionary, key, value in reversed(self._setitem): + if value is notset: + try: + del dictionary[key] + except KeyError: + pass # Was already deleted, so we have the desired state. + else: + dictionary[key] = value + self._setitem[:] = [] + if self._savesyspath is not None: + sys.path[:] = self._savesyspath + self._savesyspath = None + + if self._cwd is not None: + os.chdir(self._cwd) + self._cwd = None diff --git a/myenv/lib/python3.9/site-packages/_pytest/nodes.py b/myenv/lib/python3.9/site-packages/_pytest/nodes.py new file mode 100644 index 0000000..27434fb --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/nodes.py @@ -0,0 +1,591 @@ +import os +import warnings +from pathlib import Path +from typing import Callable +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import overload +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import py + +import _pytest._code +from _pytest._code import getfslineno +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import TerminalRepr +from _pytest.compat import cached_property +from _pytest.config import Config +from _pytest.config import ConftestImportFailure +from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH +from _pytest.mark.structures import Mark +from _pytest.mark.structures import MarkDecorator +from _pytest.mark.structures import NodeKeywords +from _pytest.outcomes import fail +from _pytest.pathlib import absolutepath +from _pytest.store import Store + +if TYPE_CHECKING: + # Imported here due to circular import. + from _pytest.main import Session + from _pytest._code.code import _TracebackStyle + + +SEP = "/" + +tracebackcutdir = py.path.local(_pytest.__file__).dirpath() + + +def iterparentnodeids(nodeid: str) -> Iterator[str]: + """Return the parent node IDs of a given node ID, inclusive. + + For the node ID + + "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source" + + the result would be + + "" + "testing" + "testing/code" + "testing/code/test_excinfo.py" + "testing/code/test_excinfo.py::TestFormattedExcinfo" + "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source" + + Note that :: parts are only considered at the last / component. + """ + pos = 0 + sep = SEP + yield "" + while True: + at = nodeid.find(sep, pos) + if at == -1 and sep == SEP: + sep = "::" + elif at == -1: + if nodeid: + yield nodeid + break + else: + if at: + yield nodeid[:at] + pos = at + len(sep) + + +_NodeType = TypeVar("_NodeType", bound="Node") + + +class NodeMeta(type): + def __call__(self, *k, **kw): + msg = ( + "Direct construction of {name} has been deprecated, please use {name}.from_parent.\n" + "See " + "https://docs.pytest.org/en/stable/deprecations.html#node-construction-changed-to-node-from-parent" + " for more details." + ).format(name=self.__name__) + fail(msg, pytrace=False) + + def _create(self, *k, **kw): + return super().__call__(*k, **kw) + + +class Node(metaclass=NodeMeta): + """Base class for Collector and Item, the components of the test + collection tree. + + Collector subclasses have children; Items are leaf nodes. + """ + + # Use __slots__ to make attribute access faster. + # Note that __dict__ is still available. + __slots__ = ( + "name", + "parent", + "config", + "session", + "fspath", + "_nodeid", + "_store", + "__dict__", + ) + + def __init__( + self, + name: str, + parent: "Optional[Node]" = None, + config: Optional[Config] = None, + session: "Optional[Session]" = None, + fspath: Optional[py.path.local] = None, + nodeid: Optional[str] = None, + ) -> None: + #: A unique name within the scope of the parent node. + self.name = name + + #: The parent collector node. + self.parent = parent + + #: The pytest config object. + if config: + self.config: Config = config + else: + if not parent: + raise TypeError("config or parent must be provided") + self.config = parent.config + + #: The pytest session this node is part of. + if session: + self.session = session + else: + if not parent: + raise TypeError("session or parent must be provided") + self.session = parent.session + + #: Filesystem path where this node was collected from (can be None). + self.fspath = fspath or getattr(parent, "fspath", None) + + #: Keywords/markers collected from all scopes. + self.keywords = NodeKeywords(self) + + #: The marker objects belonging to this node. + self.own_markers: List[Mark] = [] + + #: Allow adding of extra keywords to use for matching. + self.extra_keyword_matches: Set[str] = set() + + if nodeid is not None: + assert "::()" not in nodeid + self._nodeid = nodeid + else: + if not self.parent: + raise TypeError("nodeid or parent must be provided") + self._nodeid = self.parent.nodeid + if self.name != "()": + self._nodeid += "::" + self.name + + # A place where plugins can store information on the node for their + # own use. Currently only intended for internal plugins. + self._store = Store() + + @classmethod + def from_parent(cls, parent: "Node", **kw): + """Public constructor for Nodes. + + This indirection got introduced in order to enable removing + the fragile logic from the node constructors. + + Subclasses can use ``super().from_parent(...)`` when overriding the + construction. + + :param parent: The parent node of this Node. + """ + if "config" in kw: + raise TypeError("config is not a valid argument for from_parent") + if "session" in kw: + raise TypeError("session is not a valid argument for from_parent") + return cls._create(parent=parent, **kw) + + @property + def ihook(self): + """fspath-sensitive hook proxy used to call pytest hooks.""" + return self.session.gethookproxy(self.fspath) + + def __repr__(self) -> str: + return "<{} {}>".format(self.__class__.__name__, getattr(self, "name", None)) + + def warn(self, warning: Warning) -> None: + """Issue a warning for this Node. + + Warnings will be displayed after the test session, unless explicitly suppressed. + + :param Warning warning: + The warning instance to issue. + + :raises ValueError: If ``warning`` instance is not a subclass of Warning. + + Example usage: + + .. code-block:: python + + node.warn(PytestWarning("some message")) + node.warn(UserWarning("some message")) + + .. versionchanged:: 6.2 + Any subclass of :class:`Warning` is now accepted, rather than only + :class:`PytestWarning ` subclasses. + """ + # enforce type checks here to avoid getting a generic type error later otherwise. + if not isinstance(warning, Warning): + raise ValueError( + "warning must be an instance of Warning or subclass, got {!r}".format( + warning + ) + ) + path, lineno = get_fslocation_from_item(self) + assert lineno is not None + warnings.warn_explicit( + warning, category=None, filename=str(path), lineno=lineno + 1, + ) + + # Methods for ordering nodes. + + @property + def nodeid(self) -> str: + """A ::-separated string denoting its collection tree address.""" + return self._nodeid + + def __hash__(self) -> int: + return hash(self._nodeid) + + def setup(self) -> None: + pass + + def teardown(self) -> None: + pass + + def listchain(self) -> List["Node"]: + """Return list of all parent collectors up to self, starting from + the root of collection tree.""" + chain = [] + item: Optional[Node] = self + while item is not None: + chain.append(item) + item = item.parent + chain.reverse() + return chain + + def add_marker( + self, marker: Union[str, MarkDecorator], append: bool = True + ) -> None: + """Dynamically add a marker object to the node. + + :param append: + Whether to append the marker, or prepend it. + """ + from _pytest.mark import MARK_GEN + + if isinstance(marker, MarkDecorator): + marker_ = marker + elif isinstance(marker, str): + marker_ = getattr(MARK_GEN, marker) + else: + raise ValueError("is not a string or pytest.mark.* Marker") + self.keywords[marker_.name] = marker_ + if append: + self.own_markers.append(marker_.mark) + else: + self.own_markers.insert(0, marker_.mark) + + def iter_markers(self, name: Optional[str] = None) -> Iterator[Mark]: + """Iterate over all markers of the node. + + :param name: If given, filter the results by the name attribute. + """ + return (x[1] for x in self.iter_markers_with_node(name=name)) + + def iter_markers_with_node( + self, name: Optional[str] = None + ) -> Iterator[Tuple["Node", Mark]]: + """Iterate over all markers of the node. + + :param name: If given, filter the results by the name attribute. + :returns: An iterator of (node, mark) tuples. + """ + for node in reversed(self.listchain()): + for mark in node.own_markers: + if name is None or getattr(mark, "name", None) == name: + yield node, mark + + @overload + def get_closest_marker(self, name: str) -> Optional[Mark]: + ... + + @overload + def get_closest_marker(self, name: str, default: Mark) -> Mark: + ... + + def get_closest_marker( + self, name: str, default: Optional[Mark] = None + ) -> Optional[Mark]: + """Return the first marker matching the name, from closest (for + example function) to farther level (for example module level). + + :param default: Fallback return value if no marker was found. + :param name: Name to filter by. + """ + return next(self.iter_markers(name=name), default) + + def listextrakeywords(self) -> Set[str]: + """Return a set of all extra keywords in self and any parents.""" + extra_keywords: Set[str] = set() + for item in self.listchain(): + extra_keywords.update(item.extra_keyword_matches) + return extra_keywords + + def listnames(self) -> List[str]: + return [x.name for x in self.listchain()] + + def addfinalizer(self, fin: Callable[[], object]) -> None: + """Register a function to be called when this node is finalized. + + This method can only be called when this node is active + in a setup chain, for example during self.setup(). + """ + self.session._setupstate.addfinalizer(fin, self) + + def getparent(self, cls: Type[_NodeType]) -> Optional[_NodeType]: + """Get the next parent node (including self) which is an instance of + the given class.""" + current: Optional[Node] = self + while current and not isinstance(current, cls): + current = current.parent + assert current is None or isinstance(current, cls) + return current + + def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None: + pass + + def _repr_failure_py( + self, + excinfo: ExceptionInfo[BaseException], + style: "Optional[_TracebackStyle]" = None, + ) -> TerminalRepr: + from _pytest.fixtures import FixtureLookupError + + if isinstance(excinfo.value, ConftestImportFailure): + excinfo = ExceptionInfo(excinfo.value.excinfo) + if isinstance(excinfo.value, fail.Exception): + if not excinfo.value.pytrace: + style = "value" + if isinstance(excinfo.value, FixtureLookupError): + return excinfo.value.formatrepr() + if self.config.getoption("fulltrace", False): + style = "long" + else: + tb = _pytest._code.Traceback([excinfo.traceback[-1]]) + self._prunetraceback(excinfo) + if len(excinfo.traceback) == 0: + excinfo.traceback = tb + if style == "auto": + style = "long" + # XXX should excinfo.getrepr record all data and toterminal() process it? + if style is None: + if self.config.getoption("tbstyle", "auto") == "short": + style = "short" + else: + style = "long" + + if self.config.getoption("verbose", 0) > 1: + truncate_locals = False + else: + truncate_locals = True + + # excinfo.getrepr() formats paths relative to the CWD if `abspath` is False. + # It is possible for a fixture/test to change the CWD while this code runs, which + # would then result in the user seeing confusing paths in the failure message. + # To fix this, if the CWD changed, always display the full absolute path. + # It will be better to just always display paths relative to invocation_dir, but + # this requires a lot of plumbing (#6428). + try: + abspath = Path(os.getcwd()) != self.config.invocation_params.dir + except OSError: + abspath = True + + return excinfo.getrepr( + funcargs=True, + abspath=abspath, + showlocals=self.config.getoption("showlocals", False), + style=style, + tbfilter=False, # pruned already, or in --fulltrace mode. + truncate_locals=truncate_locals, + ) + + def repr_failure( + self, + excinfo: ExceptionInfo[BaseException], + style: "Optional[_TracebackStyle]" = None, + ) -> Union[str, TerminalRepr]: + """Return a representation of a collection or test failure. + + :param excinfo: Exception information for the failure. + """ + return self._repr_failure_py(excinfo, style) + + +def get_fslocation_from_item( + node: "Node", +) -> Tuple[Union[str, py.path.local], Optional[int]]: + """Try to extract the actual location from a node, depending on available attributes: + + * "location": a pair (path, lineno) + * "obj": a Python object that the node wraps. + * "fspath": just a path + + :rtype: A tuple of (str|py.path.local, int) with filename and line number. + """ + # See Item.location. + location: Optional[Tuple[str, Optional[int], str]] = getattr(node, "location", None) + if location is not None: + return location[:2] + obj = getattr(node, "obj", None) + if obj is not None: + return getfslineno(obj) + return getattr(node, "fspath", "unknown location"), -1 + + +class Collector(Node): + """Collector instances create children through collect() and thus + iteratively build a tree.""" + + class CollectError(Exception): + """An error during collection, contains a custom message.""" + + def collect(self) -> Iterable[Union["Item", "Collector"]]: + """Return a list of children (items and collectors) for this + collection node.""" + raise NotImplementedError("abstract") + + # TODO: This omits the style= parameter which breaks Liskov Substitution. + def repr_failure( # type: ignore[override] + self, excinfo: ExceptionInfo[BaseException] + ) -> Union[str, TerminalRepr]: + """Return a representation of a collection failure. + + :param excinfo: Exception information for the failure. + """ + if isinstance(excinfo.value, self.CollectError) and not self.config.getoption( + "fulltrace", False + ): + exc = excinfo.value + return str(exc.args[0]) + + # Respect explicit tbstyle option, but default to "short" + # (_repr_failure_py uses "long" with "fulltrace" option always). + tbstyle = self.config.getoption("tbstyle", "auto") + if tbstyle == "auto": + tbstyle = "short" + + return self._repr_failure_py(excinfo, style=tbstyle) + + def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None: + if hasattr(self, "fspath"): + traceback = excinfo.traceback + ntraceback = traceback.cut(path=self.fspath) + if ntraceback == traceback: + ntraceback = ntraceback.cut(excludepath=tracebackcutdir) + excinfo.traceback = ntraceback.filter() + + +def _check_initialpaths_for_relpath(session, fspath): + for initial_path in session._initialpaths: + if fspath.common(initial_path) == initial_path: + return fspath.relto(initial_path) + + +class FSCollector(Collector): + def __init__( + self, + fspath: py.path.local, + parent=None, + config: Optional[Config] = None, + session: Optional["Session"] = None, + nodeid: Optional[str] = None, + ) -> None: + name = fspath.basename + if parent is not None: + rel = fspath.relto(parent.fspath) + if rel: + name = rel + name = name.replace(os.sep, SEP) + self.fspath = fspath + + session = session or parent.session + + if nodeid is None: + nodeid = self.fspath.relto(session.config.rootdir) + + if not nodeid: + nodeid = _check_initialpaths_for_relpath(session, fspath) + if nodeid and os.sep != SEP: + nodeid = nodeid.replace(os.sep, SEP) + + super().__init__(name, parent, config, session, nodeid=nodeid, fspath=fspath) + + @classmethod + def from_parent(cls, parent, *, fspath, **kw): + """The public constructor.""" + return super().from_parent(parent=parent, fspath=fspath, **kw) + + def gethookproxy(self, fspath: py.path.local): + warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) + return self.session.gethookproxy(fspath) + + def isinitpath(self, path: py.path.local) -> bool: + warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) + return self.session.isinitpath(path) + + +class File(FSCollector): + """Base class for collecting tests from a file. + + :ref:`non-python tests`. + """ + + +class Item(Node): + """A basic test invocation item. + + Note that for a single function there might be multiple test invocation items. + """ + + nextitem = None + + def __init__( + self, + name, + parent=None, + config: Optional[Config] = None, + session: Optional["Session"] = None, + nodeid: Optional[str] = None, + ) -> None: + super().__init__(name, parent, config, session, nodeid=nodeid) + self._report_sections: List[Tuple[str, str, str]] = [] + + #: A list of tuples (name, value) that holds user defined properties + #: for this test. + self.user_properties: List[Tuple[str, object]] = [] + + def runtest(self) -> None: + raise NotImplementedError("runtest must be implemented by Item subclass") + + def add_report_section(self, when: str, key: str, content: str) -> None: + """Add a new report section, similar to what's done internally to add + stdout and stderr captured output:: + + item.add_report_section("call", "stdout", "report section contents") + + :param str when: + One of the possible capture states, ``"setup"``, ``"call"``, ``"teardown"``. + :param str key: + Name of the section, can be customized at will. Pytest uses ``"stdout"`` and + ``"stderr"`` internally. + :param str content: + The full contents as a string. + """ + if content: + self._report_sections.append((when, key, content)) + + def reportinfo(self) -> Tuple[Union[py.path.local, str], Optional[int], str]: + return self.fspath, None, "" + + @cached_property + def location(self) -> Tuple[str, Optional[int], str]: + location = self.reportinfo() + fspath = absolutepath(str(location[0])) + relfspath = self.session._node_location_to_relpath(fspath) + assert type(location[2]) is str + return (relfspath, location[1], location[2]) diff --git a/myenv/lib/python3.9/site-packages/_pytest/nose.py b/myenv/lib/python3.9/site-packages/_pytest/nose.py new file mode 100644 index 0000000..bb8f997 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/nose.py @@ -0,0 +1,39 @@ +"""Run testsuites written for nose.""" +from _pytest import python +from _pytest import unittest +from _pytest.config import hookimpl +from _pytest.nodes import Item + + +@hookimpl(trylast=True) +def pytest_runtest_setup(item): + if is_potential_nosetest(item): + if not call_optional(item.obj, "setup"): + # Call module level setup if there is no object level one. + call_optional(item.parent.obj, "setup") + # XXX This implies we only call teardown when setup worked. + item.session._setupstate.addfinalizer((lambda: teardown_nose(item)), item) + + +def teardown_nose(item): + if is_potential_nosetest(item): + if not call_optional(item.obj, "teardown"): + call_optional(item.parent.obj, "teardown") + + +def is_potential_nosetest(item: Item) -> bool: + # Extra check needed since we do not do nose style setup/teardown + # on direct unittest style classes. + return isinstance(item, python.Function) and not isinstance( + item, unittest.TestCaseFunction + ) + + +def call_optional(obj, name): + method = getattr(obj, name, None) + isfixture = hasattr(method, "_pytestfixturefunction") + if method is not None and not isfixture and callable(method): + # If there's any problems allow the exception to raise rather than + # silently ignoring them. + method() + return True diff --git a/myenv/lib/python3.9/site-packages/_pytest/outcomes.py b/myenv/lib/python3.9/site-packages/_pytest/outcomes.py new file mode 100644 index 0000000..8f6203f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/outcomes.py @@ -0,0 +1,227 @@ +"""Exception classes and constants handling test outcomes as well as +functions creating them.""" +import sys +from typing import Any +from typing import Callable +from typing import cast +from typing import Optional +from typing import Type +from typing import TypeVar + +TYPE_CHECKING = False # Avoid circular import through compat. + +if TYPE_CHECKING: + from typing import NoReturn + from typing_extensions import Protocol +else: + # typing.Protocol is only available starting from Python 3.8. It is also + # available from typing_extensions, but we don't want a runtime dependency + # on that. So use a dummy runtime implementation. + from typing import Generic + + Protocol = Generic + + +class OutcomeException(BaseException): + """OutcomeException and its subclass instances indicate and contain info + about test and collection outcomes.""" + + def __init__(self, msg: Optional[str] = None, pytrace: bool = True) -> None: + if msg is not None and not isinstance(msg, str): + error_msg = ( # type: ignore[unreachable] + "{} expected string as 'msg' parameter, got '{}' instead.\n" + "Perhaps you meant to use a mark?" + ) + raise TypeError(error_msg.format(type(self).__name__, type(msg).__name__)) + BaseException.__init__(self, msg) + self.msg = msg + self.pytrace = pytrace + + def __repr__(self) -> str: + if self.msg is not None: + return self.msg + return f"<{self.__class__.__name__} instance>" + + __str__ = __repr__ + + +TEST_OUTCOME = (OutcomeException, Exception) + + +class Skipped(OutcomeException): + # XXX hackish: on 3k we fake to live in the builtins + # in order to have Skipped exception printing shorter/nicer + __module__ = "builtins" + + def __init__( + self, + msg: Optional[str] = None, + pytrace: bool = True, + allow_module_level: bool = False, + ) -> None: + OutcomeException.__init__(self, msg=msg, pytrace=pytrace) + self.allow_module_level = allow_module_level + + +class Failed(OutcomeException): + """Raised from an explicit call to pytest.fail().""" + + __module__ = "builtins" + + +class Exit(Exception): + """Raised for immediate program exits (no tracebacks/summaries).""" + + def __init__( + self, msg: str = "unknown reason", returncode: Optional[int] = None + ) -> None: + self.msg = msg + self.returncode = returncode + super().__init__(msg) + + +# Elaborate hack to work around https://github.com/python/mypy/issues/2087. +# Ideally would just be `exit.Exception = Exit` etc. + +_F = TypeVar("_F", bound=Callable[..., object]) +_ET = TypeVar("_ET", bound=Type[BaseException]) + + +class _WithException(Protocol[_F, _ET]): + Exception: _ET + __call__: _F + + +def _with_exception(exception_type: _ET) -> Callable[[_F], _WithException[_F, _ET]]: + def decorate(func: _F) -> _WithException[_F, _ET]: + func_with_exception = cast(_WithException[_F, _ET], func) + func_with_exception.Exception = exception_type + return func_with_exception + + return decorate + + +# Exposed helper methods. + + +@_with_exception(Exit) +def exit(msg: str, returncode: Optional[int] = None) -> "NoReturn": + """Exit testing process. + + :param str msg: Message to display upon exit. + :param int returncode: Return code to be used when exiting pytest. + """ + __tracebackhide__ = True + raise Exit(msg, returncode) + + +@_with_exception(Skipped) +def skip(msg: str = "", *, allow_module_level: bool = False) -> "NoReturn": + """Skip an executing test with the given message. + + This function should be called only during testing (setup, call or teardown) or + during collection by using the ``allow_module_level`` flag. This function can + be called in doctests as well. + + :param bool allow_module_level: + Allows this function to be called at module level, skipping the rest + of the module. Defaults to False. + + .. note:: + It is better to use the :ref:`pytest.mark.skipif ref` marker when + possible to declare a test to be skipped under certain conditions + like mismatching platforms or dependencies. + Similarly, use the ``# doctest: +SKIP`` directive (see `doctest.SKIP + `_) + to skip a doctest statically. + """ + __tracebackhide__ = True + raise Skipped(msg=msg, allow_module_level=allow_module_level) + + +@_with_exception(Failed) +def fail(msg: str = "", pytrace: bool = True) -> "NoReturn": + """Explicitly fail an executing test with the given message. + + :param str msg: + The message to show the user as reason for the failure. + :param bool pytrace: + If False, msg represents the full failure information and no + python traceback will be reported. + """ + __tracebackhide__ = True + raise Failed(msg=msg, pytrace=pytrace) + + +class XFailed(Failed): + """Raised from an explicit call to pytest.xfail().""" + + +@_with_exception(XFailed) +def xfail(reason: str = "") -> "NoReturn": + """Imperatively xfail an executing test or setup function with the given reason. + + This function should be called only during testing (setup, call or teardown). + + .. note:: + It is better to use the :ref:`pytest.mark.xfail ref` marker when + possible to declare a test to be xfailed under certain conditions + like known bugs or missing features. + """ + __tracebackhide__ = True + raise XFailed(reason) + + +def importorskip( + modname: str, minversion: Optional[str] = None, reason: Optional[str] = None +) -> Any: + """Import and return the requested module ``modname``, or skip the + current test if the module cannot be imported. + + :param str modname: + The name of the module to import. + :param str minversion: + If given, the imported module's ``__version__`` attribute must be at + least this minimal version, otherwise the test is still skipped. + :param str reason: + If given, this reason is shown as the message when the module cannot + be imported. + + :returns: + The imported module. This should be assigned to its canonical name. + + Example:: + + docutils = pytest.importorskip("docutils") + """ + import warnings + + __tracebackhide__ = True + compile(modname, "", "eval") # to catch syntaxerrors + + with warnings.catch_warnings(): + # Make sure to ignore ImportWarnings that might happen because + # of existing directories with the same name we're trying to + # import but without a __init__.py file. + warnings.simplefilter("ignore") + try: + __import__(modname) + except ImportError as exc: + if reason is None: + reason = f"could not import {modname!r}: {exc}" + raise Skipped(reason, allow_module_level=True) from None + mod = sys.modules[modname] + if minversion is None: + return mod + verattr = getattr(mod, "__version__", None) + if minversion is not None: + # Imported lazily to improve start-up time. + from packaging.version import Version + + if verattr is None or Version(verattr) < Version(minversion): + raise Skipped( + "module %r has __version__ %r, required is: %r" + % (modname, verattr, minversion), + allow_module_level=True, + ) + return mod diff --git a/myenv/lib/python3.9/site-packages/_pytest/pastebin.py b/myenv/lib/python3.9/site-packages/_pytest/pastebin.py new file mode 100644 index 0000000..131873c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/pastebin.py @@ -0,0 +1,110 @@ +"""Submit failure or test session information to a pastebin service.""" +import tempfile +from io import StringIO +from typing import IO +from typing import Union + +import pytest +from _pytest.config import Config +from _pytest.config import create_terminal_writer +from _pytest.config.argparsing import Parser +from _pytest.store import StoreKey +from _pytest.terminal import TerminalReporter + + +pastebinfile_key = StoreKey[IO[bytes]]() + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting") + group._addoption( + "--pastebin", + metavar="mode", + action="store", + dest="pastebin", + default=None, + choices=["failed", "all"], + help="send failed|all info to bpaste.net pastebin service.", + ) + + +@pytest.hookimpl(trylast=True) +def pytest_configure(config: Config) -> None: + if config.option.pastebin == "all": + tr = config.pluginmanager.getplugin("terminalreporter") + # If no terminal reporter plugin is present, nothing we can do here; + # this can happen when this function executes in a worker node + # when using pytest-xdist, for example. + if tr is not None: + # pastebin file will be UTF-8 encoded binary file. + config._store[pastebinfile_key] = tempfile.TemporaryFile("w+b") + oldwrite = tr._tw.write + + def tee_write(s, **kwargs): + oldwrite(s, **kwargs) + if isinstance(s, str): + s = s.encode("utf-8") + config._store[pastebinfile_key].write(s) + + tr._tw.write = tee_write + + +def pytest_unconfigure(config: Config) -> None: + if pastebinfile_key in config._store: + pastebinfile = config._store[pastebinfile_key] + # Get terminal contents and delete file. + pastebinfile.seek(0) + sessionlog = pastebinfile.read() + pastebinfile.close() + del config._store[pastebinfile_key] + # Undo our patching in the terminal reporter. + tr = config.pluginmanager.getplugin("terminalreporter") + del tr._tw.__dict__["write"] + # Write summary. + tr.write_sep("=", "Sending information to Paste Service") + pastebinurl = create_new_paste(sessionlog) + tr.write_line("pastebin session-log: %s\n" % pastebinurl) + + +def create_new_paste(contents: Union[str, bytes]) -> str: + """Create a new paste using the bpaste.net service. + + :contents: Paste contents string. + :returns: URL to the pasted contents, or an error message. + """ + import re + from urllib.request import urlopen + from urllib.parse import urlencode + + params = {"code": contents, "lexer": "text", "expiry": "1week"} + url = "https://bpaste.net" + try: + response: str = ( + urlopen(url, data=urlencode(params).encode("ascii")).read().decode("utf-8") + ) + except OSError as exc_info: # urllib errors + return "bad response: %s" % exc_info + m = re.search(r'href="/raw/(\w+)"', response) + if m: + return "{}/show/{}".format(url, m.group(1)) + else: + return "bad response: invalid format ('" + response + "')" + + +def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: + if terminalreporter.config.option.pastebin != "failed": + return + if "failed" in terminalreporter.stats: + terminalreporter.write_sep("=", "Sending information to Paste Service") + for rep in terminalreporter.stats["failed"]: + try: + msg = rep.longrepr.reprtraceback.reprentries[-1].reprfileloc + except AttributeError: + msg = terminalreporter._getfailureheadline(rep) + file = StringIO() + tw = create_terminal_writer(terminalreporter.config, file) + rep.toterminal(tw) + s = file.getvalue() + assert len(s) + pastebinurl = create_new_paste(s) + terminalreporter.write_line(f"{msg} --> {pastebinurl}") diff --git a/myenv/lib/python3.9/site-packages/_pytest/pathlib.py b/myenv/lib/python3.9/site-packages/_pytest/pathlib.py new file mode 100644 index 0000000..7d9269a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/pathlib.py @@ -0,0 +1,654 @@ +import atexit +import contextlib +import fnmatch +import importlib.util +import itertools +import os +import shutil +import sys +import uuid +import warnings +from enum import Enum +from errno import EBADF +from errno import ELOOP +from errno import ENOENT +from errno import ENOTDIR +from functools import partial +from os.path import expanduser +from os.path import expandvars +from os.path import isabs +from os.path import sep +from pathlib import Path +from pathlib import PurePath +from posixpath import sep as posix_sep +from types import ModuleType +from typing import Callable +from typing import Iterable +from typing import Iterator +from typing import Optional +from typing import Set +from typing import TypeVar +from typing import Union + +import py + +from _pytest.compat import assert_never +from _pytest.outcomes import skip +from _pytest.warning_types import PytestWarning + +LOCK_TIMEOUT = 60 * 60 * 24 * 3 + + +_AnyPurePath = TypeVar("_AnyPurePath", bound=PurePath) + +# The following function, variables and comments were +# copied from cpython 3.9 Lib/pathlib.py file. + +# EBADF - guard against macOS `stat` throwing EBADF +_IGNORED_ERRORS = (ENOENT, ENOTDIR, EBADF, ELOOP) + +_IGNORED_WINERRORS = ( + 21, # ERROR_NOT_READY - drive exists but is not accessible + 1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself +) + + +def _ignore_error(exception): + return ( + getattr(exception, "errno", None) in _IGNORED_ERRORS + or getattr(exception, "winerror", None) in _IGNORED_WINERRORS + ) + + +def get_lock_path(path: _AnyPurePath) -> _AnyPurePath: + return path.joinpath(".lock") + + +def on_rm_rf_error(func, path: str, exc, *, start_path: Path) -> bool: + """Handle known read-only errors during rmtree. + + The returned value is used only by our own tests. + """ + exctype, excvalue = exc[:2] + + # Another process removed the file in the middle of the "rm_rf" (xdist for example). + # More context: https://github.com/pytest-dev/pytest/issues/5974#issuecomment-543799018 + if isinstance(excvalue, FileNotFoundError): + return False + + if not isinstance(excvalue, PermissionError): + warnings.warn( + PytestWarning(f"(rm_rf) error removing {path}\n{exctype}: {excvalue}") + ) + return False + + if func not in (os.rmdir, os.remove, os.unlink): + if func not in (os.open,): + warnings.warn( + PytestWarning( + "(rm_rf) unknown function {} when removing {}:\n{}: {}".format( + func, path, exctype, excvalue + ) + ) + ) + return False + + # Chmod + retry. + import stat + + def chmod_rw(p: str) -> None: + mode = os.stat(p).st_mode + os.chmod(p, mode | stat.S_IRUSR | stat.S_IWUSR) + + # For files, we need to recursively go upwards in the directories to + # ensure they all are also writable. + p = Path(path) + if p.is_file(): + for parent in p.parents: + chmod_rw(str(parent)) + # Stop when we reach the original path passed to rm_rf. + if parent == start_path: + break + chmod_rw(str(path)) + + func(path) + return True + + +def ensure_extended_length_path(path: Path) -> Path: + """Get the extended-length version of a path (Windows). + + On Windows, by default, the maximum length of a path (MAX_PATH) is 260 + characters, and operations on paths longer than that fail. But it is possible + to overcome this by converting the path to "extended-length" form before + performing the operation: + https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation + + On Windows, this function returns the extended-length absolute version of path. + On other platforms it returns path unchanged. + """ + if sys.platform.startswith("win32"): + path = path.resolve() + path = Path(get_extended_length_path_str(str(path))) + return path + + +def get_extended_length_path_str(path: str) -> str: + """Convert a path to a Windows extended length path.""" + long_path_prefix = "\\\\?\\" + unc_long_path_prefix = "\\\\?\\UNC\\" + if path.startswith((long_path_prefix, unc_long_path_prefix)): + return path + # UNC + if path.startswith("\\\\"): + return unc_long_path_prefix + path[2:] + return long_path_prefix + path + + +def rm_rf(path: Path) -> None: + """Remove the path contents recursively, even if some elements + are read-only.""" + path = ensure_extended_length_path(path) + onerror = partial(on_rm_rf_error, start_path=path) + shutil.rmtree(str(path), onerror=onerror) + + +def find_prefixed(root: Path, prefix: str) -> Iterator[Path]: + """Find all elements in root that begin with the prefix, case insensitive.""" + l_prefix = prefix.lower() + for x in root.iterdir(): + if x.name.lower().startswith(l_prefix): + yield x + + +def extract_suffixes(iter: Iterable[PurePath], prefix: str) -> Iterator[str]: + """Return the parts of the paths following the prefix. + + :param iter: Iterator over path names. + :param prefix: Expected prefix of the path names. + """ + p_len = len(prefix) + for p in iter: + yield p.name[p_len:] + + +def find_suffixes(root: Path, prefix: str) -> Iterator[str]: + """Combine find_prefixes and extract_suffixes.""" + return extract_suffixes(find_prefixed(root, prefix), prefix) + + +def parse_num(maybe_num) -> int: + """Parse number path suffixes, returns -1 on error.""" + try: + return int(maybe_num) + except ValueError: + return -1 + + +def _force_symlink( + root: Path, target: Union[str, PurePath], link_to: Union[str, Path] +) -> None: + """Helper to create the current symlink. + + It's full of race conditions that are reasonably OK to ignore + for the context of best effort linking to the latest test run. + + The presumption being that in case of much parallelism + the inaccuracy is going to be acceptable. + """ + current_symlink = root.joinpath(target) + try: + current_symlink.unlink() + except OSError: + pass + try: + current_symlink.symlink_to(link_to) + except Exception: + pass + + +def make_numbered_dir(root: Path, prefix: str, mode: int = 0o700) -> Path: + """Create a directory with an increased number as suffix for the given prefix.""" + for i in range(10): + # try up to 10 times to create the folder + max_existing = max(map(parse_num, find_suffixes(root, prefix)), default=-1) + new_number = max_existing + 1 + new_path = root.joinpath(f"{prefix}{new_number}") + try: + new_path.mkdir(mode=mode) + except Exception: + pass + else: + _force_symlink(root, prefix + "current", new_path) + return new_path + else: + raise OSError( + "could not create numbered dir with prefix " + "{prefix} in {root} after 10 tries".format(prefix=prefix, root=root) + ) + + +def create_cleanup_lock(p: Path) -> Path: + """Create a lock to prevent premature folder cleanup.""" + lock_path = get_lock_path(p) + try: + fd = os.open(str(lock_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) + except FileExistsError as e: + raise OSError(f"cannot create lockfile in {p}") from e + else: + pid = os.getpid() + spid = str(pid).encode() + os.write(fd, spid) + os.close(fd) + if not lock_path.is_file(): + raise OSError("lock path got renamed after successful creation") + return lock_path + + +def register_cleanup_lock_removal(lock_path: Path, register=atexit.register): + """Register a cleanup function for removing a lock, by default on atexit.""" + pid = os.getpid() + + def cleanup_on_exit(lock_path: Path = lock_path, original_pid: int = pid) -> None: + current_pid = os.getpid() + if current_pid != original_pid: + # fork + return + try: + lock_path.unlink() + except OSError: + pass + + return register(cleanup_on_exit) + + +def maybe_delete_a_numbered_dir(path: Path) -> None: + """Remove a numbered directory if its lock can be obtained and it does + not seem to be in use.""" + path = ensure_extended_length_path(path) + lock_path = None + try: + lock_path = create_cleanup_lock(path) + parent = path.parent + + garbage = parent.joinpath(f"garbage-{uuid.uuid4()}") + path.rename(garbage) + rm_rf(garbage) + except OSError: + # known races: + # * other process did a cleanup at the same time + # * deletable folder was found + # * process cwd (Windows) + return + finally: + # If we created the lock, ensure we remove it even if we failed + # to properly remove the numbered dir. + if lock_path is not None: + try: + lock_path.unlink() + except OSError: + pass + + +def ensure_deletable(path: Path, consider_lock_dead_if_created_before: float) -> bool: + """Check if `path` is deletable based on whether the lock file is expired.""" + if path.is_symlink(): + return False + lock = get_lock_path(path) + try: + if not lock.is_file(): + return True + except OSError: + # we might not have access to the lock file at all, in this case assume + # we don't have access to the entire directory (#7491). + return False + try: + lock_time = lock.stat().st_mtime + except Exception: + return False + else: + if lock_time < consider_lock_dead_if_created_before: + # We want to ignore any errors while trying to remove the lock such as: + # - PermissionDenied, like the file permissions have changed since the lock creation; + # - FileNotFoundError, in case another pytest process got here first; + # and any other cause of failure. + with contextlib.suppress(OSError): + lock.unlink() + return True + return False + + +def try_cleanup(path: Path, consider_lock_dead_if_created_before: float) -> None: + """Try to cleanup a folder if we can ensure it's deletable.""" + if ensure_deletable(path, consider_lock_dead_if_created_before): + maybe_delete_a_numbered_dir(path) + + +def cleanup_candidates(root: Path, prefix: str, keep: int) -> Iterator[Path]: + """List candidates for numbered directories to be removed - follows py.path.""" + max_existing = max(map(parse_num, find_suffixes(root, prefix)), default=-1) + max_delete = max_existing - keep + paths = find_prefixed(root, prefix) + paths, paths2 = itertools.tee(paths) + numbers = map(parse_num, extract_suffixes(paths2, prefix)) + for path, number in zip(paths, numbers): + if number <= max_delete: + yield path + + +def cleanup_numbered_dir( + root: Path, prefix: str, keep: int, consider_lock_dead_if_created_before: float +) -> None: + """Cleanup for lock driven numbered directories.""" + for path in cleanup_candidates(root, prefix, keep): + try_cleanup(path, consider_lock_dead_if_created_before) + for path in root.glob("garbage-*"): + try_cleanup(path, consider_lock_dead_if_created_before) + + +def make_numbered_dir_with_cleanup( + root: Path, prefix: str, keep: int, lock_timeout: float, mode: int, +) -> Path: + """Create a numbered dir with a cleanup lock and remove old ones.""" + e = None + for i in range(10): + try: + p = make_numbered_dir(root, prefix, mode) + lock_path = create_cleanup_lock(p) + register_cleanup_lock_removal(lock_path) + except Exception as exc: + e = exc + else: + consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout + # Register a cleanup for program exit + atexit.register( + cleanup_numbered_dir, + root, + prefix, + keep, + consider_lock_dead_if_created_before, + ) + return p + assert e is not None + raise e + + +def resolve_from_str(input: str, rootpath: Path) -> Path: + input = expanduser(input) + input = expandvars(input) + if isabs(input): + return Path(input) + else: + return rootpath.joinpath(input) + + +def fnmatch_ex(pattern: str, path) -> bool: + """A port of FNMatcher from py.path.common which works with PurePath() instances. + + The difference between this algorithm and PurePath.match() is that the + latter matches "**" glob expressions for each part of the path, while + this algorithm uses the whole path instead. + + For example: + "tests/foo/bar/doc/test_foo.py" matches pattern "tests/**/doc/test*.py" + with this algorithm, but not with PurePath.match(). + + This algorithm was ported to keep backward-compatibility with existing + settings which assume paths match according this logic. + + References: + * https://bugs.python.org/issue29249 + * https://bugs.python.org/issue34731 + """ + path = PurePath(path) + iswin32 = sys.platform.startswith("win") + + if iswin32 and sep not in pattern and posix_sep in pattern: + # Running on Windows, the pattern has no Windows path separators, + # and the pattern has one or more Posix path separators. Replace + # the Posix path separators with the Windows path separator. + pattern = pattern.replace(posix_sep, sep) + + if sep not in pattern: + name = path.name + else: + name = str(path) + if path.is_absolute() and not os.path.isabs(pattern): + pattern = f"*{os.sep}{pattern}" + return fnmatch.fnmatch(name, pattern) + + +def parts(s: str) -> Set[str]: + parts = s.split(sep) + return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))} + + +def symlink_or_skip(src, dst, **kwargs): + """Make a symlink, or skip the test in case symlinks are not supported.""" + try: + os.symlink(str(src), str(dst), **kwargs) + except OSError as e: + skip(f"symlinks not supported: {e}") + + +class ImportMode(Enum): + """Possible values for `mode` parameter of `import_path`.""" + + prepend = "prepend" + append = "append" + importlib = "importlib" + + +class ImportPathMismatchError(ImportError): + """Raised on import_path() if there is a mismatch of __file__'s. + + This can happen when `import_path` is called multiple times with different filenames that has + the same basename but reside in packages + (for example "/tests1/test_foo.py" and "/tests2/test_foo.py"). + """ + + +def import_path( + p: Union[str, py.path.local, Path], + *, + mode: Union[str, ImportMode] = ImportMode.prepend, +) -> ModuleType: + """Import and return a module from the given path, which can be a file (a module) or + a directory (a package). + + The import mechanism used is controlled by the `mode` parameter: + + * `mode == ImportMode.prepend`: the directory containing the module (or package, taking + `__init__.py` files into account) will be put at the *start* of `sys.path` before + being imported with `__import__. + + * `mode == ImportMode.append`: same as `prepend`, but the directory will be appended + to the end of `sys.path`, if not already in `sys.path`. + + * `mode == ImportMode.importlib`: uses more fine control mechanisms provided by `importlib` + to import the module, which avoids having to use `__import__` and muck with `sys.path` + at all. It effectively allows having same-named test modules in different places. + + :raises ImportPathMismatchError: + If after importing the given `path` and the module `__file__` + are different. Only raised in `prepend` and `append` modes. + """ + mode = ImportMode(mode) + + path = Path(str(p)) + + if not path.exists(): + raise ImportError(path) + + if mode is ImportMode.importlib: + module_name = path.stem + + for meta_importer in sys.meta_path: + spec = meta_importer.find_spec(module_name, [str(path.parent)]) + if spec is not None: + break + else: + spec = importlib.util.spec_from_file_location(module_name, str(path)) + + if spec is None: + raise ImportError( + "Can't find module {} at location {}".format(module_name, str(path)) + ) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) # type: ignore[union-attr] + return mod + + pkg_path = resolve_package_path(path) + if pkg_path is not None: + pkg_root = pkg_path.parent + names = list(path.with_suffix("").relative_to(pkg_root).parts) + if names[-1] == "__init__": + names.pop() + module_name = ".".join(names) + else: + pkg_root = path.parent + module_name = path.stem + + # Change sys.path permanently: restoring it at the end of this function would cause surprising + # problems because of delayed imports: for example, a conftest.py file imported by this function + # might have local imports, which would fail at runtime if we restored sys.path. + if mode is ImportMode.append: + if str(pkg_root) not in sys.path: + sys.path.append(str(pkg_root)) + elif mode is ImportMode.prepend: + if str(pkg_root) != sys.path[0]: + sys.path.insert(0, str(pkg_root)) + else: + assert_never(mode) + + importlib.import_module(module_name) + + mod = sys.modules[module_name] + if path.name == "__init__.py": + return mod + + ignore = os.environ.get("PY_IGNORE_IMPORTMISMATCH", "") + if ignore != "1": + module_file = mod.__file__ + if module_file.endswith((".pyc", ".pyo")): + module_file = module_file[:-1] + if module_file.endswith(os.path.sep + "__init__.py"): + module_file = module_file[: -(len(os.path.sep + "__init__.py"))] + + try: + is_same = _is_same(str(path), module_file) + except FileNotFoundError: + is_same = False + + if not is_same: + raise ImportPathMismatchError(module_name, module_file, path) + + return mod + + +# Implement a special _is_same function on Windows which returns True if the two filenames +# compare equal, to circumvent os.path.samefile returning False for mounts in UNC (#7678). +if sys.platform.startswith("win"): + + def _is_same(f1: str, f2: str) -> bool: + return Path(f1) == Path(f2) or os.path.samefile(f1, f2) + + +else: + + def _is_same(f1: str, f2: str) -> bool: + return os.path.samefile(f1, f2) + + +def resolve_package_path(path: Path) -> Optional[Path]: + """Return the Python package path by looking for the last + directory upwards which still contains an __init__.py. + + Returns None if it can not be determined. + """ + result = None + for parent in itertools.chain((path,), path.parents): + if parent.is_dir(): + if not parent.joinpath("__init__.py").is_file(): + break + if not parent.name.isidentifier(): + break + result = parent + return result + + +def visit( + path: str, recurse: Callable[["os.DirEntry[str]"], bool] +) -> Iterator["os.DirEntry[str]"]: + """Walk a directory recursively, in breadth-first order. + + Entries at each directory level are sorted. + """ + + # Skip entries with symlink loops and other brokenness, so the caller doesn't + # have to deal with it. + entries = [] + for entry in os.scandir(path): + try: + entry.is_file() + except OSError as err: + if _ignore_error(err): + continue + raise + entries.append(entry) + + entries.sort(key=lambda entry: entry.name) + + yield from entries + + for entry in entries: + if entry.is_dir() and recurse(entry): + yield from visit(entry.path, recurse) + + +def absolutepath(path: Union[Path, str]) -> Path: + """Convert a path to an absolute path using os.path.abspath. + + Prefer this over Path.resolve() (see #6523). + Prefer this over Path.absolute() (not public, doesn't normalize). + """ + return Path(os.path.abspath(str(path))) + + +def commonpath(path1: Path, path2: Path) -> Optional[Path]: + """Return the common part shared with the other path, or None if there is + no common part. + + If one path is relative and one is absolute, returns None. + """ + try: + return Path(os.path.commonpath((str(path1), str(path2)))) + except ValueError: + return None + + +def bestrelpath(directory: Path, dest: Path) -> str: + """Return a string which is a relative path from directory to dest such + that directory/bestrelpath == dest. + + The paths must be either both absolute or both relative. + + If no such path can be determined, returns dest. + """ + if dest == directory: + return os.curdir + # Find the longest common directory. + base = commonpath(directory, dest) + # Can be the case on Windows for two absolute paths on different drives. + # Can be the case for two relative paths without common prefix. + # Can be the case for a relative path and an absolute path. + if not base: + return str(dest) + reldirectory = directory.relative_to(base) + reldest = dest.relative_to(base) + return os.path.join( + # Back from directory to base. + *([os.pardir] * len(reldirectory.parts)), + # Forward from base to dest. + *reldest.parts, + ) diff --git a/myenv/lib/python3.9/site-packages/_pytest/py.typed b/myenv/lib/python3.9/site-packages/_pytest/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/_pytest/pytester.py b/myenv/lib/python3.9/site-packages/_pytest/pytester.py new file mode 100644 index 0000000..31259d1 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/pytester.py @@ -0,0 +1,1922 @@ +"""(Disabled by default) support for testing pytest and pytest plugins. + +PYTEST_DONT_REWRITE +""" +import collections.abc +import contextlib +import gc +import importlib +import os +import platform +import re +import shutil +import subprocess +import sys +import traceback +from fnmatch import fnmatch +from io import StringIO +from pathlib import Path +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generator +from typing import Iterable +from typing import List +from typing import Optional +from typing import overload +from typing import Sequence +from typing import TextIO +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union +from weakref import WeakKeyDictionary + +import attr +import py +from iniconfig import IniConfig +from iniconfig import SectionWrapper + +from _pytest import timing +from _pytest._code import Source +from _pytest.capture import _get_multicapture +from _pytest.compat import final +from _pytest.config import _PluggyPlugin +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config import main +from _pytest.config import PytestPluginManager +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.main import Session +from _pytest.monkeypatch import MonkeyPatch +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.outcomes import fail +from _pytest.outcomes import importorskip +from _pytest.outcomes import skip +from _pytest.pathlib import make_numbered_dir +from _pytest.reports import CollectReport +from _pytest.reports import TestReport +from _pytest.tmpdir import TempPathFactory +from _pytest.warning_types import PytestWarning + +if TYPE_CHECKING: + from typing_extensions import Literal + + import pexpect + + +pytest_plugins = ["pytester_assertions"] + + +IGNORE_PAM = [ # filenames added when obtaining details about the current user + "/var/lib/sss/mc/passwd" +] + + +def pytest_addoption(parser: Parser) -> None: + parser.addoption( + "--lsof", + action="store_true", + dest="lsof", + default=False, + help="run FD checks if lsof is available", + ) + + parser.addoption( + "--runpytest", + default="inprocess", + dest="runpytest", + choices=("inprocess", "subprocess"), + help=( + "run pytest sub runs in tests using an 'inprocess' " + "or 'subprocess' (python -m main) method" + ), + ) + + parser.addini( + "pytester_example_dir", help="directory to take the pytester example files from" + ) + + +def pytest_configure(config: Config) -> None: + if config.getvalue("lsof"): + checker = LsofFdLeakChecker() + if checker.matching_platform(): + config.pluginmanager.register(checker) + + config.addinivalue_line( + "markers", + "pytester_example_path(*path_segments): join the given path " + "segments to `pytester_example_dir` for this test.", + ) + + +class LsofFdLeakChecker: + def get_open_files(self) -> List[Tuple[str, str]]: + out = subprocess.run( + ("lsof", "-Ffn0", "-p", str(os.getpid())), + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + check=True, + universal_newlines=True, + ).stdout + + def isopen(line: str) -> bool: + return line.startswith("f") and ( + "deleted" not in line + and "mem" not in line + and "txt" not in line + and "cwd" not in line + ) + + open_files = [] + + for line in out.split("\n"): + if isopen(line): + fields = line.split("\0") + fd = fields[0][1:] + filename = fields[1][1:] + if filename in IGNORE_PAM: + continue + if filename.startswith("/"): + open_files.append((fd, filename)) + + return open_files + + def matching_platform(self) -> bool: + try: + subprocess.run(("lsof", "-v"), check=True) + except (OSError, subprocess.CalledProcessError): + return False + else: + return True + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_runtest_protocol(self, item: Item) -> Generator[None, None, None]: + lines1 = self.get_open_files() + yield + if hasattr(sys, "pypy_version_info"): + gc.collect() + lines2 = self.get_open_files() + + new_fds = {t[0] for t in lines2} - {t[0] for t in lines1} + leaked_files = [t for t in lines2 if t[0] in new_fds] + if leaked_files: + error = [ + "***** %s FD leakage detected" % len(leaked_files), + *(str(f) for f in leaked_files), + "*** Before:", + *(str(f) for f in lines1), + "*** After:", + *(str(f) for f in lines2), + "***** %s FD leakage detected" % len(leaked_files), + "*** function %s:%s: %s " % item.location, + "See issue #2366", + ] + item.warn(PytestWarning("\n".join(error))) + + +# used at least by pytest-xdist plugin + + +@fixture +def _pytest(request: FixtureRequest) -> "PytestArg": + """Return a helper which offers a gethookrecorder(hook) method which + returns a HookRecorder instance which helps to make assertions about called + hooks.""" + return PytestArg(request) + + +class PytestArg: + def __init__(self, request: FixtureRequest) -> None: + self._request = request + + def gethookrecorder(self, hook) -> "HookRecorder": + hookrecorder = HookRecorder(hook._pm) + self._request.addfinalizer(hookrecorder.finish_recording) + return hookrecorder + + +def get_public_names(values: Iterable[str]) -> List[str]: + """Only return names from iterator values without a leading underscore.""" + return [x for x in values if x[0] != "_"] + + +class ParsedCall: + def __init__(self, name: str, kwargs) -> None: + self.__dict__.update(kwargs) + self._name = name + + def __repr__(self) -> str: + d = self.__dict__.copy() + del d["_name"] + return f"" + + if TYPE_CHECKING: + # The class has undetermined attributes, this tells mypy about it. + def __getattr__(self, key: str): + ... + + +class HookRecorder: + """Record all hooks called in a plugin manager. + + This wraps all the hook calls in the plugin manager, recording each call + before propagating the normal calls. + """ + + def __init__(self, pluginmanager: PytestPluginManager) -> None: + self._pluginmanager = pluginmanager + self.calls: List[ParsedCall] = [] + self.ret: Optional[Union[int, ExitCode]] = None + + def before(hook_name: str, hook_impls, kwargs) -> None: + self.calls.append(ParsedCall(hook_name, kwargs)) + + def after(outcome, hook_name: str, hook_impls, kwargs) -> None: + pass + + self._undo_wrapping = pluginmanager.add_hookcall_monitoring(before, after) + + def finish_recording(self) -> None: + self._undo_wrapping() + + def getcalls(self, names: Union[str, Iterable[str]]) -> List[ParsedCall]: + if isinstance(names, str): + names = names.split() + return [call for call in self.calls if call._name in names] + + def assert_contains(self, entries: Sequence[Tuple[str, str]]) -> None: + __tracebackhide__ = True + i = 0 + entries = list(entries) + backlocals = sys._getframe(1).f_locals + while entries: + name, check = entries.pop(0) + for ind, call in enumerate(self.calls[i:]): + if call._name == name: + print("NAMEMATCH", name, call) + if eval(check, backlocals, call.__dict__): + print("CHECKERMATCH", repr(check), "->", call) + else: + print("NOCHECKERMATCH", repr(check), "-", call) + continue + i += ind + 1 + break + print("NONAMEMATCH", name, "with", call) + else: + fail(f"could not find {name!r} check {check!r}") + + def popcall(self, name: str) -> ParsedCall: + __tracebackhide__ = True + for i, call in enumerate(self.calls): + if call._name == name: + del self.calls[i] + return call + lines = [f"could not find call {name!r}, in:"] + lines.extend([" %s" % x for x in self.calls]) + fail("\n".join(lines)) + + def getcall(self, name: str) -> ParsedCall: + values = self.getcalls(name) + assert len(values) == 1, (name, values) + return values[0] + + # functionality for test reports + + @overload + def getreports( + self, names: "Literal['pytest_collectreport']", + ) -> Sequence[CollectReport]: + ... + + @overload + def getreports( + self, names: "Literal['pytest_runtest_logreport']", + ) -> Sequence[TestReport]: + ... + + @overload + def getreports( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + ... + + def getreports( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + return [x.report for x in self.getcalls(names)] + + def matchreport( + self, + inamepart: str = "", + names: Union[str, Iterable[str]] = ( + "pytest_runtest_logreport", + "pytest_collectreport", + ), + when: Optional[str] = None, + ) -> Union[CollectReport, TestReport]: + """Return a testreport whose dotted import path matches.""" + values = [] + for rep in self.getreports(names=names): + if not when and rep.when != "call" and rep.passed: + # setup/teardown passing reports - let's ignore those + continue + if when and rep.when != when: + continue + if not inamepart or inamepart in rep.nodeid.split("::"): + values.append(rep) + if not values: + raise ValueError( + "could not find test report matching %r: " + "no test reports at all!" % (inamepart,) + ) + if len(values) > 1: + raise ValueError( + "found 2 or more testreports matching {!r}: {}".format( + inamepart, values + ) + ) + return values[0] + + @overload + def getfailures( + self, names: "Literal['pytest_collectreport']", + ) -> Sequence[CollectReport]: + ... + + @overload + def getfailures( + self, names: "Literal['pytest_runtest_logreport']", + ) -> Sequence[TestReport]: + ... + + @overload + def getfailures( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + ... + + def getfailures( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + return [rep for rep in self.getreports(names) if rep.failed] + + def getfailedcollections(self) -> Sequence[CollectReport]: + return self.getfailures("pytest_collectreport") + + def listoutcomes( + self, + ) -> Tuple[ + Sequence[TestReport], + Sequence[Union[CollectReport, TestReport]], + Sequence[Union[CollectReport, TestReport]], + ]: + passed = [] + skipped = [] + failed = [] + for rep in self.getreports( + ("pytest_collectreport", "pytest_runtest_logreport") + ): + if rep.passed: + if rep.when == "call": + assert isinstance(rep, TestReport) + passed.append(rep) + elif rep.skipped: + skipped.append(rep) + else: + assert rep.failed, f"Unexpected outcome: {rep!r}" + failed.append(rep) + return passed, skipped, failed + + def countoutcomes(self) -> List[int]: + return [len(x) for x in self.listoutcomes()] + + def assertoutcome(self, passed: int = 0, skipped: int = 0, failed: int = 0) -> None: + __tracebackhide__ = True + from _pytest.pytester_assertions import assertoutcome + + outcomes = self.listoutcomes() + assertoutcome( + outcomes, passed=passed, skipped=skipped, failed=failed, + ) + + def clear(self) -> None: + self.calls[:] = [] + + +@fixture +def linecomp() -> "LineComp": + """A :class: `LineComp` instance for checking that an input linearly + contains a sequence of strings.""" + return LineComp() + + +@fixture(name="LineMatcher") +def LineMatcher_fixture(request: FixtureRequest) -> Type["LineMatcher"]: + """A reference to the :class: `LineMatcher`. + + This is instantiable with a list of lines (without their trailing newlines). + This is useful for testing large texts, such as the output of commands. + """ + return LineMatcher + + +@fixture +def pytester(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> "Pytester": + """ + Facilities to write tests/configuration files, execute pytest in isolation, and match + against expected output, perfect for black-box testing of pytest plugins. + + It attempts to isolate the test run from external factors as much as possible, modifying + the current working directory to ``path`` and environment variables during initialization. + + It is particularly useful for testing plugins. It is similar to the :fixture:`tmp_path` + fixture but provides methods which aid in testing pytest itself. + """ + return Pytester(request, tmp_path_factory, _ispytest=True) + + +@fixture +def testdir(pytester: "Pytester") -> "Testdir": + """ + Identical to :fixture:`pytester`, and provides an instance whose methods return + legacy ``py.path.local`` objects instead when applicable. + + New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`. + """ + return Testdir(pytester, _ispytest=True) + + +@fixture +def _sys_snapshot() -> Generator[None, None, None]: + snappaths = SysPathsSnapshot() + snapmods = SysModulesSnapshot() + yield + snapmods.restore() + snappaths.restore() + + +@fixture +def _config_for_test() -> Generator[Config, None, None]: + from _pytest.config import get_config + + config = get_config() + yield config + config._ensure_unconfigure() # cleanup, e.g. capman closing tmpfiles. + + +# Regex to match the session duration string in the summary: "74.34s". +rex_session_duration = re.compile(r"\d+\.\d\ds") +# Regex to match all the counts and phrases in the summary line: "34 passed, 111 skipped". +rex_outcome = re.compile(r"(\d+) (\w+)") + + +class RunResult: + """The result of running a command.""" + + def __init__( + self, + ret: Union[int, ExitCode], + outlines: List[str], + errlines: List[str], + duration: float, + ) -> None: + try: + self.ret: Union[int, ExitCode] = ExitCode(ret) + """The return value.""" + except ValueError: + self.ret = ret + self.outlines = outlines + """List of lines captured from stdout.""" + self.errlines = errlines + """List of lines captured from stderr.""" + self.stdout = LineMatcher(outlines) + """:class:`LineMatcher` of stdout. + + Use e.g. :func:`str(stdout) ` to reconstruct stdout, or the commonly used + :func:`stdout.fnmatch_lines() ` method. + """ + self.stderr = LineMatcher(errlines) + """:class:`LineMatcher` of stderr.""" + self.duration = duration + """Duration in seconds.""" + + def __repr__(self) -> str: + return ( + "" + % (self.ret, len(self.stdout.lines), len(self.stderr.lines), self.duration) + ) + + def parseoutcomes(self) -> Dict[str, int]: + """Return a dictionary of outcome noun -> count from parsing the terminal + output that the test process produced. + + The returned nouns will always be in plural form:: + + ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ==== + + Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``. + """ + return self.parse_summary_nouns(self.outlines) + + @classmethod + def parse_summary_nouns(cls, lines) -> Dict[str, int]: + """Extract the nouns from a pytest terminal summary line. + + It always returns the plural noun for consistency:: + + ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ==== + + Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``. + """ + for line in reversed(lines): + if rex_session_duration.search(line): + outcomes = rex_outcome.findall(line) + ret = {noun: int(count) for (count, noun) in outcomes} + break + else: + raise ValueError("Pytest terminal summary report not found") + + to_plural = { + "warning": "warnings", + "error": "errors", + } + return {to_plural.get(k, k): v for k, v in ret.items()} + + def assert_outcomes( + self, + passed: int = 0, + skipped: int = 0, + failed: int = 0, + errors: int = 0, + xpassed: int = 0, + xfailed: int = 0, + ) -> None: + """Assert that the specified outcomes appear with the respective + numbers (0 means it didn't occur) in the text output from a test run.""" + __tracebackhide__ = True + from _pytest.pytester_assertions import assert_outcomes + + outcomes = self.parseoutcomes() + assert_outcomes( + outcomes, + passed=passed, + skipped=skipped, + failed=failed, + errors=errors, + xpassed=xpassed, + xfailed=xfailed, + ) + + +class CwdSnapshot: + def __init__(self) -> None: + self.__saved = os.getcwd() + + def restore(self) -> None: + os.chdir(self.__saved) + + +class SysModulesSnapshot: + def __init__(self, preserve: Optional[Callable[[str], bool]] = None) -> None: + self.__preserve = preserve + self.__saved = dict(sys.modules) + + def restore(self) -> None: + if self.__preserve: + self.__saved.update( + (k, m) for k, m in sys.modules.items() if self.__preserve(k) + ) + sys.modules.clear() + sys.modules.update(self.__saved) + + +class SysPathsSnapshot: + def __init__(self) -> None: + self.__saved = list(sys.path), list(sys.meta_path) + + def restore(self) -> None: + sys.path[:], sys.meta_path[:] = self.__saved + + +@final +class Pytester: + """ + Facilities to write tests/configuration files, execute pytest in isolation, and match + against expected output, perfect for black-box testing of pytest plugins. + + It attempts to isolate the test run from external factors as much as possible, modifying + the current working directory to ``path`` and environment variables during initialization. + + Attributes: + + :ivar Path path: temporary directory path used to create files/run tests from, etc. + + :ivar plugins: + A list of plugins to use with :py:meth:`parseconfig` and + :py:meth:`runpytest`. Initially this is an empty list but plugins can + be added to the list. The type of items to add to the list depends on + the method using them so refer to them for details. + """ + + __test__ = False + + CLOSE_STDIN = object + + class TimeoutExpired(Exception): + pass + + def __init__( + self, + request: FixtureRequest, + tmp_path_factory: TempPathFactory, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._request = request + self._mod_collections: WeakKeyDictionary[ + Collector, List[Union[Item, Collector]] + ] = (WeakKeyDictionary()) + if request.function: + name: str = request.function.__name__ + else: + name = request.node.name + self._name = name + self._path: Path = tmp_path_factory.mktemp(name, numbered=True) + self.plugins: List[Union[str, _PluggyPlugin]] = [] + self._cwd_snapshot = CwdSnapshot() + self._sys_path_snapshot = SysPathsSnapshot() + self._sys_modules_snapshot = self.__take_sys_modules_snapshot() + self.chdir() + self._request.addfinalizer(self._finalize) + self._method = self._request.config.getoption("--runpytest") + self._test_tmproot = tmp_path_factory.mktemp(f"tmp-{name}", numbered=True) + + self._monkeypatch = mp = MonkeyPatch() + mp.setenv("PYTEST_DEBUG_TEMPROOT", str(self._test_tmproot)) + # Ensure no unexpected caching via tox. + mp.delenv("TOX_ENV_DIR", raising=False) + # Discard outer pytest options. + mp.delenv("PYTEST_ADDOPTS", raising=False) + # Ensure no user config is used. + tmphome = str(self.path) + mp.setenv("HOME", tmphome) + mp.setenv("USERPROFILE", tmphome) + # Do not use colors for inner runs by default. + mp.setenv("PY_COLORS", "0") + + @property + def path(self) -> Path: + """Temporary directory where files are created and pytest is executed.""" + return self._path + + def __repr__(self) -> str: + return f"" + + def _finalize(self) -> None: + """ + Clean up global state artifacts. + + Some methods modify the global interpreter state and this tries to + clean this up. It does not remove the temporary directory however so + it can be looked at after the test run has finished. + """ + self._sys_modules_snapshot.restore() + self._sys_path_snapshot.restore() + self._cwd_snapshot.restore() + self._monkeypatch.undo() + + def __take_sys_modules_snapshot(self) -> SysModulesSnapshot: + # Some zope modules used by twisted-related tests keep internal state + # and can't be deleted; we had some trouble in the past with + # `zope.interface` for example. + # + # Preserve readline due to https://bugs.python.org/issue41033. + # pexpect issues a SIGWINCH. + def preserve_module(name): + return name.startswith(("zope", "readline")) + + return SysModulesSnapshot(preserve=preserve_module) + + def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder: + """Create a new :py:class:`HookRecorder` for a PluginManager.""" + pluginmanager.reprec = reprec = HookRecorder(pluginmanager) + self._request.addfinalizer(reprec.finish_recording) + return reprec + + def chdir(self) -> None: + """Cd into the temporary directory. + + This is done automatically upon instantiation. + """ + os.chdir(self.path) + + def _makefile( + self, + ext: str, + lines: Sequence[Union[Any, bytes]], + files: Dict[str, str], + encoding: str = "utf-8", + ) -> Path: + items = list(files.items()) + + def to_text(s: Union[Any, bytes]) -> str: + return s.decode(encoding) if isinstance(s, bytes) else str(s) + + if lines: + source = "\n".join(to_text(x) for x in lines) + basename = self._name + items.insert(0, (basename, source)) + + ret = None + for basename, value in items: + p = self.path.joinpath(basename).with_suffix(ext) + p.parent.mkdir(parents=True, exist_ok=True) + source_ = Source(value) + source = "\n".join(to_text(line) for line in source_.lines) + p.write_text(source.strip(), encoding=encoding) + if ret is None: + ret = p + assert ret is not None + return ret + + def makefile(self, ext: str, *args: str, **kwargs: str) -> Path: + r"""Create new file(s) in the test directory. + + :param str ext: + The extension the file(s) should use, including the dot, e.g. `.py`. + :param args: + All args are treated as strings and joined using newlines. + The result is written as contents to the file. The name of the + file is based on the test function requesting this fixture. + :param kwargs: + Each keyword is the name of a file, while the value of it will + be written as contents of the file. + + Examples: + + .. code-block:: python + + pytester.makefile(".txt", "line1", "line2") + + pytester.makefile(".ini", pytest="[pytest]\naddopts=-rs\n") + + """ + return self._makefile(ext, args, kwargs) + + def makeconftest(self, source: str) -> Path: + """Write a contest.py file with 'source' as contents.""" + return self.makepyfile(conftest=source) + + def makeini(self, source: str) -> Path: + """Write a tox.ini file with 'source' as contents.""" + return self.makefile(".ini", tox=source) + + def getinicfg(self, source: str) -> SectionWrapper: + """Return the pytest section from the tox.ini config file.""" + p = self.makeini(source) + return IniConfig(str(p))["pytest"] + + def makepyprojecttoml(self, source: str) -> Path: + """Write a pyproject.toml file with 'source' as contents. + + .. versionadded:: 6.0 + """ + return self.makefile(".toml", pyproject=source) + + def makepyfile(self, *args, **kwargs) -> Path: + r"""Shortcut for .makefile() with a .py extension. + + Defaults to the test name with a '.py' extension, e.g test_foobar.py, overwriting + existing files. + + Examples: + + .. code-block:: python + + def test_something(pytester): + # Initial file is created test_something.py. + pytester.makepyfile("foobar") + # To create multiple files, pass kwargs accordingly. + pytester.makepyfile(custom="foobar") + # At this point, both 'test_something.py' & 'custom.py' exist in the test directory. + + """ + return self._makefile(".py", args, kwargs) + + def maketxtfile(self, *args, **kwargs) -> Path: + r"""Shortcut for .makefile() with a .txt extension. + + Defaults to the test name with a '.txt' extension, e.g test_foobar.txt, overwriting + existing files. + + Examples: + + .. code-block:: python + + def test_something(pytester): + # Initial file is created test_something.txt. + pytester.maketxtfile("foobar") + # To create multiple files, pass kwargs accordingly. + pytester.maketxtfile(custom="foobar") + # At this point, both 'test_something.txt' & 'custom.txt' exist in the test directory. + + """ + return self._makefile(".txt", args, kwargs) + + def syspathinsert( + self, path: Optional[Union[str, "os.PathLike[str]"]] = None + ) -> None: + """Prepend a directory to sys.path, defaults to :py:attr:`tmpdir`. + + This is undone automatically when this object dies at the end of each + test. + """ + if path is None: + path = self.path + + self._monkeypatch.syspath_prepend(str(path)) + + def mkdir(self, name: str) -> Path: + """Create a new (sub)directory.""" + p = self.path / name + p.mkdir() + return p + + def mkpydir(self, name: str) -> Path: + """Create a new python package. + + This creates a (sub)directory with an empty ``__init__.py`` file so it + gets recognised as a Python package. + """ + p = self.path / name + p.mkdir() + p.joinpath("__init__.py").touch() + return p + + def copy_example(self, name: Optional[str] = None) -> Path: + """Copy file from project's directory into the testdir. + + :param str name: The name of the file to copy. + :return: path to the copied directory (inside ``self.path``). + + """ + example_dir = self._request.config.getini("pytester_example_dir") + if example_dir is None: + raise ValueError("pytester_example_dir is unset, can't copy examples") + example_dir = Path(str(self._request.config.rootdir)) / example_dir + + for extra_element in self._request.node.iter_markers("pytester_example_path"): + assert extra_element.args + example_dir = example_dir.joinpath(*extra_element.args) + + if name is None: + func_name = self._name + maybe_dir = example_dir / func_name + maybe_file = example_dir / (func_name + ".py") + + if maybe_dir.is_dir(): + example_path = maybe_dir + elif maybe_file.is_file(): + example_path = maybe_file + else: + raise LookupError( + f"{func_name} can't be found as module or package in {example_dir}" + ) + else: + example_path = example_dir.joinpath(name) + + if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file(): + # TODO: py.path.local.copy can copy files to existing directories, + # while with shutil.copytree the destination directory cannot exist, + # we will need to roll our own in order to drop py.path.local completely + py.path.local(example_path).copy(py.path.local(self.path)) + return self.path + elif example_path.is_file(): + result = self.path.joinpath(example_path.name) + shutil.copy(example_path, result) + return result + else: + raise LookupError( + f'example "{example_path}" is not found as a file or directory' + ) + + Session = Session + + def getnode( + self, config: Config, arg: Union[str, "os.PathLike[str]"] + ) -> Optional[Union[Collector, Item]]: + """Return the collection node of a file. + + :param _pytest.config.Config config: + A pytest config. + See :py:meth:`parseconfig` and :py:meth:`parseconfigure` for creating it. + :param py.path.local arg: + Path to the file. + """ + session = Session.from_config(config) + assert "::" not in str(arg) + p = py.path.local(arg) + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([str(p)], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK) + return res + + def getpathnode(self, path: Union[str, "os.PathLike[str]"]): + """Return the collection node of a file. + + This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to + create the (configured) pytest Config instance. + + :param py.path.local path: Path to the file. + """ + path = py.path.local(path) + config = self.parseconfigure(path) + session = Session.from_config(config) + x = session.fspath.bestrelpath(path) + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK) + return res + + def genitems(self, colitems: Sequence[Union[Item, Collector]]) -> List[Item]: + """Generate all test items from a collection node. + + This recurses into the collection node and returns a list of all the + test items contained within. + """ + session = colitems[0].session + result: List[Item] = [] + for colitem in colitems: + result.extend(session.genitems(colitem)) + return result + + def runitem(self, source: str) -> Any: + """Run the "test_func" Item. + + The calling test instance (class containing the test method) must + provide a ``.getrunner()`` method which should return a runner which + can run the test protocol for a single item, e.g. + :py:func:`_pytest.runner.runtestprotocol`. + """ + # used from runner functional tests + item = self.getitem(source) + # the test class where we are called from wants to provide the runner + testclassinstance = self._request.instance + runner = testclassinstance.getrunner() + return runner(item) + + def inline_runsource(self, source: str, *cmdlineargs) -> HookRecorder: + """Run a test module in process using ``pytest.main()``. + + This run writes "source" into a temporary file and runs + ``pytest.main()`` on it, returning a :py:class:`HookRecorder` instance + for the result. + + :param source: The source code of the test module. + + :param cmdlineargs: Any extra command line arguments to use. + + :returns: :py:class:`HookRecorder` instance of the result. + """ + p = self.makepyfile(source) + values = list(cmdlineargs) + [p] + return self.inline_run(*values) + + def inline_genitems(self, *args) -> Tuple[List[Item], HookRecorder]: + """Run ``pytest.main(['--collectonly'])`` in-process. + + Runs the :py:func:`pytest.main` function to run all of pytest inside + the test process itself like :py:meth:`inline_run`, but returns a + tuple of the collected items and a :py:class:`HookRecorder` instance. + """ + rec = self.inline_run("--collect-only", *args) + items = [x.item for x in rec.getcalls("pytest_itemcollected")] + return items, rec + + def inline_run( + self, + *args: Union[str, "os.PathLike[str]"], + plugins=(), + no_reraise_ctrlc: bool = False, + ) -> HookRecorder: + """Run ``pytest.main()`` in-process, returning a HookRecorder. + + Runs the :py:func:`pytest.main` function to run all of pytest inside + the test process itself. This means it can return a + :py:class:`HookRecorder` instance which gives more detailed results + from that run than can be done by matching stdout/stderr from + :py:meth:`runpytest`. + + :param args: + Command line arguments to pass to :py:func:`pytest.main`. + :param plugins: + Extra plugin instances the ``pytest.main()`` instance should use. + :param no_reraise_ctrlc: + Typically we reraise keyboard interrupts from the child run. If + True, the KeyboardInterrupt exception is captured. + + :returns: A :py:class:`HookRecorder` instance. + """ + # (maybe a cpython bug?) the importlib cache sometimes isn't updated + # properly between file creation and inline_run (especially if imports + # are interspersed with file creation) + importlib.invalidate_caches() + + plugins = list(plugins) + finalizers = [] + try: + # Any sys.module or sys.path changes done while running pytest + # inline should be reverted after the test run completes to avoid + # clashing with later inline tests run within the same pytest test, + # e.g. just because they use matching test module names. + finalizers.append(self.__take_sys_modules_snapshot().restore) + finalizers.append(SysPathsSnapshot().restore) + + # Important note: + # - our tests should not leave any other references/registrations + # laying around other than possibly loaded test modules + # referenced from sys.modules, as nothing will clean those up + # automatically + + rec = [] + + class Collect: + def pytest_configure(x, config: Config) -> None: + rec.append(self.make_hook_recorder(config.pluginmanager)) + + plugins.append(Collect()) + ret = main([str(x) for x in args], plugins=plugins) + if len(rec) == 1: + reprec = rec.pop() + else: + + class reprec: # type: ignore + pass + + reprec.ret = ret # type: ignore + + # Typically we reraise keyboard interrupts from the child run + # because it's our user requesting interruption of the testing. + if ret == ExitCode.INTERRUPTED and not no_reraise_ctrlc: + calls = reprec.getcalls("pytest_keyboard_interrupt") + if calls and calls[-1].excinfo.type == KeyboardInterrupt: + raise KeyboardInterrupt() + return reprec + finally: + for finalizer in finalizers: + finalizer() + + def runpytest_inprocess( + self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any + ) -> RunResult: + """Return result of running pytest in-process, providing a similar + interface to what self.runpytest() provides.""" + syspathinsert = kwargs.pop("syspathinsert", False) + + if syspathinsert: + self.syspathinsert() + now = timing.time() + capture = _get_multicapture("sys") + capture.start_capturing() + try: + try: + reprec = self.inline_run(*args, **kwargs) + except SystemExit as e: + ret = e.args[0] + try: + ret = ExitCode(e.args[0]) + except ValueError: + pass + + class reprec: # type: ignore + ret = ret + + except Exception: + traceback.print_exc() + + class reprec: # type: ignore + ret = ExitCode(3) + + finally: + out, err = capture.readouterr() + capture.stop_capturing() + sys.stdout.write(out) + sys.stderr.write(err) + + assert reprec.ret is not None + res = RunResult( + reprec.ret, out.splitlines(), err.splitlines(), timing.time() - now + ) + res.reprec = reprec # type: ignore + return res + + def runpytest( + self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any + ) -> RunResult: + """Run pytest inline or in a subprocess, depending on the command line + option "--runpytest" and return a :py:class:`RunResult`.""" + new_args = self._ensure_basetemp(args) + if self._method == "inprocess": + return self.runpytest_inprocess(*new_args, **kwargs) + elif self._method == "subprocess": + return self.runpytest_subprocess(*new_args, **kwargs) + raise RuntimeError(f"Unrecognized runpytest option: {self._method}") + + def _ensure_basetemp( + self, args: Sequence[Union[str, "os.PathLike[str]"]] + ) -> List[Union[str, "os.PathLike[str]"]]: + new_args = list(args) + for x in new_args: + if str(x).startswith("--basetemp"): + break + else: + new_args.append("--basetemp=%s" % self.path.parent.joinpath("basetemp")) + return new_args + + def parseconfig(self, *args: Union[str, "os.PathLike[str]"]) -> Config: + """Return a new pytest Config instance from given commandline args. + + This invokes the pytest bootstrapping code in _pytest.config to create + a new :py:class:`_pytest.core.PluginManager` and call the + pytest_cmdline_parse hook to create a new + :py:class:`_pytest.config.Config` instance. + + If :py:attr:`plugins` has been populated they should be plugin modules + to be registered with the PluginManager. + """ + import _pytest.config + + new_args = self._ensure_basetemp(args) + new_args = [str(x) for x in new_args] + + config = _pytest.config._prepareconfig(new_args, self.plugins) # type: ignore[arg-type] + # we don't know what the test will do with this half-setup config + # object and thus we make sure it gets unconfigured properly in any + # case (otherwise capturing could still be active, for example) + self._request.addfinalizer(config._ensure_unconfigure) + return config + + def parseconfigure(self, *args: Union[str, "os.PathLike[str]"]) -> Config: + """Return a new pytest configured Config instance. + + Returns a new :py:class:`_pytest.config.Config` instance like + :py:meth:`parseconfig`, but also calls the pytest_configure hook. + """ + config = self.parseconfig(*args) + config._do_configure() + return config + + def getitem(self, source: str, funcname: str = "test_func") -> Item: + """Return the test item for a test function. + + Writes the source to a python file and runs pytest's collection on + the resulting module, returning the test item for the requested + function name. + + :param source: + The module source. + :param funcname: + The name of the test function for which to return a test item. + """ + items = self.getitems(source) + for item in items: + if item.name == funcname: + return item + assert 0, "{!r} item not found in module:\n{}\nitems: {}".format( + funcname, source, items + ) + + def getitems(self, source: str) -> List[Item]: + """Return all test items collected from the module. + + Writes the source to a Python file and runs pytest's collection on + the resulting module, returning all test items contained within. + """ + modcol = self.getmodulecol(source) + return self.genitems([modcol]) + + def getmodulecol( + self, source: Union[str, Path], configargs=(), *, withinit: bool = False + ): + """Return the module collection node for ``source``. + + Writes ``source`` to a file using :py:meth:`makepyfile` and then + runs the pytest collection on it, returning the collection node for the + test module. + + :param source: + The source code of the module to collect. + + :param configargs: + Any extra arguments to pass to :py:meth:`parseconfigure`. + + :param withinit: + Whether to also write an ``__init__.py`` file to the same + directory to ensure it is a package. + """ + if isinstance(source, Path): + path = self.path.joinpath(source) + assert not withinit, "not supported for paths" + else: + kw = {self._name: str(source)} + path = self.makepyfile(**kw) + if withinit: + self.makepyfile(__init__="#") + self.config = config = self.parseconfigure(path, *configargs) + return self.getnode(config, path) + + def collect_by_name( + self, modcol: Collector, name: str + ) -> Optional[Union[Item, Collector]]: + """Return the collection node for name from the module collection. + + Searchs a module collection node for a collection node matching the + given name. + + :param modcol: A module collection node; see :py:meth:`getmodulecol`. + :param name: The name of the node to return. + """ + if modcol not in self._mod_collections: + self._mod_collections[modcol] = list(modcol.collect()) + for colitem in self._mod_collections[modcol]: + if colitem.name == name: + return colitem + return None + + def popen( + self, + cmdargs, + stdout: Union[int, TextIO] = subprocess.PIPE, + stderr: Union[int, TextIO] = subprocess.PIPE, + stdin=CLOSE_STDIN, + **kw, + ): + """Invoke subprocess.Popen. + + Calls subprocess.Popen making sure the current working directory is + in the PYTHONPATH. + + You probably want to use :py:meth:`run` instead. + """ + env = os.environ.copy() + env["PYTHONPATH"] = os.pathsep.join( + filter(None, [os.getcwd(), env.get("PYTHONPATH", "")]) + ) + kw["env"] = env + + if stdin is self.CLOSE_STDIN: + kw["stdin"] = subprocess.PIPE + elif isinstance(stdin, bytes): + kw["stdin"] = subprocess.PIPE + else: + kw["stdin"] = stdin + + popen = subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw) + if stdin is self.CLOSE_STDIN: + assert popen.stdin is not None + popen.stdin.close() + elif isinstance(stdin, bytes): + assert popen.stdin is not None + popen.stdin.write(stdin) + + return popen + + def run( + self, + *cmdargs: Union[str, "os.PathLike[str]"], + timeout: Optional[float] = None, + stdin=CLOSE_STDIN, + ) -> RunResult: + """Run a command with arguments. + + Run a process using subprocess.Popen saving the stdout and stderr. + + :param cmdargs: + The sequence of arguments to pass to `subprocess.Popen()`, with path-like objects + being converted to ``str`` automatically. + :param timeout: + The period in seconds after which to timeout and raise + :py:class:`Pytester.TimeoutExpired`. + :param stdin: + Optional standard input. Bytes are being send, closing + the pipe, otherwise it is passed through to ``popen``. + Defaults to ``CLOSE_STDIN``, which translates to using a pipe + (``subprocess.PIPE``) that gets closed. + + :rtype: RunResult + """ + __tracebackhide__ = True + + # TODO: Remove type ignore in next mypy release. + # https://github.com/python/typeshed/pull/4582 + cmdargs = tuple( + os.fspath(arg) if isinstance(arg, os.PathLike) else arg for arg in cmdargs # type: ignore[misc] + ) + p1 = self.path.joinpath("stdout") + p2 = self.path.joinpath("stderr") + print("running:", *cmdargs) + print(" in:", Path.cwd()) + + with p1.open("w", encoding="utf8") as f1, p2.open("w", encoding="utf8") as f2: + now = timing.time() + popen = self.popen( + cmdargs, + stdin=stdin, + stdout=f1, + stderr=f2, + close_fds=(sys.platform != "win32"), + ) + if popen.stdin is not None: + popen.stdin.close() + + def handle_timeout() -> None: + __tracebackhide__ = True + + timeout_message = ( + "{seconds} second timeout expired running:" + " {command}".format(seconds=timeout, command=cmdargs) + ) + + popen.kill() + popen.wait() + raise self.TimeoutExpired(timeout_message) + + if timeout is None: + ret = popen.wait() + else: + try: + ret = popen.wait(timeout) + except subprocess.TimeoutExpired: + handle_timeout() + + with p1.open(encoding="utf8") as f1, p2.open(encoding="utf8") as f2: + out = f1.read().splitlines() + err = f2.read().splitlines() + + self._dump_lines(out, sys.stdout) + self._dump_lines(err, sys.stderr) + + with contextlib.suppress(ValueError): + ret = ExitCode(ret) + return RunResult(ret, out, err, timing.time() - now) + + def _dump_lines(self, lines, fp): + try: + for line in lines: + print(line, file=fp) + except UnicodeEncodeError: + print(f"couldn't print to {fp} because of encoding") + + def _getpytestargs(self) -> Tuple[str, ...]: + return sys.executable, "-mpytest" + + def runpython(self, script) -> RunResult: + """Run a python script using sys.executable as interpreter. + + :rtype: RunResult + """ + return self.run(sys.executable, script) + + def runpython_c(self, command): + """Run python -c "command". + + :rtype: RunResult + """ + return self.run(sys.executable, "-c", command) + + def runpytest_subprocess(self, *args, timeout: Optional[float] = None) -> RunResult: + """Run pytest as a subprocess with given arguments. + + Any plugins added to the :py:attr:`plugins` list will be added using the + ``-p`` command line option. Additionally ``--basetemp`` is used to put + any temporary files and directories in a numbered directory prefixed + with "runpytest-" to not conflict with the normal numbered pytest + location for temporary files and directories. + + :param args: + The sequence of arguments to pass to the pytest subprocess. + :param timeout: + The period in seconds after which to timeout and raise + :py:class:`Pytester.TimeoutExpired`. + + :rtype: RunResult + """ + __tracebackhide__ = True + p = make_numbered_dir(root=self.path, prefix="runpytest-", mode=0o700) + args = ("--basetemp=%s" % p,) + args + plugins = [x for x in self.plugins if isinstance(x, str)] + if plugins: + args = ("-p", plugins[0]) + args + args = self._getpytestargs() + args + return self.run(*args, timeout=timeout) + + def spawn_pytest( + self, string: str, expect_timeout: float = 10.0 + ) -> "pexpect.spawn": + """Run pytest using pexpect. + + This makes sure to use the right pytest and sets up the temporary + directory locations. + + The pexpect child is returned. + """ + basetemp = self.path / "temp-pexpect" + basetemp.mkdir(mode=0o700) + invoke = " ".join(map(str, self._getpytestargs())) + cmd = f"{invoke} --basetemp={basetemp} {string}" + return self.spawn(cmd, expect_timeout=expect_timeout) + + def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn": + """Run a command using pexpect. + + The pexpect child is returned. + """ + pexpect = importorskip("pexpect", "3.0") + if hasattr(sys, "pypy_version_info") and "64" in platform.machine(): + skip("pypy-64 bit not supported") + if not hasattr(pexpect, "spawn"): + skip("pexpect.spawn not available") + logfile = self.path.joinpath("spawn.out").open("wb") + + child = pexpect.spawn(cmd, logfile=logfile, timeout=expect_timeout) + self._request.addfinalizer(logfile.close) + return child + + +class LineComp: + def __init__(self) -> None: + self.stringio = StringIO() + """:class:`python:io.StringIO()` instance used for input.""" + + def assert_contains_lines(self, lines2: Sequence[str]) -> None: + """Assert that ``lines2`` are contained (linearly) in :attr:`stringio`'s value. + + Lines are matched using :func:`LineMatcher.fnmatch_lines`. + """ + __tracebackhide__ = True + val = self.stringio.getvalue() + self.stringio.truncate(0) + self.stringio.seek(0) + lines1 = val.split("\n") + LineMatcher(lines1).fnmatch_lines(lines2) + + +@final +@attr.s(repr=False, str=False, init=False) +class Testdir: + """ + Similar to :class:`Pytester`, but this class works with legacy py.path.local objects instead. + + All methods just forward to an internal :class:`Pytester` instance, converting results + to `py.path.local` objects as necessary. + """ + + __test__ = False + + CLOSE_STDIN = Pytester.CLOSE_STDIN + TimeoutExpired = Pytester.TimeoutExpired + Session = Pytester.Session + + def __init__(self, pytester: Pytester, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + self._pytester = pytester + + @property + def tmpdir(self) -> py.path.local: + """Temporary directory where tests are executed.""" + return py.path.local(self._pytester.path) + + @property + def test_tmproot(self) -> py.path.local: + return py.path.local(self._pytester._test_tmproot) + + @property + def request(self): + return self._pytester._request + + @property + def plugins(self): + return self._pytester.plugins + + @plugins.setter + def plugins(self, plugins): + self._pytester.plugins = plugins + + @property + def monkeypatch(self) -> MonkeyPatch: + return self._pytester._monkeypatch + + def make_hook_recorder(self, pluginmanager) -> HookRecorder: + """See :meth:`Pytester.make_hook_recorder`.""" + return self._pytester.make_hook_recorder(pluginmanager) + + def chdir(self) -> None: + """See :meth:`Pytester.chdir`.""" + return self._pytester.chdir() + + def finalize(self) -> None: + """See :meth:`Pytester._finalize`.""" + return self._pytester._finalize() + + def makefile(self, ext, *args, **kwargs) -> py.path.local: + """See :meth:`Pytester.makefile`.""" + return py.path.local(str(self._pytester.makefile(ext, *args, **kwargs))) + + def makeconftest(self, source) -> py.path.local: + """See :meth:`Pytester.makeconftest`.""" + return py.path.local(str(self._pytester.makeconftest(source))) + + def makeini(self, source) -> py.path.local: + """See :meth:`Pytester.makeini`.""" + return py.path.local(str(self._pytester.makeini(source))) + + def getinicfg(self, source: str) -> SectionWrapper: + """See :meth:`Pytester.getinicfg`.""" + return self._pytester.getinicfg(source) + + def makepyprojecttoml(self, source) -> py.path.local: + """See :meth:`Pytester.makepyprojecttoml`.""" + return py.path.local(str(self._pytester.makepyprojecttoml(source))) + + def makepyfile(self, *args, **kwargs) -> py.path.local: + """See :meth:`Pytester.makepyfile`.""" + return py.path.local(str(self._pytester.makepyfile(*args, **kwargs))) + + def maketxtfile(self, *args, **kwargs) -> py.path.local: + """See :meth:`Pytester.maketxtfile`.""" + return py.path.local(str(self._pytester.maketxtfile(*args, **kwargs))) + + def syspathinsert(self, path=None) -> None: + """See :meth:`Pytester.syspathinsert`.""" + return self._pytester.syspathinsert(path) + + def mkdir(self, name) -> py.path.local: + """See :meth:`Pytester.mkdir`.""" + return py.path.local(str(self._pytester.mkdir(name))) + + def mkpydir(self, name) -> py.path.local: + """See :meth:`Pytester.mkpydir`.""" + return py.path.local(str(self._pytester.mkpydir(name))) + + def copy_example(self, name=None) -> py.path.local: + """See :meth:`Pytester.copy_example`.""" + return py.path.local(str(self._pytester.copy_example(name))) + + def getnode(self, config: Config, arg) -> Optional[Union[Item, Collector]]: + """See :meth:`Pytester.getnode`.""" + return self._pytester.getnode(config, arg) + + def getpathnode(self, path): + """See :meth:`Pytester.getpathnode`.""" + return self._pytester.getpathnode(path) + + def genitems(self, colitems: List[Union[Item, Collector]]) -> List[Item]: + """See :meth:`Pytester.genitems`.""" + return self._pytester.genitems(colitems) + + def runitem(self, source): + """See :meth:`Pytester.runitem`.""" + return self._pytester.runitem(source) + + def inline_runsource(self, source, *cmdlineargs): + """See :meth:`Pytester.inline_runsource`.""" + return self._pytester.inline_runsource(source, *cmdlineargs) + + def inline_genitems(self, *args): + """See :meth:`Pytester.inline_genitems`.""" + return self._pytester.inline_genitems(*args) + + def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False): + """See :meth:`Pytester.inline_run`.""" + return self._pytester.inline_run( + *args, plugins=plugins, no_reraise_ctrlc=no_reraise_ctrlc + ) + + def runpytest_inprocess(self, *args, **kwargs) -> RunResult: + """See :meth:`Pytester.runpytest_inprocess`.""" + return self._pytester.runpytest_inprocess(*args, **kwargs) + + def runpytest(self, *args, **kwargs) -> RunResult: + """See :meth:`Pytester.runpytest`.""" + return self._pytester.runpytest(*args, **kwargs) + + def parseconfig(self, *args) -> Config: + """See :meth:`Pytester.parseconfig`.""" + return self._pytester.parseconfig(*args) + + def parseconfigure(self, *args) -> Config: + """See :meth:`Pytester.parseconfigure`.""" + return self._pytester.parseconfigure(*args) + + def getitem(self, source, funcname="test_func"): + """See :meth:`Pytester.getitem`.""" + return self._pytester.getitem(source, funcname) + + def getitems(self, source): + """See :meth:`Pytester.getitems`.""" + return self._pytester.getitems(source) + + def getmodulecol(self, source, configargs=(), withinit=False): + """See :meth:`Pytester.getmodulecol`.""" + return self._pytester.getmodulecol( + source, configargs=configargs, withinit=withinit + ) + + def collect_by_name( + self, modcol: Collector, name: str + ) -> Optional[Union[Item, Collector]]: + """See :meth:`Pytester.collect_by_name`.""" + return self._pytester.collect_by_name(modcol, name) + + def popen( + self, + cmdargs, + stdout: Union[int, TextIO] = subprocess.PIPE, + stderr: Union[int, TextIO] = subprocess.PIPE, + stdin=CLOSE_STDIN, + **kw, + ): + """See :meth:`Pytester.popen`.""" + return self._pytester.popen(cmdargs, stdout, stderr, stdin, **kw) + + def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> RunResult: + """See :meth:`Pytester.run`.""" + return self._pytester.run(*cmdargs, timeout=timeout, stdin=stdin) + + def runpython(self, script) -> RunResult: + """See :meth:`Pytester.runpython`.""" + return self._pytester.runpython(script) + + def runpython_c(self, command): + """See :meth:`Pytester.runpython_c`.""" + return self._pytester.runpython_c(command) + + def runpytest_subprocess(self, *args, timeout=None) -> RunResult: + """See :meth:`Pytester.runpytest_subprocess`.""" + return self._pytester.runpytest_subprocess(*args, timeout=timeout) + + def spawn_pytest( + self, string: str, expect_timeout: float = 10.0 + ) -> "pexpect.spawn": + """See :meth:`Pytester.spawn_pytest`.""" + return self._pytester.spawn_pytest(string, expect_timeout=expect_timeout) + + def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn": + """See :meth:`Pytester.spawn`.""" + return self._pytester.spawn(cmd, expect_timeout=expect_timeout) + + def __repr__(self) -> str: + return f"" + + def __str__(self) -> str: + return str(self.tmpdir) + + +class LineMatcher: + """Flexible matching of text. + + This is a convenience class to test large texts like the output of + commands. + + The constructor takes a list of lines without their trailing newlines, i.e. + ``text.splitlines()``. + """ + + def __init__(self, lines: List[str]) -> None: + self.lines = lines + self._log_output: List[str] = [] + + def __str__(self) -> str: + """Return the entire original text. + + .. versionadded:: 6.2 + You can use :meth:`str` in older versions. + """ + return "\n".join(self.lines) + + def _getlines(self, lines2: Union[str, Sequence[str], Source]) -> Sequence[str]: + if isinstance(lines2, str): + lines2 = Source(lines2) + if isinstance(lines2, Source): + lines2 = lines2.strip().lines + return lines2 + + def fnmatch_lines_random(self, lines2: Sequence[str]) -> None: + """Check lines exist in the output in any order (using :func:`python:fnmatch.fnmatch`).""" + __tracebackhide__ = True + self._match_lines_random(lines2, fnmatch) + + def re_match_lines_random(self, lines2: Sequence[str]) -> None: + """Check lines exist in the output in any order (using :func:`python:re.match`).""" + __tracebackhide__ = True + self._match_lines_random(lines2, lambda name, pat: bool(re.match(pat, name))) + + def _match_lines_random( + self, lines2: Sequence[str], match_func: Callable[[str, str], bool] + ) -> None: + __tracebackhide__ = True + lines2 = self._getlines(lines2) + for line in lines2: + for x in self.lines: + if line == x or match_func(x, line): + self._log("matched: ", repr(line)) + break + else: + msg = "line %r not found in output" % line + self._log(msg) + self._fail(msg) + + def get_lines_after(self, fnline: str) -> Sequence[str]: + """Return all lines following the given line in the text. + + The given line can contain glob wildcards. + """ + for i, line in enumerate(self.lines): + if fnline == line or fnmatch(line, fnline): + return self.lines[i + 1 :] + raise ValueError("line %r not found in output" % fnline) + + def _log(self, *args) -> None: + self._log_output.append(" ".join(str(x) for x in args)) + + @property + def _log_text(self) -> str: + return "\n".join(self._log_output) + + def fnmatch_lines( + self, lines2: Sequence[str], *, consecutive: bool = False + ) -> None: + """Check lines exist in the output (using :func:`python:fnmatch.fnmatch`). + + The argument is a list of lines which have to match and can use glob + wildcards. If they do not match a pytest.fail() is called. The + matches and non-matches are also shown as part of the error message. + + :param lines2: String patterns to match. + :param consecutive: Match lines consecutively? + """ + __tracebackhide__ = True + self._match_lines(lines2, fnmatch, "fnmatch", consecutive=consecutive) + + def re_match_lines( + self, lines2: Sequence[str], *, consecutive: bool = False + ) -> None: + """Check lines exist in the output (using :func:`python:re.match`). + + The argument is a list of lines which have to match using ``re.match``. + If they do not match a pytest.fail() is called. + + The matches and non-matches are also shown as part of the error message. + + :param lines2: string patterns to match. + :param consecutive: match lines consecutively? + """ + __tracebackhide__ = True + self._match_lines( + lines2, + lambda name, pat: bool(re.match(pat, name)), + "re.match", + consecutive=consecutive, + ) + + def _match_lines( + self, + lines2: Sequence[str], + match_func: Callable[[str, str], bool], + match_nickname: str, + *, + consecutive: bool = False, + ) -> None: + """Underlying implementation of ``fnmatch_lines`` and ``re_match_lines``. + + :param Sequence[str] lines2: + List of string patterns to match. The actual format depends on + ``match_func``. + :param match_func: + A callable ``match_func(line, pattern)`` where line is the + captured line from stdout/stderr and pattern is the matching + pattern. + :param str match_nickname: + The nickname for the match function that will be logged to stdout + when a match occurs. + :param consecutive: + Match lines consecutively? + """ + if not isinstance(lines2, collections.abc.Sequence): + raise TypeError("invalid type for lines2: {}".format(type(lines2).__name__)) + lines2 = self._getlines(lines2) + lines1 = self.lines[:] + extralines = [] + __tracebackhide__ = True + wnick = len(match_nickname) + 1 + started = False + for line in lines2: + nomatchprinted = False + while lines1: + nextline = lines1.pop(0) + if line == nextline: + self._log("exact match:", repr(line)) + started = True + break + elif match_func(nextline, line): + self._log("%s:" % match_nickname, repr(line)) + self._log( + "{:>{width}}".format("with:", width=wnick), repr(nextline) + ) + started = True + break + else: + if consecutive and started: + msg = f"no consecutive match: {line!r}" + self._log(msg) + self._log( + "{:>{width}}".format("with:", width=wnick), repr(nextline) + ) + self._fail(msg) + if not nomatchprinted: + self._log( + "{:>{width}}".format("nomatch:", width=wnick), repr(line) + ) + nomatchprinted = True + self._log("{:>{width}}".format("and:", width=wnick), repr(nextline)) + extralines.append(nextline) + else: + msg = f"remains unmatched: {line!r}" + self._log(msg) + self._fail(msg) + self._log_output = [] + + def no_fnmatch_line(self, pat: str) -> None: + """Ensure captured lines do not match the given pattern, using ``fnmatch.fnmatch``. + + :param str pat: The pattern to match lines. + """ + __tracebackhide__ = True + self._no_match_line(pat, fnmatch, "fnmatch") + + def no_re_match_line(self, pat: str) -> None: + """Ensure captured lines do not match the given pattern, using ``re.match``. + + :param str pat: The regular expression to match lines. + """ + __tracebackhide__ = True + self._no_match_line( + pat, lambda name, pat: bool(re.match(pat, name)), "re.match" + ) + + def _no_match_line( + self, pat: str, match_func: Callable[[str, str], bool], match_nickname: str + ) -> None: + """Ensure captured lines does not have a the given pattern, using ``fnmatch.fnmatch``. + + :param str pat: The pattern to match lines. + """ + __tracebackhide__ = True + nomatch_printed = False + wnick = len(match_nickname) + 1 + for line in self.lines: + if match_func(line, pat): + msg = f"{match_nickname}: {pat!r}" + self._log(msg) + self._log("{:>{width}}".format("with:", width=wnick), repr(line)) + self._fail(msg) + else: + if not nomatch_printed: + self._log("{:>{width}}".format("nomatch:", width=wnick), repr(pat)) + nomatch_printed = True + self._log("{:>{width}}".format("and:", width=wnick), repr(line)) + self._log_output = [] + + def _fail(self, msg: str) -> None: + __tracebackhide__ = True + log_text = self._log_text + self._log_output = [] + fail(log_text) + + def str(self) -> str: + """Return the entire original text.""" + return str(self) diff --git a/myenv/lib/python3.9/site-packages/_pytest/pytester_assertions.py b/myenv/lib/python3.9/site-packages/_pytest/pytester_assertions.py new file mode 100644 index 0000000..630c1d3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/pytester_assertions.py @@ -0,0 +1,66 @@ +"""Helper plugin for pytester; should not be loaded on its own.""" +# This plugin contains assertions used by pytester. pytester cannot +# contain them itself, since it is imported by the `pytest` module, +# hence cannot be subject to assertion rewriting, which requires a +# module to not be already imported. +from typing import Dict +from typing import Sequence +from typing import Tuple +from typing import Union + +from _pytest.reports import CollectReport +from _pytest.reports import TestReport + + +def assertoutcome( + outcomes: Tuple[ + Sequence[TestReport], + Sequence[Union[CollectReport, TestReport]], + Sequence[Union[CollectReport, TestReport]], + ], + passed: int = 0, + skipped: int = 0, + failed: int = 0, +) -> None: + __tracebackhide__ = True + + realpassed, realskipped, realfailed = outcomes + obtained = { + "passed": len(realpassed), + "skipped": len(realskipped), + "failed": len(realfailed), + } + expected = {"passed": passed, "skipped": skipped, "failed": failed} + assert obtained == expected, outcomes + + +def assert_outcomes( + outcomes: Dict[str, int], + passed: int = 0, + skipped: int = 0, + failed: int = 0, + errors: int = 0, + xpassed: int = 0, + xfailed: int = 0, +) -> None: + """Assert that the specified outcomes appear with the respective + numbers (0 means it didn't occur) in the text output from a test run.""" + __tracebackhide__ = True + + obtained = { + "passed": outcomes.get("passed", 0), + "skipped": outcomes.get("skipped", 0), + "failed": outcomes.get("failed", 0), + "errors": outcomes.get("errors", 0), + "xpassed": outcomes.get("xpassed", 0), + "xfailed": outcomes.get("xfailed", 0), + } + expected = { + "passed": passed, + "skipped": skipped, + "failed": failed, + "errors": errors, + "xpassed": xpassed, + "xfailed": xfailed, + } + assert obtained == expected diff --git a/myenv/lib/python3.9/site-packages/_pytest/python.py b/myenv/lib/python3.9/site-packages/_pytest/python.py new file mode 100644 index 0000000..e48e753 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/python.py @@ -0,0 +1,1689 @@ +"""Python test discovery, setup and run of test functions.""" +import enum +import fnmatch +import inspect +import itertools +import os +import sys +import types +import warnings +from collections import Counter +from collections import defaultdict +from functools import partial +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generator +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Mapping +from typing import Optional +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +import py + +import _pytest +from _pytest import fixtures +from _pytest import nodes +from _pytest._code import filter_traceback +from _pytest._code import getfslineno +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import TerminalRepr +from _pytest._io import TerminalWriter +from _pytest._io.saferepr import saferepr +from _pytest.compat import ascii_escaped +from _pytest.compat import final +from _pytest.compat import get_default_arg_names +from _pytest.compat import get_real_func +from _pytest.compat import getimfunc +from _pytest.compat import getlocation +from _pytest.compat import is_async_function +from _pytest.compat import is_generator +from _pytest.compat import NOTSET +from _pytest.compat import REGEX_TYPE +from _pytest.compat import safe_getattr +from _pytest.compat import safe_isclass +from _pytest.compat import STRING_TYPES +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH +from _pytest.fixtures import FuncFixtureInfo +from _pytest.main import Session +from _pytest.mark import MARK_GEN +from _pytest.mark import ParameterSet +from _pytest.mark.structures import get_unpacked_marks +from _pytest.mark.structures import Mark +from _pytest.mark.structures import MarkDecorator +from _pytest.mark.structures import normalize_mark_list +from _pytest.outcomes import fail +from _pytest.outcomes import skip +from _pytest.pathlib import import_path +from _pytest.pathlib import ImportPathMismatchError +from _pytest.pathlib import parts +from _pytest.pathlib import visit +from _pytest.warning_types import PytestCollectionWarning +from _pytest.warning_types import PytestUnhandledCoroutineWarning + +if TYPE_CHECKING: + from typing_extensions import Literal + from _pytest.fixtures import _Scope + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--fixtures", + "--funcargs", + action="store_true", + dest="showfixtures", + default=False, + help="show available fixtures, sorted by plugin appearance " + "(fixtures with leading '_' are only shown with '-v')", + ) + group.addoption( + "--fixtures-per-test", + action="store_true", + dest="show_fixtures_per_test", + default=False, + help="show fixtures per test", + ) + parser.addini( + "python_files", + type="args", + # NOTE: default is also used in AssertionRewritingHook. + default=["test_*.py", "*_test.py"], + help="glob-style file patterns for Python test module discovery", + ) + parser.addini( + "python_classes", + type="args", + default=["Test"], + help="prefixes or glob names for Python test class discovery", + ) + parser.addini( + "python_functions", + type="args", + default=["test"], + help="prefixes or glob names for Python test function and method discovery", + ) + parser.addini( + "disable_test_id_escaping_and_forfeit_all_rights_to_community_support", + type="bool", + default=False, + help="disable string escape non-ascii characters, might cause unwanted " + "side effects(use at your own risk)", + ) + + +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.showfixtures: + showfixtures(config) + return 0 + if config.option.show_fixtures_per_test: + show_fixtures_per_test(config) + return 0 + return None + + +def pytest_generate_tests(metafunc: "Metafunc") -> None: + for marker in metafunc.definition.iter_markers(name="parametrize"): + # TODO: Fix this type-ignore (overlapping kwargs). + metafunc.parametrize(*marker.args, **marker.kwargs, _param_mark=marker) # type: ignore[misc] + + +def pytest_configure(config: Config) -> None: + config.addinivalue_line( + "markers", + "parametrize(argnames, argvalues): call a test function multiple " + "times passing in different arguments in turn. argvalues generally " + "needs to be a list of values if argnames specifies only one name " + "or a list of tuples of values if argnames specifies multiple names. " + "Example: @parametrize('arg1', [1,2]) would lead to two calls of the " + "decorated test function, one with arg1=1 and another with arg1=2." + "see https://docs.pytest.org/en/stable/parametrize.html for more info " + "and examples.", + ) + config.addinivalue_line( + "markers", + "usefixtures(fixturename1, fixturename2, ...): mark tests as needing " + "all of the specified fixtures. see " + "https://docs.pytest.org/en/stable/fixture.html#usefixtures ", + ) + + +def async_warn_and_skip(nodeid: str) -> None: + msg = "async def functions are not natively supported and have been skipped.\n" + msg += ( + "You need to install a suitable plugin for your async framework, for example:\n" + ) + msg += " - anyio\n" + msg += " - pytest-asyncio\n" + msg += " - pytest-tornasync\n" + msg += " - pytest-trio\n" + msg += " - pytest-twisted" + warnings.warn(PytestUnhandledCoroutineWarning(msg.format(nodeid))) + skip(msg="async def function and no async plugin installed (see warnings)") + + +@hookimpl(trylast=True) +def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: + testfunction = pyfuncitem.obj + if is_async_function(testfunction): + async_warn_and_skip(pyfuncitem.nodeid) + funcargs = pyfuncitem.funcargs + testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} + result = testfunction(**testargs) + if hasattr(result, "__await__") or hasattr(result, "__aiter__"): + async_warn_and_skip(pyfuncitem.nodeid) + return True + + +def pytest_collect_file( + path: py.path.local, parent: nodes.Collector +) -> Optional["Module"]: + ext = path.ext + if ext == ".py": + if not parent.session.isinitpath(path): + if not path_matches_patterns( + path, parent.config.getini("python_files") + ["__init__.py"] + ): + return None + ihook = parent.session.gethookproxy(path) + module: Module = ihook.pytest_pycollect_makemodule(path=path, parent=parent) + return module + return None + + +def path_matches_patterns(path: py.path.local, patterns: Iterable[str]) -> bool: + """Return whether path matches any of the patterns in the list of globs given.""" + return any(path.fnmatch(pattern) for pattern in patterns) + + +def pytest_pycollect_makemodule(path: py.path.local, parent) -> "Module": + if path.basename == "__init__.py": + pkg: Package = Package.from_parent(parent, fspath=path) + return pkg + mod: Module = Module.from_parent(parent, fspath=path) + return mod + + +@hookimpl(trylast=True) +def pytest_pycollect_makeitem(collector: "PyCollector", name: str, obj: object): + # Nothing was collected elsewhere, let's do it here. + if safe_isclass(obj): + if collector.istestclass(obj, name): + return Class.from_parent(collector, name=name, obj=obj) + elif collector.istestfunction(obj, name): + # mock seems to store unbound methods (issue473), normalize it. + obj = getattr(obj, "__func__", obj) + # We need to try and unwrap the function if it's a functools.partial + # or a functools.wrapped. + # We mustn't if it's been wrapped with mock.patch (python 2 only). + if not (inspect.isfunction(obj) or inspect.isfunction(get_real_func(obj))): + filename, lineno = getfslineno(obj) + warnings.warn_explicit( + message=PytestCollectionWarning( + "cannot collect %r because it is not a function." % name + ), + category=None, + filename=str(filename), + lineno=lineno + 1, + ) + elif getattr(obj, "__test__", True): + if is_generator(obj): + res = Function.from_parent(collector, name=name) + reason = "yield tests were removed in pytest 4.0 - {name} will be ignored".format( + name=name + ) + res.add_marker(MARK_GEN.xfail(run=False, reason=reason)) + res.warn(PytestCollectionWarning(reason)) + else: + res = list(collector._genfunctions(name, obj)) + return res + + +class PyobjMixin: + _ALLOW_MARKERS = True + + # Function and attributes that the mixin needs (for type-checking only). + if TYPE_CHECKING: + name: str = "" + parent: Optional[nodes.Node] = None + own_markers: List[Mark] = [] + + def getparent(self, cls: Type[nodes._NodeType]) -> Optional[nodes._NodeType]: + ... + + def listchain(self) -> List[nodes.Node]: + ... + + @property + def module(self): + """Python module object this node was collected from (can be None).""" + node = self.getparent(Module) + return node.obj if node is not None else None + + @property + def cls(self): + """Python class object this node was collected from (can be None).""" + node = self.getparent(Class) + return node.obj if node is not None else None + + @property + def instance(self): + """Python instance object this node was collected from (can be None).""" + node = self.getparent(Instance) + return node.obj if node is not None else None + + @property + def obj(self): + """Underlying Python object.""" + obj = getattr(self, "_obj", None) + if obj is None: + self._obj = obj = self._getobj() + # XXX evil hack + # used to avoid Instance collector marker duplication + if self._ALLOW_MARKERS: + self.own_markers.extend(get_unpacked_marks(self.obj)) + return obj + + @obj.setter + def obj(self, value): + self._obj = value + + def _getobj(self): + """Get the underlying Python object. May be overwritten by subclasses.""" + # TODO: Improve the type of `parent` such that assert/ignore aren't needed. + assert self.parent is not None + obj = self.parent.obj # type: ignore[attr-defined] + return getattr(obj, self.name) + + def getmodpath(self, stopatmodule: bool = True, includemodule: bool = False) -> str: + """Return Python path relative to the containing module.""" + chain = self.listchain() + chain.reverse() + parts = [] + for node in chain: + if isinstance(node, Instance): + continue + name = node.name + if isinstance(node, Module): + name = os.path.splitext(name)[0] + if stopatmodule: + if includemodule: + parts.append(name) + break + parts.append(name) + parts.reverse() + return ".".join(parts) + + def reportinfo(self) -> Tuple[Union[py.path.local, str], int, str]: + # XXX caching? + obj = self.obj + compat_co_firstlineno = getattr(obj, "compat_co_firstlineno", None) + if isinstance(compat_co_firstlineno, int): + # nose compatibility + file_path = sys.modules[obj.__module__].__file__ + if file_path.endswith(".pyc"): + file_path = file_path[:-1] + fspath: Union[py.path.local, str] = file_path + lineno = compat_co_firstlineno + else: + fspath, lineno = getfslineno(obj) + modpath = self.getmodpath() + assert isinstance(lineno, int) + return fspath, lineno, modpath + + +# As an optimization, these builtin attribute names are pre-ignored when +# iterating over an object during collection -- the pytest_pycollect_makeitem +# hook is not called for them. +# fmt: off +class _EmptyClass: pass # noqa: E701 +IGNORED_ATTRIBUTES = frozenset.union( # noqa: E305 + frozenset(), + # Module. + dir(types.ModuleType("empty_module")), + # Some extra module attributes the above doesn't catch. + {"__builtins__", "__file__", "__cached__"}, + # Class. + dir(_EmptyClass), + # Instance. + dir(_EmptyClass()), +) +del _EmptyClass +# fmt: on + + +class PyCollector(PyobjMixin, nodes.Collector): + def funcnamefilter(self, name: str) -> bool: + return self._matches_prefix_or_glob_option("python_functions", name) + + def isnosetest(self, obj: object) -> bool: + """Look for the __test__ attribute, which is applied by the + @nose.tools.istest decorator. + """ + # We explicitly check for "is True" here to not mistakenly treat + # classes with a custom __getattr__ returning something truthy (like a + # function) as test classes. + return safe_getattr(obj, "__test__", False) is True + + def classnamefilter(self, name: str) -> bool: + return self._matches_prefix_or_glob_option("python_classes", name) + + def istestfunction(self, obj: object, name: str) -> bool: + if self.funcnamefilter(name) or self.isnosetest(obj): + if isinstance(obj, staticmethod): + # staticmethods need to be unwrapped. + obj = safe_getattr(obj, "__func__", False) + return ( + safe_getattr(obj, "__call__", False) + and fixtures.getfixturemarker(obj) is None + ) + else: + return False + + def istestclass(self, obj: object, name: str) -> bool: + return self.classnamefilter(name) or self.isnosetest(obj) + + def _matches_prefix_or_glob_option(self, option_name: str, name: str) -> bool: + """Check if the given name matches the prefix or glob-pattern defined + in ini configuration.""" + for option in self.config.getini(option_name): + if name.startswith(option): + return True + # Check that name looks like a glob-string before calling fnmatch + # because this is called for every name in each collected module, + # and fnmatch is somewhat expensive to call. + elif ("*" in option or "?" in option or "[" in option) and fnmatch.fnmatch( + name, option + ): + return True + return False + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + if not getattr(self.obj, "__test__", True): + return [] + + # NB. we avoid random getattrs and peek in the __dict__ instead + # (XXX originally introduced from a PyPy need, still true?) + dicts = [getattr(self.obj, "__dict__", {})] + for basecls in self.obj.__class__.__mro__: + dicts.append(basecls.__dict__) + seen: Set[str] = set() + values: List[Union[nodes.Item, nodes.Collector]] = [] + ihook = self.ihook + for dic in dicts: + # Note: seems like the dict can change during iteration - + # be careful not to remove the list() without consideration. + for name, obj in list(dic.items()): + if name in IGNORED_ATTRIBUTES: + continue + if name in seen: + continue + seen.add(name) + res = ihook.pytest_pycollect_makeitem( + collector=self, name=name, obj=obj + ) + if res is None: + continue + elif isinstance(res, list): + values.extend(res) + else: + values.append(res) + + def sort_key(item): + fspath, lineno, _ = item.reportinfo() + return (str(fspath), lineno) + + values.sort(key=sort_key) + return values + + def _genfunctions(self, name: str, funcobj) -> Iterator["Function"]: + modulecol = self.getparent(Module) + assert modulecol is not None + module = modulecol.obj + clscol = self.getparent(Class) + cls = clscol and clscol.obj or None + fm = self.session._fixturemanager + + definition = FunctionDefinition.from_parent(self, name=name, callobj=funcobj) + fixtureinfo = definition._fixtureinfo + + metafunc = Metafunc( + definition, fixtureinfo, self.config, cls=cls, module=module + ) + methods = [] + if hasattr(module, "pytest_generate_tests"): + methods.append(module.pytest_generate_tests) + if cls is not None and hasattr(cls, "pytest_generate_tests"): + methods.append(cls().pytest_generate_tests) + + self.ihook.pytest_generate_tests.call_extra(methods, dict(metafunc=metafunc)) + + if not metafunc._calls: + yield Function.from_parent(self, name=name, fixtureinfo=fixtureinfo) + else: + # Add funcargs() as fixturedefs to fixtureinfo.arg2fixturedefs. + fixtures.add_funcarg_pseudo_fixture_def(self, metafunc, fm) + + # Add_funcarg_pseudo_fixture_def may have shadowed some fixtures + # with direct parametrization, so make sure we update what the + # function really needs. + fixtureinfo.prune_dependency_tree() + + for callspec in metafunc._calls: + subname = f"{name}[{callspec.id}]" + yield Function.from_parent( + self, + name=subname, + callspec=callspec, + callobj=funcobj, + fixtureinfo=fixtureinfo, + keywords={callspec.id: True}, + originalname=name, + ) + + +class Module(nodes.File, PyCollector): + """Collector for test classes and functions.""" + + def _getobj(self): + return self._importtestmodule() + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + self._inject_setup_module_fixture() + self._inject_setup_function_fixture() + self.session._fixturemanager.parsefactories(self) + return super().collect() + + def _inject_setup_module_fixture(self) -> None: + """Inject a hidden autouse, module scoped fixture into the collected module object + that invokes setUpModule/tearDownModule if either or both are available. + + Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + setup_module = _get_first_non_fixture_func( + self.obj, ("setUpModule", "setup_module") + ) + teardown_module = _get_first_non_fixture_func( + self.obj, ("tearDownModule", "teardown_module") + ) + + if setup_module is None and teardown_module is None: + return + + @fixtures.fixture( + autouse=True, + scope="module", + # Use a unique name to speed up lookup. + name=f"xunit_setup_module_fixture_{self.obj.__name__}", + ) + def xunit_setup_module_fixture(request) -> Generator[None, None, None]: + if setup_module is not None: + _call_with_optional_argument(setup_module, request.module) + yield + if teardown_module is not None: + _call_with_optional_argument(teardown_module, request.module) + + self.obj.__pytest_setup_module = xunit_setup_module_fixture + + def _inject_setup_function_fixture(self) -> None: + """Inject a hidden autouse, function scoped fixture into the collected module object + that invokes setup_function/teardown_function if either or both are available. + + Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + setup_function = _get_first_non_fixture_func(self.obj, ("setup_function",)) + teardown_function = _get_first_non_fixture_func( + self.obj, ("teardown_function",) + ) + if setup_function is None and teardown_function is None: + return + + @fixtures.fixture( + autouse=True, + scope="function", + # Use a unique name to speed up lookup. + name=f"xunit_setup_function_fixture_{self.obj.__name__}", + ) + def xunit_setup_function_fixture(request) -> Generator[None, None, None]: + if request.instance is not None: + # in this case we are bound to an instance, so we need to let + # setup_method handle this + yield + return + if setup_function is not None: + _call_with_optional_argument(setup_function, request.function) + yield + if teardown_function is not None: + _call_with_optional_argument(teardown_function, request.function) + + self.obj.__pytest_setup_function = xunit_setup_function_fixture + + def _importtestmodule(self): + # We assume we are only called once per module. + importmode = self.config.getoption("--import-mode") + try: + mod = import_path(self.fspath, mode=importmode) + except SyntaxError as e: + raise self.CollectError( + ExceptionInfo.from_current().getrepr(style="short") + ) from e + except ImportPathMismatchError as e: + raise self.CollectError( + "import file mismatch:\n" + "imported module %r has this __file__ attribute:\n" + " %s\n" + "which is not the same as the test file we want to collect:\n" + " %s\n" + "HINT: remove __pycache__ / .pyc files and/or use a " + "unique basename for your test file modules" % e.args + ) from e + except ImportError as e: + exc_info = ExceptionInfo.from_current() + if self.config.getoption("verbose") < 2: + exc_info.traceback = exc_info.traceback.filter(filter_traceback) + exc_repr = ( + exc_info.getrepr(style="short") + if exc_info.traceback + else exc_info.exconly() + ) + formatted_tb = str(exc_repr) + raise self.CollectError( + "ImportError while importing test module '{fspath}'.\n" + "Hint: make sure your test modules/packages have valid Python names.\n" + "Traceback:\n" + "{traceback}".format(fspath=self.fspath, traceback=formatted_tb) + ) from e + except skip.Exception as e: + if e.allow_module_level: + raise + raise self.CollectError( + "Using pytest.skip outside of a test is not allowed. " + "To decorate a test function, use the @pytest.mark.skip " + "or @pytest.mark.skipif decorators instead, and to skip a " + "module use `pytestmark = pytest.mark.{skip,skipif}." + ) from e + self.config.pluginmanager.consider_module(mod) + return mod + + +class Package(Module): + def __init__( + self, + fspath: py.path.local, + parent: nodes.Collector, + # NOTE: following args are unused: + config=None, + session=None, + nodeid=None, + ) -> None: + # NOTE: Could be just the following, but kept as-is for compat. + # nodes.FSCollector.__init__(self, fspath, parent=parent) + session = parent.session + nodes.FSCollector.__init__( + self, fspath, parent=parent, config=config, session=session, nodeid=nodeid + ) + self.name = os.path.basename(str(fspath.dirname)) + + def setup(self) -> None: + # Not using fixtures to call setup_module here because autouse fixtures + # from packages are not called automatically (#4085). + setup_module = _get_first_non_fixture_func( + self.obj, ("setUpModule", "setup_module") + ) + if setup_module is not None: + _call_with_optional_argument(setup_module, self.obj) + + teardown_module = _get_first_non_fixture_func( + self.obj, ("tearDownModule", "teardown_module") + ) + if teardown_module is not None: + func = partial(_call_with_optional_argument, teardown_module, self.obj) + self.addfinalizer(func) + + def gethookproxy(self, fspath: py.path.local): + warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) + return self.session.gethookproxy(fspath) + + def isinitpath(self, path: py.path.local) -> bool: + warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) + return self.session.isinitpath(path) + + def _recurse(self, direntry: "os.DirEntry[str]") -> bool: + if direntry.name == "__pycache__": + return False + path = py.path.local(direntry.path) + ihook = self.session.gethookproxy(path.dirpath()) + if ihook.pytest_ignore_collect(path=path, config=self.config): + return False + norecursepatterns = self.config.getini("norecursedirs") + if any(path.check(fnmatch=pat) for pat in norecursepatterns): + return False + return True + + def _collectfile( + self, path: py.path.local, handle_dupes: bool = True + ) -> Sequence[nodes.Collector]: + assert ( + path.isfile() + ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( + path, path.isdir(), path.exists(), path.islink() + ) + ihook = self.session.gethookproxy(path) + if not self.session.isinitpath(path): + if ihook.pytest_ignore_collect(path=path, config=self.config): + return () + + if handle_dupes: + keepduplicates = self.config.getoption("keepduplicates") + if not keepduplicates: + duplicate_paths = self.config.pluginmanager._duplicatepaths + if path in duplicate_paths: + return () + else: + duplicate_paths.add(path) + + return ihook.pytest_collect_file(path=path, parent=self) # type: ignore[no-any-return] + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + this_path = self.fspath.dirpath() + init_module = this_path.join("__init__.py") + if init_module.check(file=1) and path_matches_patterns( + init_module, self.config.getini("python_files") + ): + yield Module.from_parent(self, fspath=init_module) + pkg_prefixes: Set[py.path.local] = set() + for direntry in visit(str(this_path), recurse=self._recurse): + path = py.path.local(direntry.path) + + # We will visit our own __init__.py file, in which case we skip it. + if direntry.is_file(): + if direntry.name == "__init__.py" and path.dirpath() == this_path: + continue + + parts_ = parts(direntry.path) + if any( + str(pkg_prefix) in parts_ and pkg_prefix.join("__init__.py") != path + for pkg_prefix in pkg_prefixes + ): + continue + + if direntry.is_file(): + yield from self._collectfile(path) + elif not direntry.is_dir(): + # Broken symlink or invalid/missing file. + continue + elif path.join("__init__.py").check(file=1): + pkg_prefixes.add(path) + + +def _call_with_optional_argument(func, arg) -> None: + """Call the given function with the given argument if func accepts one argument, otherwise + calls func without arguments.""" + arg_count = func.__code__.co_argcount + if inspect.ismethod(func): + arg_count -= 1 + if arg_count: + func(arg) + else: + func() + + +def _get_first_non_fixture_func(obj: object, names: Iterable[str]): + """Return the attribute from the given object to be used as a setup/teardown + xunit-style function, but only if not marked as a fixture to avoid calling it twice.""" + for name in names: + meth = getattr(obj, name, None) + if meth is not None and fixtures.getfixturemarker(meth) is None: + return meth + + +class Class(PyCollector): + """Collector for test methods.""" + + @classmethod + def from_parent(cls, parent, *, name, obj=None): + """The public constructor.""" + return super().from_parent(name=name, parent=parent) + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + if not safe_getattr(self.obj, "__test__", True): + return [] + if hasinit(self.obj): + assert self.parent is not None + self.warn( + PytestCollectionWarning( + "cannot collect test class %r because it has a " + "__init__ constructor (from: %s)" + % (self.obj.__name__, self.parent.nodeid) + ) + ) + return [] + elif hasnew(self.obj): + assert self.parent is not None + self.warn( + PytestCollectionWarning( + "cannot collect test class %r because it has a " + "__new__ constructor (from: %s)" + % (self.obj.__name__, self.parent.nodeid) + ) + ) + return [] + + self._inject_setup_class_fixture() + self._inject_setup_method_fixture() + + return [Instance.from_parent(self, name="()")] + + def _inject_setup_class_fixture(self) -> None: + """Inject a hidden autouse, class scoped fixture into the collected class object + that invokes setup_class/teardown_class if either or both are available. + + Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + setup_class = _get_first_non_fixture_func(self.obj, ("setup_class",)) + teardown_class = getattr(self.obj, "teardown_class", None) + if setup_class is None and teardown_class is None: + return + + @fixtures.fixture( + autouse=True, + scope="class", + # Use a unique name to speed up lookup. + name=f"xunit_setup_class_fixture_{self.obj.__qualname__}", + ) + def xunit_setup_class_fixture(cls) -> Generator[None, None, None]: + if setup_class is not None: + func = getimfunc(setup_class) + _call_with_optional_argument(func, self.obj) + yield + if teardown_class is not None: + func = getimfunc(teardown_class) + _call_with_optional_argument(func, self.obj) + + self.obj.__pytest_setup_class = xunit_setup_class_fixture + + def _inject_setup_method_fixture(self) -> None: + """Inject a hidden autouse, function scoped fixture into the collected class object + that invokes setup_method/teardown_method if either or both are available. + + Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + setup_method = _get_first_non_fixture_func(self.obj, ("setup_method",)) + teardown_method = getattr(self.obj, "teardown_method", None) + if setup_method is None and teardown_method is None: + return + + @fixtures.fixture( + autouse=True, + scope="function", + # Use a unique name to speed up lookup. + name=f"xunit_setup_method_fixture_{self.obj.__qualname__}", + ) + def xunit_setup_method_fixture(self, request) -> Generator[None, None, None]: + method = request.function + if setup_method is not None: + func = getattr(self, "setup_method") + _call_with_optional_argument(func, method) + yield + if teardown_method is not None: + func = getattr(self, "teardown_method") + _call_with_optional_argument(func, method) + + self.obj.__pytest_setup_method = xunit_setup_method_fixture + + +class Instance(PyCollector): + _ALLOW_MARKERS = False # hack, destroy later + # Instances share the object with their parents in a way + # that duplicates markers instances if not taken out + # can be removed at node structure reorganization time. + + def _getobj(self): + # TODO: Improve the type of `parent` such that assert/ignore aren't needed. + assert self.parent is not None + obj = self.parent.obj # type: ignore[attr-defined] + return obj() + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + self.session._fixturemanager.parsefactories(self) + return super().collect() + + def newinstance(self): + self.obj = self._getobj() + return self.obj + + +def hasinit(obj: object) -> bool: + init: object = getattr(obj, "__init__", None) + if init: + return init != object.__init__ + return False + + +def hasnew(obj: object) -> bool: + new: object = getattr(obj, "__new__", None) + if new: + return new != object.__new__ + return False + + +@final +class CallSpec2: + def __init__(self, metafunc: "Metafunc") -> None: + self.metafunc = metafunc + self.funcargs: Dict[str, object] = {} + self._idlist: List[str] = [] + self.params: Dict[str, object] = {} + # Used for sorting parametrized resources. + self._arg2scopenum: Dict[str, int] = {} + self.marks: List[Mark] = [] + self.indices: Dict[str, int] = {} + + def copy(self) -> "CallSpec2": + cs = CallSpec2(self.metafunc) + cs.funcargs.update(self.funcargs) + cs.params.update(self.params) + cs.marks.extend(self.marks) + cs.indices.update(self.indices) + cs._arg2scopenum.update(self._arg2scopenum) + cs._idlist = list(self._idlist) + return cs + + def _checkargnotcontained(self, arg: str) -> None: + if arg in self.params or arg in self.funcargs: + raise ValueError(f"duplicate {arg!r}") + + def getparam(self, name: str) -> object: + try: + return self.params[name] + except KeyError as e: + raise ValueError(name) from e + + @property + def id(self) -> str: + return "-".join(map(str, self._idlist)) + + def setmulti2( + self, + valtypes: Mapping[str, "Literal['params', 'funcargs']"], + argnames: Sequence[str], + valset: Iterable[object], + id: str, + marks: Iterable[Union[Mark, MarkDecorator]], + scopenum: int, + param_index: int, + ) -> None: + for arg, val in zip(argnames, valset): + self._checkargnotcontained(arg) + valtype_for_arg = valtypes[arg] + if valtype_for_arg == "params": + self.params[arg] = val + elif valtype_for_arg == "funcargs": + self.funcargs[arg] = val + else: # pragma: no cover + assert False, f"Unhandled valtype for arg: {valtype_for_arg}" + self.indices[arg] = param_index + self._arg2scopenum[arg] = scopenum + self._idlist.append(id) + self.marks.extend(normalize_mark_list(marks)) + + +@final +class Metafunc: + """Objects passed to the :func:`pytest_generate_tests <_pytest.hookspec.pytest_generate_tests>` hook. + + They help to inspect a test function and to generate tests according to + test configuration or values specified in the class or module where a + test function is defined. + """ + + def __init__( + self, + definition: "FunctionDefinition", + fixtureinfo: fixtures.FuncFixtureInfo, + config: Config, + cls=None, + module=None, + ) -> None: + #: Access to the underlying :class:`_pytest.python.FunctionDefinition`. + self.definition = definition + + #: Access to the :class:`_pytest.config.Config` object for the test session. + self.config = config + + #: The module object where the test function is defined in. + self.module = module + + #: Underlying Python test function. + self.function = definition.obj + + #: Set of fixture names required by the test function. + self.fixturenames = fixtureinfo.names_closure + + #: Class object where the test function is defined in or ``None``. + self.cls = cls + + self._calls: List[CallSpec2] = [] + self._arg2fixturedefs = fixtureinfo.name2fixturedefs + + def parametrize( + self, + argnames: Union[str, List[str], Tuple[str, ...]], + argvalues: Iterable[Union[ParameterSet, Sequence[object], object]], + indirect: Union[bool, Sequence[str]] = False, + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = None, + scope: "Optional[_Scope]" = None, + *, + _param_mark: Optional[Mark] = None, + ) -> None: + """Add new invocations to the underlying test function using the list + of argvalues for the given argnames. Parametrization is performed + during the collection phase. If you need to setup expensive resources + see about setting indirect to do it rather at test setup time. + + :param argnames: + A comma-separated string denoting one or more argument names, or + a list/tuple of argument strings. + + :param argvalues: + The list of argvalues determines how often a test is invoked with + different argument values. + + If only one argname was specified argvalues is a list of values. + If N argnames were specified, argvalues must be a list of + N-tuples, where each tuple-element specifies a value for its + respective argname. + + :param indirect: + A list of arguments' names (subset of argnames) or a boolean. + If True the list contains all names from the argnames. Each + argvalue corresponding to an argname in this list will + be passed as request.param to its respective argname fixture + function so that it can perform more expensive setups during the + setup phase of a test rather than at collection time. + + :param ids: + Sequence of (or generator for) ids for ``argvalues``, + or a callable to return part of the id for each argvalue. + + With sequences (and generators like ``itertools.count()``) the + returned ids should be of type ``string``, ``int``, ``float``, + ``bool``, or ``None``. + They are mapped to the corresponding index in ``argvalues``. + ``None`` means to use the auto-generated id. + + If it is a callable it will be called for each entry in + ``argvalues``, and the return value is used as part of the + auto-generated id for the whole set (where parts are joined with + dashes ("-")). + This is useful to provide more specific ids for certain items, e.g. + dates. Returning ``None`` will use an auto-generated id. + + If no ids are provided they will be generated automatically from + the argvalues. + + :param scope: + If specified it denotes the scope of the parameters. + The scope is used for grouping tests by parameter instances. + It will also override any fixture-function defined scope, allowing + to set a dynamic scope using test context or configuration. + """ + from _pytest.fixtures import scope2index + + argnames, parameters = ParameterSet._for_parametrize( + argnames, + argvalues, + self.function, + self.config, + nodeid=self.definition.nodeid, + ) + del argvalues + + if "request" in argnames: + fail( + "'request' is a reserved name and cannot be used in @pytest.mark.parametrize", + pytrace=False, + ) + + if scope is None: + scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect) + + self._validate_if_using_arg_names(argnames, indirect) + + arg_values_types = self._resolve_arg_value_types(argnames, indirect) + + # Use any already (possibly) generated ids with parametrize Marks. + if _param_mark and _param_mark._param_ids_from: + generated_ids = _param_mark._param_ids_from._param_ids_generated + if generated_ids is not None: + ids = generated_ids + + ids = self._resolve_arg_ids( + argnames, ids, parameters, nodeid=self.definition.nodeid + ) + + # Store used (possibly generated) ids with parametrize Marks. + if _param_mark and _param_mark._param_ids_from and generated_ids is None: + object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids) + + scopenum = scope2index( + scope, descr=f"parametrize() call in {self.function.__name__}" + ) + + # Create the new calls: if we are parametrize() multiple times (by applying the decorator + # more than once) then we accumulate those calls generating the cartesian product + # of all calls. + newcalls = [] + for callspec in self._calls or [CallSpec2(self)]: + for param_index, (param_id, param_set) in enumerate(zip(ids, parameters)): + newcallspec = callspec.copy() + newcallspec.setmulti2( + arg_values_types, + argnames, + param_set.values, + param_id, + param_set.marks, + scopenum, + param_index, + ) + newcalls.append(newcallspec) + self._calls = newcalls + + def _resolve_arg_ids( + self, + argnames: Sequence[str], + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ], + parameters: Sequence[ParameterSet], + nodeid: str, + ) -> List[str]: + """Resolve the actual ids for the given argnames, based on the ``ids`` parameter given + to ``parametrize``. + + :param List[str] argnames: List of argument names passed to ``parametrize()``. + :param ids: The ids parameter of the parametrized call (see docs). + :param List[ParameterSet] parameters: The list of parameter values, same size as ``argnames``. + :param str str: The nodeid of the item that generated this parametrized call. + :rtype: List[str] + :returns: The list of ids for each argname given. + """ + if ids is None: + idfn = None + ids_ = None + elif callable(ids): + idfn = ids + ids_ = None + else: + idfn = None + ids_ = self._validate_ids(ids, parameters, self.function.__name__) + return idmaker(argnames, parameters, idfn, ids_, self.config, nodeid=nodeid) + + def _validate_ids( + self, + ids: Iterable[Union[None, str, float, int, bool]], + parameters: Sequence[ParameterSet], + func_name: str, + ) -> List[Union[None, str]]: + try: + num_ids = len(ids) # type: ignore[arg-type] + except TypeError: + try: + iter(ids) + except TypeError as e: + raise TypeError("ids must be a callable or an iterable") from e + num_ids = len(parameters) + + # num_ids == 0 is a special case: https://github.com/pytest-dev/pytest/issues/1849 + if num_ids != len(parameters) and num_ids != 0: + msg = "In {}: {} parameter sets specified, with different number of ids: {}" + fail(msg.format(func_name, len(parameters), num_ids), pytrace=False) + + new_ids = [] + for idx, id_value in enumerate(itertools.islice(ids, num_ids)): + if id_value is None or isinstance(id_value, str): + new_ids.append(id_value) + elif isinstance(id_value, (float, int, bool)): + new_ids.append(str(id_value)) + else: + msg = ( # type: ignore[unreachable] + "In {}: ids must be list of string/float/int/bool, " + "found: {} (type: {!r}) at index {}" + ) + fail( + msg.format(func_name, saferepr(id_value), type(id_value), idx), + pytrace=False, + ) + return new_ids + + def _resolve_arg_value_types( + self, argnames: Sequence[str], indirect: Union[bool, Sequence[str]], + ) -> Dict[str, "Literal['params', 'funcargs']"]: + """Resolve if each parametrized argument must be considered a + parameter to a fixture or a "funcarg" to the function, based on the + ``indirect`` parameter of the parametrized() call. + + :param List[str] argnames: List of argument names passed to ``parametrize()``. + :param indirect: Same as the ``indirect`` parameter of ``parametrize()``. + :rtype: Dict[str, str] + A dict mapping each arg name to either: + * "params" if the argname should be the parameter of a fixture of the same name. + * "funcargs" if the argname should be a parameter to the parametrized test function. + """ + if isinstance(indirect, bool): + valtypes: Dict[str, Literal["params", "funcargs"]] = dict.fromkeys( + argnames, "params" if indirect else "funcargs" + ) + elif isinstance(indirect, Sequence): + valtypes = dict.fromkeys(argnames, "funcargs") + for arg in indirect: + if arg not in argnames: + fail( + "In {}: indirect fixture '{}' doesn't exist".format( + self.function.__name__, arg + ), + pytrace=False, + ) + valtypes[arg] = "params" + else: + fail( + "In {func}: expected Sequence or boolean for indirect, got {type}".format( + type=type(indirect).__name__, func=self.function.__name__ + ), + pytrace=False, + ) + return valtypes + + def _validate_if_using_arg_names( + self, argnames: Sequence[str], indirect: Union[bool, Sequence[str]], + ) -> None: + """Check if all argnames are being used, by default values, or directly/indirectly. + + :param List[str] argnames: List of argument names passed to ``parametrize()``. + :param indirect: Same as the ``indirect`` parameter of ``parametrize()``. + :raises ValueError: If validation fails. + """ + default_arg_names = set(get_default_arg_names(self.function)) + func_name = self.function.__name__ + for arg in argnames: + if arg not in self.fixturenames: + if arg in default_arg_names: + fail( + "In {}: function already takes an argument '{}' with a default value".format( + func_name, arg + ), + pytrace=False, + ) + else: + if isinstance(indirect, Sequence): + name = "fixture" if arg in indirect else "argument" + else: + name = "fixture" if indirect else "argument" + fail( + f"In {func_name}: function uses no {name} '{arg}'", + pytrace=False, + ) + + +def _find_parametrized_scope( + argnames: Sequence[str], + arg2fixturedefs: Mapping[str, Sequence[fixtures.FixtureDef[object]]], + indirect: Union[bool, Sequence[str]], +) -> "fixtures._Scope": + """Find the most appropriate scope for a parametrized call based on its arguments. + + When there's at least one direct argument, always use "function" scope. + + When a test function is parametrized and all its arguments are indirect + (e.g. fixtures), return the most narrow scope based on the fixtures used. + + Related to issue #1832, based on code posted by @Kingdread. + """ + if isinstance(indirect, Sequence): + all_arguments_are_fixtures = len(indirect) == len(argnames) + else: + all_arguments_are_fixtures = bool(indirect) + + if all_arguments_are_fixtures: + fixturedefs = arg2fixturedefs or {} + used_scopes = [ + fixturedef[0].scope + for name, fixturedef in fixturedefs.items() + if name in argnames + ] + if used_scopes: + # Takes the most narrow scope from used fixtures. + for scope in reversed(fixtures.scopes): + if scope in used_scopes: + return scope + + return "function" + + +def _ascii_escaped_by_config(val: Union[str, bytes], config: Optional[Config]) -> str: + if config is None: + escape_option = False + else: + escape_option = config.getini( + "disable_test_id_escaping_and_forfeit_all_rights_to_community_support" + ) + # TODO: If escaping is turned off and the user passes bytes, + # will return a bytes. For now we ignore this but the + # code *probably* doesn't handle this case. + return val if escape_option else ascii_escaped(val) # type: ignore + + +def _idval( + val: object, + argname: str, + idx: int, + idfn: Optional[Callable[[Any], Optional[object]]], + nodeid: Optional[str], + config: Optional[Config], +) -> str: + if idfn: + try: + generated_id = idfn(val) + if generated_id is not None: + val = generated_id + except Exception as e: + prefix = f"{nodeid}: " if nodeid is not None else "" + msg = "error raised while trying to determine id of parameter '{}' at position {}" + msg = prefix + msg.format(argname, idx) + raise ValueError(msg) from e + elif config: + hook_id: Optional[str] = config.hook.pytest_make_parametrize_id( + config=config, val=val, argname=argname + ) + if hook_id: + return hook_id + + if isinstance(val, STRING_TYPES): + return _ascii_escaped_by_config(val, config) + elif val is None or isinstance(val, (float, int, bool)): + return str(val) + elif isinstance(val, REGEX_TYPE): + return ascii_escaped(val.pattern) + elif val is NOTSET: + # Fallback to default. Note that NOTSET is an enum.Enum. + pass + elif isinstance(val, enum.Enum): + return str(val) + elif isinstance(getattr(val, "__name__", None), str): + # Name of a class, function, module, etc. + name: str = getattr(val, "__name__") + return name + return str(argname) + str(idx) + + +def _idvalset( + idx: int, + parameterset: ParameterSet, + argnames: Iterable[str], + idfn: Optional[Callable[[Any], Optional[object]]], + ids: Optional[List[Union[None, str]]], + nodeid: Optional[str], + config: Optional[Config], +) -> str: + if parameterset.id is not None: + return parameterset.id + id = None if ids is None or idx >= len(ids) else ids[idx] + if id is None: + this_id = [ + _idval(val, argname, idx, idfn, nodeid=nodeid, config=config) + for val, argname in zip(parameterset.values, argnames) + ] + return "-".join(this_id) + else: + return _ascii_escaped_by_config(id, config) + + +def idmaker( + argnames: Iterable[str], + parametersets: Iterable[ParameterSet], + idfn: Optional[Callable[[Any], Optional[object]]] = None, + ids: Optional[List[Union[None, str]]] = None, + config: Optional[Config] = None, + nodeid: Optional[str] = None, +) -> List[str]: + resolved_ids = [ + _idvalset( + valindex, parameterset, argnames, idfn, ids, config=config, nodeid=nodeid + ) + for valindex, parameterset in enumerate(parametersets) + ] + + # All IDs must be unique! + unique_ids = set(resolved_ids) + if len(unique_ids) != len(resolved_ids): + + # Record the number of occurrences of each test ID. + test_id_counts = Counter(resolved_ids) + + # Map the test ID to its next suffix. + test_id_suffixes: Dict[str, int] = defaultdict(int) + + # Suffix non-unique IDs to make them unique. + for index, test_id in enumerate(resolved_ids): + if test_id_counts[test_id] > 1: + resolved_ids[index] = "{}{}".format(test_id, test_id_suffixes[test_id]) + test_id_suffixes[test_id] += 1 + + return resolved_ids + + +def show_fixtures_per_test(config): + from _pytest.main import wrap_session + + return wrap_session(config, _show_fixtures_per_test) + + +def _show_fixtures_per_test(config: Config, session: Session) -> None: + import _pytest.config + + session.perform_collect() + curdir = py.path.local() + tw = _pytest.config.create_terminal_writer(config) + verbose = config.getvalue("verbose") + + def get_best_relpath(func): + loc = getlocation(func, str(curdir)) + return curdir.bestrelpath(py.path.local(loc)) + + def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None: + argname = fixture_def.argname + if verbose <= 0 and argname.startswith("_"): + return + if verbose > 0: + bestrel = get_best_relpath(fixture_def.func) + funcargspec = f"{argname} -- {bestrel}" + else: + funcargspec = argname + tw.line(funcargspec, green=True) + fixture_doc = inspect.getdoc(fixture_def.func) + if fixture_doc: + write_docstring(tw, fixture_doc) + else: + tw.line(" no docstring available", red=True) + + def write_item(item: nodes.Item) -> None: + # Not all items have _fixtureinfo attribute. + info: Optional[FuncFixtureInfo] = getattr(item, "_fixtureinfo", None) + if info is None or not info.name2fixturedefs: + # This test item does not use any fixtures. + return + tw.line() + tw.sep("-", f"fixtures used by {item.name}") + # TODO: Fix this type ignore. + tw.sep("-", "({})".format(get_best_relpath(item.function))) # type: ignore[attr-defined] + # dict key not used in loop but needed for sorting. + for _, fixturedefs in sorted(info.name2fixturedefs.items()): + assert fixturedefs is not None + if not fixturedefs: + continue + # Last item is expected to be the one used by the test item. + write_fixture(fixturedefs[-1]) + + for session_item in session.items: + write_item(session_item) + + +def showfixtures(config: Config) -> Union[int, ExitCode]: + from _pytest.main import wrap_session + + return wrap_session(config, _showfixtures_main) + + +def _showfixtures_main(config: Config, session: Session) -> None: + import _pytest.config + + session.perform_collect() + curdir = py.path.local() + tw = _pytest.config.create_terminal_writer(config) + verbose = config.getvalue("verbose") + + fm = session._fixturemanager + + available = [] + seen: Set[Tuple[str, str]] = set() + + for argname, fixturedefs in fm._arg2fixturedefs.items(): + assert fixturedefs is not None + if not fixturedefs: + continue + for fixturedef in fixturedefs: + loc = getlocation(fixturedef.func, str(curdir)) + if (fixturedef.argname, loc) in seen: + continue + seen.add((fixturedef.argname, loc)) + available.append( + ( + len(fixturedef.baseid), + fixturedef.func.__module__, + curdir.bestrelpath(py.path.local(loc)), + fixturedef.argname, + fixturedef, + ) + ) + + available.sort() + currentmodule = None + for baseid, module, bestrel, argname, fixturedef in available: + if currentmodule != module: + if not module.startswith("_pytest."): + tw.line() + tw.sep("-", f"fixtures defined from {module}") + currentmodule = module + if verbose <= 0 and argname[0] == "_": + continue + tw.write(argname, green=True) + if fixturedef.scope != "function": + tw.write(" [%s scope]" % fixturedef.scope, cyan=True) + if verbose > 0: + tw.write(" -- %s" % bestrel, yellow=True) + tw.write("\n") + loc = getlocation(fixturedef.func, str(curdir)) + doc = inspect.getdoc(fixturedef.func) + if doc: + write_docstring(tw, doc) + else: + tw.line(f" {loc}: no docstring available", red=True) + tw.line() + + +def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None: + for line in doc.split("\n"): + tw.line(indent + line) + + +class Function(PyobjMixin, nodes.Item): + """An Item responsible for setting up and executing a Python test function. + + param name: + The full function name, including any decorations like those + added by parametrization (``my_func[my_param]``). + param parent: + The parent Node. + param config: + The pytest Config object. + param callspec: + If given, this is function has been parametrized and the callspec contains + meta information about the parametrization. + param callobj: + If given, the object which will be called when the Function is invoked, + otherwise the callobj will be obtained from ``parent`` using ``originalname``. + param keywords: + Keywords bound to the function object for "-k" matching. + param session: + The pytest Session object. + param fixtureinfo: + Fixture information already resolved at this fixture node.. + param originalname: + The attribute name to use for accessing the underlying function object. + Defaults to ``name``. Set this if name is different from the original name, + for example when it contains decorations like those added by parametrization + (``my_func[my_param]``). + """ + + # Disable since functions handle it themselves. + _ALLOW_MARKERS = False + + def __init__( + self, + name: str, + parent, + config: Optional[Config] = None, + callspec: Optional[CallSpec2] = None, + callobj=NOTSET, + keywords=None, + session: Optional[Session] = None, + fixtureinfo: Optional[FuncFixtureInfo] = None, + originalname: Optional[str] = None, + ) -> None: + super().__init__(name, parent, config=config, session=session) + + if callobj is not NOTSET: + self.obj = callobj + + #: Original function name, without any decorations (for example + #: parametrization adds a ``"[...]"`` suffix to function names), used to access + #: the underlying function object from ``parent`` (in case ``callobj`` is not given + #: explicitly). + #: + #: .. versionadded:: 3.0 + self.originalname = originalname or name + + # Note: when FunctionDefinition is introduced, we should change ``originalname`` + # to a readonly property that returns FunctionDefinition.name. + + self.keywords.update(self.obj.__dict__) + self.own_markers.extend(get_unpacked_marks(self.obj)) + if callspec: + self.callspec = callspec + # this is total hostile and a mess + # keywords are broken by design by now + # this will be redeemed later + for mark in callspec.marks: + # feel free to cry, this was broken for years before + # and keywords cant fix it per design + self.keywords[mark.name] = mark + self.own_markers.extend(normalize_mark_list(callspec.marks)) + if keywords: + self.keywords.update(keywords) + + # todo: this is a hell of a hack + # https://github.com/pytest-dev/pytest/issues/4569 + + self.keywords.update( + { + mark.name: True + for mark in self.iter_markers() + if mark.name not in self.keywords + } + ) + + if fixtureinfo is None: + fixtureinfo = self.session._fixturemanager.getfixtureinfo( + self, self.obj, self.cls, funcargs=True + ) + self._fixtureinfo: FuncFixtureInfo = fixtureinfo + self.fixturenames = fixtureinfo.names_closure + self._initrequest() + + @classmethod + def from_parent(cls, parent, **kw): # todo: determine sound type limitations + """The public constructor.""" + return super().from_parent(parent=parent, **kw) + + def _initrequest(self) -> None: + self.funcargs: Dict[str, object] = {} + self._request = fixtures.FixtureRequest(self, _ispytest=True) + + @property + def function(self): + """Underlying python 'function' object.""" + return getimfunc(self.obj) + + def _getobj(self): + assert self.parent is not None + return getattr(self.parent.obj, self.originalname) # type: ignore[attr-defined] + + @property + def _pyfuncitem(self): + """(compatonly) for code expecting pytest-2.2 style request objects.""" + return self + + def runtest(self) -> None: + """Execute the underlying test function.""" + self.ihook.pytest_pyfunc_call(pyfuncitem=self) + + def setup(self) -> None: + if isinstance(self.parent, Instance): + self.parent.newinstance() + self.obj = self._getobj() + self._request._fillfixtures() + + def _prunetraceback(self, excinfo: ExceptionInfo[BaseException]) -> None: + if hasattr(self, "_obj") and not self.config.getoption("fulltrace", False): + code = _pytest._code.Code.from_function(get_real_func(self.obj)) + path, firstlineno = code.path, code.firstlineno + traceback = excinfo.traceback + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + if ntraceback == traceback: + ntraceback = ntraceback.filter(filter_traceback) + if not ntraceback: + ntraceback = traceback + + excinfo.traceback = ntraceback.filter() + # issue364: mark all but first and last frames to + # only show a single-line message for each frame. + if self.config.getoption("tbstyle", "auto") == "auto": + if len(excinfo.traceback) > 2: + for entry in excinfo.traceback[1:-1]: + entry.set_repr_style("short") + + # TODO: Type ignored -- breaks Liskov Substitution. + def repr_failure( # type: ignore[override] + self, excinfo: ExceptionInfo[BaseException], + ) -> Union[str, TerminalRepr]: + style = self.config.getoption("tbstyle", "auto") + if style == "auto": + style = "long" + return self._repr_failure_py(excinfo, style=style) + + +class FunctionDefinition(Function): + """ + This class is a step gap solution until we evolve to have actual function definition nodes + and manage to get rid of ``metafunc``. + """ + + def runtest(self) -> None: + raise RuntimeError("function definitions are not supposed to be run as tests") + + setup = runtest diff --git a/myenv/lib/python3.9/site-packages/_pytest/python_api.py b/myenv/lib/python3.9/site-packages/_pytest/python_api.py new file mode 100644 index 0000000..81ce4f8 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/python_api.py @@ -0,0 +1,786 @@ +import math +import pprint +from collections.abc import Iterable +from collections.abc import Mapping +from collections.abc import Sized +from decimal import Decimal +from numbers import Complex +from types import TracebackType +from typing import Any +from typing import Callable +from typing import cast +from typing import Generic +from typing import Optional +from typing import overload +from typing import Pattern +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +if TYPE_CHECKING: + from numpy import ndarray + + +import _pytest._code +from _pytest.compat import final +from _pytest.compat import STRING_TYPES +from _pytest.outcomes import fail + + +def _non_numeric_type_error(value, at: Optional[str]) -> TypeError: + at_str = f" at {at}" if at else "" + return TypeError( + "cannot make approximate comparisons to non-numeric values: {!r} {}".format( + value, at_str + ) + ) + + +# builtin pytest.approx helper + + +class ApproxBase: + """Provide shared utilities for making approximate comparisons between + numbers or sequences of numbers.""" + + # Tell numpy to use our `__eq__` operator instead of its. + __array_ufunc__ = None + __array_priority__ = 100 + + def __init__(self, expected, rel=None, abs=None, nan_ok: bool = False) -> None: + __tracebackhide__ = True + self.expected = expected + self.abs = abs + self.rel = rel + self.nan_ok = nan_ok + self._check_type() + + def __repr__(self) -> str: + raise NotImplementedError + + def __eq__(self, actual) -> bool: + return all( + a == self._approx_scalar(x) for a, x in self._yield_comparisons(actual) + ) + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + def __ne__(self, actual) -> bool: + return not (actual == self) + + def _approx_scalar(self, x) -> "ApproxScalar": + return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) + + def _yield_comparisons(self, actual): + """Yield all the pairs of numbers to be compared. + + This is used to implement the `__eq__` method. + """ + raise NotImplementedError + + def _check_type(self) -> None: + """Raise a TypeError if the expected value is not a valid type.""" + # This is only a concern if the expected value is a sequence. In every + # other case, the approx() function ensures that the expected value has + # a numeric type. For this reason, the default is to do nothing. The + # classes that deal with sequences should reimplement this method to + # raise if there are any non-numeric elements in the sequence. + pass + + +def _recursive_list_map(f, x): + if isinstance(x, list): + return list(_recursive_list_map(f, xi) for xi in x) + else: + return f(x) + + +class ApproxNumpy(ApproxBase): + """Perform approximate comparisons where the expected value is numpy array.""" + + def __repr__(self) -> str: + list_scalars = _recursive_list_map(self._approx_scalar, self.expected.tolist()) + return f"approx({list_scalars!r})" + + def __eq__(self, actual) -> bool: + import numpy as np + + # self.expected is supposed to always be an array here. + + if not np.isscalar(actual): + try: + actual = np.asarray(actual) + except Exception as e: + raise TypeError(f"cannot compare '{actual}' to numpy.ndarray") from e + + if not np.isscalar(actual) and actual.shape != self.expected.shape: + return False + + return ApproxBase.__eq__(self, actual) + + def _yield_comparisons(self, actual): + import numpy as np + + # `actual` can either be a numpy array or a scalar, it is treated in + # `__eq__` before being passed to `ApproxBase.__eq__`, which is the + # only method that calls this one. + + if np.isscalar(actual): + for i in np.ndindex(self.expected.shape): + yield actual, self.expected[i].item() + else: + for i in np.ndindex(self.expected.shape): + yield actual[i].item(), self.expected[i].item() + + +class ApproxMapping(ApproxBase): + """Perform approximate comparisons where the expected value is a mapping + with numeric values (the keys can be anything).""" + + def __repr__(self) -> str: + return "approx({!r})".format( + {k: self._approx_scalar(v) for k, v in self.expected.items()} + ) + + def __eq__(self, actual) -> bool: + try: + if set(actual.keys()) != set(self.expected.keys()): + return False + except AttributeError: + return False + + return ApproxBase.__eq__(self, actual) + + def _yield_comparisons(self, actual): + for k in self.expected.keys(): + yield actual[k], self.expected[k] + + def _check_type(self) -> None: + __tracebackhide__ = True + for key, value in self.expected.items(): + if isinstance(value, type(self.expected)): + msg = "pytest.approx() does not support nested dictionaries: key={!r} value={!r}\n full mapping={}" + raise TypeError(msg.format(key, value, pprint.pformat(self.expected))) + + +class ApproxSequencelike(ApproxBase): + """Perform approximate comparisons where the expected value is a sequence of numbers.""" + + def __repr__(self) -> str: + seq_type = type(self.expected) + if seq_type not in (tuple, list, set): + seq_type = list + return "approx({!r})".format( + seq_type(self._approx_scalar(x) for x in self.expected) + ) + + def __eq__(self, actual) -> bool: + try: + if len(actual) != len(self.expected): + return False + except TypeError: + return False + return ApproxBase.__eq__(self, actual) + + def _yield_comparisons(self, actual): + return zip(actual, self.expected) + + def _check_type(self) -> None: + __tracebackhide__ = True + for index, x in enumerate(self.expected): + if isinstance(x, type(self.expected)): + msg = "pytest.approx() does not support nested data structures: {!r} at index {}\n full sequence: {}" + raise TypeError(msg.format(x, index, pprint.pformat(self.expected))) + + +class ApproxScalar(ApproxBase): + """Perform approximate comparisons where the expected value is a single number.""" + + # Using Real should be better than this Union, but not possible yet: + # https://github.com/python/typeshed/pull/3108 + DEFAULT_ABSOLUTE_TOLERANCE: Union[float, Decimal] = 1e-12 + DEFAULT_RELATIVE_TOLERANCE: Union[float, Decimal] = 1e-6 + + def __repr__(self) -> str: + """Return a string communicating both the expected value and the + tolerance for the comparison being made. + + For example, ``1.0 ± 1e-6``, ``(3+4j) ± 5e-6 ∠ ±180°``. + """ + + # Don't show a tolerance for values that aren't compared using + # tolerances, i.e. non-numerics and infinities. Need to call abs to + # handle complex numbers, e.g. (inf + 1j). + if (not isinstance(self.expected, (Complex, Decimal))) or math.isinf( + abs(self.expected) # type: ignore[arg-type] + ): + return str(self.expected) + + # If a sensible tolerance can't be calculated, self.tolerance will + # raise a ValueError. In this case, display '???'. + try: + vetted_tolerance = f"{self.tolerance:.1e}" + if ( + isinstance(self.expected, Complex) + and self.expected.imag + and not math.isinf(self.tolerance) + ): + vetted_tolerance += " ∠ ±180°" + except ValueError: + vetted_tolerance = "???" + + return f"{self.expected} ± {vetted_tolerance}" + + def __eq__(self, actual) -> bool: + """Return whether the given value is equal to the expected value + within the pre-specified tolerance.""" + asarray = _as_numpy_array(actual) + if asarray is not None: + # Call ``__eq__()`` manually to prevent infinite-recursion with + # numpy<1.13. See #3748. + return all(self.__eq__(a) for a in asarray.flat) + + # Short-circuit exact equality. + if actual == self.expected: + return True + + # If either type is non-numeric, fall back to strict equality. + # NB: we need Complex, rather than just Number, to ensure that __abs__, + # __sub__, and __float__ are defined. + if not ( + isinstance(self.expected, (Complex, Decimal)) + and isinstance(actual, (Complex, Decimal)) + ): + return False + + # Allow the user to control whether NaNs are considered equal to each + # other or not. The abs() calls are for compatibility with complex + # numbers. + if math.isnan(abs(self.expected)): # type: ignore[arg-type] + return self.nan_ok and math.isnan(abs(actual)) # type: ignore[arg-type] + + # Infinity shouldn't be approximately equal to anything but itself, but + # if there's a relative tolerance, it will be infinite and infinity + # will seem approximately equal to everything. The equal-to-itself + # case would have been short circuited above, so here we can just + # return false if the expected value is infinite. The abs() call is + # for compatibility with complex numbers. + if math.isinf(abs(self.expected)): # type: ignore[arg-type] + return False + + # Return true if the two numbers are within the tolerance. + result: bool = abs(self.expected - actual) <= self.tolerance + return result + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + @property + def tolerance(self): + """Return the tolerance for the comparison. + + This could be either an absolute tolerance or a relative tolerance, + depending on what the user specified or which would be larger. + """ + + def set_default(x, default): + return x if x is not None else default + + # Figure out what the absolute tolerance should be. ``self.abs`` is + # either None or a value specified by the user. + absolute_tolerance = set_default(self.abs, self.DEFAULT_ABSOLUTE_TOLERANCE) + + if absolute_tolerance < 0: + raise ValueError( + f"absolute tolerance can't be negative: {absolute_tolerance}" + ) + if math.isnan(absolute_tolerance): + raise ValueError("absolute tolerance can't be NaN.") + + # If the user specified an absolute tolerance but not a relative one, + # just return the absolute tolerance. + if self.rel is None: + if self.abs is not None: + return absolute_tolerance + + # Figure out what the relative tolerance should be. ``self.rel`` is + # either None or a value specified by the user. This is done after + # we've made sure the user didn't ask for an absolute tolerance only, + # because we don't want to raise errors about the relative tolerance if + # we aren't even going to use it. + relative_tolerance = set_default( + self.rel, self.DEFAULT_RELATIVE_TOLERANCE + ) * abs(self.expected) + + if relative_tolerance < 0: + raise ValueError( + f"relative tolerance can't be negative: {absolute_tolerance}" + ) + if math.isnan(relative_tolerance): + raise ValueError("relative tolerance can't be NaN.") + + # Return the larger of the relative and absolute tolerances. + return max(relative_tolerance, absolute_tolerance) + + +class ApproxDecimal(ApproxScalar): + """Perform approximate comparisons where the expected value is a Decimal.""" + + DEFAULT_ABSOLUTE_TOLERANCE = Decimal("1e-12") + DEFAULT_RELATIVE_TOLERANCE = Decimal("1e-6") + + +def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase: + """Assert that two numbers (or two sets of numbers) are equal to each other + within some tolerance. + + Due to the `intricacies of floating-point arithmetic`__, numbers that we + would intuitively expect to be equal are not always so:: + + >>> 0.1 + 0.2 == 0.3 + False + + __ https://docs.python.org/3/tutorial/floatingpoint.html + + This problem is commonly encountered when writing tests, e.g. when making + sure that floating-point values are what you expect them to be. One way to + deal with this problem is to assert that two floating-point numbers are + equal to within some appropriate tolerance:: + + >>> abs((0.1 + 0.2) - 0.3) < 1e-6 + True + + However, comparisons like this are tedious to write and difficult to + understand. Furthermore, absolute comparisons like the one above are + usually discouraged because there's no tolerance that works well for all + situations. ``1e-6`` is good for numbers around ``1``, but too small for + very big numbers and too big for very small ones. It's better to express + the tolerance as a fraction of the expected value, but relative comparisons + like that are even more difficult to write correctly and concisely. + + The ``approx`` class performs floating-point comparisons using a syntax + that's as intuitive as possible:: + + >>> from pytest import approx + >>> 0.1 + 0.2 == approx(0.3) + True + + The same syntax also works for sequences of numbers:: + + >>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6)) + True + + Dictionary *values*:: + + >>> {'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6}) + True + + ``numpy`` arrays:: + + >>> import numpy as np # doctest: +SKIP + >>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6])) # doctest: +SKIP + True + + And for a ``numpy`` array against a scalar:: + + >>> import numpy as np # doctest: +SKIP + >>> np.array([0.1, 0.2]) + np.array([0.2, 0.1]) == approx(0.3) # doctest: +SKIP + True + + By default, ``approx`` considers numbers within a relative tolerance of + ``1e-6`` (i.e. one part in a million) of its expected value to be equal. + This treatment would lead to surprising results if the expected value was + ``0.0``, because nothing but ``0.0`` itself is relatively close to ``0.0``. + To handle this case less surprisingly, ``approx`` also considers numbers + within an absolute tolerance of ``1e-12`` of its expected value to be + equal. Infinity and NaN are special cases. Infinity is only considered + equal to itself, regardless of the relative tolerance. NaN is not + considered equal to anything by default, but you can make it be equal to + itself by setting the ``nan_ok`` argument to True. (This is meant to + facilitate comparing arrays that use NaN to mean "no data".) + + Both the relative and absolute tolerances can be changed by passing + arguments to the ``approx`` constructor:: + + >>> 1.0001 == approx(1) + False + >>> 1.0001 == approx(1, rel=1e-3) + True + >>> 1.0001 == approx(1, abs=1e-3) + True + + If you specify ``abs`` but not ``rel``, the comparison will not consider + the relative tolerance at all. In other words, two numbers that are within + the default relative tolerance of ``1e-6`` will still be considered unequal + if they exceed the specified absolute tolerance. If you specify both + ``abs`` and ``rel``, the numbers will be considered equal if either + tolerance is met:: + + >>> 1 + 1e-8 == approx(1) + True + >>> 1 + 1e-8 == approx(1, abs=1e-12) + False + >>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12) + True + + You can also use ``approx`` to compare nonnumeric types, or dicts and + sequences containing nonnumeric types, in which case it falls back to + strict equality. This can be useful for comparing dicts and sequences that + can contain optional values:: + + >>> {"required": 1.0000005, "optional": None} == approx({"required": 1, "optional": None}) + True + >>> [None, 1.0000005] == approx([None,1]) + True + >>> ["foo", 1.0000005] == approx([None,1]) + False + + If you're thinking about using ``approx``, then you might want to know how + it compares to other good ways of comparing floating-point numbers. All of + these algorithms are based on relative and absolute tolerances and should + agree for the most part, but they do have meaningful differences: + + - ``math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)``: True if the relative + tolerance is met w.r.t. either ``a`` or ``b`` or if the absolute + tolerance is met. Because the relative tolerance is calculated w.r.t. + both ``a`` and ``b``, this test is symmetric (i.e. neither ``a`` nor + ``b`` is a "reference value"). You have to specify an absolute tolerance + if you want to compare to ``0.0`` because there is no tolerance by + default. `More information...`__ + + __ https://docs.python.org/3/library/math.html#math.isclose + + - ``numpy.isclose(a, b, rtol=1e-5, atol=1e-8)``: True if the difference + between ``a`` and ``b`` is less that the sum of the relative tolerance + w.r.t. ``b`` and the absolute tolerance. Because the relative tolerance + is only calculated w.r.t. ``b``, this test is asymmetric and you can + think of ``b`` as the reference value. Support for comparing sequences + is provided by ``numpy.allclose``. `More information...`__ + + __ https://numpy.org/doc/stable/reference/generated/numpy.isclose.html + + - ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b`` + are within an absolute tolerance of ``1e-7``. No relative tolerance is + considered and the absolute tolerance cannot be changed, so this function + is not appropriate for very large or very small numbers. Also, it's only + available in subclasses of ``unittest.TestCase`` and it's ugly because it + doesn't follow PEP8. `More information...`__ + + __ https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertAlmostEqual + + - ``a == pytest.approx(b, rel=1e-6, abs=1e-12)``: True if the relative + tolerance is met w.r.t. ``b`` or if the absolute tolerance is met. + Because the relative tolerance is only calculated w.r.t. ``b``, this test + is asymmetric and you can think of ``b`` as the reference value. In the + special case that you explicitly specify an absolute tolerance but not a + relative tolerance, only the absolute tolerance is considered. + + .. warning:: + + .. versionchanged:: 3.2 + + In order to avoid inconsistent behavior, ``TypeError`` is + raised for ``>``, ``>=``, ``<`` and ``<=`` comparisons. + The example below illustrates the problem:: + + assert approx(0.1) > 0.1 + 1e-10 # calls approx(0.1).__gt__(0.1 + 1e-10) + assert 0.1 + 1e-10 > approx(0.1) # calls approx(0.1).__lt__(0.1 + 1e-10) + + In the second example one expects ``approx(0.1).__le__(0.1 + 1e-10)`` + to be called. But instead, ``approx(0.1).__lt__(0.1 + 1e-10)`` is used to + comparison. This is because the call hierarchy of rich comparisons + follows a fixed behavior. `More information...`__ + + __ https://docs.python.org/3/reference/datamodel.html#object.__ge__ + + .. versionchanged:: 3.7.1 + ``approx`` raises ``TypeError`` when it encounters a dict value or + sequence element of nonnumeric type. + + .. versionchanged:: 6.1.0 + ``approx`` falls back to strict equality for nonnumeric types instead + of raising ``TypeError``. + """ + + # Delegate the comparison to a class that knows how to deal with the type + # of the expected value (e.g. int, float, list, dict, numpy.array, etc). + # + # The primary responsibility of these classes is to implement ``__eq__()`` + # and ``__repr__()``. The former is used to actually check if some + # "actual" value is equivalent to the given expected value within the + # allowed tolerance. The latter is used to show the user the expected + # value and tolerance, in the case that a test failed. + # + # The actual logic for making approximate comparisons can be found in + # ApproxScalar, which is used to compare individual numbers. All of the + # other Approx classes eventually delegate to this class. The ApproxBase + # class provides some convenient methods and overloads, but isn't really + # essential. + + __tracebackhide__ = True + + if isinstance(expected, Decimal): + cls: Type[ApproxBase] = ApproxDecimal + elif isinstance(expected, Mapping): + cls = ApproxMapping + elif _is_numpy_array(expected): + expected = _as_numpy_array(expected) + cls = ApproxNumpy + elif ( + isinstance(expected, Iterable) + and isinstance(expected, Sized) + # Type ignored because the error is wrong -- not unreachable. + and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable] + ): + cls = ApproxSequencelike + else: + cls = ApproxScalar + + return cls(expected, rel, abs, nan_ok) + + +def _is_numpy_array(obj: object) -> bool: + """ + Return true if the given object is implicitly convertible to ndarray, + and numpy is already imported. + """ + return _as_numpy_array(obj) is not None + + +def _as_numpy_array(obj: object) -> Optional["ndarray"]: + """ + Return an ndarray if the given object is implicitly convertible to ndarray, + and numpy is already imported, otherwise None. + """ + import sys + + np: Any = sys.modules.get("numpy") + if np is not None: + # avoid infinite recursion on numpy scalars, which have __array__ + if np.isscalar(obj): + return None + elif isinstance(obj, np.ndarray): + return obj + elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"): + return np.asarray(obj) + return None + + +# builtin pytest.raises helper + +_E = TypeVar("_E", bound=BaseException) + + +@overload +def raises( + expected_exception: Union[Type[_E], Tuple[Type[_E], ...]], + *, + match: Optional[Union[str, Pattern[str]]] = ..., +) -> "RaisesContext[_E]": + ... + + +@overload +def raises( + expected_exception: Union[Type[_E], Tuple[Type[_E], ...]], + func: Callable[..., Any], + *args: Any, + **kwargs: Any, +) -> _pytest._code.ExceptionInfo[_E]: + ... + + +def raises( + expected_exception: Union[Type[_E], Tuple[Type[_E], ...]], *args: Any, **kwargs: Any +) -> Union["RaisesContext[_E]", _pytest._code.ExceptionInfo[_E]]: + r"""Assert that a code block/function call raises ``expected_exception`` + or raise a failure exception otherwise. + + :kwparam match: + If specified, a string containing a regular expression, + or a regular expression object, that is tested against the string + representation of the exception using ``re.search``. To match a literal + string that may contain `special characters`__, the pattern can + first be escaped with ``re.escape``. + + (This is only used when ``pytest.raises`` is used as a context manager, + and passed through to the function otherwise. + When using ``pytest.raises`` as a function, you can use: + ``pytest.raises(Exc, func, match="passed on").match("my pattern")``.) + + __ https://docs.python.org/3/library/re.html#regular-expression-syntax + + .. currentmodule:: _pytest._code + + Use ``pytest.raises`` as a context manager, which will capture the exception of the given + type:: + + >>> import pytest + >>> with pytest.raises(ZeroDivisionError): + ... 1/0 + + If the code block does not raise the expected exception (``ZeroDivisionError`` in the example + above), or no exception at all, the check will fail instead. + + You can also use the keyword argument ``match`` to assert that the + exception matches a text or regex:: + + >>> with pytest.raises(ValueError, match='must be 0 or None'): + ... raise ValueError("value must be 0 or None") + + >>> with pytest.raises(ValueError, match=r'must be \d+$'): + ... raise ValueError("value must be 42") + + The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the + details of the captured exception:: + + >>> with pytest.raises(ValueError) as exc_info: + ... raise ValueError("value must be 42") + >>> assert exc_info.type is ValueError + >>> assert exc_info.value.args[0] == "value must be 42" + + .. note:: + + When using ``pytest.raises`` as a context manager, it's worthwhile to + note that normal context manager rules apply and that the exception + raised *must* be the final line in the scope of the context manager. + Lines of code after that, within the scope of the context manager will + not be executed. For example:: + + >>> value = 15 + >>> with pytest.raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... assert exc_info.type is ValueError # this will not execute + + Instead, the following approach must be taken (note the difference in + scope):: + + >>> with pytest.raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... + >>> assert exc_info.type is ValueError + + **Using with** ``pytest.mark.parametrize`` + + When using :ref:`pytest.mark.parametrize ref` + it is possible to parametrize tests such that + some runs raise an exception and others do not. + + See :ref:`parametrizing_conditional_raising` for an example. + + **Legacy form** + + It is possible to specify a callable by passing a to-be-called lambda:: + + >>> raises(ZeroDivisionError, lambda: 1/0) + + + or you can specify an arbitrary callable with arguments:: + + >>> def f(x): return 1/x + ... + >>> raises(ZeroDivisionError, f, 0) + + >>> raises(ZeroDivisionError, f, x=0) + + + The form above is fully supported but discouraged for new code because the + context manager form is regarded as more readable and less error-prone. + + .. note:: + Similar to caught exception objects in Python, explicitly clearing + local references to returned ``ExceptionInfo`` objects can + help the Python interpreter speed up its garbage collection. + + Clearing those references breaks a reference cycle + (``ExceptionInfo`` --> caught exception --> frame stack raising + the exception --> current frame stack --> local variables --> + ``ExceptionInfo``) which makes Python keep all objects referenced + from that cycle (including all local variables in the current + frame) alive until the next cyclic garbage collection run. + More detailed information can be found in the official Python + documentation for :ref:`the try statement `. + """ + __tracebackhide__ = True + + if isinstance(expected_exception, type): + excepted_exceptions: Tuple[Type[_E], ...] = (expected_exception,) + else: + excepted_exceptions = expected_exception + for exc in excepted_exceptions: + if not isinstance(exc, type) or not issubclass(exc, BaseException): # type: ignore[unreachable] + msg = "expected exception must be a BaseException type, not {}" # type: ignore[unreachable] + not_a = exc.__name__ if isinstance(exc, type) else type(exc).__name__ + raise TypeError(msg.format(not_a)) + + message = f"DID NOT RAISE {expected_exception}" + + if not args: + match: Optional[Union[str, Pattern[str]]] = kwargs.pop("match", None) + if kwargs: + msg = "Unexpected keyword arguments passed to pytest.raises: " + msg += ", ".join(sorted(kwargs)) + msg += "\nUse context-manager form instead?" + raise TypeError(msg) + return RaisesContext(expected_exception, message, match) + else: + func = args[0] + if not callable(func): + raise TypeError( + "{!r} object (type: {}) must be callable".format(func, type(func)) + ) + try: + func(*args[1:], **kwargs) + except expected_exception as e: + # We just caught the exception - there is a traceback. + assert e.__traceback__ is not None + return _pytest._code.ExceptionInfo.from_exc_info( + (type(e), e, e.__traceback__) + ) + fail(message) + + +# This doesn't work with mypy for now. Use fail.Exception instead. +raises.Exception = fail.Exception # type: ignore + + +@final +class RaisesContext(Generic[_E]): + def __init__( + self, + expected_exception: Union[Type[_E], Tuple[Type[_E], ...]], + message: str, + match_expr: Optional[Union[str, Pattern[str]]] = None, + ) -> None: + self.expected_exception = expected_exception + self.message = message + self.match_expr = match_expr + self.excinfo: Optional[_pytest._code.ExceptionInfo[_E]] = None + + def __enter__(self) -> _pytest._code.ExceptionInfo[_E]: + self.excinfo = _pytest._code.ExceptionInfo.for_later() + return self.excinfo + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> bool: + __tracebackhide__ = True + if exc_type is None: + fail(self.message) + assert self.excinfo is not None + if not issubclass(exc_type, self.expected_exception): + return False + # Cast to narrow the exception type now that it's verified. + exc_info = cast(Tuple[Type[_E], _E, TracebackType], (exc_type, exc_val, exc_tb)) + self.excinfo.fill_unfilled(exc_info) + if self.match_expr is not None: + self.excinfo.match(self.match_expr) + return True diff --git a/myenv/lib/python3.9/site-packages/_pytest/recwarn.py b/myenv/lib/python3.9/site-packages/_pytest/recwarn.py new file mode 100644 index 0000000..d872d9d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/recwarn.py @@ -0,0 +1,296 @@ +"""Record warnings during test function execution.""" +import re +import warnings +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Generator +from typing import Iterator +from typing import List +from typing import Optional +from typing import overload +from typing import Pattern +from typing import Tuple +from typing import Type +from typing import TypeVar +from typing import Union + +from _pytest.compat import final +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.outcomes import fail + + +T = TypeVar("T") + + +@fixture +def recwarn() -> Generator["WarningsRecorder", None, None]: + """Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions. + + See http://docs.python.org/library/warnings.html for information + on warning categories. + """ + wrec = WarningsRecorder(_ispytest=True) + with wrec: + warnings.simplefilter("default") + yield wrec + + +@overload +def deprecated_call( + *, match: Optional[Union[str, Pattern[str]]] = ... +) -> "WarningsRecorder": + ... + + +@overload +def deprecated_call(func: Callable[..., T], *args: Any, **kwargs: Any) -> T: + ... + + +def deprecated_call( + func: Optional[Callable[..., Any]] = None, *args: Any, **kwargs: Any +) -> Union["WarningsRecorder", Any]: + """Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning``. + + This function can be used as a context manager:: + + >>> import warnings + >>> def api_call_v2(): + ... warnings.warn('use v3 of this api', DeprecationWarning) + ... return 200 + + >>> import pytest + >>> with pytest.deprecated_call(): + ... assert api_call_v2() == 200 + + It can also be used by passing a function and ``*args`` and ``**kwargs``, + in which case it will ensure calling ``func(*args, **kwargs)`` produces one of + the warnings types above. The return value is the return value of the function. + + In the context manager form you may use the keyword argument ``match`` to assert + that the warning matches a text or regex. + + The context manager produces a list of :class:`warnings.WarningMessage` objects, + one for each warning raised. + """ + __tracebackhide__ = True + if func is not None: + args = (func,) + args + return warns((DeprecationWarning, PendingDeprecationWarning), *args, **kwargs) + + +@overload +def warns( + expected_warning: Optional[Union[Type[Warning], Tuple[Type[Warning], ...]]], + *, + match: Optional[Union[str, Pattern[str]]] = ..., +) -> "WarningsChecker": + ... + + +@overload +def warns( + expected_warning: Optional[Union[Type[Warning], Tuple[Type[Warning], ...]]], + func: Callable[..., T], + *args: Any, + **kwargs: Any, +) -> T: + ... + + +def warns( + expected_warning: Optional[Union[Type[Warning], Tuple[Type[Warning], ...]]], + *args: Any, + match: Optional[Union[str, Pattern[str]]] = None, + **kwargs: Any, +) -> Union["WarningsChecker", Any]: + r"""Assert that code raises a particular class of warning. + + Specifically, the parameter ``expected_warning`` can be a warning class or + sequence of warning classes, and the inside the ``with`` block must issue a warning of that class or + classes. + + This helper produces a list of :class:`warnings.WarningMessage` objects, + one for each warning raised. + + This function can be used as a context manager, or any of the other ways + :func:`pytest.raises` can be used:: + + >>> import pytest + >>> with pytest.warns(RuntimeWarning): + ... warnings.warn("my warning", RuntimeWarning) + + In the context manager form you may use the keyword argument ``match`` to assert + that the warning matches a text or regex:: + + >>> with pytest.warns(UserWarning, match='must be 0 or None'): + ... warnings.warn("value must be 0 or None", UserWarning) + + >>> with pytest.warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("value must be 42", UserWarning) + + >>> with pytest.warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("this is not here", UserWarning) + Traceback (most recent call last): + ... + Failed: DID NOT WARN. No warnings of type ...UserWarning... was emitted... + + """ + __tracebackhide__ = True + if not args: + if kwargs: + msg = "Unexpected keyword arguments passed to pytest.warns: " + msg += ", ".join(sorted(kwargs)) + msg += "\nUse context-manager form instead?" + raise TypeError(msg) + return WarningsChecker(expected_warning, match_expr=match, _ispytest=True) + else: + func = args[0] + if not callable(func): + raise TypeError( + "{!r} object (type: {}) must be callable".format(func, type(func)) + ) + with WarningsChecker(expected_warning, _ispytest=True): + return func(*args[1:], **kwargs) + + +class WarningsRecorder(warnings.catch_warnings): + """A context manager to record raised warnings. + + Adapted from `warnings.catch_warnings`. + """ + + def __init__(self, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + # Type ignored due to the way typeshed handles warnings.catch_warnings. + super().__init__(record=True) # type: ignore[call-arg] + self._entered = False + self._list: List[warnings.WarningMessage] = [] + + @property + def list(self) -> List["warnings.WarningMessage"]: + """The list of recorded warnings.""" + return self._list + + def __getitem__(self, i: int) -> "warnings.WarningMessage": + """Get a recorded warning by index.""" + return self._list[i] + + def __iter__(self) -> Iterator["warnings.WarningMessage"]: + """Iterate through the recorded warnings.""" + return iter(self._list) + + def __len__(self) -> int: + """The number of recorded warnings.""" + return len(self._list) + + def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage": + """Pop the first recorded warning, raise exception if not exists.""" + for i, w in enumerate(self._list): + if issubclass(w.category, cls): + return self._list.pop(i) + __tracebackhide__ = True + raise AssertionError("%r not found in warning list" % cls) + + def clear(self) -> None: + """Clear the list of recorded warnings.""" + self._list[:] = [] + + # Type ignored because it doesn't exactly warnings.catch_warnings.__enter__ + # -- it returns a List but we only emulate one. + def __enter__(self) -> "WarningsRecorder": # type: ignore + if self._entered: + __tracebackhide__ = True + raise RuntimeError("Cannot enter %r twice" % self) + _list = super().__enter__() + # record=True means it's None. + assert _list is not None + self._list = _list + warnings.simplefilter("always") + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if not self._entered: + __tracebackhide__ = True + raise RuntimeError("Cannot exit %r without entering first" % self) + + super().__exit__(exc_type, exc_val, exc_tb) + + # Built-in catch_warnings does not reset entered state so we do it + # manually here for this context manager to become reusable. + self._entered = False + + +@final +class WarningsChecker(WarningsRecorder): + def __init__( + self, + expected_warning: Optional[ + Union[Type[Warning], Tuple[Type[Warning], ...]] + ] = None, + match_expr: Optional[Union[str, Pattern[str]]] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + super().__init__(_ispytest=True) + + msg = "exceptions must be derived from Warning, not %s" + if expected_warning is None: + expected_warning_tup = None + elif isinstance(expected_warning, tuple): + for exc in expected_warning: + if not issubclass(exc, Warning): + raise TypeError(msg % type(exc)) + expected_warning_tup = expected_warning + elif issubclass(expected_warning, Warning): + expected_warning_tup = (expected_warning,) + else: + raise TypeError(msg % type(expected_warning)) + + self.expected_warning = expected_warning_tup + self.match_expr = match_expr + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + super().__exit__(exc_type, exc_val, exc_tb) + + __tracebackhide__ = True + + # only check if we're not currently handling an exception + if exc_type is None and exc_val is None and exc_tb is None: + if self.expected_warning is not None: + if not any(issubclass(r.category, self.expected_warning) for r in self): + __tracebackhide__ = True + fail( + "DID NOT WARN. No warnings of type {} was emitted. " + "The list of emitted warnings is: {}.".format( + self.expected_warning, [each.message for each in self] + ) + ) + elif self.match_expr is not None: + for r in self: + if issubclass(r.category, self.expected_warning): + if re.compile(self.match_expr).search(str(r.message)): + break + else: + fail( + "DID NOT WARN. No warnings of type {} matching" + " ('{}') was emitted. The list of emitted warnings" + " is: {}.".format( + self.expected_warning, + self.match_expr, + [each.message for each in self], + ) + ) diff --git a/myenv/lib/python3.9/site-packages/_pytest/reports.py b/myenv/lib/python3.9/site-packages/_pytest/reports.py new file mode 100644 index 0000000..58f1251 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/reports.py @@ -0,0 +1,572 @@ +from io import StringIO +from pathlib import Path +from pprint import pprint +from typing import Any +from typing import cast +from typing import Dict +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import attr +import py + +from _pytest._code.code import ExceptionChainRepr +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import ExceptionRepr +from _pytest._code.code import ReprEntry +from _pytest._code.code import ReprEntryNative +from _pytest._code.code import ReprExceptionInfo +from _pytest._code.code import ReprFileLocation +from _pytest._code.code import ReprFuncArgs +from _pytest._code.code import ReprLocals +from _pytest._code.code import ReprTraceback +from _pytest._code.code import TerminalRepr +from _pytest._io import TerminalWriter +from _pytest.compat import final +from _pytest.config import Config +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.outcomes import skip + +if TYPE_CHECKING: + from typing import NoReturn + from typing_extensions import Literal + + from _pytest.runner import CallInfo + + +def getworkerinfoline(node): + try: + return node._workerinfocache + except AttributeError: + d = node.workerinfo + ver = "%s.%s.%s" % d["version_info"][:3] + node._workerinfocache = s = "[{}] {} -- Python {} {}".format( + d["id"], d["sysplatform"], ver, d["executable"] + ) + return s + + +_R = TypeVar("_R", bound="BaseReport") + + +class BaseReport: + when: Optional[str] + location: Optional[Tuple[str, Optional[int], str]] + longrepr: Union[ + None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr + ] + sections: List[Tuple[str, str]] + nodeid: str + + def __init__(self, **kw: Any) -> None: + self.__dict__.update(kw) + + if TYPE_CHECKING: + # Can have arbitrary fields given to __init__(). + def __getattr__(self, key: str) -> Any: + ... + + def toterminal(self, out: TerminalWriter) -> None: + if hasattr(self, "node"): + out.line(getworkerinfoline(self.node)) + + longrepr = self.longrepr + if longrepr is None: + return + + if hasattr(longrepr, "toterminal"): + longrepr_terminal = cast(TerminalRepr, longrepr) + longrepr_terminal.toterminal(out) + else: + try: + s = str(longrepr) + except UnicodeEncodeError: + s = "" + out.line(s) + + def get_sections(self, prefix: str) -> Iterator[Tuple[str, str]]: + for name, content in self.sections: + if name.startswith(prefix): + yield prefix, content + + @property + def longreprtext(self) -> str: + """Read-only property that returns the full string representation of + ``longrepr``. + + .. versionadded:: 3.0 + """ + file = StringIO() + tw = TerminalWriter(file) + tw.hasmarkup = False + self.toterminal(tw) + exc = file.getvalue() + return exc.strip() + + @property + def caplog(self) -> str: + """Return captured log lines, if log capturing is enabled. + + .. versionadded:: 3.5 + """ + return "\n".join( + content for (prefix, content) in self.get_sections("Captured log") + ) + + @property + def capstdout(self) -> str: + """Return captured text from stdout, if capturing is enabled. + + .. versionadded:: 3.0 + """ + return "".join( + content for (prefix, content) in self.get_sections("Captured stdout") + ) + + @property + def capstderr(self) -> str: + """Return captured text from stderr, if capturing is enabled. + + .. versionadded:: 3.0 + """ + return "".join( + content for (prefix, content) in self.get_sections("Captured stderr") + ) + + passed = property(lambda x: x.outcome == "passed") + failed = property(lambda x: x.outcome == "failed") + skipped = property(lambda x: x.outcome == "skipped") + + @property + def fspath(self) -> str: + return self.nodeid.split("::")[0] + + @property + def count_towards_summary(self) -> bool: + """**Experimental** Whether this report should be counted towards the + totals shown at the end of the test session: "1 passed, 1 failure, etc". + + .. note:: + + This function is considered **experimental**, so beware that it is subject to changes + even in patch releases. + """ + return True + + @property + def head_line(self) -> Optional[str]: + """**Experimental** The head line shown with longrepr output for this + report, more commonly during traceback representation during + failures:: + + ________ Test.foo ________ + + + In the example above, the head_line is "Test.foo". + + .. note:: + + This function is considered **experimental**, so beware that it is subject to changes + even in patch releases. + """ + if self.location is not None: + fspath, lineno, domain = self.location + return domain + return None + + def _get_verbose_word(self, config: Config): + _category, _short, verbose = config.hook.pytest_report_teststatus( + report=self, config=config + ) + return verbose + + def _to_json(self) -> Dict[str, Any]: + """Return the contents of this report as a dict of builtin entries, + suitable for serialization. + + This was originally the serialize_report() function from xdist (ca03269). + + Experimental method. + """ + return _report_to_json(self) + + @classmethod + def _from_json(cls: Type[_R], reportdict: Dict[str, object]) -> _R: + """Create either a TestReport or CollectReport, depending on the calling class. + + It is the callers responsibility to know which class to pass here. + + This was originally the serialize_report() function from xdist (ca03269). + + Experimental method. + """ + kwargs = _report_kwargs_from_json(reportdict) + return cls(**kwargs) + + +def _report_unserialization_failure( + type_name: str, report_class: Type[BaseReport], reportdict +) -> "NoReturn": + url = "https://github.com/pytest-dev/pytest/issues" + stream = StringIO() + pprint("-" * 100, stream=stream) + pprint("INTERNALERROR: Unknown entry type returned: %s" % type_name, stream=stream) + pprint("report_name: %s" % report_class, stream=stream) + pprint(reportdict, stream=stream) + pprint("Please report this bug at %s" % url, stream=stream) + pprint("-" * 100, stream=stream) + raise RuntimeError(stream.getvalue()) + + +@final +class TestReport(BaseReport): + """Basic test report object (also used for setup and teardown calls if + they fail).""" + + __test__ = False + + def __init__( + self, + nodeid: str, + location: Tuple[str, Optional[int], str], + keywords, + outcome: "Literal['passed', 'failed', 'skipped']", + longrepr: Union[ + None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr + ], + when: "Literal['setup', 'call', 'teardown']", + sections: Iterable[Tuple[str, str]] = (), + duration: float = 0, + user_properties: Optional[Iterable[Tuple[str, object]]] = None, + **extra, + ) -> None: + #: Normalized collection nodeid. + self.nodeid = nodeid + + #: A (filesystempath, lineno, domaininfo) tuple indicating the + #: actual location of a test item - it might be different from the + #: collected one e.g. if a method is inherited from a different module. + self.location: Tuple[str, Optional[int], str] = location + + #: A name -> value dictionary containing all keywords and + #: markers associated with a test invocation. + self.keywords = keywords + + #: Test outcome, always one of "passed", "failed", "skipped". + self.outcome = outcome + + #: None or a failure representation. + self.longrepr = longrepr + + #: One of 'setup', 'call', 'teardown' to indicate runtest phase. + self.when = when + + #: User properties is a list of tuples (name, value) that holds user + #: defined properties of the test. + self.user_properties = list(user_properties or []) + + #: List of pairs ``(str, str)`` of extra information which needs to + #: marshallable. Used by pytest to add captured text + #: from ``stdout`` and ``stderr``, but may be used by other plugins + #: to add arbitrary information to reports. + self.sections = list(sections) + + #: Time it took to run just the test. + self.duration = duration + + self.__dict__.update(extra) + + def __repr__(self) -> str: + return "<{} {!r} when={!r} outcome={!r}>".format( + self.__class__.__name__, self.nodeid, self.when, self.outcome + ) + + @classmethod + def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport": + """Create and fill a TestReport with standard item and call info.""" + when = call.when + # Remove "collect" from the Literal type -- only for collection calls. + assert when != "collect" + duration = call.duration + keywords = {x: 1 for x in item.keywords} + excinfo = call.excinfo + sections = [] + if not call.excinfo: + outcome: Literal["passed", "failed", "skipped"] = "passed" + longrepr: Union[ + None, + ExceptionInfo[BaseException], + Tuple[str, int, str], + str, + TerminalRepr, + ] = (None) + else: + if not isinstance(excinfo, ExceptionInfo): + outcome = "failed" + longrepr = excinfo + elif isinstance(excinfo.value, skip.Exception): + outcome = "skipped" + r = excinfo._getreprcrash() + longrepr = (str(r.path), r.lineno, r.message) + else: + outcome = "failed" + if call.when == "call": + longrepr = item.repr_failure(excinfo) + else: # exception in setup or teardown + longrepr = item._repr_failure_py( + excinfo, style=item.config.getoption("tbstyle", "auto") + ) + for rwhen, key, content in item._report_sections: + sections.append((f"Captured {key} {rwhen}", content)) + return cls( + item.nodeid, + item.location, + keywords, + outcome, + longrepr, + when, + sections, + duration, + user_properties=item.user_properties, + ) + + +@final +class CollectReport(BaseReport): + """Collection report object.""" + + when = "collect" + + def __init__( + self, + nodeid: str, + outcome: "Literal['passed', 'skipped', 'failed']", + longrepr, + result: Optional[List[Union[Item, Collector]]], + sections: Iterable[Tuple[str, str]] = (), + **extra, + ) -> None: + #: Normalized collection nodeid. + self.nodeid = nodeid + + #: Test outcome, always one of "passed", "failed", "skipped". + self.outcome = outcome + + #: None or a failure representation. + self.longrepr = longrepr + + #: The collected items and collection nodes. + self.result = result or [] + + #: List of pairs ``(str, str)`` of extra information which needs to + #: marshallable. + # Used by pytest to add captured text : from ``stdout`` and ``stderr``, + # but may be used by other plugins : to add arbitrary information to + # reports. + self.sections = list(sections) + + self.__dict__.update(extra) + + @property + def location(self): + return (self.fspath, None, self.fspath) + + def __repr__(self) -> str: + return "".format( + self.nodeid, len(self.result), self.outcome + ) + + +class CollectErrorRepr(TerminalRepr): + def __init__(self, msg: str) -> None: + self.longrepr = msg + + def toterminal(self, out: TerminalWriter) -> None: + out.line(self.longrepr, red=True) + + +def pytest_report_to_serializable( + report: Union[CollectReport, TestReport] +) -> Optional[Dict[str, Any]]: + if isinstance(report, (TestReport, CollectReport)): + data = report._to_json() + data["$report_type"] = report.__class__.__name__ + return data + # TODO: Check if this is actually reachable. + return None # type: ignore[unreachable] + + +def pytest_report_from_serializable( + data: Dict[str, Any], +) -> Optional[Union[CollectReport, TestReport]]: + if "$report_type" in data: + if data["$report_type"] == "TestReport": + return TestReport._from_json(data) + elif data["$report_type"] == "CollectReport": + return CollectReport._from_json(data) + assert False, "Unknown report_type unserialize data: {}".format( + data["$report_type"] + ) + return None + + +def _report_to_json(report: BaseReport) -> Dict[str, Any]: + """Return the contents of this report as a dict of builtin entries, + suitable for serialization. + + This was originally the serialize_report() function from xdist (ca03269). + """ + + def serialize_repr_entry( + entry: Union[ReprEntry, ReprEntryNative] + ) -> Dict[str, Any]: + data = attr.asdict(entry) + for key, value in data.items(): + if hasattr(value, "__dict__"): + data[key] = attr.asdict(value) + entry_data = {"type": type(entry).__name__, "data": data} + return entry_data + + def serialize_repr_traceback(reprtraceback: ReprTraceback) -> Dict[str, Any]: + result = attr.asdict(reprtraceback) + result["reprentries"] = [ + serialize_repr_entry(x) for x in reprtraceback.reprentries + ] + return result + + def serialize_repr_crash( + reprcrash: Optional[ReprFileLocation], + ) -> Optional[Dict[str, Any]]: + if reprcrash is not None: + return attr.asdict(reprcrash) + else: + return None + + def serialize_exception_longrepr(rep: BaseReport) -> Dict[str, Any]: + assert rep.longrepr is not None + # TODO: Investigate whether the duck typing is really necessary here. + longrepr = cast(ExceptionRepr, rep.longrepr) + result: Dict[str, Any] = { + "reprcrash": serialize_repr_crash(longrepr.reprcrash), + "reprtraceback": serialize_repr_traceback(longrepr.reprtraceback), + "sections": longrepr.sections, + } + if isinstance(longrepr, ExceptionChainRepr): + result["chain"] = [] + for repr_traceback, repr_crash, description in longrepr.chain: + result["chain"].append( + ( + serialize_repr_traceback(repr_traceback), + serialize_repr_crash(repr_crash), + description, + ) + ) + else: + result["chain"] = None + return result + + d = report.__dict__.copy() + if hasattr(report.longrepr, "toterminal"): + if hasattr(report.longrepr, "reprtraceback") and hasattr( + report.longrepr, "reprcrash" + ): + d["longrepr"] = serialize_exception_longrepr(report) + else: + d["longrepr"] = str(report.longrepr) + else: + d["longrepr"] = report.longrepr + for name in d: + if isinstance(d[name], (py.path.local, Path)): + d[name] = str(d[name]) + elif name == "result": + d[name] = None # for now + return d + + +def _report_kwargs_from_json(reportdict: Dict[str, Any]) -> Dict[str, Any]: + """Return **kwargs that can be used to construct a TestReport or + CollectReport instance. + + This was originally the serialize_report() function from xdist (ca03269). + """ + + def deserialize_repr_entry(entry_data): + data = entry_data["data"] + entry_type = entry_data["type"] + if entry_type == "ReprEntry": + reprfuncargs = None + reprfileloc = None + reprlocals = None + if data["reprfuncargs"]: + reprfuncargs = ReprFuncArgs(**data["reprfuncargs"]) + if data["reprfileloc"]: + reprfileloc = ReprFileLocation(**data["reprfileloc"]) + if data["reprlocals"]: + reprlocals = ReprLocals(data["reprlocals"]["lines"]) + + reprentry: Union[ReprEntry, ReprEntryNative] = ReprEntry( + lines=data["lines"], + reprfuncargs=reprfuncargs, + reprlocals=reprlocals, + reprfileloc=reprfileloc, + style=data["style"], + ) + elif entry_type == "ReprEntryNative": + reprentry = ReprEntryNative(data["lines"]) + else: + _report_unserialization_failure(entry_type, TestReport, reportdict) + return reprentry + + def deserialize_repr_traceback(repr_traceback_dict): + repr_traceback_dict["reprentries"] = [ + deserialize_repr_entry(x) for x in repr_traceback_dict["reprentries"] + ] + return ReprTraceback(**repr_traceback_dict) + + def deserialize_repr_crash(repr_crash_dict: Optional[Dict[str, Any]]): + if repr_crash_dict is not None: + return ReprFileLocation(**repr_crash_dict) + else: + return None + + if ( + reportdict["longrepr"] + and "reprcrash" in reportdict["longrepr"] + and "reprtraceback" in reportdict["longrepr"] + ): + + reprtraceback = deserialize_repr_traceback( + reportdict["longrepr"]["reprtraceback"] + ) + reprcrash = deserialize_repr_crash(reportdict["longrepr"]["reprcrash"]) + if reportdict["longrepr"]["chain"]: + chain = [] + for repr_traceback_data, repr_crash_data, description in reportdict[ + "longrepr" + ]["chain"]: + chain.append( + ( + deserialize_repr_traceback(repr_traceback_data), + deserialize_repr_crash(repr_crash_data), + description, + ) + ) + exception_info: Union[ + ExceptionChainRepr, ReprExceptionInfo + ] = ExceptionChainRepr(chain) + else: + exception_info = ReprExceptionInfo(reprtraceback, reprcrash) + + for section in reportdict["longrepr"]["sections"]: + exception_info.addsection(*section) + reportdict["longrepr"] = exception_info + + return reportdict diff --git a/myenv/lib/python3.9/site-packages/_pytest/runner.py b/myenv/lib/python3.9/site-packages/_pytest/runner.py new file mode 100644 index 0000000..794690d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/runner.py @@ -0,0 +1,462 @@ +"""Basic collect and runtest protocol implementations.""" +import bdb +import os +import sys +from typing import Callable +from typing import cast +from typing import Dict +from typing import Generic +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import attr + +from .reports import BaseReport +from .reports import CollectErrorRepr +from .reports import CollectReport +from .reports import TestReport +from _pytest import timing +from _pytest._code.code import ExceptionChainRepr +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import TerminalRepr +from _pytest.compat import final +from _pytest.config.argparsing import Parser +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.nodes import Node +from _pytest.outcomes import Exit +from _pytest.outcomes import Skipped +from _pytest.outcomes import TEST_OUTCOME + +if TYPE_CHECKING: + from typing_extensions import Literal + + from _pytest.main import Session + from _pytest.terminal import TerminalReporter + +# +# pytest plugin hooks. + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting", "reporting", after="general") + group.addoption( + "--durations", + action="store", + type=int, + default=None, + metavar="N", + help="show N slowest setup/test durations (N=0 for all).", + ) + group.addoption( + "--durations-min", + action="store", + type=float, + default=0.005, + metavar="N", + help="Minimal duration in seconds for inclusion in slowest list. Default 0.005", + ) + + +def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None: + durations = terminalreporter.config.option.durations + durations_min = terminalreporter.config.option.durations_min + verbose = terminalreporter.config.getvalue("verbose") + if durations is None: + return + tr = terminalreporter + dlist = [] + for replist in tr.stats.values(): + for rep in replist: + if hasattr(rep, "duration"): + dlist.append(rep) + if not dlist: + return + dlist.sort(key=lambda x: x.duration, reverse=True) # type: ignore[no-any-return] + if not durations: + tr.write_sep("=", "slowest durations") + else: + tr.write_sep("=", "slowest %s durations" % durations) + dlist = dlist[:durations] + + for i, rep in enumerate(dlist): + if verbose < 2 and rep.duration < durations_min: + tr.write_line("") + tr.write_line( + "(%s durations < %gs hidden. Use -vv to show these durations.)" + % (len(dlist) - i, durations_min) + ) + break + tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}") + + +def pytest_sessionstart(session: "Session") -> None: + session._setupstate = SetupState() + + +def pytest_sessionfinish(session: "Session") -> None: + session._setupstate.teardown_all() + + +def pytest_runtest_protocol(item: Item, nextitem: Optional[Item]) -> bool: + ihook = item.ihook + ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location) + runtestprotocol(item, nextitem=nextitem) + ihook.pytest_runtest_logfinish(nodeid=item.nodeid, location=item.location) + return True + + +def runtestprotocol( + item: Item, log: bool = True, nextitem: Optional[Item] = None +) -> List[TestReport]: + hasrequest = hasattr(item, "_request") + if hasrequest and not item._request: # type: ignore[attr-defined] + item._initrequest() # type: ignore[attr-defined] + rep = call_and_report(item, "setup", log) + reports = [rep] + if rep.passed: + if item.config.getoption("setupshow", False): + show_test_item(item) + if not item.config.getoption("setuponly", False): + reports.append(call_and_report(item, "call", log)) + reports.append(call_and_report(item, "teardown", log, nextitem=nextitem)) + # After all teardown hooks have been called + # want funcargs and request info to go away. + if hasrequest: + item._request = False # type: ignore[attr-defined] + item.funcargs = None # type: ignore[attr-defined] + return reports + + +def show_test_item(item: Item) -> None: + """Show test function, parameters and the fixtures of the test item.""" + tw = item.config.get_terminal_writer() + tw.line() + tw.write(" " * 8) + tw.write(item.nodeid) + used_fixtures = sorted(getattr(item, "fixturenames", [])) + if used_fixtures: + tw.write(" (fixtures used: {})".format(", ".join(used_fixtures))) + tw.flush() + + +def pytest_runtest_setup(item: Item) -> None: + _update_current_test_var(item, "setup") + item.session._setupstate.prepare(item) + + +def pytest_runtest_call(item: Item) -> None: + _update_current_test_var(item, "call") + try: + del sys.last_type + del sys.last_value + del sys.last_traceback + except AttributeError: + pass + try: + item.runtest() + except Exception as e: + # Store trace info to allow postmortem debugging + sys.last_type = type(e) + sys.last_value = e + assert e.__traceback__ is not None + # Skip *this* frame + sys.last_traceback = e.__traceback__.tb_next + raise e + + +def pytest_runtest_teardown(item: Item, nextitem: Optional[Item]) -> None: + _update_current_test_var(item, "teardown") + item.session._setupstate.teardown_exact(item, nextitem) + _update_current_test_var(item, None) + + +def _update_current_test_var( + item: Item, when: Optional["Literal['setup', 'call', 'teardown']"] +) -> None: + """Update :envvar:`PYTEST_CURRENT_TEST` to reflect the current item and stage. + + If ``when`` is None, delete ``PYTEST_CURRENT_TEST`` from the environment. + """ + var_name = "PYTEST_CURRENT_TEST" + if when: + value = f"{item.nodeid} ({when})" + # don't allow null bytes on environment variables (see #2644, #2957) + value = value.replace("\x00", "(null)") + os.environ[var_name] = value + else: + os.environ.pop(var_name) + + +def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]: + if report.when in ("setup", "teardown"): + if report.failed: + # category, shortletter, verbose-word + return "error", "E", "ERROR" + elif report.skipped: + return "skipped", "s", "SKIPPED" + else: + return "", "", "" + return None + + +# +# Implementation + + +def call_and_report( + item: Item, when: "Literal['setup', 'call', 'teardown']", log: bool = True, **kwds +) -> TestReport: + call = call_runtest_hook(item, when, **kwds) + hook = item.ihook + report: TestReport = hook.pytest_runtest_makereport(item=item, call=call) + if log: + hook.pytest_runtest_logreport(report=report) + if check_interactive_exception(call, report): + hook.pytest_exception_interact(node=item, call=call, report=report) + return report + + +def check_interactive_exception(call: "CallInfo[object]", report: BaseReport) -> bool: + """Check whether the call raised an exception that should be reported as + interactive.""" + if call.excinfo is None: + # Didn't raise. + return False + if hasattr(report, "wasxfail"): + # Exception was expected. + return False + if isinstance(call.excinfo.value, (Skipped, bdb.BdbQuit)): + # Special control flow exception. + return False + return True + + +def call_runtest_hook( + item: Item, when: "Literal['setup', 'call', 'teardown']", **kwds +) -> "CallInfo[None]": + if when == "setup": + ihook: Callable[..., None] = item.ihook.pytest_runtest_setup + elif when == "call": + ihook = item.ihook.pytest_runtest_call + elif when == "teardown": + ihook = item.ihook.pytest_runtest_teardown + else: + assert False, f"Unhandled runtest hook case: {when}" + reraise: Tuple[Type[BaseException], ...] = (Exit,) + if not item.config.getoption("usepdb", False): + reraise += (KeyboardInterrupt,) + return CallInfo.from_call( + lambda: ihook(item=item, **kwds), when=when, reraise=reraise + ) + + +TResult = TypeVar("TResult", covariant=True) + + +@final +@attr.s(repr=False) +class CallInfo(Generic[TResult]): + """Result/Exception info a function invocation. + + :param T result: + The return value of the call, if it didn't raise. Can only be + accessed if excinfo is None. + :param Optional[ExceptionInfo] excinfo: + The captured exception of the call, if it raised. + :param float start: + The system time when the call started, in seconds since the epoch. + :param float stop: + The system time when the call ended, in seconds since the epoch. + :param float duration: + The call duration, in seconds. + :param str when: + The context of invocation: "setup", "call", "teardown", ... + """ + + _result = attr.ib(type="Optional[TResult]") + excinfo = attr.ib(type=Optional[ExceptionInfo[BaseException]]) + start = attr.ib(type=float) + stop = attr.ib(type=float) + duration = attr.ib(type=float) + when = attr.ib(type="Literal['collect', 'setup', 'call', 'teardown']") + + @property + def result(self) -> TResult: + if self.excinfo is not None: + raise AttributeError(f"{self!r} has no valid result") + # The cast is safe because an exception wasn't raised, hence + # _result has the expected function return type (which may be + # None, that's why a cast and not an assert). + return cast(TResult, self._result) + + @classmethod + def from_call( + cls, + func: "Callable[[], TResult]", + when: "Literal['collect', 'setup', 'call', 'teardown']", + reraise: Optional[ + Union[Type[BaseException], Tuple[Type[BaseException], ...]] + ] = None, + ) -> "CallInfo[TResult]": + excinfo = None + start = timing.time() + precise_start = timing.perf_counter() + try: + result: Optional[TResult] = func() + except BaseException: + excinfo = ExceptionInfo.from_current() + if reraise is not None and isinstance(excinfo.value, reraise): + raise + result = None + # use the perf counter + precise_stop = timing.perf_counter() + duration = precise_stop - precise_start + stop = timing.time() + return cls( + start=start, + stop=stop, + duration=duration, + when=when, + result=result, + excinfo=excinfo, + ) + + def __repr__(self) -> str: + if self.excinfo is None: + return f"" + return f"" + + +def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> TestReport: + return TestReport.from_item_and_call(item, call) + + +def pytest_make_collect_report(collector: Collector) -> CollectReport: + call = CallInfo.from_call(lambda: list(collector.collect()), "collect") + longrepr: Union[None, Tuple[str, int, str], str, TerminalRepr] = None + if not call.excinfo: + outcome: Literal["passed", "skipped", "failed"] = "passed" + else: + skip_exceptions = [Skipped] + unittest = sys.modules.get("unittest") + if unittest is not None: + # Type ignored because unittest is loaded dynamically. + skip_exceptions.append(unittest.SkipTest) # type: ignore + if isinstance(call.excinfo.value, tuple(skip_exceptions)): + outcome = "skipped" + r_ = collector._repr_failure_py(call.excinfo, "line") + assert isinstance(r_, ExceptionChainRepr), repr(r_) + r = r_.reprcrash + assert r + longrepr = (str(r.path), r.lineno, r.message) + else: + outcome = "failed" + errorinfo = collector.repr_failure(call.excinfo) + if not hasattr(errorinfo, "toterminal"): + assert isinstance(errorinfo, str) + errorinfo = CollectErrorRepr(errorinfo) + longrepr = errorinfo + result = call.result if not call.excinfo else None + rep = CollectReport(collector.nodeid, outcome, longrepr, result) + rep.call = call # type: ignore # see collect_one_node + return rep + + +class SetupState: + """Shared state for setting up/tearing down test items or collectors.""" + + def __init__(self): + self.stack: List[Node] = [] + self._finalizers: Dict[Node, List[Callable[[], object]]] = {} + + def addfinalizer(self, finalizer: Callable[[], object], colitem) -> None: + """Attach a finalizer to the given colitem.""" + assert colitem and not isinstance(colitem, tuple) + assert callable(finalizer) + # assert colitem in self.stack # some unit tests don't setup stack :/ + self._finalizers.setdefault(colitem, []).append(finalizer) + + def _pop_and_teardown(self): + colitem = self.stack.pop() + self._teardown_with_finalization(colitem) + + def _callfinalizers(self, colitem) -> None: + finalizers = self._finalizers.pop(colitem, None) + exc = None + while finalizers: + fin = finalizers.pop() + try: + fin() + except TEST_OUTCOME as e: + # XXX Only first exception will be seen by user, + # ideally all should be reported. + if exc is None: + exc = e + if exc: + raise exc + + def _teardown_with_finalization(self, colitem) -> None: + self._callfinalizers(colitem) + colitem.teardown() + for colitem in self._finalizers: + assert colitem in self.stack + + def teardown_all(self) -> None: + while self.stack: + self._pop_and_teardown() + for key in list(self._finalizers): + self._teardown_with_finalization(key) + assert not self._finalizers + + def teardown_exact(self, item, nextitem) -> None: + needed_collectors = nextitem and nextitem.listchain() or [] + self._teardown_towards(needed_collectors) + + def _teardown_towards(self, needed_collectors) -> None: + exc = None + while self.stack: + if self.stack == needed_collectors[: len(self.stack)]: + break + try: + self._pop_and_teardown() + except TEST_OUTCOME as e: + # XXX Only first exception will be seen by user, + # ideally all should be reported. + if exc is None: + exc = e + if exc: + raise exc + + def prepare(self, colitem) -> None: + """Setup objects along the collector chain to the test-method.""" + + # Check if the last collection node has raised an error. + for col in self.stack: + if hasattr(col, "_prepare_exc"): + exc = col._prepare_exc # type: ignore[attr-defined] + raise exc + + needed_collectors = colitem.listchain() + for col in needed_collectors[len(self.stack) :]: + self.stack.append(col) + try: + col.setup() + except TEST_OUTCOME as e: + col._prepare_exc = e # type: ignore[attr-defined] + raise e + + +def collect_one_node(collector: Collector) -> CollectReport: + ihook = collector.ihook + ihook.pytest_collectstart(collector=collector) + rep: CollectReport = ihook.pytest_make_collect_report(collector=collector) + call = rep.__dict__.pop("call", None) + if call and check_interactive_exception(call, rep): + ihook.pytest_exception_interact(node=collector, call=call, report=rep) + return rep diff --git a/myenv/lib/python3.9/site-packages/_pytest/setuponly.py b/myenv/lib/python3.9/site-packages/_pytest/setuponly.py new file mode 100644 index 0000000..44a1094 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/setuponly.py @@ -0,0 +1,94 @@ +from typing import Generator +from typing import Optional +from typing import Union + +import pytest +from _pytest._io.saferepr import saferepr +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureDef +from _pytest.fixtures import SubRequest + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--setuponly", + "--setup-only", + action="store_true", + help="only setup fixtures, do not execute tests.", + ) + group.addoption( + "--setupshow", + "--setup-show", + action="store_true", + help="show setup of fixtures while executing tests.", + ) + + +@pytest.hookimpl(hookwrapper=True) +def pytest_fixture_setup( + fixturedef: FixtureDef[object], request: SubRequest +) -> Generator[None, None, None]: + yield + if request.config.option.setupshow: + if hasattr(request, "param"): + # Save the fixture parameter so ._show_fixture_action() can + # display it now and during the teardown (in .finish()). + if fixturedef.ids: + if callable(fixturedef.ids): + param = fixturedef.ids(request.param) + else: + param = fixturedef.ids[request.param_index] + else: + param = request.param + fixturedef.cached_param = param # type: ignore[attr-defined] + _show_fixture_action(fixturedef, "SETUP") + + +def pytest_fixture_post_finalizer(fixturedef: FixtureDef[object]) -> None: + if fixturedef.cached_result is not None: + config = fixturedef._fixturemanager.config + if config.option.setupshow: + _show_fixture_action(fixturedef, "TEARDOWN") + if hasattr(fixturedef, "cached_param"): + del fixturedef.cached_param # type: ignore[attr-defined] + + +def _show_fixture_action(fixturedef: FixtureDef[object], msg: str) -> None: + config = fixturedef._fixturemanager.config + capman = config.pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend_global_capture() + + tw = config.get_terminal_writer() + tw.line() + tw.write(" " * 2 * fixturedef.scopenum) + tw.write( + "{step} {scope} {fixture}".format( + step=msg.ljust(8), # align the output to TEARDOWN + scope=fixturedef.scope[0].upper(), + fixture=fixturedef.argname, + ) + ) + + if msg == "SETUP": + deps = sorted(arg for arg in fixturedef.argnames if arg != "request") + if deps: + tw.write(" (fixtures used: {})".format(", ".join(deps))) + + if hasattr(fixturedef, "cached_param"): + tw.write("[{}]".format(saferepr(fixturedef.cached_param, maxsize=42))) # type: ignore[attr-defined] + + tw.flush() + + if capman: + capman.resume_global_capture() + + +@pytest.hookimpl(tryfirst=True) +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.setuponly: + config.option.setupshow = True + return None diff --git a/myenv/lib/python3.9/site-packages/_pytest/setupplan.py b/myenv/lib/python3.9/site-packages/_pytest/setupplan.py new file mode 100644 index 0000000..9ba81cc --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/setupplan.py @@ -0,0 +1,40 @@ +from typing import Optional +from typing import Union + +import pytest +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureDef +from _pytest.fixtures import SubRequest + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--setupplan", + "--setup-plan", + action="store_true", + help="show what fixtures and tests would be executed but " + "don't execute anything.", + ) + + +@pytest.hookimpl(tryfirst=True) +def pytest_fixture_setup( + fixturedef: FixtureDef[object], request: SubRequest +) -> Optional[object]: + # Will return a dummy fixture if the setuponly option is provided. + if request.config.option.setupplan: + my_cache_key = fixturedef.cache_key(request) + fixturedef.cached_result = (None, my_cache_key, None) + return fixturedef.cached_result + return None + + +@pytest.hookimpl(tryfirst=True) +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.setupplan: + config.option.setuponly = True + config.option.setupshow = True + return None diff --git a/myenv/lib/python3.9/site-packages/_pytest/skipping.py b/myenv/lib/python3.9/site-packages/_pytest/skipping.py new file mode 100644 index 0000000..9aacfec --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/skipping.py @@ -0,0 +1,324 @@ +"""Support for skip/xfail functions and markers.""" +import os +import platform +import sys +import traceback +from collections.abc import Mapping +from typing import Generator +from typing import Optional +from typing import Tuple +from typing import Type + +import attr + +from _pytest.config import Config +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.mark.structures import Mark +from _pytest.nodes import Item +from _pytest.outcomes import fail +from _pytest.outcomes import skip +from _pytest.outcomes import xfail +from _pytest.reports import BaseReport +from _pytest.runner import CallInfo +from _pytest.store import StoreKey + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--runxfail", + action="store_true", + dest="runxfail", + default=False, + help="report the results of xfail tests as if they were not marked", + ) + + parser.addini( + "xfail_strict", + "default for the strict parameter of xfail " + "markers when not given explicitly (default: False)", + default=False, + type="bool", + ) + + +def pytest_configure(config: Config) -> None: + if config.option.runxfail: + # yay a hack + import pytest + + old = pytest.xfail + config._cleanup.append(lambda: setattr(pytest, "xfail", old)) + + def nop(*args, **kwargs): + pass + + nop.Exception = xfail.Exception # type: ignore[attr-defined] + setattr(pytest, "xfail", nop) + + config.addinivalue_line( + "markers", + "skip(reason=None): skip the given test function with an optional reason. " + 'Example: skip(reason="no way of currently testing this") skips the ' + "test.", + ) + config.addinivalue_line( + "markers", + "skipif(condition, ..., *, reason=...): " + "skip the given test function if any of the conditions evaluate to True. " + "Example: skipif(sys.platform == 'win32') skips the test if we are on the win32 platform. " + "See https://docs.pytest.org/en/stable/reference.html#pytest-mark-skipif", + ) + config.addinivalue_line( + "markers", + "xfail(condition, ..., *, reason=..., run=True, raises=None, strict=xfail_strict): " + "mark the test function as an expected failure if any of the conditions " + "evaluate to True. Optionally specify a reason for better reporting " + "and run=False if you don't even want to execute the test function. " + "If only specific exception(s) are expected, you can list them in " + "raises, and if the test fails in other ways, it will be reported as " + "a true failure. See https://docs.pytest.org/en/stable/reference.html#pytest-mark-xfail", + ) + + +def evaluate_condition(item: Item, mark: Mark, condition: object) -> Tuple[bool, str]: + """Evaluate a single skipif/xfail condition. + + If an old-style string condition is given, it is eval()'d, otherwise the + condition is bool()'d. If this fails, an appropriately formatted pytest.fail + is raised. + + Returns (result, reason). The reason is only relevant if the result is True. + """ + # String condition. + if isinstance(condition, str): + globals_ = { + "os": os, + "sys": sys, + "platform": platform, + "config": item.config, + } + for dictionary in reversed( + item.ihook.pytest_markeval_namespace(config=item.config) + ): + if not isinstance(dictionary, Mapping): + raise ValueError( + "pytest_markeval_namespace() needs to return a dict, got {!r}".format( + dictionary + ) + ) + globals_.update(dictionary) + if hasattr(item, "obj"): + globals_.update(item.obj.__globals__) # type: ignore[attr-defined] + try: + filename = f"<{mark.name} condition>" + condition_code = compile(condition, filename, "eval") + result = eval(condition_code, globals_) + except SyntaxError as exc: + msglines = [ + "Error evaluating %r condition" % mark.name, + " " + condition, + " " + " " * (exc.offset or 0) + "^", + "SyntaxError: invalid syntax", + ] + fail("\n".join(msglines), pytrace=False) + except Exception as exc: + msglines = [ + "Error evaluating %r condition" % mark.name, + " " + condition, + *traceback.format_exception_only(type(exc), exc), + ] + fail("\n".join(msglines), pytrace=False) + + # Boolean condition. + else: + try: + result = bool(condition) + except Exception as exc: + msglines = [ + "Error evaluating %r condition as a boolean" % mark.name, + *traceback.format_exception_only(type(exc), exc), + ] + fail("\n".join(msglines), pytrace=False) + + reason = mark.kwargs.get("reason", None) + if reason is None: + if isinstance(condition, str): + reason = "condition: " + condition + else: + # XXX better be checked at collection time + msg = ( + "Error evaluating %r: " % mark.name + + "you need to specify reason=STRING when using booleans as conditions." + ) + fail(msg, pytrace=False) + + return result, reason + + +@attr.s(slots=True, frozen=True) +class Skip: + """The result of evaluate_skip_marks().""" + + reason = attr.ib(type=str) + + +def evaluate_skip_marks(item: Item) -> Optional[Skip]: + """Evaluate skip and skipif marks on item, returning Skip if triggered.""" + for mark in item.iter_markers(name="skipif"): + if "condition" not in mark.kwargs: + conditions = mark.args + else: + conditions = (mark.kwargs["condition"],) + + # Unconditional. + if not conditions: + reason = mark.kwargs.get("reason", "") + return Skip(reason) + + # If any of the conditions are true. + for condition in conditions: + result, reason = evaluate_condition(item, mark, condition) + if result: + return Skip(reason) + + for mark in item.iter_markers(name="skip"): + if "reason" in mark.kwargs: + reason = mark.kwargs["reason"] + elif mark.args: + reason = mark.args[0] + else: + reason = "unconditional skip" + return Skip(reason) + + return None + + +@attr.s(slots=True, frozen=True) +class Xfail: + """The result of evaluate_xfail_marks().""" + + reason = attr.ib(type=str) + run = attr.ib(type=bool) + strict = attr.ib(type=bool) + raises = attr.ib(type=Optional[Tuple[Type[BaseException], ...]]) + + +def evaluate_xfail_marks(item: Item) -> Optional[Xfail]: + """Evaluate xfail marks on item, returning Xfail if triggered.""" + for mark in item.iter_markers(name="xfail"): + run = mark.kwargs.get("run", True) + strict = mark.kwargs.get("strict", item.config.getini("xfail_strict")) + raises = mark.kwargs.get("raises", None) + if "condition" not in mark.kwargs: + conditions = mark.args + else: + conditions = (mark.kwargs["condition"],) + + # Unconditional. + if not conditions: + reason = mark.kwargs.get("reason", "") + return Xfail(reason, run, strict, raises) + + # If any of the conditions are true. + for condition in conditions: + result, reason = evaluate_condition(item, mark, condition) + if result: + return Xfail(reason, run, strict, raises) + + return None + + +# Whether skipped due to skip or skipif marks. +skipped_by_mark_key = StoreKey[bool]() +# Saves the xfail mark evaluation. Can be refreshed during call if None. +xfailed_key = StoreKey[Optional[Xfail]]() +unexpectedsuccess_key = StoreKey[str]() + + +@hookimpl(tryfirst=True) +def pytest_runtest_setup(item: Item) -> None: + skipped = evaluate_skip_marks(item) + item._store[skipped_by_mark_key] = skipped is not None + if skipped: + skip(skipped.reason) + + item._store[xfailed_key] = xfailed = evaluate_xfail_marks(item) + if xfailed and not item.config.option.runxfail and not xfailed.run: + xfail("[NOTRUN] " + xfailed.reason) + + +@hookimpl(hookwrapper=True) +def pytest_runtest_call(item: Item) -> Generator[None, None, None]: + xfailed = item._store.get(xfailed_key, None) + if xfailed is None: + item._store[xfailed_key] = xfailed = evaluate_xfail_marks(item) + + if xfailed and not item.config.option.runxfail and not xfailed.run: + xfail("[NOTRUN] " + xfailed.reason) + + yield + + # The test run may have added an xfail mark dynamically. + xfailed = item._store.get(xfailed_key, None) + if xfailed is None: + item._store[xfailed_key] = xfailed = evaluate_xfail_marks(item) + + +@hookimpl(hookwrapper=True) +def pytest_runtest_makereport(item: Item, call: CallInfo[None]): + outcome = yield + rep = outcome.get_result() + xfailed = item._store.get(xfailed_key, None) + # unittest special case, see setting of unexpectedsuccess_key + if unexpectedsuccess_key in item._store and rep.when == "call": + reason = item._store[unexpectedsuccess_key] + if reason: + rep.longrepr = f"Unexpected success: {reason}" + else: + rep.longrepr = "Unexpected success" + rep.outcome = "failed" + elif item.config.option.runxfail: + pass # don't interfere + elif call.excinfo and isinstance(call.excinfo.value, xfail.Exception): + assert call.excinfo.value.msg is not None + rep.wasxfail = "reason: " + call.excinfo.value.msg + rep.outcome = "skipped" + elif not rep.skipped and xfailed: + if call.excinfo: + raises = xfailed.raises + if raises is not None and not isinstance(call.excinfo.value, raises): + rep.outcome = "failed" + else: + rep.outcome = "skipped" + rep.wasxfail = xfailed.reason + elif call.when == "call": + if xfailed.strict: + rep.outcome = "failed" + rep.longrepr = "[XPASS(strict)] " + xfailed.reason + else: + rep.outcome = "passed" + rep.wasxfail = xfailed.reason + + if ( + item._store.get(skipped_by_mark_key, True) + and rep.skipped + and type(rep.longrepr) is tuple + ): + # Skipped by mark.skipif; change the location of the failure + # to point to the item definition, otherwise it will display + # the location of where the skip exception was raised within pytest. + _, _, reason = rep.longrepr + filename, line = item.reportinfo()[:2] + assert line is not None + rep.longrepr = str(filename), line + 1, reason + + +def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]: + if hasattr(report, "wasxfail"): + if report.skipped: + return "xfailed", "x", "XFAIL" + elif report.passed: + return "xpassed", "X", "XPASS" + return None diff --git a/myenv/lib/python3.9/site-packages/_pytest/stepwise.py b/myenv/lib/python3.9/site-packages/_pytest/stepwise.py new file mode 100644 index 0000000..197577c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/stepwise.py @@ -0,0 +1,119 @@ +from typing import List +from typing import Optional +from typing import TYPE_CHECKING + +import pytest +from _pytest import nodes +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.main import Session +from _pytest.reports import TestReport + +if TYPE_CHECKING: + from _pytest.cacheprovider import Cache + +STEPWISE_CACHE_DIR = "cache/stepwise" + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--sw", + "--stepwise", + action="store_true", + default=False, + dest="stepwise", + help="exit on test failure and continue from last failing test next time", + ) + group.addoption( + "--sw-skip", + "--stepwise-skip", + action="store_true", + default=False, + dest="stepwise_skip", + help="ignore the first failing test but stop on the next failing test", + ) + + +@pytest.hookimpl +def pytest_configure(config: Config) -> None: + # We should always have a cache as cache provider plugin uses tryfirst=True + if config.getoption("stepwise"): + config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin") + + +def pytest_sessionfinish(session: Session) -> None: + if not session.config.getoption("stepwise"): + assert session.config.cache is not None + # Clear the list of failing tests if the plugin is not active. + session.config.cache.set(STEPWISE_CACHE_DIR, []) + + +class StepwisePlugin: + def __init__(self, config: Config) -> None: + self.config = config + self.session: Optional[Session] = None + self.report_status = "" + assert config.cache is not None + self.cache: Cache = config.cache + self.lastfailed: Optional[str] = self.cache.get(STEPWISE_CACHE_DIR, None) + self.skip: bool = config.getoption("stepwise_skip") + + def pytest_sessionstart(self, session: Session) -> None: + self.session = session + + def pytest_collection_modifyitems( + self, config: Config, items: List[nodes.Item] + ) -> None: + if not self.lastfailed: + self.report_status = "no previously failed tests, not skipping." + return + + # check all item nodes until we find a match on last failed + failed_index = None + for index, item in enumerate(items): + if item.nodeid == self.lastfailed: + failed_index = index + break + + # If the previously failed test was not found among the test items, + # do not skip any tests. + if failed_index is None: + self.report_status = "previously failed test not found, not skipping." + else: + self.report_status = f"skipping {failed_index} already passed items." + deselected = items[:failed_index] + del items[:failed_index] + config.hook.pytest_deselected(items=deselected) + + def pytest_runtest_logreport(self, report: TestReport) -> None: + if report.failed: + if self.skip: + # Remove test from the failed ones (if it exists) and unset the skip option + # to make sure the following tests will not be skipped. + if report.nodeid == self.lastfailed: + self.lastfailed = None + + self.skip = False + else: + # Mark test as the last failing and interrupt the test session. + self.lastfailed = report.nodeid + assert self.session is not None + self.session.shouldstop = ( + "Test failed, continuing from this test next run." + ) + + else: + # If the test was actually run and did pass. + if report.when == "call": + # Remove test from the failed ones, if exists. + if report.nodeid == self.lastfailed: + self.lastfailed = None + + def pytest_report_collectionfinish(self) -> Optional[str]: + if self.config.getoption("verbose") >= 0 and self.report_status: + return f"stepwise: {self.report_status}" + return None + + def pytest_sessionfinish(self) -> None: + self.cache.set(STEPWISE_CACHE_DIR, self.lastfailed) diff --git a/myenv/lib/python3.9/site-packages/_pytest/store.py b/myenv/lib/python3.9/site-packages/_pytest/store.py new file mode 100644 index 0000000..e5008cf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/store.py @@ -0,0 +1,125 @@ +from typing import Any +from typing import cast +from typing import Dict +from typing import Generic +from typing import TypeVar +from typing import Union + + +__all__ = ["Store", "StoreKey"] + + +T = TypeVar("T") +D = TypeVar("D") + + +class StoreKey(Generic[T]): + """StoreKey is an object used as a key to a Store. + + A StoreKey is associated with the type T of the value of the key. + + A StoreKey is unique and cannot conflict with another key. + """ + + __slots__ = () + + +class Store: + """Store is a type-safe heterogenous mutable mapping that + allows keys and value types to be defined separately from + where it (the Store) is created. + + Usually you will be given an object which has a ``Store``: + + .. code-block:: python + + store: Store = some_object.store + + If a module wants to store data in this Store, it creates StoreKeys + for its keys (at the module level): + + .. code-block:: python + + some_str_key = StoreKey[str]() + some_bool_key = StoreKey[bool]() + + To store information: + + .. code-block:: python + + # Value type must match the key. + store[some_str_key] = "value" + store[some_bool_key] = True + + To retrieve the information: + + .. code-block:: python + + # The static type of some_str is str. + some_str = store[some_str_key] + # The static type of some_bool is bool. + some_bool = store[some_bool_key] + + Why use this? + ------------- + + Problem: module Internal defines an object. Module External, which + module Internal doesn't know about, receives the object and wants to + attach information to it, to be retrieved later given the object. + + Bad solution 1: Module External assigns private attributes directly on + the object. This doesn't work well because the type checker doesn't + know about these attributes and it complains about undefined attributes. + + Bad solution 2: module Internal adds a ``Dict[str, Any]`` attribute to + the object. Module External stores its data in private keys of this dict. + This doesn't work well because retrieved values are untyped. + + Good solution: module Internal adds a ``Store`` to the object. Module + External mints StoreKeys for its own keys. Module External stores and + retrieves its data using these keys. + """ + + __slots__ = ("_store",) + + def __init__(self) -> None: + self._store: Dict[StoreKey[Any], object] = {} + + def __setitem__(self, key: StoreKey[T], value: T) -> None: + """Set a value for key.""" + self._store[key] = value + + def __getitem__(self, key: StoreKey[T]) -> T: + """Get the value for key. + + Raises ``KeyError`` if the key wasn't set before. + """ + return cast(T, self._store[key]) + + def get(self, key: StoreKey[T], default: D) -> Union[T, D]: + """Get the value for key, or return default if the key wasn't set + before.""" + try: + return self[key] + except KeyError: + return default + + def setdefault(self, key: StoreKey[T], default: T) -> T: + """Return the value of key if already set, otherwise set the value + of key to default and return default.""" + try: + return self[key] + except KeyError: + self[key] = default + return default + + def __delitem__(self, key: StoreKey[T]) -> None: + """Delete the value for key. + + Raises ``KeyError`` if the key wasn't set before. + """ + del self._store[key] + + def __contains__(self, key: StoreKey[T]) -> bool: + """Return whether key was set.""" + return key in self._store diff --git a/myenv/lib/python3.9/site-packages/_pytest/terminal.py b/myenv/lib/python3.9/site-packages/_pytest/terminal.py new file mode 100644 index 0000000..fbfb09a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/terminal.py @@ -0,0 +1,1405 @@ +"""Terminal reporting of the full testing process. + +This is a good source for looking at the various reporting hooks. +""" +import argparse +import datetime +import inspect +import platform +import sys +import warnings +from collections import Counter +from functools import partial +from pathlib import Path +from typing import Any +from typing import Callable +from typing import cast +from typing import Dict +from typing import Generator +from typing import List +from typing import Mapping +from typing import Optional +from typing import Sequence +from typing import Set +from typing import TextIO +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import attr +import pluggy +import py + +import _pytest._version +from _pytest import nodes +from _pytest import timing +from _pytest._code import ExceptionInfo +from _pytest._code.code import ExceptionRepr +from _pytest._io.wcwidth import wcswidth +from _pytest.compat import final +from _pytest.config import _PluggyPlugin +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.nodes import Item +from _pytest.nodes import Node +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath +from _pytest.reports import BaseReport +from _pytest.reports import CollectReport +from _pytest.reports import TestReport + +if TYPE_CHECKING: + from typing_extensions import Literal + + from _pytest.main import Session + + +REPORT_COLLECTING_RESOLUTION = 0.5 + +KNOWN_TYPES = ( + "failed", + "passed", + "skipped", + "deselected", + "xfailed", + "xpassed", + "warnings", + "error", +) + +_REPORTCHARS_DEFAULT = "fE" + + +class MoreQuietAction(argparse.Action): + """A modified copy of the argparse count action which counts down and updates + the legacy quiet attribute at the same time. + + Used to unify verbosity handling. + """ + + def __init__( + self, + option_strings: Sequence[str], + dest: str, + default: object = None, + required: bool = False, + help: Optional[str] = None, + ) -> None: + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=0, + default=default, + required=required, + help=help, + ) + + def __call__( + self, + parser: argparse.ArgumentParser, + namespace: argparse.Namespace, + values: Union[str, Sequence[object], None], + option_string: Optional[str] = None, + ) -> None: + new_count = getattr(namespace, self.dest, 0) - 1 + setattr(namespace, self.dest, new_count) + # todo Deprecate config.quiet + namespace.quiet = getattr(namespace, "quiet", 0) + 1 + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting", "reporting", after="general") + group._addoption( + "-v", + "--verbose", + action="count", + default=0, + dest="verbose", + help="increase verbosity.", + ) + group._addoption( + "--no-header", + action="store_true", + default=False, + dest="no_header", + help="disable header", + ) + group._addoption( + "--no-summary", + action="store_true", + default=False, + dest="no_summary", + help="disable summary", + ) + group._addoption( + "-q", + "--quiet", + action=MoreQuietAction, + default=0, + dest="verbose", + help="decrease verbosity.", + ) + group._addoption( + "--verbosity", + dest="verbose", + type=int, + default=0, + help="set verbosity. Default is 0.", + ) + group._addoption( + "-r", + action="store", + dest="reportchars", + default=_REPORTCHARS_DEFAULT, + metavar="chars", + help="show extra test summary info as specified by chars: (f)ailed, " + "(E)rror, (s)kipped, (x)failed, (X)passed, " + "(p)assed, (P)assed with output, (a)ll except passed (p/P), or (A)ll. " + "(w)arnings are enabled by default (see --disable-warnings), " + "'N' can be used to reset the list. (default: 'fE').", + ) + group._addoption( + "--disable-warnings", + "--disable-pytest-warnings", + default=False, + dest="disable_warnings", + action="store_true", + help="disable warnings summary", + ) + group._addoption( + "-l", + "--showlocals", + action="store_true", + dest="showlocals", + default=False, + help="show locals in tracebacks (disabled by default).", + ) + group._addoption( + "--tb", + metavar="style", + action="store", + dest="tbstyle", + default="auto", + choices=["auto", "long", "short", "no", "line", "native"], + help="traceback print mode (auto/long/short/line/native/no).", + ) + group._addoption( + "--show-capture", + action="store", + dest="showcapture", + choices=["no", "stdout", "stderr", "log", "all"], + default="all", + help="Controls how captured stdout/stderr/log is shown on failed tests. " + "Default is 'all'.", + ) + group._addoption( + "--fulltrace", + "--full-trace", + action="store_true", + default=False, + help="don't cut any tracebacks (default is to cut).", + ) + group._addoption( + "--color", + metavar="color", + action="store", + dest="color", + default="auto", + choices=["yes", "no", "auto"], + help="color terminal output (yes/no/auto).", + ) + group._addoption( + "--code-highlight", + default="yes", + choices=["yes", "no"], + help="Whether code should be highlighted (only if --color is also enabled)", + ) + + parser.addini( + "console_output_style", + help='console output: "classic", or with additional progress information ("progress" (percentage) | "count").', + default="progress", + ) + + +def pytest_configure(config: Config) -> None: + reporter = TerminalReporter(config, sys.stdout) + config.pluginmanager.register(reporter, "terminalreporter") + if config.option.debug or config.option.traceconfig: + + def mywriter(tags, args): + msg = " ".join(map(str, args)) + reporter.write_line("[traceconfig] " + msg) + + config.trace.root.setprocessor("pytest:config", mywriter) + + +def getreportopt(config: Config) -> str: + reportchars: str = config.option.reportchars + + old_aliases = {"F", "S"} + reportopts = "" + for char in reportchars: + if char in old_aliases: + char = char.lower() + if char == "a": + reportopts = "sxXEf" + elif char == "A": + reportopts = "PpsxXEf" + elif char == "N": + reportopts = "" + elif char not in reportopts: + reportopts += char + + if not config.option.disable_warnings and "w" not in reportopts: + reportopts = "w" + reportopts + elif config.option.disable_warnings and "w" in reportopts: + reportopts = reportopts.replace("w", "") + + return reportopts + + +@hookimpl(trylast=True) # after _pytest.runner +def pytest_report_teststatus(report: BaseReport) -> Tuple[str, str, str]: + letter = "F" + if report.passed: + letter = "." + elif report.skipped: + letter = "s" + + outcome: str = report.outcome + if report.when in ("collect", "setup", "teardown") and outcome == "failed": + outcome = "error" + letter = "E" + + return outcome, letter, outcome.upper() + + +@attr.s +class WarningReport: + """Simple structure to hold warnings information captured by ``pytest_warning_recorded``. + + :ivar str message: + User friendly message about the warning. + :ivar str|None nodeid: + nodeid that generated the warning (see ``get_location``). + :ivar tuple|py.path.local fslocation: + File system location of the source of the warning (see ``get_location``). + """ + + message = attr.ib(type=str) + nodeid = attr.ib(type=Optional[str], default=None) + fslocation = attr.ib( + type=Optional[Union[Tuple[str, int], py.path.local]], default=None + ) + count_towards_summary = True + + def get_location(self, config: Config) -> Optional[str]: + """Return the more user-friendly information about the location of a warning, or None.""" + if self.nodeid: + return self.nodeid + if self.fslocation: + if isinstance(self.fslocation, tuple) and len(self.fslocation) >= 2: + filename, linenum = self.fslocation[:2] + relpath = bestrelpath( + config.invocation_params.dir, absolutepath(filename) + ) + return f"{relpath}:{linenum}" + else: + return str(self.fslocation) + return None + + +@final +class TerminalReporter: + def __init__(self, config: Config, file: Optional[TextIO] = None) -> None: + import _pytest.config + + self.config = config + self._numcollected = 0 + self._session: Optional[Session] = None + self._showfspath: Optional[bool] = None + + self.stats: Dict[str, List[Any]] = {} + self._main_color: Optional[str] = None + self._known_types: Optional[List[str]] = None + self.startdir = config.invocation_dir + self.startpath = config.invocation_params.dir + if file is None: + file = sys.stdout + self._tw = _pytest.config.create_terminal_writer(config, file) + self._screen_width = self._tw.fullwidth + self.currentfspath: Union[None, Path, str, int] = None + self.reportchars = getreportopt(config) + self.hasmarkup = self._tw.hasmarkup + self.isatty = file.isatty() + self._progress_nodeids_reported: Set[str] = set() + self._show_progress_info = self._determine_show_progress_info() + self._collect_report_last_write: Optional[float] = None + self._already_displayed_warnings: Optional[int] = None + self._keyboardinterrupt_memo: Optional[ExceptionRepr] = None + + def _determine_show_progress_info(self) -> "Literal['progress', 'count', False]": + """Return whether we should display progress information based on the current config.""" + # do not show progress if we are not capturing output (#3038) + if self.config.getoption("capture", "no") == "no": + return False + # do not show progress if we are showing fixture setup/teardown + if self.config.getoption("setupshow", False): + return False + cfg: str = self.config.getini("console_output_style") + if cfg == "progress": + return "progress" + elif cfg == "count": + return "count" + else: + return False + + @property + def verbosity(self) -> int: + verbosity: int = self.config.option.verbose + return verbosity + + @property + def showheader(self) -> bool: + return self.verbosity >= 0 + + @property + def no_header(self) -> bool: + return bool(self.config.option.no_header) + + @property + def no_summary(self) -> bool: + return bool(self.config.option.no_summary) + + @property + def showfspath(self) -> bool: + if self._showfspath is None: + return self.verbosity >= 0 + return self._showfspath + + @showfspath.setter + def showfspath(self, value: Optional[bool]) -> None: + self._showfspath = value + + @property + def showlongtestinfo(self) -> bool: + return self.verbosity > 0 + + def hasopt(self, char: str) -> bool: + char = {"xfailed": "x", "skipped": "s"}.get(char, char) + return char in self.reportchars + + def write_fspath_result(self, nodeid: str, res, **markup: bool) -> None: + fspath = self.config.rootpath / nodeid.split("::")[0] + if self.currentfspath is None or fspath != self.currentfspath: + if self.currentfspath is not None and self._show_progress_info: + self._write_progress_information_filling_space() + self.currentfspath = fspath + relfspath = bestrelpath(self.startpath, fspath) + self._tw.line() + self._tw.write(relfspath + " ") + self._tw.write(res, flush=True, **markup) + + def write_ensure_prefix(self, prefix: str, extra: str = "", **kwargs) -> None: + if self.currentfspath != prefix: + self._tw.line() + self.currentfspath = prefix + self._tw.write(prefix) + if extra: + self._tw.write(extra, **kwargs) + self.currentfspath = -2 + + def ensure_newline(self) -> None: + if self.currentfspath: + self._tw.line() + self.currentfspath = None + + def write(self, content: str, *, flush: bool = False, **markup: bool) -> None: + self._tw.write(content, flush=flush, **markup) + + def flush(self) -> None: + self._tw.flush() + + def write_line(self, line: Union[str, bytes], **markup: bool) -> None: + if not isinstance(line, str): + line = str(line, errors="replace") + self.ensure_newline() + self._tw.line(line, **markup) + + def rewrite(self, line: str, **markup: bool) -> None: + """Rewinds the terminal cursor to the beginning and writes the given line. + + :param erase: + If True, will also add spaces until the full terminal width to ensure + previous lines are properly erased. + + The rest of the keyword arguments are markup instructions. + """ + erase = markup.pop("erase", False) + if erase: + fill_count = self._tw.fullwidth - len(line) - 1 + fill = " " * fill_count + else: + fill = "" + line = str(line) + self._tw.write("\r" + line + fill, **markup) + + def write_sep( + self, + sep: str, + title: Optional[str] = None, + fullwidth: Optional[int] = None, + **markup: bool, + ) -> None: + self.ensure_newline() + self._tw.sep(sep, title, fullwidth, **markup) + + def section(self, title: str, sep: str = "=", **kw: bool) -> None: + self._tw.sep(sep, title, **kw) + + def line(self, msg: str, **kw: bool) -> None: + self._tw.line(msg, **kw) + + def _add_stats(self, category: str, items: Sequence[Any]) -> None: + set_main_color = category not in self.stats + self.stats.setdefault(category, []).extend(items) + if set_main_color: + self._set_main_color() + + def pytest_internalerror(self, excrepr: ExceptionRepr) -> bool: + for line in str(excrepr).split("\n"): + self.write_line("INTERNALERROR> " + line) + return True + + def pytest_warning_recorded( + self, warning_message: warnings.WarningMessage, nodeid: str, + ) -> None: + from _pytest.warnings import warning_record_to_str + + fslocation = warning_message.filename, warning_message.lineno + message = warning_record_to_str(warning_message) + + warning_report = WarningReport( + fslocation=fslocation, message=message, nodeid=nodeid + ) + self._add_stats("warnings", [warning_report]) + + def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None: + if self.config.option.traceconfig: + msg = f"PLUGIN registered: {plugin}" + # XXX This event may happen during setup/teardown time + # which unfortunately captures our output here + # which garbles our output if we use self.write_line. + self.write_line(msg) + + def pytest_deselected(self, items: Sequence[Item]) -> None: + self._add_stats("deselected", items) + + def pytest_runtest_logstart( + self, nodeid: str, location: Tuple[str, Optional[int], str] + ) -> None: + # Ensure that the path is printed before the + # 1st test of a module starts running. + if self.showlongtestinfo: + line = self._locationline(nodeid, *location) + self.write_ensure_prefix(line, "") + self.flush() + elif self.showfspath: + self.write_fspath_result(nodeid, "") + self.flush() + + def pytest_runtest_logreport(self, report: TestReport) -> None: + self._tests_ran = True + rep = report + res: Tuple[ + str, str, Union[str, Tuple[str, Mapping[str, bool]]] + ] = self.config.hook.pytest_report_teststatus(report=rep, config=self.config) + category, letter, word = res + if not isinstance(word, tuple): + markup = None + else: + word, markup = word + self._add_stats(category, [rep]) + if not letter and not word: + # Probably passed setup/teardown. + return + running_xdist = hasattr(rep, "node") + if markup is None: + was_xfail = hasattr(report, "wasxfail") + if rep.passed and not was_xfail: + markup = {"green": True} + elif rep.passed and was_xfail: + markup = {"yellow": True} + elif rep.failed: + markup = {"red": True} + elif rep.skipped: + markup = {"yellow": True} + else: + markup = {} + if self.verbosity <= 0: + self._tw.write(letter, **markup) + else: + self._progress_nodeids_reported.add(rep.nodeid) + line = self._locationline(rep.nodeid, *rep.location) + if not running_xdist: + self.write_ensure_prefix(line, word, **markup) + if rep.skipped or hasattr(report, "wasxfail"): + available_width = ( + (self._tw.fullwidth - self._tw.width_of_current_line) + - len(" [100%]") + - 1 + ) + reason = _get_raw_skip_reason(rep) + reason_ = _format_trimmed(" ({})", reason, available_width) + if reason and reason_ is not None: + self._tw.write(reason_) + if self._show_progress_info: + self._write_progress_information_filling_space() + else: + self.ensure_newline() + self._tw.write("[%s]" % rep.node.gateway.id) + if self._show_progress_info: + self._tw.write( + self._get_progress_information_message() + " ", cyan=True + ) + else: + self._tw.write(" ") + self._tw.write(word, **markup) + self._tw.write(" " + line) + self.currentfspath = -2 + self.flush() + + @property + def _is_last_item(self) -> bool: + assert self._session is not None + return len(self._progress_nodeids_reported) == self._session.testscollected + + def pytest_runtest_logfinish(self, nodeid: str) -> None: + assert self._session + if self.verbosity <= 0 and self._show_progress_info: + if self._show_progress_info == "count": + num_tests = self._session.testscollected + progress_length = len(" [{}/{}]".format(str(num_tests), str(num_tests))) + else: + progress_length = len(" [100%]") + + self._progress_nodeids_reported.add(nodeid) + + if self._is_last_item: + self._write_progress_information_filling_space() + else: + main_color, _ = self._get_main_color() + w = self._width_of_current_line + past_edge = w + progress_length + 1 >= self._screen_width + if past_edge: + msg = self._get_progress_information_message() + self._tw.write(msg + "\n", **{main_color: True}) + + def _get_progress_information_message(self) -> str: + assert self._session + collected = self._session.testscollected + if self._show_progress_info == "count": + if collected: + progress = self._progress_nodeids_reported + counter_format = "{{:{}d}}".format(len(str(collected))) + format_string = f" [{counter_format}/{{}}]" + return format_string.format(len(progress), collected) + return f" [ {collected} / {collected} ]" + else: + if collected: + return " [{:3d}%]".format( + len(self._progress_nodeids_reported) * 100 // collected + ) + return " [100%]" + + def _write_progress_information_filling_space(self) -> None: + color, _ = self._get_main_color() + msg = self._get_progress_information_message() + w = self._width_of_current_line + fill = self._tw.fullwidth - w - 1 + self.write(msg.rjust(fill), flush=True, **{color: True}) + + @property + def _width_of_current_line(self) -> int: + """Return the width of the current line.""" + return self._tw.width_of_current_line + + def pytest_collection(self) -> None: + if self.isatty: + if self.config.option.verbose >= 0: + self.write("collecting ... ", flush=True, bold=True) + self._collect_report_last_write = timing.time() + elif self.config.option.verbose >= 1: + self.write("collecting ... ", flush=True, bold=True) + + def pytest_collectreport(self, report: CollectReport) -> None: + if report.failed: + self._add_stats("error", [report]) + elif report.skipped: + self._add_stats("skipped", [report]) + items = [x for x in report.result if isinstance(x, Item)] + self._numcollected += len(items) + if self.isatty: + self.report_collect() + + def report_collect(self, final: bool = False) -> None: + if self.config.option.verbose < 0: + return + + if not final: + # Only write "collecting" report every 0.5s. + t = timing.time() + if ( + self._collect_report_last_write is not None + and self._collect_report_last_write > t - REPORT_COLLECTING_RESOLUTION + ): + return + self._collect_report_last_write = t + + errors = len(self.stats.get("error", [])) + skipped = len(self.stats.get("skipped", [])) + deselected = len(self.stats.get("deselected", [])) + selected = self._numcollected - errors - skipped - deselected + if final: + line = "collected " + else: + line = "collecting " + line += ( + str(self._numcollected) + " item" + ("" if self._numcollected == 1 else "s") + ) + if errors: + line += " / %d error%s" % (errors, "s" if errors != 1 else "") + if deselected: + line += " / %d deselected" % deselected + if skipped: + line += " / %d skipped" % skipped + if self._numcollected > selected > 0: + line += " / %d selected" % selected + if self.isatty: + self.rewrite(line, bold=True, erase=True) + if final: + self.write("\n") + else: + self.write_line(line) + + @hookimpl(trylast=True) + def pytest_sessionstart(self, session: "Session") -> None: + self._session = session + self._sessionstarttime = timing.time() + if not self.showheader: + return + self.write_sep("=", "test session starts", bold=True) + verinfo = platform.python_version() + if not self.no_header: + msg = f"platform {sys.platform} -- Python {verinfo}" + pypy_version_info = getattr(sys, "pypy_version_info", None) + if pypy_version_info: + verinfo = ".".join(map(str, pypy_version_info[:3])) + msg += "[pypy-{}-{}]".format(verinfo, pypy_version_info[3]) + msg += ", pytest-{}, py-{}, pluggy-{}".format( + _pytest._version.version, py.__version__, pluggy.__version__ + ) + if ( + self.verbosity > 0 + or self.config.option.debug + or getattr(self.config.option, "pastebin", None) + ): + msg += " -- " + str(sys.executable) + self.write_line(msg) + lines = self.config.hook.pytest_report_header( + config=self.config, startdir=self.startdir + ) + self._write_report_lines_from_hooks(lines) + + def _write_report_lines_from_hooks( + self, lines: Sequence[Union[str, Sequence[str]]] + ) -> None: + for line_or_lines in reversed(lines): + if isinstance(line_or_lines, str): + self.write_line(line_or_lines) + else: + for line in line_or_lines: + self.write_line(line) + + def pytest_report_header(self, config: Config) -> List[str]: + line = "rootdir: %s" % config.rootpath + + if config.inipath: + line += ", configfile: " + bestrelpath(config.rootpath, config.inipath) + + testpaths: List[str] = config.getini("testpaths") + if config.invocation_params.dir == config.rootpath and config.args == testpaths: + line += ", testpaths: {}".format(", ".join(testpaths)) + + result = [line] + + plugininfo = config.pluginmanager.list_plugin_distinfo() + if plugininfo: + result.append("plugins: %s" % ", ".join(_plugin_nameversions(plugininfo))) + return result + + def pytest_collection_finish(self, session: "Session") -> None: + self.report_collect(True) + + lines = self.config.hook.pytest_report_collectionfinish( + config=self.config, startdir=self.startdir, items=session.items + ) + self._write_report_lines_from_hooks(lines) + + if self.config.getoption("collectonly"): + if session.items: + if self.config.option.verbose > -1: + self._tw.line("") + self._printcollecteditems(session.items) + + failed = self.stats.get("failed") + if failed: + self._tw.sep("!", "collection failures") + for rep in failed: + rep.toterminal(self._tw) + + def _printcollecteditems(self, items: Sequence[Item]) -> None: + # To print out items and their parent collectors + # we take care to leave out Instances aka () + # because later versions are going to get rid of them anyway. + if self.config.option.verbose < 0: + if self.config.option.verbose < -1: + counts = Counter(item.nodeid.split("::", 1)[0] for item in items) + for name, count in sorted(counts.items()): + self._tw.line("%s: %d" % (name, count)) + else: + for item in items: + self._tw.line(item.nodeid) + return + stack: List[Node] = [] + indent = "" + for item in items: + needed_collectors = item.listchain()[1:] # strip root node + while stack: + if stack == needed_collectors[: len(stack)]: + break + stack.pop() + for col in needed_collectors[len(stack) :]: + stack.append(col) + if col.name == "()": # Skip Instances. + continue + indent = (len(stack) - 1) * " " + self._tw.line(f"{indent}{col}") + if self.config.option.verbose >= 1: + obj = getattr(col, "obj", None) + doc = inspect.getdoc(obj) if obj else None + if doc: + for line in doc.splitlines(): + self._tw.line("{}{}".format(indent + " ", line)) + + @hookimpl(hookwrapper=True) + def pytest_sessionfinish( + self, session: "Session", exitstatus: Union[int, ExitCode] + ): + outcome = yield + outcome.get_result() + self._tw.line("") + summary_exit_codes = ( + ExitCode.OK, + ExitCode.TESTS_FAILED, + ExitCode.INTERRUPTED, + ExitCode.USAGE_ERROR, + ExitCode.NO_TESTS_COLLECTED, + ) + if exitstatus in summary_exit_codes and not self.no_summary: + self.config.hook.pytest_terminal_summary( + terminalreporter=self, exitstatus=exitstatus, config=self.config + ) + if session.shouldfail: + self.write_sep("!", str(session.shouldfail), red=True) + if exitstatus == ExitCode.INTERRUPTED: + self._report_keyboardinterrupt() + self._keyboardinterrupt_memo = None + elif session.shouldstop: + self.write_sep("!", str(session.shouldstop), red=True) + self.summary_stats() + + @hookimpl(hookwrapper=True) + def pytest_terminal_summary(self) -> Generator[None, None, None]: + self.summary_errors() + self.summary_failures() + self.summary_warnings() + self.summary_passes() + yield + self.short_test_summary() + # Display any extra warnings from teardown here (if any). + self.summary_warnings() + + def pytest_keyboard_interrupt(self, excinfo: ExceptionInfo[BaseException]) -> None: + self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True) + + def pytest_unconfigure(self) -> None: + if self._keyboardinterrupt_memo is not None: + self._report_keyboardinterrupt() + + def _report_keyboardinterrupt(self) -> None: + excrepr = self._keyboardinterrupt_memo + assert excrepr is not None + assert excrepr.reprcrash is not None + msg = excrepr.reprcrash.message + self.write_sep("!", msg) + if "KeyboardInterrupt" in msg: + if self.config.option.fulltrace: + excrepr.toterminal(self._tw) + else: + excrepr.reprcrash.toterminal(self._tw) + self._tw.line( + "(to show a full traceback on KeyboardInterrupt use --full-trace)", + yellow=True, + ) + + def _locationline(self, nodeid, fspath, lineno, domain): + def mkrel(nodeid): + line = self.config.cwd_relative_nodeid(nodeid) + if domain and line.endswith(domain): + line = line[: -len(domain)] + values = domain.split("[") + values[0] = values[0].replace(".", "::") # don't replace '.' in params + line += "[".join(values) + return line + + # collect_fspath comes from testid which has a "/"-normalized path. + + if fspath: + res = mkrel(nodeid) + if self.verbosity >= 2 and nodeid.split("::")[0] != fspath.replace( + "\\", nodes.SEP + ): + res += " <- " + bestrelpath(self.startpath, fspath) + else: + res = "[location]" + return res + " " + + def _getfailureheadline(self, rep): + head_line = rep.head_line + if head_line: + return head_line + return "test session" # XXX? + + def _getcrashline(self, rep): + try: + return str(rep.longrepr.reprcrash) + except AttributeError: + try: + return str(rep.longrepr)[:50] + except AttributeError: + return "" + + # + # Summaries for sessionfinish. + # + def getreports(self, name: str): + values = [] + for x in self.stats.get(name, []): + if not hasattr(x, "_pdbshown"): + values.append(x) + return values + + def summary_warnings(self) -> None: + if self.hasopt("w"): + all_warnings: Optional[List[WarningReport]] = self.stats.get("warnings") + if not all_warnings: + return + + final = self._already_displayed_warnings is not None + if final: + warning_reports = all_warnings[self._already_displayed_warnings :] + else: + warning_reports = all_warnings + self._already_displayed_warnings = len(warning_reports) + if not warning_reports: + return + + reports_grouped_by_message: Dict[str, List[WarningReport]] = {} + for wr in warning_reports: + reports_grouped_by_message.setdefault(wr.message, []).append(wr) + + def collapsed_location_report(reports: List[WarningReport]) -> str: + locations = [] + for w in reports: + location = w.get_location(self.config) + if location: + locations.append(location) + + if len(locations) < 10: + return "\n".join(map(str, locations)) + + counts_by_filename = Counter( + str(loc).split("::", 1)[0] for loc in locations + ) + return "\n".join( + "{}: {} warning{}".format(k, v, "s" if v > 1 else "") + for k, v in counts_by_filename.items() + ) + + title = "warnings summary (final)" if final else "warnings summary" + self.write_sep("=", title, yellow=True, bold=False) + for message, message_reports in reports_grouped_by_message.items(): + maybe_location = collapsed_location_report(message_reports) + if maybe_location: + self._tw.line(maybe_location) + lines = message.splitlines() + indented = "\n".join(" " + x for x in lines) + message = indented.rstrip() + else: + message = message.rstrip() + self._tw.line(message) + self._tw.line() + self._tw.line("-- Docs: https://docs.pytest.org/en/stable/warnings.html") + + def summary_passes(self) -> None: + if self.config.option.tbstyle != "no": + if self.hasopt("P"): + reports: List[TestReport] = self.getreports("passed") + if not reports: + return + self.write_sep("=", "PASSES") + for rep in reports: + if rep.sections: + msg = self._getfailureheadline(rep) + self.write_sep("_", msg, green=True, bold=True) + self._outrep_summary(rep) + self._handle_teardown_sections(rep.nodeid) + + def _get_teardown_reports(self, nodeid: str) -> List[TestReport]: + reports = self.getreports("") + return [ + report + for report in reports + if report.when == "teardown" and report.nodeid == nodeid + ] + + def _handle_teardown_sections(self, nodeid: str) -> None: + for report in self._get_teardown_reports(nodeid): + self.print_teardown_sections(report) + + def print_teardown_sections(self, rep: TestReport) -> None: + showcapture = self.config.option.showcapture + if showcapture == "no": + return + for secname, content in rep.sections: + if showcapture != "all" and showcapture not in secname: + continue + if "teardown" in secname: + self._tw.sep("-", secname) + if content[-1:] == "\n": + content = content[:-1] + self._tw.line(content) + + def summary_failures(self) -> None: + if self.config.option.tbstyle != "no": + reports: List[BaseReport] = self.getreports("failed") + if not reports: + return + self.write_sep("=", "FAILURES") + if self.config.option.tbstyle == "line": + for rep in reports: + line = self._getcrashline(rep) + self.write_line(line) + else: + for rep in reports: + msg = self._getfailureheadline(rep) + self.write_sep("_", msg, red=True, bold=True) + self._outrep_summary(rep) + self._handle_teardown_sections(rep.nodeid) + + def summary_errors(self) -> None: + if self.config.option.tbstyle != "no": + reports: List[BaseReport] = self.getreports("error") + if not reports: + return + self.write_sep("=", "ERRORS") + for rep in self.stats["error"]: + msg = self._getfailureheadline(rep) + if rep.when == "collect": + msg = "ERROR collecting " + msg + else: + msg = f"ERROR at {rep.when} of {msg}" + self.write_sep("_", msg, red=True, bold=True) + self._outrep_summary(rep) + + def _outrep_summary(self, rep: BaseReport) -> None: + rep.toterminal(self._tw) + showcapture = self.config.option.showcapture + if showcapture == "no": + return + for secname, content in rep.sections: + if showcapture != "all" and showcapture not in secname: + continue + self._tw.sep("-", secname) + if content[-1:] == "\n": + content = content[:-1] + self._tw.line(content) + + def summary_stats(self) -> None: + if self.verbosity < -1: + return + + session_duration = timing.time() - self._sessionstarttime + (parts, main_color) = self.build_summary_stats_line() + line_parts = [] + + display_sep = self.verbosity >= 0 + if display_sep: + fullwidth = self._tw.fullwidth + for text, markup in parts: + with_markup = self._tw.markup(text, **markup) + if display_sep: + fullwidth += len(with_markup) - len(text) + line_parts.append(with_markup) + msg = ", ".join(line_parts) + + main_markup = {main_color: True} + duration = " in {}".format(format_session_duration(session_duration)) + duration_with_markup = self._tw.markup(duration, **main_markup) + if display_sep: + fullwidth += len(duration_with_markup) - len(duration) + msg += duration_with_markup + + if display_sep: + markup_for_end_sep = self._tw.markup("", **main_markup) + if markup_for_end_sep.endswith("\x1b[0m"): + markup_for_end_sep = markup_for_end_sep[:-4] + fullwidth += len(markup_for_end_sep) + msg += markup_for_end_sep + + if display_sep: + self.write_sep("=", msg, fullwidth=fullwidth, **main_markup) + else: + self.write_line(msg, **main_markup) + + def short_test_summary(self) -> None: + if not self.reportchars: + return + + def show_simple(stat, lines: List[str]) -> None: + failed = self.stats.get(stat, []) + if not failed: + return + termwidth = self._tw.fullwidth + config = self.config + for rep in failed: + line = _get_line_with_reprcrash_message(config, rep, termwidth) + lines.append(line) + + def show_xfailed(lines: List[str]) -> None: + xfailed = self.stats.get("xfailed", []) + for rep in xfailed: + verbose_word = rep._get_verbose_word(self.config) + pos = _get_pos(self.config, rep) + lines.append(f"{verbose_word} {pos}") + reason = rep.wasxfail + if reason: + lines.append(" " + str(reason)) + + def show_xpassed(lines: List[str]) -> None: + xpassed = self.stats.get("xpassed", []) + for rep in xpassed: + verbose_word = rep._get_verbose_word(self.config) + pos = _get_pos(self.config, rep) + reason = rep.wasxfail + lines.append(f"{verbose_word} {pos} {reason}") + + def show_skipped(lines: List[str]) -> None: + skipped: List[CollectReport] = self.stats.get("skipped", []) + fskips = _folded_skips(self.startpath, skipped) if skipped else [] + if not fskips: + return + verbose_word = skipped[0]._get_verbose_word(self.config) + for num, fspath, lineno, reason in fskips: + if reason.startswith("Skipped: "): + reason = reason[9:] + if lineno is not None: + lines.append( + "%s [%d] %s:%d: %s" + % (verbose_word, num, fspath, lineno, reason) + ) + else: + lines.append("%s [%d] %s: %s" % (verbose_word, num, fspath, reason)) + + REPORTCHAR_ACTIONS: Mapping[str, Callable[[List[str]], None]] = { + "x": show_xfailed, + "X": show_xpassed, + "f": partial(show_simple, "failed"), + "s": show_skipped, + "p": partial(show_simple, "passed"), + "E": partial(show_simple, "error"), + } + + lines: List[str] = [] + for char in self.reportchars: + action = REPORTCHAR_ACTIONS.get(char) + if action: # skipping e.g. "P" (passed with output) here. + action(lines) + + if lines: + self.write_sep("=", "short test summary info") + for line in lines: + self.write_line(line) + + def _get_main_color(self) -> Tuple[str, List[str]]: + if self._main_color is None or self._known_types is None or self._is_last_item: + self._set_main_color() + assert self._main_color + assert self._known_types + return self._main_color, self._known_types + + def _determine_main_color(self, unknown_type_seen: bool) -> str: + stats = self.stats + if "failed" in stats or "error" in stats: + main_color = "red" + elif "warnings" in stats or "xpassed" in stats or unknown_type_seen: + main_color = "yellow" + elif "passed" in stats or not self._is_last_item: + main_color = "green" + else: + main_color = "yellow" + return main_color + + def _set_main_color(self) -> None: + unknown_types: List[str] = [] + for found_type in self.stats.keys(): + if found_type: # setup/teardown reports have an empty key, ignore them + if found_type not in KNOWN_TYPES and found_type not in unknown_types: + unknown_types.append(found_type) + self._known_types = list(KNOWN_TYPES) + unknown_types + self._main_color = self._determine_main_color(bool(unknown_types)) + + def build_summary_stats_line(self) -> Tuple[List[Tuple[str, Dict[str, bool]]], str]: + """ + Build the parts used in the last summary stats line. + + The summary stats line is the line shown at the end, "=== 12 passed, 2 errors in Xs===". + + This function builds a list of the "parts" that make up for the text in that line, in + the example above it would be: + + [ + ("12 passed", {"green": True}), + ("2 errors", {"red": True} + ] + + That last dict for each line is a "markup dictionary", used by TerminalWriter to + color output. + + The final color of the line is also determined by this function, and is the second + element of the returned tuple. + """ + if self.config.getoption("collectonly"): + return self._build_collect_only_summary_stats_line() + else: + return self._build_normal_summary_stats_line() + + def _get_reports_to_display(self, key: str) -> List[Any]: + """Get test/collection reports for the given status key, such as `passed` or `error`.""" + reports = self.stats.get(key, []) + return [x for x in reports if getattr(x, "count_towards_summary", True)] + + def _build_normal_summary_stats_line( + self, + ) -> Tuple[List[Tuple[str, Dict[str, bool]]], str]: + main_color, known_types = self._get_main_color() + parts = [] + + for key in known_types: + reports = self._get_reports_to_display(key) + if reports: + count = len(reports) + color = _color_for_type.get(key, _color_for_type_default) + markup = {color: True, "bold": color == main_color} + parts.append(("%d %s" % pluralize(count, key), markup)) + + if not parts: + parts = [("no tests ran", {_color_for_type_default: True})] + + return parts, main_color + + def _build_collect_only_summary_stats_line( + self, + ) -> Tuple[List[Tuple[str, Dict[str, bool]]], str]: + deselected = len(self._get_reports_to_display("deselected")) + errors = len(self._get_reports_to_display("error")) + + if self._numcollected == 0: + parts = [("no tests collected", {"yellow": True})] + main_color = "yellow" + + elif deselected == 0: + main_color = "green" + collected_output = "%d %s collected" % pluralize(self._numcollected, "test") + parts = [(collected_output, {main_color: True})] + else: + all_tests_were_deselected = self._numcollected == deselected + if all_tests_were_deselected: + main_color = "yellow" + collected_output = f"no tests collected ({deselected} deselected)" + else: + main_color = "green" + selected = self._numcollected - deselected + collected_output = f"{selected}/{self._numcollected} tests collected ({deselected} deselected)" + + parts = [(collected_output, {main_color: True})] + + if errors: + main_color = _color_for_type["error"] + parts += [("%d %s" % pluralize(errors, "error"), {main_color: True})] + + return parts, main_color + + +def _get_pos(config: Config, rep: BaseReport): + nodeid = config.cwd_relative_nodeid(rep.nodeid) + return nodeid + + +def _format_trimmed(format: str, msg: str, available_width: int) -> Optional[str]: + """Format msg into format, ellipsizing it if doesn't fit in available_width. + + Returns None if even the ellipsis can't fit. + """ + # Only use the first line. + i = msg.find("\n") + if i != -1: + msg = msg[:i] + + ellipsis = "..." + format_width = wcswidth(format.format("")) + if format_width + len(ellipsis) > available_width: + return None + + if format_width + wcswidth(msg) > available_width: + available_width -= len(ellipsis) + msg = msg[:available_width] + while format_width + wcswidth(msg) > available_width: + msg = msg[:-1] + msg += ellipsis + + return format.format(msg) + + +def _get_line_with_reprcrash_message( + config: Config, rep: BaseReport, termwidth: int +) -> str: + """Get summary line for a report, trying to add reprcrash message.""" + verbose_word = rep._get_verbose_word(config) + pos = _get_pos(config, rep) + + line = f"{verbose_word} {pos}" + line_width = wcswidth(line) + + try: + # Type ignored intentionally -- possible AttributeError expected. + msg = rep.longrepr.reprcrash.message # type: ignore[union-attr] + except AttributeError: + pass + else: + available_width = termwidth - line_width + msg = _format_trimmed(" - {}", msg, available_width) + if msg is not None: + line += msg + + return line + + +def _folded_skips( + startpath: Path, skipped: Sequence[CollectReport], +) -> List[Tuple[int, str, Optional[int], str]]: + d: Dict[Tuple[str, Optional[int], str], List[CollectReport]] = {} + for event in skipped: + assert event.longrepr is not None + assert isinstance(event.longrepr, tuple), (event, event.longrepr) + assert len(event.longrepr) == 3, (event, event.longrepr) + fspath, lineno, reason = event.longrepr + # For consistency, report all fspaths in relative form. + fspath = bestrelpath(startpath, Path(fspath)) + keywords = getattr(event, "keywords", {}) + # Folding reports with global pytestmark variable. + # This is a workaround, because for now we cannot identify the scope of a skip marker + # TODO: Revisit after marks scope would be fixed. + if ( + event.when == "setup" + and "skip" in keywords + and "pytestmark" not in keywords + ): + key: Tuple[str, Optional[int], str] = (fspath, None, reason) + else: + key = (fspath, lineno, reason) + d.setdefault(key, []).append(event) + values: List[Tuple[int, str, Optional[int], str]] = [] + for key, events in d.items(): + values.append((len(events), *key)) + return values + + +_color_for_type = { + "failed": "red", + "error": "red", + "warnings": "yellow", + "passed": "green", +} +_color_for_type_default = "yellow" + + +def pluralize(count: int, noun: str) -> Tuple[int, str]: + # No need to pluralize words such as `failed` or `passed`. + if noun not in ["error", "warnings", "test"]: + return count, noun + + # The `warnings` key is plural. To avoid API breakage, we keep it that way but + # set it to singular here so we can determine plurality in the same way as we do + # for `error`. + noun = noun.replace("warnings", "warning") + + return count, noun + "s" if count != 1 else noun + + +def _plugin_nameversions(plugininfo) -> List[str]: + values: List[str] = [] + for plugin, dist in plugininfo: + # Gets us name and version! + name = "{dist.project_name}-{dist.version}".format(dist=dist) + # Questionable convenience, but it keeps things short. + if name.startswith("pytest-"): + name = name[7:] + # We decided to print python package names they can have more than one plugin. + if name not in values: + values.append(name) + return values + + +def format_session_duration(seconds: float) -> str: + """Format the given seconds in a human readable manner to show in the final summary.""" + if seconds < 60: + return f"{seconds:.2f}s" + else: + dt = datetime.timedelta(seconds=int(seconds)) + return f"{seconds:.2f}s ({dt})" + + +def _get_raw_skip_reason(report: TestReport) -> str: + """Get the reason string of a skip/xfail/xpass test report. + + The string is just the part given by the user. + """ + if hasattr(report, "wasxfail"): + reason = cast(str, report.wasxfail) + if reason.startswith("reason: "): + reason = reason[len("reason: ") :] + return reason + else: + assert report.skipped + assert isinstance(report.longrepr, tuple) + _, _, reason = report.longrepr + if reason.startswith("Skipped: "): + reason = reason[len("Skipped: ") :] + elif reason == "Skipped": + reason = "" + return reason diff --git a/myenv/lib/python3.9/site-packages/_pytest/threadexception.py b/myenv/lib/python3.9/site-packages/_pytest/threadexception.py new file mode 100644 index 0000000..1c1f62f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/threadexception.py @@ -0,0 +1,90 @@ +import threading +import traceback +import warnings +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Generator +from typing import Optional +from typing import Type + +import pytest + + +# Copied from cpython/Lib/test/support/threading_helper.py, with modifications. +class catch_threading_exception: + """Context manager catching threading.Thread exception using + threading.excepthook. + + Storing exc_value using a custom hook can create a reference cycle. The + reference cycle is broken explicitly when the context manager exits. + + Storing thread using a custom hook can resurrect it if it is set to an + object which is being finalized. Exiting the context manager clears the + stored object. + + Usage: + with threading_helper.catch_threading_exception() as cm: + # code spawning a thread which raises an exception + ... + # check the thread exception: use cm.args + ... + # cm.args attribute no longer exists at this point + # (to break a reference cycle) + """ + + def __init__(self) -> None: + # See https://github.com/python/typeshed/issues/4767 regarding the underscore. + self.args: Optional["threading._ExceptHookArgs"] = None + self._old_hook: Optional[Callable[["threading._ExceptHookArgs"], Any]] = None + + def _hook(self, args: "threading._ExceptHookArgs") -> None: + self.args = args + + def __enter__(self) -> "catch_threading_exception": + self._old_hook = threading.excepthook + threading.excepthook = self._hook + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + assert self._old_hook is not None + threading.excepthook = self._old_hook + self._old_hook = None + del self.args + + +def thread_exception_runtest_hook() -> Generator[None, None, None]: + with catch_threading_exception() as cm: + yield + if cm.args: + if cm.args.thread is not None: + thread_name = cm.args.thread.name + else: + thread_name = "" + msg = f"Exception in thread {thread_name}\n\n" + msg += "".join( + traceback.format_exception( + cm.args.exc_type, cm.args.exc_value, cm.args.exc_traceback, + ) + ) + warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg)) + + +@pytest.hookimpl(hookwrapper=True, trylast=True) +def pytest_runtest_setup() -> Generator[None, None, None]: + yield from thread_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_call() -> Generator[None, None, None]: + yield from thread_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_teardown() -> Generator[None, None, None]: + yield from thread_exception_runtest_hook() diff --git a/myenv/lib/python3.9/site-packages/_pytest/timing.py b/myenv/lib/python3.9/site-packages/_pytest/timing.py new file mode 100644 index 0000000..925163a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/timing.py @@ -0,0 +1,12 @@ +"""Indirection for time functions. + +We intentionally grab some "time" functions internally to avoid tests mocking "time" to affect +pytest runtime information (issue #185). + +Fixture "mock_timing" also interacts with this module for pytest's own tests. +""" +from time import perf_counter +from time import sleep +from time import time + +__all__ = ["perf_counter", "sleep", "time"] diff --git a/myenv/lib/python3.9/site-packages/_pytest/tmpdir.py b/myenv/lib/python3.9/site-packages/_pytest/tmpdir.py new file mode 100644 index 0000000..a6bd383 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/tmpdir.py @@ -0,0 +1,254 @@ +"""Support for providing temporary directories to test functions.""" +import os +import re +import sys +import tempfile +from pathlib import Path +from typing import Optional + +import attr +import py + +from .pathlib import LOCK_TIMEOUT +from .pathlib import make_numbered_dir +from .pathlib import make_numbered_dir_with_cleanup +from .pathlib import rm_rf +from _pytest.compat import final +from _pytest.config import Config +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.monkeypatch import MonkeyPatch + + +@final +@attr.s(init=False) +class TempPathFactory: + """Factory for temporary directories under the common base temp directory. + + The base directory can be configured using the ``--basetemp`` option. + """ + + _given_basetemp = attr.ib(type=Optional[Path]) + _trace = attr.ib() + _basetemp = attr.ib(type=Optional[Path]) + + def __init__( + self, + given_basetemp: Optional[Path], + trace, + basetemp: Optional[Path] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + if given_basetemp is None: + self._given_basetemp = None + else: + # Use os.path.abspath() to get absolute path instead of resolve() as it + # does not work the same in all platforms (see #4427). + # Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012). + self._given_basetemp = Path(os.path.abspath(str(given_basetemp))) + self._trace = trace + self._basetemp = basetemp + + @classmethod + def from_config( + cls, config: Config, *, _ispytest: bool = False, + ) -> "TempPathFactory": + """Create a factory according to pytest configuration. + + :meta private: + """ + check_ispytest(_ispytest) + return cls( + given_basetemp=config.option.basetemp, + trace=config.trace.get("tmpdir"), + _ispytest=True, + ) + + def _ensure_relative_to_basetemp(self, basename: str) -> str: + basename = os.path.normpath(basename) + if (self.getbasetemp() / basename).resolve().parent != self.getbasetemp(): + raise ValueError(f"{basename} is not a normalized and relative path") + return basename + + def mktemp(self, basename: str, numbered: bool = True) -> Path: + """Create a new temporary directory managed by the factory. + + :param basename: + Directory base name, must be a relative path. + + :param numbered: + If ``True``, ensure the directory is unique by adding a numbered + suffix greater than any existing one: ``basename="foo-"`` and ``numbered=True`` + means that this function will create directories named ``"foo-0"``, + ``"foo-1"``, ``"foo-2"`` and so on. + + :returns: + The path to the new directory. + """ + basename = self._ensure_relative_to_basetemp(basename) + if not numbered: + p = self.getbasetemp().joinpath(basename) + p.mkdir(mode=0o700) + else: + p = make_numbered_dir(root=self.getbasetemp(), prefix=basename, mode=0o700) + self._trace("mktemp", p) + return p + + def getbasetemp(self) -> Path: + """Return the base temporary directory, creating it if needed.""" + if self._basetemp is not None: + return self._basetemp + + if self._given_basetemp is not None: + basetemp = self._given_basetemp + if basetemp.exists(): + rm_rf(basetemp) + basetemp.mkdir(mode=0o700) + basetemp = basetemp.resolve() + else: + from_env = os.environ.get("PYTEST_DEBUG_TEMPROOT") + temproot = Path(from_env or tempfile.gettempdir()).resolve() + user = get_user() or "unknown" + # use a sub-directory in the temproot to speed-up + # make_numbered_dir() call + rootdir = temproot.joinpath(f"pytest-of-{user}") + rootdir.mkdir(mode=0o700, exist_ok=True) + # Because we use exist_ok=True with a predictable name, make sure + # we are the owners, to prevent any funny business (on unix, where + # temproot is usually shared). + # Also, to keep things private, fixup any world-readable temp + # rootdir's permissions. Historically 0o755 was used, so we can't + # just error out on this, at least for a while. + if sys.platform != "win32": + uid = os.getuid() + rootdir_stat = rootdir.stat() + # getuid shouldn't fail, but cpython defines such a case. + # Let's hope for the best. + if uid != -1: + if rootdir_stat.st_uid != uid: + raise OSError( + f"The temporary directory {rootdir} is not owned by the current user. " + "Fix this and try again." + ) + if (rootdir_stat.st_mode & 0o077) != 0: + os.chmod(rootdir, rootdir_stat.st_mode & ~0o077) + basetemp = make_numbered_dir_with_cleanup( + prefix="pytest-", + root=rootdir, + keep=3, + lock_timeout=LOCK_TIMEOUT, + mode=0o700, + ) + assert basetemp is not None, basetemp + self._basetemp = basetemp + self._trace("new basetemp", basetemp) + return basetemp + + +@final +@attr.s(init=False) +class TempdirFactory: + """Backward comptibility wrapper that implements :class:``py.path.local`` + for :class:``TempPathFactory``.""" + + _tmppath_factory = attr.ib(type=TempPathFactory) + + def __init__( + self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False + ) -> None: + check_ispytest(_ispytest) + self._tmppath_factory = tmppath_factory + + def mktemp(self, basename: str, numbered: bool = True) -> py.path.local: + """Same as :meth:`TempPathFactory.mktemp`, but returns a ``py.path.local`` object.""" + return py.path.local(self._tmppath_factory.mktemp(basename, numbered).resolve()) + + def getbasetemp(self) -> py.path.local: + """Backward compat wrapper for ``_tmppath_factory.getbasetemp``.""" + return py.path.local(self._tmppath_factory.getbasetemp().resolve()) + + +def get_user() -> Optional[str]: + """Return the current user name, or None if getuser() does not work + in the current environment (see #1010).""" + import getpass + + try: + return getpass.getuser() + except (ImportError, KeyError): + return None + + +def pytest_configure(config: Config) -> None: + """Create a TempdirFactory and attach it to the config object. + + This is to comply with existing plugins which expect the handler to be + available at pytest_configure time, but ideally should be moved entirely + to the tmpdir_factory session fixture. + """ + mp = MonkeyPatch() + tmppath_handler = TempPathFactory.from_config(config, _ispytest=True) + t = TempdirFactory(tmppath_handler, _ispytest=True) + config._cleanup.append(mp.undo) + mp.setattr(config, "_tmp_path_factory", tmppath_handler, raising=False) + mp.setattr(config, "_tmpdirhandler", t, raising=False) + + +@fixture(scope="session") +def tmpdir_factory(request: FixtureRequest) -> TempdirFactory: + """Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.""" + # Set dynamically by pytest_configure() above. + return request.config._tmpdirhandler # type: ignore + + +@fixture(scope="session") +def tmp_path_factory(request: FixtureRequest) -> TempPathFactory: + """Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.""" + # Set dynamically by pytest_configure() above. + return request.config._tmp_path_factory # type: ignore + + +def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path: + name = request.node.name + name = re.sub(r"[\W]", "_", name) + MAXVAL = 30 + name = name[:MAXVAL] + return factory.mktemp(name, numbered=True) + + +@fixture +def tmpdir(tmp_path: Path) -> py.path.local: + """Return a temporary directory path object which is unique to each test + function invocation, created as a sub directory of the base temporary + directory. + + By default, a new base temporary directory is created each test session, + and old bases are removed after 3 sessions, to aid in debugging. If + ``--basetemp`` is used then it is cleared each session. See :ref:`base + temporary directory`. + + The returned object is a `py.path.local`_ path object. + + .. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html + """ + return py.path.local(tmp_path) + + +@fixture +def tmp_path(request: FixtureRequest, tmp_path_factory: TempPathFactory) -> Path: + """Return a temporary directory path object which is unique to each test + function invocation, created as a sub directory of the base temporary + directory. + + By default, a new base temporary directory is created each test session, + and old bases are removed after 3 sessions, to aid in debugging. If + ``--basetemp`` is used then it is cleared each session. See :ref:`base + temporary directory`. + + The returned object is a :class:`pathlib.Path` object. + """ + + return _mk_tmp(request, tmp_path_factory) diff --git a/myenv/lib/python3.9/site-packages/_pytest/unittest.py b/myenv/lib/python3.9/site-packages/_pytest/unittest.py new file mode 100644 index 0000000..55f15ef --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/unittest.py @@ -0,0 +1,405 @@ +"""Discover and run std-library "unittest" style tests.""" +import sys +import traceback +import types +from typing import Any +from typing import Callable +from typing import Generator +from typing import Iterable +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +import _pytest._code +import pytest +from _pytest.compat import getimfunc +from _pytest.compat import is_async_function +from _pytest.config import hookimpl +from _pytest.fixtures import FixtureRequest +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.outcomes import exit +from _pytest.outcomes import fail +from _pytest.outcomes import skip +from _pytest.outcomes import xfail +from _pytest.python import Class +from _pytest.python import Function +from _pytest.python import PyCollector +from _pytest.runner import CallInfo +from _pytest.skipping import skipped_by_mark_key +from _pytest.skipping import unexpectedsuccess_key + +if TYPE_CHECKING: + import unittest + + from _pytest.fixtures import _Scope + + _SysExcInfoType = Union[ + Tuple[Type[BaseException], BaseException, types.TracebackType], + Tuple[None, None, None], + ] + + +def pytest_pycollect_makeitem( + collector: PyCollector, name: str, obj: object +) -> Optional["UnitTestCase"]: + # Has unittest been imported and is obj a subclass of its TestCase? + try: + ut = sys.modules["unittest"] + # Type ignored because `ut` is an opaque module. + if not issubclass(obj, ut.TestCase): # type: ignore + return None + except Exception: + return None + # Yes, so let's collect it. + item: UnitTestCase = UnitTestCase.from_parent(collector, name=name, obj=obj) + return item + + +class UnitTestCase(Class): + # Marker for fixturemanger.getfixtureinfo() + # to declare that our children do not support funcargs. + nofuncargs = True + + def collect(self) -> Iterable[Union[Item, Collector]]: + from unittest import TestLoader + + cls = self.obj + if not getattr(cls, "__test__", True): + return + + skipped = _is_skipped(cls) + if not skipped: + self._inject_setup_teardown_fixtures(cls) + self._inject_setup_class_fixture() + + self.session._fixturemanager.parsefactories(self, unittest=True) + loader = TestLoader() + foundsomething = False + for name in loader.getTestCaseNames(self.obj): + x = getattr(self.obj, name) + if not getattr(x, "__test__", True): + continue + funcobj = getimfunc(x) + yield TestCaseFunction.from_parent(self, name=name, callobj=funcobj) + foundsomething = True + + if not foundsomething: + runtest = getattr(self.obj, "runTest", None) + if runtest is not None: + ut = sys.modules.get("twisted.trial.unittest", None) + # Type ignored because `ut` is an opaque module. + if ut is None or runtest != ut.TestCase.runTest: # type: ignore + yield TestCaseFunction.from_parent(self, name="runTest") + + def _inject_setup_teardown_fixtures(self, cls: type) -> None: + """Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding + teardown functions (#517).""" + class_fixture = _make_xunit_fixture( + cls, + "setUpClass", + "tearDownClass", + "doClassCleanups", + scope="class", + pass_self=False, + ) + if class_fixture: + cls.__pytest_class_setup = class_fixture # type: ignore[attr-defined] + + method_fixture = _make_xunit_fixture( + cls, + "setup_method", + "teardown_method", + None, + scope="function", + pass_self=True, + ) + if method_fixture: + cls.__pytest_method_setup = method_fixture # type: ignore[attr-defined] + + +def _make_xunit_fixture( + obj: type, + setup_name: str, + teardown_name: str, + cleanup_name: Optional[str], + scope: "_Scope", + pass_self: bool, +): + setup = getattr(obj, setup_name, None) + teardown = getattr(obj, teardown_name, None) + if setup is None and teardown is None: + return None + + if cleanup_name: + cleanup = getattr(obj, cleanup_name, lambda *args: None) + else: + + def cleanup(*args): + pass + + @pytest.fixture( + scope=scope, + autouse=True, + # Use a unique name to speed up lookup. + name=f"unittest_{setup_name}_fixture_{obj.__qualname__}", + ) + def fixture(self, request: FixtureRequest) -> Generator[None, None, None]: + if _is_skipped(self): + reason = self.__unittest_skip_why__ + pytest.skip(reason) + if setup is not None: + try: + if pass_self: + setup(self, request.function) + else: + setup() + # unittest does not call the cleanup function for every BaseException, so we + # follow this here. + except Exception: + if pass_self: + cleanup(self) + else: + cleanup() + + raise + yield + try: + if teardown is not None: + if pass_self: + teardown(self, request.function) + else: + teardown() + finally: + if pass_self: + cleanup(self) + else: + cleanup() + + return fixture + + +class TestCaseFunction(Function): + nofuncargs = True + _excinfo: Optional[List[_pytest._code.ExceptionInfo[BaseException]]] = None + _testcase: Optional["unittest.TestCase"] = None + + def setup(self) -> None: + # A bound method to be called during teardown() if set (see 'runtest()'). + self._explicit_tearDown: Optional[Callable[[], None]] = None + assert self.parent is not None + self._testcase = self.parent.obj(self.name) # type: ignore[attr-defined] + self._obj = getattr(self._testcase, self.name) + if hasattr(self, "_request"): + self._request._fillfixtures() + + def teardown(self) -> None: + if self._explicit_tearDown is not None: + self._explicit_tearDown() + self._explicit_tearDown = None + self._testcase = None + self._obj = None + + def startTest(self, testcase: "unittest.TestCase") -> None: + pass + + def _addexcinfo(self, rawexcinfo: "_SysExcInfoType") -> None: + # Unwrap potential exception info (see twisted trial support below). + rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo) + try: + excinfo = _pytest._code.ExceptionInfo(rawexcinfo) # type: ignore[arg-type] + # Invoke the attributes to trigger storing the traceback + # trial causes some issue there. + excinfo.value + excinfo.traceback + except TypeError: + try: + try: + values = traceback.format_exception(*rawexcinfo) + values.insert( + 0, + "NOTE: Incompatible Exception Representation, " + "displaying natively:\n\n", + ) + fail("".join(values), pytrace=False) + except (fail.Exception, KeyboardInterrupt): + raise + except BaseException: + fail( + "ERROR: Unknown Incompatible Exception " + "representation:\n%r" % (rawexcinfo,), + pytrace=False, + ) + except KeyboardInterrupt: + raise + except fail.Exception: + excinfo = _pytest._code.ExceptionInfo.from_current() + self.__dict__.setdefault("_excinfo", []).append(excinfo) + + def addError( + self, testcase: "unittest.TestCase", rawexcinfo: "_SysExcInfoType" + ) -> None: + try: + if isinstance(rawexcinfo[1], exit.Exception): + exit(rawexcinfo[1].msg) + except TypeError: + pass + self._addexcinfo(rawexcinfo) + + def addFailure( + self, testcase: "unittest.TestCase", rawexcinfo: "_SysExcInfoType" + ) -> None: + self._addexcinfo(rawexcinfo) + + def addSkip(self, testcase: "unittest.TestCase", reason: str) -> None: + try: + skip(reason) + except skip.Exception: + self._store[skipped_by_mark_key] = True + self._addexcinfo(sys.exc_info()) + + def addExpectedFailure( + self, + testcase: "unittest.TestCase", + rawexcinfo: "_SysExcInfoType", + reason: str = "", + ) -> None: + try: + xfail(str(reason)) + except xfail.Exception: + self._addexcinfo(sys.exc_info()) + + def addUnexpectedSuccess( + self, testcase: "unittest.TestCase", reason: str = "" + ) -> None: + self._store[unexpectedsuccess_key] = reason + + def addSuccess(self, testcase: "unittest.TestCase") -> None: + pass + + def stopTest(self, testcase: "unittest.TestCase") -> None: + pass + + def _expecting_failure(self, test_method) -> bool: + """Return True if the given unittest method (or the entire class) is marked + with @expectedFailure.""" + expecting_failure_method = getattr( + test_method, "__unittest_expecting_failure__", False + ) + expecting_failure_class = getattr(self, "__unittest_expecting_failure__", False) + return bool(expecting_failure_class or expecting_failure_method) + + def runtest(self) -> None: + from _pytest.debugging import maybe_wrap_pytest_function_for_tracing + + assert self._testcase is not None + + maybe_wrap_pytest_function_for_tracing(self) + + # Let the unittest framework handle async functions. + if is_async_function(self.obj): + # Type ignored because self acts as the TestResult, but is not actually one. + self._testcase(result=self) # type: ignore[arg-type] + else: + # When --pdb is given, we want to postpone calling tearDown() otherwise + # when entering the pdb prompt, tearDown() would have probably cleaned up + # instance variables, which makes it difficult to debug. + # Arguably we could always postpone tearDown(), but this changes the moment where the + # TestCase instance interacts with the results object, so better to only do it + # when absolutely needed. + if self.config.getoption("usepdb") and not _is_skipped(self.obj): + self._explicit_tearDown = self._testcase.tearDown + setattr(self._testcase, "tearDown", lambda *args: None) + + # We need to update the actual bound method with self.obj, because + # wrap_pytest_function_for_tracing replaces self.obj by a wrapper. + setattr(self._testcase, self.name, self.obj) + try: + self._testcase(result=self) # type: ignore[arg-type] + finally: + delattr(self._testcase, self.name) + + def _prunetraceback( + self, excinfo: _pytest._code.ExceptionInfo[BaseException] + ) -> None: + Function._prunetraceback(self, excinfo) + traceback = excinfo.traceback.filter( + lambda x: not x.frame.f_globals.get("__unittest") + ) + if traceback: + excinfo.traceback = traceback + + +@hookimpl(tryfirst=True) +def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None: + if isinstance(item, TestCaseFunction): + if item._excinfo: + call.excinfo = item._excinfo.pop(0) + try: + del call.result + except AttributeError: + pass + + unittest = sys.modules.get("unittest") + if ( + unittest + and call.excinfo + and isinstance(call.excinfo.value, unittest.SkipTest) # type: ignore[attr-defined] + ): + excinfo = call.excinfo + # Let's substitute the excinfo with a pytest.skip one. + call2 = CallInfo[None].from_call( + lambda: pytest.skip(str(excinfo.value)), call.when + ) + call.excinfo = call2.excinfo + + +# Twisted trial support. + + +@hookimpl(hookwrapper=True) +def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]: + if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules: + ut: Any = sys.modules["twisted.python.failure"] + Failure__init__ = ut.Failure.__init__ + check_testcase_implements_trial_reporter() + + def excstore( + self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None + ): + if exc_value is None: + self._rawexcinfo = sys.exc_info() + else: + if exc_type is None: + exc_type = type(exc_value) + self._rawexcinfo = (exc_type, exc_value, exc_tb) + try: + Failure__init__( + self, exc_value, exc_type, exc_tb, captureVars=captureVars + ) + except TypeError: + Failure__init__(self, exc_value, exc_type, exc_tb) + + ut.Failure.__init__ = excstore + yield + ut.Failure.__init__ = Failure__init__ + else: + yield + + +def check_testcase_implements_trial_reporter(done: List[int] = []) -> None: + if done: + return + from zope.interface import classImplements + from twisted.trial.itrial import IReporter + + classImplements(TestCaseFunction, IReporter) + done.append(1) + + +def _is_skipped(obj) -> bool: + """Return True if the given object has been marked with @unittest.skip.""" + return bool(getattr(obj, "__unittest_skip__", False)) diff --git a/myenv/lib/python3.9/site-packages/_pytest/unraisableexception.py b/myenv/lib/python3.9/site-packages/_pytest/unraisableexception.py new file mode 100644 index 0000000..fcb5d82 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/unraisableexception.py @@ -0,0 +1,93 @@ +import sys +import traceback +import warnings +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Generator +from typing import Optional +from typing import Type + +import pytest + + +# Copied from cpython/Lib/test/support/__init__.py, with modifications. +class catch_unraisable_exception: + """Context manager catching unraisable exception using sys.unraisablehook. + + Storing the exception value (cm.unraisable.exc_value) creates a reference + cycle. The reference cycle is broken explicitly when the context manager + exits. + + Storing the object (cm.unraisable.object) can resurrect it if it is set to + an object which is being finalized. Exiting the context manager clears the + stored object. + + Usage: + with catch_unraisable_exception() as cm: + # code creating an "unraisable exception" + ... + # check the unraisable exception: use cm.unraisable + ... + # cm.unraisable attribute no longer exists at this point + # (to break a reference cycle) + """ + + def __init__(self) -> None: + self.unraisable: Optional["sys.UnraisableHookArgs"] = None + self._old_hook: Optional[Callable[["sys.UnraisableHookArgs"], Any]] = None + + def _hook(self, unraisable: "sys.UnraisableHookArgs") -> None: + # Storing unraisable.object can resurrect an object which is being + # finalized. Storing unraisable.exc_value creates a reference cycle. + self.unraisable = unraisable + + def __enter__(self) -> "catch_unraisable_exception": + self._old_hook = sys.unraisablehook + sys.unraisablehook = self._hook + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + assert self._old_hook is not None + sys.unraisablehook = self._old_hook + self._old_hook = None + del self.unraisable + + +def unraisable_exception_runtest_hook() -> Generator[None, None, None]: + with catch_unraisable_exception() as cm: + yield + if cm.unraisable: + if cm.unraisable.err_msg is not None: + err_msg = cm.unraisable.err_msg + else: + err_msg = "Exception ignored in" + msg = f"{err_msg}: {cm.unraisable.object!r}\n\n" + msg += "".join( + traceback.format_exception( + cm.unraisable.exc_type, + cm.unraisable.exc_value, + cm.unraisable.exc_traceback, + ) + ) + warnings.warn(pytest.PytestUnraisableExceptionWarning(msg)) + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_setup() -> Generator[None, None, None]: + yield from unraisable_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_call() -> Generator[None, None, None]: + yield from unraisable_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_teardown() -> Generator[None, None, None]: + yield from unraisable_exception_runtest_hook() diff --git a/myenv/lib/python3.9/site-packages/_pytest/warning_types.py b/myenv/lib/python3.9/site-packages/_pytest/warning_types.py new file mode 100644 index 0000000..2eadd9f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/warning_types.py @@ -0,0 +1,132 @@ +from typing import Any +from typing import Generic +from typing import Type +from typing import TypeVar + +import attr + +from _pytest.compat import final + + +class PytestWarning(UserWarning): + """Base class for all warnings emitted by pytest.""" + + __module__ = "pytest" + + +@final +class PytestAssertRewriteWarning(PytestWarning): + """Warning emitted by the pytest assert rewrite module.""" + + __module__ = "pytest" + + +@final +class PytestCacheWarning(PytestWarning): + """Warning emitted by the cache plugin in various situations.""" + + __module__ = "pytest" + + +@final +class PytestConfigWarning(PytestWarning): + """Warning emitted for configuration issues.""" + + __module__ = "pytest" + + +@final +class PytestCollectionWarning(PytestWarning): + """Warning emitted when pytest is not able to collect a file or symbol in a module.""" + + __module__ = "pytest" + + +@final +class PytestDeprecationWarning(PytestWarning, DeprecationWarning): + """Warning class for features that will be removed in a future version.""" + + __module__ = "pytest" + + +@final +class PytestExperimentalApiWarning(PytestWarning, FutureWarning): + """Warning category used to denote experiments in pytest. + + Use sparingly as the API might change or even be removed completely in a + future version. + """ + + __module__ = "pytest" + + @classmethod + def simple(cls, apiname: str) -> "PytestExperimentalApiWarning": + return cls( + "{apiname} is an experimental api that may change over time".format( + apiname=apiname + ) + ) + + +@final +class PytestUnhandledCoroutineWarning(PytestWarning): + """Warning emitted for an unhandled coroutine. + + A coroutine was encountered when collecting test functions, but was not + handled by any async-aware plugin. + Coroutine test functions are not natively supported. + """ + + __module__ = "pytest" + + +@final +class PytestUnknownMarkWarning(PytestWarning): + """Warning emitted on use of unknown markers. + + See :ref:`mark` for details. + """ + + __module__ = "pytest" + + +@final +class PytestUnraisableExceptionWarning(PytestWarning): + """An unraisable exception was reported. + + Unraisable exceptions are exceptions raised in :meth:`__del__ ` + implementations and similar situations when the exception cannot be raised + as normal. + """ + + __module__ = "pytest" + + +@final +class PytestUnhandledThreadExceptionWarning(PytestWarning): + """An unhandled exception occurred in a :class:`~threading.Thread`. + + Such exceptions don't propagate normally. + """ + + __module__ = "pytest" + + +_W = TypeVar("_W", bound=PytestWarning) + + +@final +@attr.s +class UnformattedWarning(Generic[_W]): + """A warning meant to be formatted during runtime. + + This is used to hold warnings that need to format their message at runtime, + as opposed to a direct message. + """ + + category = attr.ib(type=Type["_W"]) + template = attr.ib(type=str) + + def format(self, **kwargs: Any) -> _W: + """Return an instance of the warning category, formatted with given kwargs.""" + return self.category(self.template.format(**kwargs)) diff --git a/myenv/lib/python3.9/site-packages/_pytest/warnings.py b/myenv/lib/python3.9/site-packages/_pytest/warnings.py new file mode 100644 index 0000000..35eed96 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_pytest/warnings.py @@ -0,0 +1,139 @@ +import sys +import warnings +from contextlib import contextmanager +from typing import Generator +from typing import Optional +from typing import TYPE_CHECKING + +import pytest +from _pytest.config import apply_warning_filters +from _pytest.config import Config +from _pytest.config import parse_warning_filter +from _pytest.main import Session +from _pytest.nodes import Item +from _pytest.terminal import TerminalReporter + +if TYPE_CHECKING: + from typing_extensions import Literal + + +def pytest_configure(config: Config) -> None: + config.addinivalue_line( + "markers", + "filterwarnings(warning): add a warning filter to the given test. " + "see https://docs.pytest.org/en/stable/warnings.html#pytest-mark-filterwarnings ", + ) + + +@contextmanager +def catch_warnings_for_item( + config: Config, + ihook, + when: "Literal['config', 'collect', 'runtest']", + item: Optional[Item], +) -> Generator[None, None, None]: + """Context manager that catches warnings generated in the contained execution block. + + ``item`` can be None if we are not in the context of an item execution. + + Each warning captured triggers the ``pytest_warning_recorded`` hook. + """ + config_filters = config.getini("filterwarnings") + cmdline_filters = config.known_args_namespace.pythonwarnings or [] + with warnings.catch_warnings(record=True) as log: + # mypy can't infer that record=True means log is not None; help it. + assert log is not None + + if not sys.warnoptions: + # If user is not explicitly configuring warning filters, show deprecation warnings by default (#2908). + warnings.filterwarnings("always", category=DeprecationWarning) + warnings.filterwarnings("always", category=PendingDeprecationWarning) + + apply_warning_filters(config_filters, cmdline_filters) + + # apply filters from "filterwarnings" marks + nodeid = "" if item is None else item.nodeid + if item is not None: + for mark in item.iter_markers(name="filterwarnings"): + for arg in mark.args: + warnings.filterwarnings(*parse_warning_filter(arg, escape=False)) + + yield + + for warning_message in log: + ihook.pytest_warning_captured.call_historic( + kwargs=dict( + warning_message=warning_message, + when=when, + item=item, + location=None, + ) + ) + ihook.pytest_warning_recorded.call_historic( + kwargs=dict( + warning_message=warning_message, + nodeid=nodeid, + when=when, + location=None, + ) + ) + + +def warning_record_to_str(warning_message: warnings.WarningMessage) -> str: + """Convert a warnings.WarningMessage to a string.""" + warn_msg = warning_message.message + msg = warnings.formatwarning( + str(warn_msg), + warning_message.category, + warning_message.filename, + warning_message.lineno, + warning_message.line, + ) + return msg + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]: + with catch_warnings_for_item( + config=item.config, ihook=item.ihook, when="runtest", item=item + ): + yield + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_collection(session: Session) -> Generator[None, None, None]: + config = session.config + with catch_warnings_for_item( + config=config, ihook=config.hook, when="collect", item=None + ): + yield + + +@pytest.hookimpl(hookwrapper=True) +def pytest_terminal_summary( + terminalreporter: TerminalReporter, +) -> Generator[None, None, None]: + config = terminalreporter.config + with catch_warnings_for_item( + config=config, ihook=config.hook, when="config", item=None + ): + yield + + +@pytest.hookimpl(hookwrapper=True) +def pytest_sessionfinish(session: Session) -> Generator[None, None, None]: + config = session.config + with catch_warnings_for_item( + config=config, ihook=config.hook, when="config", item=None + ): + yield + + +@pytest.hookimpl(hookwrapper=True) +def pytest_load_initial_conftests( + early_config: "Config", +) -> Generator[None, None, None]: + with catch_warnings_for_item( + config=early_config, ihook=early_config.hook, when="config", item=None + ): + yield diff --git a/myenv/lib/python3.9/site-packages/_yaml/__init__.py b/myenv/lib/python3.9/site-packages/_yaml/__init__.py new file mode 100644 index 0000000..7baa8c4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/_yaml/__init__.py @@ -0,0 +1,33 @@ +# This is a stub package designed to roughly emulate the _yaml +# extension module, which previously existed as a standalone module +# and has been moved into the `yaml` package namespace. +# It does not perfectly mimic its old counterpart, but should get +# close enough for anyone who's relying on it even when they shouldn't. +import yaml + +# in some circumstances, the yaml module we imoprted may be from a different version, so we need +# to tread carefully when poking at it here (it may not have the attributes we expect) +if not getattr(yaml, '__with_libyaml__', False): + from sys import version_info + + exc = ModuleNotFoundError if version_info >= (3, 6) else ImportError + raise exc("No module named '_yaml'") +else: + from yaml._yaml import * + import warnings + warnings.warn( + 'The _yaml extension module is now located at yaml._yaml' + ' and its location is subject to change. To use the' + ' LibYAML-based parser and emitter, import from `yaml`:' + ' `from yaml import CLoader as Loader, CDumper as Dumper`.', + DeprecationWarning + ) + del warnings + # Don't `del yaml` here because yaml is actually an existing + # namespace member of _yaml. + +__name__ = '_yaml' +# If the module is top-level (i.e. not a part of any specific package) +# then the attribute should be set to ''. +# https://docs.python.org/3.8/library/types.html +__package__ = '' diff --git a/myenv/lib/python3.9/site-packages/aaaaa_future_fstrings.pth b/myenv/lib/python3.9/site-packages/aaaaa_future_fstrings.pth new file mode 100644 index 0000000..74682bf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/aaaaa_future_fstrings.pth @@ -0,0 +1,2 @@ +import sys; exec('try:\n import future_fstrings\nexcept ImportError:\n pass\nelse:\n future_fstrings.register()\n') + diff --git a/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/LICENSE new file mode 100644 index 0000000..104eebf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2018 Alex Grönholm + +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. diff --git a/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/METADATA b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/METADATA new file mode 100644 index 0000000..600c1fe --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/METADATA @@ -0,0 +1,102 @@ +Metadata-Version: 2.1 +Name: anyio +Version: 3.6.1 +Summary: High level compatibility layer for multiple asynchronous event loop implementations +Author: Alex Grönholm +Author-email: alex.gronholm@nextday.fi +License: MIT +Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/ +Project-URL: Source code, https://github.com/agronholm/anyio +Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Framework :: AnyIO +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Requires-Python: >=3.6.2 +License-File: LICENSE +Requires-Dist: idna (>=2.8) +Requires-Dist: sniffio (>=1.1) +Requires-Dist: contextvars ; python_version < "3.7" +Requires-Dist: dataclasses ; python_version < "3.7" +Requires-Dist: typing-extensions ; python_version < "3.8" +Provides-Extra: doc +Requires-Dist: packaging ; extra == 'doc' +Requires-Dist: sphinx-rtd-theme ; extra == 'doc' +Requires-Dist: sphinx-autodoc-typehints (>=1.2.0) ; extra == 'doc' +Provides-Extra: test +Requires-Dist: coverage[toml] (>=4.5) ; extra == 'test' +Requires-Dist: hypothesis (>=4.0) ; extra == 'test' +Requires-Dist: pytest (>=7.0) ; extra == 'test' +Requires-Dist: pytest-mock (>=3.6.1) ; extra == 'test' +Requires-Dist: trustme ; extra == 'test' +Requires-Dist: contextlib2 ; (python_version < "3.7") and extra == 'test' +Requires-Dist: uvloop (<0.15) ; (python_version < "3.7" and (platform_python_implementation == "CPython" and platform_system != "Windows")) and extra == 'test' +Requires-Dist: mock (>=4) ; (python_version < "3.8") and extra == 'test' +Requires-Dist: uvloop (>=0.15) ; (python_version >= "3.7" and (platform_python_implementation == "CPython" and platform_system != "Windows")) and extra == 'test' +Provides-Extra: trio +Requires-Dist: trio (>=0.16) ; extra == 'trio' + +.. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg + :target: https://github.com/agronholm/anyio/actions/workflows/test.yml + :alt: Build Status +.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master + :target: https://coveralls.io/github/agronholm/anyio?branch=master + :alt: Code Coverage +.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest + :target: https://anyio.readthedocs.io/en/latest/?badge=latest + :alt: Documentation +.. image:: https://badges.gitter.im/gitterHQ/gitter.svg + :target: https://gitter.im/python-trio/AnyIO + :alt: Gitter chat + +AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or +trio_. It implements trio-like `structured concurrency`_ (SC) on top of asyncio, and works in harmony +with the native SC of trio itself. + +Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or +trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full +refactoring necessary. It will blend in with native libraries of your chosen backend. + +Documentation +------------- + +View full documentation at: https://anyio.readthedocs.io/ + +Features +-------- + +AnyIO offers the following functionality: + +* Task groups (nurseries_ in trio terminology) +* High level networking (TCP, UDP and UNIX sockets) + + * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python + 3.8) + * async/await style UDP sockets (unlike asyncio where you still have to use Transports and + Protocols) + +* A versatile API for byte streams and object streams +* Inter-task synchronization and communication (locks, conditions, events, semaphores, object + streams) +* Worker threads +* Subprocesses +* Asynchronous file I/O (using worker threads) +* Signal handling + +AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures. +It even works with the popular Hypothesis_ library. + +.. _asyncio: https://docs.python.org/3/library/asyncio.html +.. _trio: https://github.com/python-trio/trio +.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency +.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning +.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs +.. _pytest: https://docs.pytest.org/en/latest/ +.. _Hypothesis: https://hypothesis.works/ diff --git a/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/RECORD b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/RECORD new file mode 100644 index 0000000..7864a5f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/RECORD @@ -0,0 +1,45 @@ +anyio/__init__.py,sha256=M2R8dk6L5gL5lXHArzpSfEn2oH5jMyUKhzyrkRiv2AM,4037 +anyio/from_thread.py,sha256=nSq6mafYMqwxKmzdJyISg8cp-AyBj9rxZPMt_b7klSM,16497 +anyio/lowlevel.py,sha256=W4ydshns7f86YuSESFc2igTf46AWMXnGPQGsY_Esl2E,4679 +anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/pytest_plugin.py,sha256=kWj2B8BJehePJd1sztRBmJBRh8O4hk1oGSYQRlX5Gr8,5134 +anyio/to_process.py,sha256=hu0ES3HJC-VEjcdPJMzAzjyTaekaCNToO3coj3jvnus,9247 +anyio/to_thread.py,sha256=VeMQoo8Va2zz0WFk2p123QikDpqk2wYZGw20COC3wqw,2124 +anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_backends/_asyncio.py,sha256=ZJDvRwfS4wv9WWcqWledNJyl8hx8A8-m9-gSKAJ6nBM,69238 +anyio/_backends/_trio.py,sha256=CebCaqr8Szi6uCnUzwtBRLfUitR5OnDT_wfH-KiqvBQ,29696 +anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_core/_compat.py,sha256=X99W70r-O-JLdkKNtbddcIY5H2Nyg3Nk34oUYE9WZRs,5790 +anyio/_core/_eventloop.py,sha256=DRn_hy679LtsJFsPX7dXjDv72bLtSFkTnWY9WVVfgCQ,4108 +anyio/_core/_exceptions.py,sha256=1wqraNldZroYkoyB0HZStAruz_7yDCBaW-4zYwsKj8s,2904 +anyio/_core/_fileio.py,sha256=au82uZXZX4fia8EoZq_E-JDwZFKe6ZtI0J6IkxK8FmQ,18298 +anyio/_core/_resources.py,sha256=M_uN-90N8eSsWuvo-0xluWU_OG2BTyccAgsQ7XtHxzs,399 +anyio/_core/_signals.py,sha256=D4btJN527tAADspKBeNKaCds-ZcEZJP8LWM_MjVuQRA,827 +anyio/_core/_sockets.py,sha256=fW_Cbg6kfw4xgYuVuWbcWrAYspOcDSEjwxVATMzf2fo,19820 +anyio/_core/_streams.py,sha256=gjT5xChJ1OoV8nNinljSv1yW4nqUS-QzZzIydQz3exQ,1494 +anyio/_core/_subprocesses.py,sha256=pcchMI2OII0QSjiVxRiTEz4M0B7TlQPzGurfCuka-xc,5049 +anyio/_core/_synchronization.py,sha256=xOOG4hF9783N6E2IcD3YKiukguA5bPrj6BodDsKNaJY,16822 +anyio/_core/_tasks.py,sha256=ebGLjHvwL6I9aGyPwvCig1drebSVYFzvY3pnN3TsB4o,5273 +anyio/_core/_testing.py,sha256=VZka_yebIhJ6mJ6Vo_ilO3Nbz53ieqg0WBijwciMwdY,2196 +anyio/_core/_typedattr.py,sha256=k5-wBvMlDlKHIpn18INVnXAlGwI3CrAvPmWoceHjnOQ,2534 +anyio/abc/__init__.py,sha256=hMa47CMs5O1twC2bBcSbzwX-3Q08BAgAPTRekQobb3E,2123 +anyio/abc/_resources.py,sha256=js737mWPG6IW0fH8W4Tz9eNWLztse7dKxEC61z934Vk,752 +anyio/abc/_sockets.py,sha256=i1VdcJTLAuRlYeZoL6s5RBSWbX62Cu6ln5YZBL2YrWk,5754 +anyio/abc/_streams.py,sha256=0g70fhKAzbnK0KKmWwRgwmKdApBwduAcVj4TpjSzjzU,6501 +anyio/abc/_subprocesses.py,sha256=iREP_YQ91it88lDU4XIcI3HZ9HUvV5UmjQk_sSPonrw,2071 +anyio/abc/_tasks.py,sha256=mQQd1DANqpySKyehVVPdMfi_UEG49zZUJpt5blunOjg,3119 +anyio/abc/_testing.py,sha256=ifKCUPzcQdHAEGO-weu2GQvzjMQPPIWO24mQ0z6zkdU,1928 +anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/streams/buffered.py,sha256=FegOSO4Xcxa5SaDfU1A3ZkTTxaPrv6G435Y_giZ8k44,4437 +anyio/streams/file.py,sha256=pujJ-m6BX-gOLnVoZwkE5kh-YDs5Vx9eJFVkvliQ0S4,4353 +anyio/streams/memory.py,sha256=3RGeZoevoGIgBWfD2_X1cqxIPOz-BqQkRf6lUcOnBYc,9209 +anyio/streams/stapled.py,sha256=0E0V15v8M5GVelpHe5RT0S33tQ9hGe4ZCXo_KJEjtt4,4258 +anyio/streams/text.py,sha256=WRFyjsRpBjQKdCmR4ZuzYTEAJqGx2s5oTJmGI1C6Ng0,5014 +anyio/streams/tls.py,sha256=-WXGsMV14XHXAxc38WpBvGusjuY7e449g4UCEHIlnWw,12040 +anyio-3.6.1.dist-info/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081 +anyio-3.6.1.dist-info/METADATA,sha256=cXu3CLppFqT_rBl4Eo2HOb0J1zm6Ltu_tMFuzjuQnew,4654 +anyio-3.6.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +anyio-3.6.1.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39 +anyio-3.6.1.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6 +anyio-3.6.1.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +anyio-3.6.1.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/entry_points.txt b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/entry_points.txt new file mode 100644 index 0000000..44dd9bd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[pytest11] +anyio = anyio.pytest_plugin diff --git a/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/top_level.txt new file mode 100644 index 0000000..c77c069 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio-3.6.1.dist-info/top_level.txt @@ -0,0 +1 @@ +anyio diff --git a/myenv/lib/python3.9/site-packages/anyio/__init__.py b/myenv/lib/python3.9/site-packages/anyio/__init__.py new file mode 100644 index 0000000..6e81178 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/__init__.py @@ -0,0 +1,167 @@ +__all__ = ( + "maybe_async", + "maybe_async_cm", + "run", + "sleep", + "sleep_forever", + "sleep_until", + "current_time", + "get_all_backends", + "get_cancelled_exc_class", + "BrokenResourceError", + "BrokenWorkerProcess", + "BusyResourceError", + "ClosedResourceError", + "DelimiterNotFound", + "EndOfStream", + "ExceptionGroup", + "IncompleteRead", + "TypedAttributeLookupError", + "WouldBlock", + "AsyncFile", + "Path", + "open_file", + "wrap_file", + "aclose_forcefully", + "open_signal_receiver", + "connect_tcp", + "connect_unix", + "create_tcp_listener", + "create_unix_listener", + "create_udp_socket", + "create_connected_udp_socket", + "getaddrinfo", + "getnameinfo", + "wait_socket_readable", + "wait_socket_writable", + "create_memory_object_stream", + "run_process", + "open_process", + "create_lock", + "CapacityLimiter", + "CapacityLimiterStatistics", + "Condition", + "ConditionStatistics", + "Event", + "EventStatistics", + "Lock", + "LockStatistics", + "Semaphore", + "SemaphoreStatistics", + "create_condition", + "create_event", + "create_semaphore", + "create_capacity_limiter", + "open_cancel_scope", + "fail_after", + "move_on_after", + "current_effective_deadline", + "TASK_STATUS_IGNORED", + "CancelScope", + "create_task_group", + "TaskInfo", + "get_current_task", + "get_running_tasks", + "wait_all_tasks_blocked", + "run_sync_in_worker_thread", + "run_async_from_thread", + "run_sync_from_thread", + "current_default_worker_thread_limiter", + "create_blocking_portal", + "start_blocking_portal", + "typed_attribute", + "TypedAttributeSet", + "TypedAttributeProvider", +) + +from typing import Any + +from ._core._compat import maybe_async, maybe_async_cm +from ._core._eventloop import ( + current_time, + get_all_backends, + get_cancelled_exc_class, + run, + sleep, + sleep_forever, + sleep_until, +) +from ._core._exceptions import ( + BrokenResourceError, + BrokenWorkerProcess, + BusyResourceError, + ClosedResourceError, + DelimiterNotFound, + EndOfStream, + ExceptionGroup, + IncompleteRead, + TypedAttributeLookupError, + WouldBlock, +) +from ._core._fileio import AsyncFile, Path, open_file, wrap_file +from ._core._resources import aclose_forcefully +from ._core._signals import open_signal_receiver +from ._core._sockets import ( + connect_tcp, + connect_unix, + create_connected_udp_socket, + create_tcp_listener, + create_udp_socket, + create_unix_listener, + getaddrinfo, + getnameinfo, + wait_socket_readable, + wait_socket_writable, +) +from ._core._streams import create_memory_object_stream +from ._core._subprocesses import open_process, run_process +from ._core._synchronization import ( + CapacityLimiter, + CapacityLimiterStatistics, + Condition, + ConditionStatistics, + Event, + EventStatistics, + Lock, + LockStatistics, + Semaphore, + SemaphoreStatistics, + create_capacity_limiter, + create_condition, + create_event, + create_lock, + create_semaphore, +) +from ._core._tasks import ( + TASK_STATUS_IGNORED, + CancelScope, + create_task_group, + current_effective_deadline, + fail_after, + move_on_after, + open_cancel_scope, +) +from ._core._testing import ( + TaskInfo, + get_current_task, + get_running_tasks, + wait_all_tasks_blocked, +) +from ._core._typedattr import TypedAttributeProvider, TypedAttributeSet, typed_attribute + +# Re-exported here, for backwards compatibility +# isort: off +from .to_thread import current_default_worker_thread_limiter, run_sync_in_worker_thread +from .from_thread import ( + create_blocking_portal, + run_async_from_thread, + run_sync_from_thread, + start_blocking_portal, +) + +# Re-export imports so they look like they live directly in this package +key: str +value: Any +for key, value in list(locals().items()): + if getattr(value, "__module__", "").startswith("anyio."): + value.__module__ = __name__ diff --git a/myenv/lib/python3.9/site-packages/anyio/_backends/__init__.py b/myenv/lib/python3.9/site-packages/anyio/_backends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/anyio/_backends/_asyncio.py b/myenv/lib/python3.9/site-packages/anyio/_backends/_asyncio.py new file mode 100644 index 0000000..d2bbc94 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_backends/_asyncio.py @@ -0,0 +1,2181 @@ +import array +import asyncio +import concurrent.futures +import math +import socket +import sys +from asyncio.base_events import _run_until_complete_cb # type: ignore[attr-defined] +from collections import OrderedDict, deque +from concurrent.futures import Future +from contextvars import Context, copy_context +from dataclasses import dataclass +from functools import partial, wraps +from inspect import ( + CORO_RUNNING, + CORO_SUSPENDED, + GEN_RUNNING, + GEN_SUSPENDED, + getcoroutinestate, + getgeneratorstate, +) +from io import IOBase +from os import PathLike +from queue import Queue +from socket import AddressFamily, SocketKind +from threading import Thread +from types import TracebackType +from typing import ( + IO, + Any, + AsyncGenerator, + Awaitable, + Callable, + Collection, + Coroutine, + Deque, + Dict, + Generator, + Iterable, + List, + Mapping, + Optional, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, +) +from weakref import WeakKeyDictionary + +import sniffio + +from .. import CapacityLimiterStatistics, EventStatistics, TaskInfo, abc +from .._core._compat import DeprecatedAsyncContextManager, DeprecatedAwaitable +from .._core._eventloop import claim_worker_thread, threadlocals +from .._core._exceptions import ( + BrokenResourceError, + BusyResourceError, + ClosedResourceError, + EndOfStream, +) +from .._core._exceptions import ExceptionGroup as BaseExceptionGroup +from .._core._exceptions import WouldBlock +from .._core._sockets import GetAddrInfoReturnType, convert_ipv6_sockaddr +from .._core._synchronization import CapacityLimiter as BaseCapacityLimiter +from .._core._synchronization import Event as BaseEvent +from .._core._synchronization import ResourceGuard +from .._core._tasks import CancelScope as BaseCancelScope +from ..abc import IPSockAddrType, UDPPacketType +from ..lowlevel import RunVar + +if sys.version_info >= (3, 8): + + def get_coro(task: asyncio.Task) -> Union[Generator, Awaitable[Any]]: + return task.get_coro() + +else: + + def get_coro(task: asyncio.Task) -> Union[Generator, Awaitable[Any]]: + return task._coro + + +if sys.version_info >= (3, 7): + from asyncio import all_tasks, create_task, current_task, get_running_loop + from asyncio import run as native_run + + def _get_task_callbacks(task: asyncio.Task) -> Iterable[Callable]: + return [cb for cb, context in task._callbacks] # type: ignore[attr-defined] + +else: + _T = TypeVar("_T") + + def _get_task_callbacks(task: asyncio.Task) -> Iterable[Callable]: + return task._callbacks + + def native_run(main, *, debug=False): + # Snatched from Python 3.7 + from asyncio import coroutines, events, tasks + + def _cancel_all_tasks(loop): + to_cancel = all_tasks(loop) + if not to_cancel: + return + + for task in to_cancel: + task.cancel() + + loop.run_until_complete( + tasks.gather(*to_cancel, loop=loop, return_exceptions=True) + ) + + for task in to_cancel: + if task.cancelled(): + continue + if task.exception() is not None: + loop.call_exception_handler( + { + "message": "unhandled exception during asyncio.run() shutdown", + "exception": task.exception(), + "task": task, + } + ) + + if events._get_running_loop() is not None: + raise RuntimeError( + "asyncio.run() cannot be called from a running event loop" + ) + + if not coroutines.iscoroutine(main): + raise ValueError(f"a coroutine was expected, got {main!r}") + + loop = events.new_event_loop() + try: + events.set_event_loop(loop) + loop.set_debug(debug) + return loop.run_until_complete(main) + finally: + try: + _cancel_all_tasks(loop) + loop.run_until_complete(loop.shutdown_asyncgens()) + finally: + events.set_event_loop(None) + loop.close() + + def create_task( + coro: Union[Generator[Any, None, _T], Awaitable[_T]], *, name: object = None + ) -> asyncio.Task: + return get_running_loop().create_task(coro) + + def get_running_loop() -> asyncio.AbstractEventLoop: + loop = asyncio._get_running_loop() + if loop is not None: + return loop + else: + raise RuntimeError("no running event loop") + + def all_tasks( + loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> Set[asyncio.Task]: + """Return a set of all tasks for the loop.""" + from asyncio import Task + + if loop is None: + loop = get_running_loop() + + return {t for t in Task.all_tasks(loop) if not t.done()} + + def current_task( + loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> Optional[asyncio.Task]: + if loop is None: + loop = get_running_loop() + + return asyncio.Task.current_task(loop) + + +T_Retval = TypeVar("T_Retval") + +# Check whether there is native support for task names in asyncio (3.8+) +_native_task_names = hasattr(asyncio.Task, "get_name") + + +_root_task: RunVar[Optional[asyncio.Task]] = RunVar("_root_task") + + +def find_root_task() -> asyncio.Task: + root_task = _root_task.get(None) + if root_task is not None and not root_task.done(): + return root_task + + # Look for a task that has been started via run_until_complete() + for task in all_tasks(): + if task._callbacks and not task.done(): + for cb in _get_task_callbacks(task): + if ( + cb is _run_until_complete_cb + or getattr(cb, "__module__", None) == "uvloop.loop" + ): + _root_task.set(task) + return task + + # Look up the topmost task in the AnyIO task tree, if possible + task = cast(asyncio.Task, current_task()) + state = _task_states.get(task) + if state: + cancel_scope = state.cancel_scope + while cancel_scope and cancel_scope._parent_scope is not None: + cancel_scope = cancel_scope._parent_scope + + if cancel_scope is not None: + return cast(asyncio.Task, cancel_scope._host_task) + + return task + + +def get_callable_name(func: Callable) -> str: + module = getattr(func, "__module__", None) + qualname = getattr(func, "__qualname__", None) + return ".".join([x for x in (module, qualname) if x]) + + +# +# Event loop +# + +_run_vars = ( + WeakKeyDictionary() +) # type: WeakKeyDictionary[asyncio.AbstractEventLoop, Any] + +current_token = get_running_loop + + +def _task_started(task: asyncio.Task) -> bool: + """Return ``True`` if the task has been started and has not finished.""" + coro = cast(Coroutine[Any, Any, Any], get_coro(task)) + try: + return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED) + except AttributeError: + try: + return getgeneratorstate(cast(Generator, coro)) in ( + GEN_RUNNING, + GEN_SUSPENDED, + ) + except AttributeError: + # task coro is async_genenerator_asend https://bugs.python.org/issue37771 + raise Exception(f"Cannot determine if task {task} has started or not") + + +def _maybe_set_event_loop_policy( + policy: Optional[asyncio.AbstractEventLoopPolicy], use_uvloop: bool +) -> None: + # On CPython, use uvloop when possible if no other policy has been given and if not + # explicitly disabled + if policy is None and use_uvloop and sys.implementation.name == "cpython": + try: + import uvloop + except ImportError: + pass + else: + # Test for missing shutdown_default_executor() (uvloop 0.14.0 and earlier) + if not hasattr( + asyncio.AbstractEventLoop, "shutdown_default_executor" + ) or hasattr(uvloop.loop.Loop, "shutdown_default_executor"): + policy = uvloop.EventLoopPolicy() + + if policy is not None: + asyncio.set_event_loop_policy(policy) + + +def run( + func: Callable[..., Awaitable[T_Retval]], + *args: object, + debug: bool = False, + use_uvloop: bool = False, + policy: Optional[asyncio.AbstractEventLoopPolicy] = None, +) -> T_Retval: + @wraps(func) + async def wrapper() -> T_Retval: + task = cast(asyncio.Task, current_task()) + task_state = TaskState(None, get_callable_name(func), None) + _task_states[task] = task_state + if _native_task_names: + task.set_name(task_state.name) + + try: + return await func(*args) + finally: + del _task_states[task] + + _maybe_set_event_loop_policy(policy, use_uvloop) + return native_run(wrapper(), debug=debug) + + +# +# Miscellaneous +# + +sleep = asyncio.sleep + + +# +# Timeouts and cancellation +# + +CancelledError = asyncio.CancelledError + + +class CancelScope(BaseCancelScope): + def __new__( + cls, *, deadline: float = math.inf, shield: bool = False + ) -> "CancelScope": + return object.__new__(cls) + + def __init__(self, deadline: float = math.inf, shield: bool = False): + self._deadline = deadline + self._shield = shield + self._parent_scope: Optional[CancelScope] = None + self._cancel_called = False + self._active = False + self._timeout_handle: Optional[asyncio.TimerHandle] = None + self._cancel_handle: Optional[asyncio.Handle] = None + self._tasks: Set[asyncio.Task] = set() + self._host_task: Optional[asyncio.Task] = None + self._timeout_expired = False + + def __enter__(self) -> "CancelScope": + if self._active: + raise RuntimeError( + "Each CancelScope may only be used for a single 'with' block" + ) + + self._host_task = host_task = cast(asyncio.Task, current_task()) + self._tasks.add(host_task) + try: + task_state = _task_states[host_task] + except KeyError: + task_name = host_task.get_name() if _native_task_names else None + task_state = TaskState(None, task_name, self) + _task_states[host_task] = task_state + else: + self._parent_scope = task_state.cancel_scope + task_state.cancel_scope = self + + self._timeout() + self._active = True + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + if not self._active: + raise RuntimeError("This cancel scope is not active") + if current_task() is not self._host_task: + raise RuntimeError( + "Attempted to exit cancel scope in a different task than it was " + "entered in" + ) + + assert self._host_task is not None + host_task_state = _task_states.get(self._host_task) + if host_task_state is None or host_task_state.cancel_scope is not self: + raise RuntimeError( + "Attempted to exit a cancel scope that isn't the current tasks's " + "current cancel scope" + ) + + self._active = False + if self._timeout_handle: + self._timeout_handle.cancel() + self._timeout_handle = None + + self._tasks.remove(self._host_task) + + host_task_state.cancel_scope = self._parent_scope + + # Restart the cancellation effort in the farthest directly cancelled parent scope if this + # one was shielded + if self._shield: + self._deliver_cancellation_to_parent() + + if exc_val is not None: + exceptions = ( + exc_val.exceptions if isinstance(exc_val, ExceptionGroup) else [exc_val] + ) + if all(isinstance(exc, CancelledError) for exc in exceptions): + if self._timeout_expired: + return True + elif not self._cancel_called: + # Task was cancelled natively + return None + elif not self._parent_cancelled(): + # This scope was directly cancelled + return True + + return None + + def _timeout(self) -> None: + if self._deadline != math.inf: + loop = get_running_loop() + if loop.time() >= self._deadline: + self._timeout_expired = True + self.cancel() + else: + self._timeout_handle = loop.call_at(self._deadline, self._timeout) + + def _deliver_cancellation(self) -> None: + """ + Deliver cancellation to directly contained tasks and nested cancel scopes. + + Schedule another run at the end if we still have tasks eligible for cancellation. + """ + should_retry = False + current = current_task() + for task in self._tasks: + if task._must_cancel: # type: ignore[attr-defined] + continue + + # The task is eligible for cancellation if it has started and is not in a cancel + # scope shielded from this one + cancel_scope = _task_states[task].cancel_scope + while cancel_scope is not self: + if cancel_scope is None or cancel_scope._shield: + break + else: + cancel_scope = cancel_scope._parent_scope + else: + should_retry = True + if task is not current and ( + task is self._host_task or _task_started(task) + ): + task.cancel() + + # Schedule another callback if there are still tasks left + if should_retry: + self._cancel_handle = get_running_loop().call_soon( + self._deliver_cancellation + ) + else: + self._cancel_handle = None + + def _deliver_cancellation_to_parent(self) -> None: + """Start cancellation effort in the farthest directly cancelled parent scope""" + scope = self._parent_scope + scope_to_cancel: Optional[CancelScope] = None + while scope is not None: + if scope._cancel_called and scope._cancel_handle is None: + scope_to_cancel = scope + + # No point in looking beyond any shielded scope + if scope._shield: + break + + scope = scope._parent_scope + + if scope_to_cancel is not None: + scope_to_cancel._deliver_cancellation() + + def _parent_cancelled(self) -> bool: + # Check whether any parent has been cancelled + cancel_scope = self._parent_scope + while cancel_scope is not None and not cancel_scope._shield: + if cancel_scope._cancel_called: + return True + else: + cancel_scope = cancel_scope._parent_scope + + return False + + def cancel(self) -> DeprecatedAwaitable: + if not self._cancel_called: + if self._timeout_handle: + self._timeout_handle.cancel() + self._timeout_handle = None + + self._cancel_called = True + self._deliver_cancellation() + + return DeprecatedAwaitable(self.cancel) + + @property + def deadline(self) -> float: + return self._deadline + + @deadline.setter + def deadline(self, value: float) -> None: + self._deadline = float(value) + if self._timeout_handle is not None: + self._timeout_handle.cancel() + self._timeout_handle = None + + if self._active and not self._cancel_called: + self._timeout() + + @property + def cancel_called(self) -> bool: + return self._cancel_called + + @property + def shield(self) -> bool: + return self._shield + + @shield.setter + def shield(self, value: bool) -> None: + if self._shield != value: + self._shield = value + if not value: + self._deliver_cancellation_to_parent() + + +async def checkpoint() -> None: + await sleep(0) + + +async def checkpoint_if_cancelled() -> None: + task = current_task() + if task is None: + return + + try: + cancel_scope = _task_states[task].cancel_scope + except KeyError: + return + + while cancel_scope: + if cancel_scope.cancel_called: + await sleep(0) + elif cancel_scope.shield: + break + else: + cancel_scope = cancel_scope._parent_scope + + +async def cancel_shielded_checkpoint() -> None: + with CancelScope(shield=True): + await sleep(0) + + +def current_effective_deadline() -> float: + try: + cancel_scope = _task_states[current_task()].cancel_scope # type: ignore[index] + except KeyError: + return math.inf + + deadline = math.inf + while cancel_scope: + deadline = min(deadline, cancel_scope.deadline) + if cancel_scope.shield: + break + else: + cancel_scope = cancel_scope._parent_scope + + return deadline + + +def current_time() -> float: + return get_running_loop().time() + + +# +# Task states +# + + +class TaskState: + """ + Encapsulates auxiliary task information that cannot be added to the Task instance itself + because there are no guarantees about its implementation. + """ + + __slots__ = "parent_id", "name", "cancel_scope" + + def __init__( + self, + parent_id: Optional[int], + name: Optional[str], + cancel_scope: Optional[CancelScope], + ): + self.parent_id = parent_id + self.name = name + self.cancel_scope = cancel_scope + + +_task_states = WeakKeyDictionary() # type: WeakKeyDictionary[asyncio.Task, TaskState] + + +# +# Task groups +# + + +class ExceptionGroup(BaseExceptionGroup): + def __init__(self, exceptions: List[BaseException]): + super().__init__() + self.exceptions = exceptions + + +class _AsyncioTaskStatus(abc.TaskStatus): + def __init__(self, future: asyncio.Future, parent_id: int): + self._future = future + self._parent_id = parent_id + + def started(self, value: object = None) -> None: + try: + self._future.set_result(value) + except asyncio.InvalidStateError: + raise RuntimeError( + "called 'started' twice on the same task status" + ) from None + + task = cast(asyncio.Task, current_task()) + _task_states[task].parent_id = self._parent_id + + +class TaskGroup(abc.TaskGroup): + def __init__(self) -> None: + self.cancel_scope: CancelScope = CancelScope() + self._active = False + self._exceptions: List[BaseException] = [] + + async def __aenter__(self) -> "TaskGroup": + self.cancel_scope.__enter__() + self._active = True + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + ignore_exception = self.cancel_scope.__exit__(exc_type, exc_val, exc_tb) + if exc_val is not None: + self.cancel_scope.cancel() + self._exceptions.append(exc_val) + + while self.cancel_scope._tasks: + try: + await asyncio.wait(self.cancel_scope._tasks) + except asyncio.CancelledError: + self.cancel_scope.cancel() + + self._active = False + if not self.cancel_scope._parent_cancelled(): + exceptions = self._filter_cancellation_errors(self._exceptions) + else: + exceptions = self._exceptions + + try: + if len(exceptions) > 1: + if all( + isinstance(e, CancelledError) and not e.args for e in exceptions + ): + # Tasks were cancelled natively, without a cancellation message + raise CancelledError + else: + raise ExceptionGroup(exceptions) + elif exceptions and exceptions[0] is not exc_val: + raise exceptions[0] + except BaseException as exc: + # Clear the context here, as it can only be done in-flight. + # If the context is not cleared, it can result in recursive tracebacks (see #145). + exc.__context__ = None + raise + + return ignore_exception + + @staticmethod + def _filter_cancellation_errors( + exceptions: Sequence[BaseException], + ) -> List[BaseException]: + filtered_exceptions: List[BaseException] = [] + for exc in exceptions: + if isinstance(exc, ExceptionGroup): + new_exceptions = TaskGroup._filter_cancellation_errors(exc.exceptions) + if len(new_exceptions) > 1: + filtered_exceptions.append(exc) + elif len(new_exceptions) == 1: + filtered_exceptions.append(new_exceptions[0]) + elif new_exceptions: + new_exc = ExceptionGroup(new_exceptions) + new_exc.__cause__ = exc.__cause__ + new_exc.__context__ = exc.__context__ + new_exc.__traceback__ = exc.__traceback__ + filtered_exceptions.append(new_exc) + elif not isinstance(exc, CancelledError) or exc.args: + filtered_exceptions.append(exc) + + return filtered_exceptions + + async def _run_wrapped_task( + self, coro: Coroutine, task_status_future: Optional[asyncio.Future] + ) -> None: + # This is the code path for Python 3.6 and 3.7 on which asyncio freaks out if a task raises + # a BaseException. + __traceback_hide__ = __tracebackhide__ = True # noqa: F841 + task = cast(asyncio.Task, current_task()) + try: + await coro + except BaseException as exc: + if task_status_future is None or task_status_future.done(): + self._exceptions.append(exc) + self.cancel_scope.cancel() + else: + task_status_future.set_exception(exc) + else: + if task_status_future is not None and not task_status_future.done(): + task_status_future.set_exception( + RuntimeError("Child exited without calling task_status.started()") + ) + finally: + if task in self.cancel_scope._tasks: + self.cancel_scope._tasks.remove(task) + del _task_states[task] + + def _spawn( + self, + func: Callable[..., Coroutine], + args: tuple, + name: object, + task_status_future: Optional[asyncio.Future] = None, + ) -> asyncio.Task: + def task_done(_task: asyncio.Task) -> None: + # This is the code path for Python 3.8+ + assert _task in self.cancel_scope._tasks + self.cancel_scope._tasks.remove(_task) + del _task_states[_task] + + try: + exc = _task.exception() + except CancelledError as e: + while isinstance(e.__context__, CancelledError): + e = e.__context__ + + exc = e + + if exc is not None: + if task_status_future is None or task_status_future.done(): + self._exceptions.append(exc) + self.cancel_scope.cancel() + else: + task_status_future.set_exception(exc) + elif task_status_future is not None and not task_status_future.done(): + task_status_future.set_exception( + RuntimeError("Child exited without calling task_status.started()") + ) + + if not self._active: + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + options = {} + name = get_callable_name(func) if name is None else str(name) + if _native_task_names: + options["name"] = name + + kwargs = {} + if task_status_future: + parent_id = id(current_task()) + kwargs["task_status"] = _AsyncioTaskStatus( + task_status_future, id(self.cancel_scope._host_task) + ) + else: + parent_id = id(self.cancel_scope._host_task) + + coro = func(*args, **kwargs) + if not asyncio.iscoroutine(coro): + raise TypeError( + f"Expected an async function, but {func} appears to be synchronous" + ) + + foreign_coro = not hasattr(coro, "cr_frame") and not hasattr(coro, "gi_frame") + if foreign_coro or sys.version_info < (3, 8): + coro = self._run_wrapped_task(coro, task_status_future) + + task = create_task(coro, **options) + if not foreign_coro and sys.version_info >= (3, 8): + task.add_done_callback(task_done) + + # Make the spawned task inherit the task group's cancel scope + _task_states[task] = TaskState( + parent_id=parent_id, name=name, cancel_scope=self.cancel_scope + ) + self.cancel_scope._tasks.add(task) + return task + + def start_soon( + self, func: Callable[..., Coroutine], *args: object, name: object = None + ) -> None: + self._spawn(func, args, name) + + async def start( + self, func: Callable[..., Coroutine], *args: object, name: object = None + ) -> None: + future: asyncio.Future = asyncio.Future() + task = self._spawn(func, args, name, future) + + # If the task raises an exception after sending a start value without a switch point + # between, the task group is cancelled and this method never proceeds to process the + # completed future. That's why we have to have a shielded cancel scope here. + with CancelScope(shield=True): + try: + return await future + except CancelledError: + task.cancel() + raise + + +# +# Threads +# + +_Retval_Queue_Type = Tuple[Optional[T_Retval], Optional[BaseException]] + + +class WorkerThread(Thread): + MAX_IDLE_TIME = 10 # seconds + + def __init__( + self, + root_task: asyncio.Task, + workers: Set["WorkerThread"], + idle_workers: Deque["WorkerThread"], + ): + super().__init__(name="AnyIO worker thread") + self.root_task = root_task + self.workers = workers + self.idle_workers = idle_workers + self.loop = root_task._loop + self.queue: Queue[ + Union[Tuple[Context, Callable, tuple, asyncio.Future], None] + ] = Queue(2) + self.idle_since = current_time() + self.stopping = False + + def _report_result( + self, future: asyncio.Future, result: Any, exc: Optional[BaseException] + ) -> None: + self.idle_since = current_time() + if not self.stopping: + self.idle_workers.append(self) + + if not future.cancelled(): + if exc is not None: + future.set_exception(exc) + else: + future.set_result(result) + + def run(self) -> None: + with claim_worker_thread("asyncio"): + threadlocals.loop = self.loop + while True: + item = self.queue.get() + if item is None: + # Shutdown command received + return + + context, func, args, future = item + if not future.cancelled(): + result = None + exception: Optional[BaseException] = None + try: + result = context.run(func, *args) + except BaseException as exc: + exception = exc + + if not self.loop.is_closed(): + self.loop.call_soon_threadsafe( + self._report_result, future, result, exception + ) + + self.queue.task_done() + + def stop(self, f: Optional[asyncio.Task] = None) -> None: + self.stopping = True + self.queue.put_nowait(None) + self.workers.discard(self) + try: + self.idle_workers.remove(self) + except ValueError: + pass + + +_threadpool_idle_workers: RunVar[Deque[WorkerThread]] = RunVar( + "_threadpool_idle_workers" +) +_threadpool_workers: RunVar[Set[WorkerThread]] = RunVar("_threadpool_workers") + + +async def run_sync_in_worker_thread( + func: Callable[..., T_Retval], + *args: object, + cancellable: bool = False, + limiter: Optional["CapacityLimiter"] = None, +) -> T_Retval: + await checkpoint() + + # If this is the first run in this event loop thread, set up the necessary variables + try: + idle_workers = _threadpool_idle_workers.get() + workers = _threadpool_workers.get() + except LookupError: + idle_workers = deque() + workers = set() + _threadpool_idle_workers.set(idle_workers) + _threadpool_workers.set(workers) + + async with (limiter or current_default_thread_limiter()): + with CancelScope(shield=not cancellable): + future: asyncio.Future = asyncio.Future() + root_task = find_root_task() + if not idle_workers: + worker = WorkerThread(root_task, workers, idle_workers) + worker.start() + workers.add(worker) + root_task.add_done_callback(worker.stop) + else: + worker = idle_workers.pop() + + # Prune any other workers that have been idle for MAX_IDLE_TIME seconds or longer + now = current_time() + while idle_workers: + if now - idle_workers[0].idle_since < WorkerThread.MAX_IDLE_TIME: + break + + expired_worker = idle_workers.popleft() + expired_worker.root_task.remove_done_callback(expired_worker.stop) + expired_worker.stop() + + context = copy_context() + context.run(sniffio.current_async_library_cvar.set, None) + worker.queue.put_nowait((context, func, args, future)) + return await future + + +def run_sync_from_thread( + func: Callable[..., T_Retval], + *args: object, + loop: Optional[asyncio.AbstractEventLoop] = None, +) -> T_Retval: + @wraps(func) + def wrapper() -> None: + try: + f.set_result(func(*args)) + except BaseException as exc: + f.set_exception(exc) + if not isinstance(exc, Exception): + raise + + f: concurrent.futures.Future[T_Retval] = Future() + loop = loop or threadlocals.loop + if sys.version_info < (3, 7): + loop.call_soon_threadsafe(copy_context().run, wrapper) + else: + loop.call_soon_threadsafe(wrapper) + + return f.result() + + +def run_async_from_thread( + func: Callable[..., Coroutine[Any, Any, T_Retval]], *args: object +) -> T_Retval: + f: concurrent.futures.Future[T_Retval] = asyncio.run_coroutine_threadsafe( + func(*args), threadlocals.loop + ) + return f.result() + + +class BlockingPortal(abc.BlockingPortal): + def __new__(cls) -> "BlockingPortal": + return object.__new__(cls) + + def __init__(self) -> None: + super().__init__() + self._loop = get_running_loop() + + def _spawn_task_from_thread( + self, + func: Callable, + args: tuple, + kwargs: Dict[str, Any], + name: object, + future: Future, + ) -> None: + run_sync_from_thread( + partial(self._task_group.start_soon, name=name), + self._call_func, + func, + args, + kwargs, + future, + loop=self._loop, + ) + + +# +# Subprocesses +# + + +@dataclass(eq=False) +class StreamReaderWrapper(abc.ByteReceiveStream): + _stream: asyncio.StreamReader + + async def receive(self, max_bytes: int = 65536) -> bytes: + data = await self._stream.read(max_bytes) + if data: + return data + else: + raise EndOfStream + + async def aclose(self) -> None: + self._stream.feed_eof() + + +@dataclass(eq=False) +class StreamWriterWrapper(abc.ByteSendStream): + _stream: asyncio.StreamWriter + + async def send(self, item: bytes) -> None: + self._stream.write(item) + await self._stream.drain() + + async def aclose(self) -> None: + self._stream.close() + + +@dataclass(eq=False) +class Process(abc.Process): + _process: asyncio.subprocess.Process + _stdin: Optional[StreamWriterWrapper] + _stdout: Optional[StreamReaderWrapper] + _stderr: Optional[StreamReaderWrapper] + + async def aclose(self) -> None: + if self._stdin: + await self._stdin.aclose() + if self._stdout: + await self._stdout.aclose() + if self._stderr: + await self._stderr.aclose() + + await self.wait() + + async def wait(self) -> int: + return await self._process.wait() + + def terminate(self) -> None: + self._process.terminate() + + def kill(self) -> None: + self._process.kill() + + def send_signal(self, signal: int) -> None: + self._process.send_signal(signal) + + @property + def pid(self) -> int: + return self._process.pid + + @property + def returncode(self) -> Optional[int]: + return self._process.returncode + + @property + def stdin(self) -> Optional[abc.ByteSendStream]: + return self._stdin + + @property + def stdout(self) -> Optional[abc.ByteReceiveStream]: + return self._stdout + + @property + def stderr(self) -> Optional[abc.ByteReceiveStream]: + return self._stderr + + +async def open_process( + command: Union[str, bytes, Sequence[Union[str, bytes]]], + *, + shell: bool, + stdin: Union[int, IO[Any], None], + stdout: Union[int, IO[Any], None], + stderr: Union[int, IO[Any], None], + cwd: Union[str, bytes, PathLike, None] = None, + env: Optional[Mapping[str, str]] = None, + start_new_session: bool = False, +) -> Process: + await checkpoint() + if shell: + process = await asyncio.create_subprocess_shell( + cast(Union[str, bytes], command), + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) + else: + process = await asyncio.create_subprocess_exec( + *command, + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) + + stdin_stream = StreamWriterWrapper(process.stdin) if process.stdin else None + stdout_stream = StreamReaderWrapper(process.stdout) if process.stdout else None + stderr_stream = StreamReaderWrapper(process.stderr) if process.stderr else None + return Process(process, stdin_stream, stdout_stream, stderr_stream) + + +def _forcibly_shutdown_process_pool_on_exit( + workers: Set[Process], _task: object +) -> None: + """ + Forcibly shuts down worker processes belonging to this event loop.""" + child_watcher: Optional[asyncio.AbstractChildWatcher] + try: + child_watcher = asyncio.get_event_loop_policy().get_child_watcher() + except NotImplementedError: + child_watcher = None + + # Close as much as possible (w/o async/await) to avoid warnings + for process in workers: + if process.returncode is None: + continue + + process._stdin._stream._transport.close() # type: ignore[union-attr] + process._stdout._stream._transport.close() # type: ignore[union-attr] + process._stderr._stream._transport.close() # type: ignore[union-attr] + process.kill() + if child_watcher: + child_watcher.remove_child_handler(process.pid) + + +async def _shutdown_process_pool_on_exit(workers: Set[Process]) -> None: + """ + Shuts down worker processes belonging to this event loop. + + NOTE: this only works when the event loop was started using asyncio.run() or anyio.run(). + + """ + process: Process + try: + await sleep(math.inf) + except asyncio.CancelledError: + for process in workers: + if process.returncode is None: + process.kill() + + for process in workers: + await process.aclose() + + +def setup_process_pool_exit_at_shutdown(workers: Set[Process]) -> None: + kwargs = {"name": "AnyIO process pool shutdown task"} if _native_task_names else {} + create_task(_shutdown_process_pool_on_exit(workers), **kwargs) + find_root_task().add_done_callback( + partial(_forcibly_shutdown_process_pool_on_exit, workers) + ) + + +# +# Sockets and networking +# + + +class StreamProtocol(asyncio.Protocol): + read_queue: Deque[bytes] + read_event: asyncio.Event + write_event: asyncio.Event + exception: Optional[Exception] = None + + def connection_made(self, transport: asyncio.BaseTransport) -> None: + self.read_queue = deque() + self.read_event = asyncio.Event() + self.write_event = asyncio.Event() + self.write_event.set() + cast(asyncio.Transport, transport).set_write_buffer_limits(0) + + def connection_lost(self, exc: Optional[Exception]) -> None: + if exc: + self.exception = BrokenResourceError() + self.exception.__cause__ = exc + + self.read_event.set() + self.write_event.set() + + def data_received(self, data: bytes) -> None: + self.read_queue.append(data) + self.read_event.set() + + def eof_received(self) -> Optional[bool]: + self.read_event.set() + return True + + def pause_writing(self) -> None: + self.write_event = asyncio.Event() + + def resume_writing(self) -> None: + self.write_event.set() + + +class DatagramProtocol(asyncio.DatagramProtocol): + read_queue: Deque[Tuple[bytes, IPSockAddrType]] + read_event: asyncio.Event + write_event: asyncio.Event + exception: Optional[Exception] = None + + def connection_made(self, transport: asyncio.BaseTransport) -> None: + self.read_queue = deque(maxlen=100) # arbitrary value + self.read_event = asyncio.Event() + self.write_event = asyncio.Event() + self.write_event.set() + + def connection_lost(self, exc: Optional[Exception]) -> None: + self.read_event.set() + self.write_event.set() + + def datagram_received(self, data: bytes, addr: IPSockAddrType) -> None: + addr = convert_ipv6_sockaddr(addr) + self.read_queue.append((data, addr)) + self.read_event.set() + + def error_received(self, exc: Exception) -> None: + self.exception = exc + + def pause_writing(self) -> None: + self.write_event.clear() + + def resume_writing(self) -> None: + self.write_event.set() + + +class SocketStream(abc.SocketStream): + def __init__(self, transport: asyncio.Transport, protocol: StreamProtocol): + self._transport = transport + self._protocol = protocol + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + self._closed = False + + @property + def _raw_socket(self) -> socket.socket: + return self._transport.get_extra_info("socket") + + async def receive(self, max_bytes: int = 65536) -> bytes: + with self._receive_guard: + await checkpoint() + + if ( + not self._protocol.read_event.is_set() + and not self._transport.is_closing() + ): + self._transport.resume_reading() + await self._protocol.read_event.wait() + self._transport.pause_reading() + + try: + chunk = self._protocol.read_queue.popleft() + except IndexError: + if self._closed: + raise ClosedResourceError from None + elif self._protocol.exception: + raise self._protocol.exception + else: + raise EndOfStream from None + + if len(chunk) > max_bytes: + # Split the oversized chunk + chunk, leftover = chunk[:max_bytes], chunk[max_bytes:] + self._protocol.read_queue.appendleft(leftover) + + # If the read queue is empty, clear the flag so that the next call will block until + # data is available + if not self._protocol.read_queue: + self._protocol.read_event.clear() + + return chunk + + async def send(self, item: bytes) -> None: + with self._send_guard: + await checkpoint() + + if self._closed: + raise ClosedResourceError + elif self._protocol.exception is not None: + raise self._protocol.exception + + try: + self._transport.write(item) + except RuntimeError as exc: + if self._transport.is_closing(): + raise BrokenResourceError from exc + else: + raise + + await self._protocol.write_event.wait() + + async def send_eof(self) -> None: + try: + self._transport.write_eof() + except OSError: + pass + + async def aclose(self) -> None: + if not self._transport.is_closing(): + self._closed = True + try: + self._transport.write_eof() + except OSError: + pass + + self._transport.close() + await sleep(0) + self._transport.abort() + + +class UNIXSocketStream(abc.SocketStream): + _receive_future: Optional[asyncio.Future] = None + _send_future: Optional[asyncio.Future] = None + _closing = False + + def __init__(self, raw_socket: socket.socket): + self.__raw_socket = raw_socket + self._loop = get_running_loop() + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + @property + def _raw_socket(self) -> socket.socket: + return self.__raw_socket + + def _wait_until_readable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: + def callback(f: object) -> None: + del self._receive_future + loop.remove_reader(self.__raw_socket) + + f = self._receive_future = asyncio.Future() + self._loop.add_reader(self.__raw_socket, f.set_result, None) + f.add_done_callback(callback) + return f + + def _wait_until_writable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: + def callback(f: object) -> None: + del self._send_future + loop.remove_writer(self.__raw_socket) + + f = self._send_future = asyncio.Future() + self._loop.add_writer(self.__raw_socket, f.set_result, None) + f.add_done_callback(callback) + return f + + async def send_eof(self) -> None: + with self._send_guard: + self._raw_socket.shutdown(socket.SHUT_WR) + + async def receive(self, max_bytes: int = 65536) -> bytes: + loop = get_running_loop() + await checkpoint() + with self._receive_guard: + while True: + try: + data = self.__raw_socket.recv(max_bytes) + except BlockingIOError: + await self._wait_until_readable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + if not data: + raise EndOfStream + + return data + + async def send(self, item: bytes) -> None: + loop = get_running_loop() + await checkpoint() + with self._send_guard: + view = memoryview(item) + while view: + try: + bytes_sent = self.__raw_socket.send(item) + except BlockingIOError: + await self._wait_until_writable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + view = view[bytes_sent:] + + async def receive_fds(self, msglen: int, maxfds: int) -> Tuple[bytes, List[int]]: + if not isinstance(msglen, int) or msglen < 0: + raise ValueError("msglen must be a non-negative integer") + if not isinstance(maxfds, int) or maxfds < 1: + raise ValueError("maxfds must be a positive integer") + + loop = get_running_loop() + fds = array.array("i") + await checkpoint() + with self._receive_guard: + while True: + try: + message, ancdata, flags, addr = self.__raw_socket.recvmsg( + msglen, socket.CMSG_LEN(maxfds * fds.itemsize) + ) + except BlockingIOError: + await self._wait_until_readable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + if not message and not ancdata: + raise EndOfStream + + break + + for cmsg_level, cmsg_type, cmsg_data in ancdata: + if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: + raise RuntimeError( + f"Received unexpected ancillary data; message = {message!r}, " + f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" + ) + + fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) + + return message, list(fds) + + async def send_fds( + self, message: bytes, fds: Collection[Union[int, IOBase]] + ) -> None: + if not message: + raise ValueError("message must not be empty") + if not fds: + raise ValueError("fds must not be empty") + + loop = get_running_loop() + filenos: List[int] = [] + for fd in fds: + if isinstance(fd, int): + filenos.append(fd) + elif isinstance(fd, IOBase): + filenos.append(fd.fileno()) + + fdarray = array.array("i", filenos) + await checkpoint() + with self._send_guard: + while True: + try: + # The ignore can be removed after mypy picks up + # https://github.com/python/typeshed/pull/5545 + self.__raw_socket.sendmsg( + [message], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fdarray)] + ) + break + except BlockingIOError: + await self._wait_until_writable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + + async def aclose(self) -> None: + if not self._closing: + self._closing = True + if self.__raw_socket.fileno() != -1: + self.__raw_socket.close() + + if self._receive_future: + self._receive_future.set_result(None) + if self._send_future: + self._send_future.set_result(None) + + +class TCPSocketListener(abc.SocketListener): + _accept_scope: Optional[CancelScope] = None + _closed = False + + def __init__(self, raw_socket: socket.socket): + self.__raw_socket = raw_socket + self._loop = cast(asyncio.BaseEventLoop, get_running_loop()) + self._accept_guard = ResourceGuard("accepting connections from") + + @property + def _raw_socket(self) -> socket.socket: + return self.__raw_socket + + async def accept(self) -> abc.SocketStream: + if self._closed: + raise ClosedResourceError + + with self._accept_guard: + await checkpoint() + with CancelScope() as self._accept_scope: + try: + client_sock, _addr = await self._loop.sock_accept(self._raw_socket) + except asyncio.CancelledError: + # Workaround for https://bugs.python.org/issue41317 + try: + self._loop.remove_reader(self._raw_socket) + except (ValueError, NotImplementedError): + pass + + if self._closed: + raise ClosedResourceError from None + + raise + finally: + self._accept_scope = None + + client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + transport, protocol = await self._loop.connect_accepted_socket( + StreamProtocol, client_sock + ) + return SocketStream(cast(asyncio.Transport, transport), protocol) + + async def aclose(self) -> None: + if self._closed: + return + + self._closed = True + if self._accept_scope: + # Workaround for https://bugs.python.org/issue41317 + try: + self._loop.remove_reader(self._raw_socket) + except (ValueError, NotImplementedError): + pass + + self._accept_scope.cancel() + await sleep(0) + + self._raw_socket.close() + + +class UNIXSocketListener(abc.SocketListener): + def __init__(self, raw_socket: socket.socket): + self.__raw_socket = raw_socket + self._loop = get_running_loop() + self._accept_guard = ResourceGuard("accepting connections from") + self._closed = False + + async def accept(self) -> abc.SocketStream: + await checkpoint() + with self._accept_guard: + while True: + try: + client_sock, _ = self.__raw_socket.accept() + client_sock.setblocking(False) + return UNIXSocketStream(client_sock) + except BlockingIOError: + f: asyncio.Future = asyncio.Future() + self._loop.add_reader(self.__raw_socket, f.set_result, None) + f.add_done_callback( + lambda _: self._loop.remove_reader(self.__raw_socket) + ) + await f + except OSError as exc: + if self._closed: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + + async def aclose(self) -> None: + self._closed = True + self.__raw_socket.close() + + @property + def _raw_socket(self) -> socket.socket: + return self.__raw_socket + + +class UDPSocket(abc.UDPSocket): + def __init__( + self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol + ): + self._transport = transport + self._protocol = protocol + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + self._closed = False + + @property + def _raw_socket(self) -> socket.socket: + return self._transport.get_extra_info("socket") + + async def aclose(self) -> None: + if not self._transport.is_closing(): + self._closed = True + self._transport.close() + + async def receive(self) -> Tuple[bytes, IPSockAddrType]: + with self._receive_guard: + await checkpoint() + + # If the buffer is empty, ask for more data + if not self._protocol.read_queue and not self._transport.is_closing(): + self._protocol.read_event.clear() + await self._protocol.read_event.wait() + + try: + return self._protocol.read_queue.popleft() + except IndexError: + if self._closed: + raise ClosedResourceError from None + else: + raise BrokenResourceError from None + + async def send(self, item: UDPPacketType) -> None: + with self._send_guard: + await checkpoint() + await self._protocol.write_event.wait() + if self._closed: + raise ClosedResourceError + elif self._transport.is_closing(): + raise BrokenResourceError + else: + self._transport.sendto(*item) + + +class ConnectedUDPSocket(abc.ConnectedUDPSocket): + def __init__( + self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol + ): + self._transport = transport + self._protocol = protocol + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + self._closed = False + + @property + def _raw_socket(self) -> socket.socket: + return self._transport.get_extra_info("socket") + + async def aclose(self) -> None: + if not self._transport.is_closing(): + self._closed = True + self._transport.close() + + async def receive(self) -> bytes: + with self._receive_guard: + await checkpoint() + + # If the buffer is empty, ask for more data + if not self._protocol.read_queue and not self._transport.is_closing(): + self._protocol.read_event.clear() + await self._protocol.read_event.wait() + + try: + packet = self._protocol.read_queue.popleft() + except IndexError: + if self._closed: + raise ClosedResourceError from None + else: + raise BrokenResourceError from None + + return packet[0] + + async def send(self, item: bytes) -> None: + with self._send_guard: + await checkpoint() + await self._protocol.write_event.wait() + if self._closed: + raise ClosedResourceError + elif self._transport.is_closing(): + raise BrokenResourceError + else: + self._transport.sendto(item) + + +async def connect_tcp( + host: str, port: int, local_addr: Optional[Tuple[str, int]] = None +) -> SocketStream: + transport, protocol = cast( + Tuple[asyncio.Transport, StreamProtocol], + await get_running_loop().create_connection( + StreamProtocol, host, port, local_addr=local_addr + ), + ) + transport.pause_reading() + return SocketStream(transport, protocol) + + +async def connect_unix(path: str) -> UNIXSocketStream: + await checkpoint() + loop = get_running_loop() + raw_socket = socket.socket(socket.AF_UNIX) + raw_socket.setblocking(False) + while True: + try: + raw_socket.connect(path) + except BlockingIOError: + f: asyncio.Future = asyncio.Future() + loop.add_writer(raw_socket, f.set_result, None) + f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) + await f + except BaseException: + raw_socket.close() + raise + else: + return UNIXSocketStream(raw_socket) + + +async def create_udp_socket( + family: socket.AddressFamily, + local_address: Optional[IPSockAddrType], + remote_address: Optional[IPSockAddrType], + reuse_port: bool, +) -> Union[UDPSocket, ConnectedUDPSocket]: + result = await get_running_loop().create_datagram_endpoint( + DatagramProtocol, + local_addr=local_address, + remote_addr=remote_address, + family=family, + reuse_port=reuse_port, + ) + transport = cast(asyncio.DatagramTransport, result[0]) + protocol = result[1] + if protocol.exception: + transport.close() + raise protocol.exception + + if not remote_address: + return UDPSocket(transport, protocol) + else: + return ConnectedUDPSocket(transport, protocol) + + +async def getaddrinfo( + host: Union[bytes, str], + port: Union[str, int, None], + *, + family: Union[int, AddressFamily] = 0, + type: Union[int, SocketKind] = 0, + proto: int = 0, + flags: int = 0, +) -> GetAddrInfoReturnType: + # https://github.com/python/typeshed/pull/4304 + result = await get_running_loop().getaddrinfo( + host, port, family=family, type=type, proto=proto, flags=flags + ) + return cast(GetAddrInfoReturnType, result) + + +async def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Tuple[str, str]: + return await get_running_loop().getnameinfo(sockaddr, flags) + + +_read_events: RunVar[Dict[Any, asyncio.Event]] = RunVar("read_events") +_write_events: RunVar[Dict[Any, asyncio.Event]] = RunVar("write_events") + + +async def wait_socket_readable(sock: socket.socket) -> None: + await checkpoint() + try: + read_events = _read_events.get() + except LookupError: + read_events = {} + _read_events.set(read_events) + + if read_events.get(sock): + raise BusyResourceError("reading from") from None + + loop = get_running_loop() + event = read_events[sock] = asyncio.Event() + loop.add_reader(sock, event.set) + try: + await event.wait() + finally: + if read_events.pop(sock, None) is not None: + loop.remove_reader(sock) + readable = True + else: + readable = False + + if not readable: + raise ClosedResourceError + + +async def wait_socket_writable(sock: socket.socket) -> None: + await checkpoint() + try: + write_events = _write_events.get() + except LookupError: + write_events = {} + _write_events.set(write_events) + + if write_events.get(sock): + raise BusyResourceError("writing to") from None + + loop = get_running_loop() + event = write_events[sock] = asyncio.Event() + loop.add_writer(sock.fileno(), event.set) + try: + await event.wait() + finally: + if write_events.pop(sock, None) is not None: + loop.remove_writer(sock) + writable = True + else: + writable = False + + if not writable: + raise ClosedResourceError + + +# +# Synchronization +# + + +class Event(BaseEvent): + def __new__(cls) -> "Event": + return object.__new__(cls) + + def __init__(self) -> None: + self._event = asyncio.Event() + + def set(self) -> DeprecatedAwaitable: + self._event.set() + return DeprecatedAwaitable(self.set) + + def is_set(self) -> bool: + return self._event.is_set() + + async def wait(self) -> None: + if await self._event.wait(): + await checkpoint() + + def statistics(self) -> EventStatistics: + return EventStatistics(len(self._event._waiters)) # type: ignore[attr-defined] + + +class CapacityLimiter(BaseCapacityLimiter): + _total_tokens: float = 0 + + def __new__(cls, total_tokens: float) -> "CapacityLimiter": + return object.__new__(cls) + + def __init__(self, total_tokens: float): + self._borrowers: Set[Any] = set() + self._wait_queue: Dict[Any, asyncio.Event] = OrderedDict() + self.total_tokens = total_tokens + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.release() + + @property + def total_tokens(self) -> float: + return self._total_tokens + + @total_tokens.setter + def total_tokens(self, value: float) -> None: + if not isinstance(value, int) and not math.isinf(value): + raise TypeError("total_tokens must be an int or math.inf") + if value < 1: + raise ValueError("total_tokens must be >= 1") + + old_value = self._total_tokens + self._total_tokens = value + events = [] + for event in self._wait_queue.values(): + if value <= old_value: + break + + if not event.is_set(): + events.append(event) + old_value += 1 + + for event in events: + event.set() + + @property + def borrowed_tokens(self) -> int: + return len(self._borrowers) + + @property + def available_tokens(self) -> float: + return self._total_tokens - len(self._borrowers) + + def acquire_nowait(self) -> DeprecatedAwaitable: + self.acquire_on_behalf_of_nowait(current_task()) + return DeprecatedAwaitable(self.acquire_nowait) + + def acquire_on_behalf_of_nowait(self, borrower: object) -> DeprecatedAwaitable: + if borrower in self._borrowers: + raise RuntimeError( + "this borrower is already holding one of this CapacityLimiter's " + "tokens" + ) + + if self._wait_queue or len(self._borrowers) >= self._total_tokens: + raise WouldBlock + + self._borrowers.add(borrower) + return DeprecatedAwaitable(self.acquire_on_behalf_of_nowait) + + async def acquire(self) -> None: + return await self.acquire_on_behalf_of(current_task()) + + async def acquire_on_behalf_of(self, borrower: object) -> None: + await checkpoint_if_cancelled() + try: + self.acquire_on_behalf_of_nowait(borrower) + except WouldBlock: + event = asyncio.Event() + self._wait_queue[borrower] = event + try: + await event.wait() + except BaseException: + self._wait_queue.pop(borrower, None) + raise + + self._borrowers.add(borrower) + else: + try: + await cancel_shielded_checkpoint() + except BaseException: + self.release() + raise + + def release(self) -> None: + self.release_on_behalf_of(current_task()) + + def release_on_behalf_of(self, borrower: object) -> None: + try: + self._borrowers.remove(borrower) + except KeyError: + raise RuntimeError( + "this borrower isn't holding any of this CapacityLimiter's " "tokens" + ) from None + + # Notify the next task in line if this limiter has free capacity now + if self._wait_queue and len(self._borrowers) < self._total_tokens: + event = self._wait_queue.popitem()[1] + event.set() + + def statistics(self) -> CapacityLimiterStatistics: + return CapacityLimiterStatistics( + self.borrowed_tokens, + self.total_tokens, + tuple(self._borrowers), + len(self._wait_queue), + ) + + +_default_thread_limiter: RunVar[CapacityLimiter] = RunVar("_default_thread_limiter") + + +def current_default_thread_limiter() -> CapacityLimiter: + try: + return _default_thread_limiter.get() + except LookupError: + limiter = CapacityLimiter(40) + _default_thread_limiter.set(limiter) + return limiter + + +# +# Operating system signals +# + + +class _SignalReceiver(DeprecatedAsyncContextManager["_SignalReceiver"]): + def __init__(self, signals: Tuple[int, ...]): + self._signals = signals + self._loop = get_running_loop() + self._signal_queue: Deque[int] = deque() + self._future: asyncio.Future = asyncio.Future() + self._handled_signals: Set[int] = set() + + def _deliver(self, signum: int) -> None: + self._signal_queue.append(signum) + if not self._future.done(): + self._future.set_result(None) + + def __enter__(self) -> "_SignalReceiver": + for sig in set(self._signals): + self._loop.add_signal_handler(sig, self._deliver, sig) + self._handled_signals.add(sig) + + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + for sig in self._handled_signals: + self._loop.remove_signal_handler(sig) + return None + + def __aiter__(self) -> "_SignalReceiver": + return self + + async def __anext__(self) -> int: + await checkpoint() + if not self._signal_queue: + self._future = asyncio.Future() + await self._future + + return self._signal_queue.popleft() + + +def open_signal_receiver(*signals: int) -> _SignalReceiver: + return _SignalReceiver(signals) + + +# +# Testing and debugging +# + + +def _create_task_info(task: asyncio.Task) -> TaskInfo: + task_state = _task_states.get(task) + if task_state is None: + name = task.get_name() if _native_task_names else None + parent_id = None + else: + name = task_state.name + parent_id = task_state.parent_id + + return TaskInfo(id(task), parent_id, name, get_coro(task)) + + +def get_current_task() -> TaskInfo: + return _create_task_info(current_task()) # type: ignore[arg-type] + + +def get_running_tasks() -> List[TaskInfo]: + return [_create_task_info(task) for task in all_tasks() if not task.done()] + + +async def wait_all_tasks_blocked() -> None: + await checkpoint() + this_task = current_task() + while True: + for task in all_tasks(): + if task is this_task: + continue + + if task._fut_waiter is None or task._fut_waiter.done(): # type: ignore[attr-defined] + await sleep(0.1) + break + else: + return + + +class TestRunner(abc.TestRunner): + def __init__( + self, + debug: bool = False, + use_uvloop: bool = False, + policy: Optional[asyncio.AbstractEventLoopPolicy] = None, + ): + self._exceptions: List[BaseException] = [] + _maybe_set_event_loop_policy(policy, use_uvloop) + self._loop = asyncio.new_event_loop() + self._loop.set_debug(debug) + self._loop.set_exception_handler(self._exception_handler) + asyncio.set_event_loop(self._loop) + + def _cancel_all_tasks(self) -> None: + to_cancel = all_tasks(self._loop) + if not to_cancel: + return + + for task in to_cancel: + task.cancel() + + self._loop.run_until_complete( + asyncio.gather(*to_cancel, return_exceptions=True) + ) + + for task in to_cancel: + if task.cancelled(): + continue + if task.exception() is not None: + raise cast(BaseException, task.exception()) + + def _exception_handler( + self, loop: asyncio.AbstractEventLoop, context: Dict[str, Any] + ) -> None: + if isinstance(context.get("exception"), Exception): + self._exceptions.append(context["exception"]) + else: + loop.default_exception_handler(context) + + def _raise_async_exceptions(self) -> None: + # Re-raise any exceptions raised in asynchronous callbacks + if self._exceptions: + exceptions, self._exceptions = self._exceptions, [] + if len(exceptions) == 1: + raise exceptions[0] + elif exceptions: + raise ExceptionGroup(exceptions) + + def close(self) -> None: + try: + self._cancel_all_tasks() + self._loop.run_until_complete(self._loop.shutdown_asyncgens()) + finally: + asyncio.set_event_loop(None) + self._loop.close() + + def run_asyncgen_fixture( + self, + fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], + kwargs: Dict[str, Any], + ) -> Iterable[T_Retval]: + async def fixture_runner() -> None: + agen = fixture_func(**kwargs) + try: + retval = await agen.asend(None) + self._raise_async_exceptions() + except BaseException as exc: + f.set_exception(exc) + return + else: + f.set_result(retval) + + await event.wait() + try: + await agen.asend(None) + except StopAsyncIteration: + pass + else: + await agen.aclose() + raise RuntimeError("Async generator fixture did not stop") + + f = self._loop.create_future() + event = asyncio.Event() + fixture_task = self._loop.create_task(fixture_runner()) + self._loop.run_until_complete(f) + yield f.result() + event.set() + self._loop.run_until_complete(fixture_task) + self._raise_async_exceptions() + + def run_fixture( + self, + fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], + kwargs: Dict[str, Any], + ) -> T_Retval: + retval = self._loop.run_until_complete(fixture_func(**kwargs)) + self._raise_async_exceptions() + return retval + + def run_test( + self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: Dict[str, Any] + ) -> None: + try: + self._loop.run_until_complete(test_func(**kwargs)) + except Exception as exc: + self._exceptions.append(exc) + + self._raise_async_exceptions() diff --git a/myenv/lib/python3.9/site-packages/anyio/_backends/_trio.py b/myenv/lib/python3.9/site-packages/anyio/_backends/_trio.py new file mode 100644 index 0000000..cf2aaec --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_backends/_trio.py @@ -0,0 +1,988 @@ +import array +import math +import socket +from concurrent.futures import Future +from contextvars import copy_context +from dataclasses import dataclass +from functools import partial +from io import IOBase +from os import PathLike +from signal import Signals +from types import TracebackType +from typing import ( + IO, + TYPE_CHECKING, + Any, + AsyncGenerator, + Awaitable, + Callable, + Collection, + ContextManager, + Coroutine, + Deque, + Dict, + Generic, + Iterable, + List, + Mapping, + NoReturn, + Optional, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, +) + +import sniffio +import trio.from_thread +from outcome import Error, Outcome, Value +from trio.socket import SocketType as TrioSocketType +from trio.to_thread import run_sync + +from .. import CapacityLimiterStatistics, EventStatistics, TaskInfo, abc +from .._core._compat import DeprecatedAsyncContextManager, DeprecatedAwaitable, T +from .._core._eventloop import claim_worker_thread +from .._core._exceptions import ( + BrokenResourceError, + BusyResourceError, + ClosedResourceError, + EndOfStream, +) +from .._core._exceptions import ExceptionGroup as BaseExceptionGroup +from .._core._sockets import convert_ipv6_sockaddr +from .._core._synchronization import CapacityLimiter as BaseCapacityLimiter +from .._core._synchronization import Event as BaseEvent +from .._core._synchronization import ResourceGuard +from .._core._tasks import CancelScope as BaseCancelScope +from ..abc import IPSockAddrType, UDPPacketType + +if TYPE_CHECKING: + from trio_typing import TaskStatus + +try: + from trio import lowlevel as trio_lowlevel +except ImportError: + from trio import hazmat as trio_lowlevel # type: ignore[no-redef] + from trio.hazmat import wait_readable, wait_writable +else: + from trio.lowlevel import wait_readable, wait_writable + +try: + trio_open_process = trio_lowlevel.open_process # type: ignore[attr-defined] +except AttributeError: + from trio import open_process as trio_open_process + +T_Retval = TypeVar("T_Retval") +T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType) + + +# +# Event loop +# + +run = trio.run +current_token = trio.lowlevel.current_trio_token +RunVar = trio.lowlevel.RunVar + + +# +# Miscellaneous +# + +sleep = trio.sleep + + +# +# Timeouts and cancellation +# + + +class CancelScope(BaseCancelScope): + def __new__( + cls, original: Optional[trio.CancelScope] = None, **kwargs: object + ) -> "CancelScope": + return object.__new__(cls) + + def __init__( + self, original: Optional[trio.CancelScope] = None, **kwargs: Any + ) -> None: + self.__original = original or trio.CancelScope(**kwargs) + + def __enter__(self) -> "CancelScope": + self.__original.__enter__() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + return self.__original.__exit__(exc_type, exc_val, exc_tb) + + def cancel(self) -> DeprecatedAwaitable: + self.__original.cancel() + return DeprecatedAwaitable(self.cancel) + + @property + def deadline(self) -> float: + return self.__original.deadline + + @deadline.setter + def deadline(self, value: float) -> None: + self.__original.deadline = value + + @property + def cancel_called(self) -> bool: + return self.__original.cancel_called + + @property + def shield(self) -> bool: + return self.__original.shield + + @shield.setter + def shield(self, value: bool) -> None: + self.__original.shield = value + + +CancelledError = trio.Cancelled +checkpoint = trio.lowlevel.checkpoint +checkpoint_if_cancelled = trio.lowlevel.checkpoint_if_cancelled +cancel_shielded_checkpoint = trio.lowlevel.cancel_shielded_checkpoint +current_effective_deadline = trio.current_effective_deadline +current_time = trio.current_time + + +# +# Task groups +# + + +class ExceptionGroup(BaseExceptionGroup, trio.MultiError): + pass + + +class TaskGroup(abc.TaskGroup): + def __init__(self) -> None: + self._active = False + self._nursery_manager = trio.open_nursery() + self.cancel_scope = None # type: ignore[assignment] + + async def __aenter__(self) -> "TaskGroup": + self._active = True + self._nursery = await self._nursery_manager.__aenter__() + self.cancel_scope = CancelScope(self._nursery.cancel_scope) + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + try: + return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) + except trio.MultiError as exc: + raise ExceptionGroup(exc.exceptions) from None + finally: + self._active = False + + def start_soon(self, func: Callable, *args: object, name: object = None) -> None: + if not self._active: + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + self._nursery.start_soon(func, *args, name=name) + + async def start( + self, func: Callable[..., Coroutine], *args: object, name: object = None + ) -> object: + if not self._active: + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + return await self._nursery.start(func, *args, name=name) + + +# +# Threads +# + + +async def run_sync_in_worker_thread( + func: Callable[..., T_Retval], + *args: object, + cancellable: bool = False, + limiter: Optional[trio.CapacityLimiter] = None, +) -> T_Retval: + def wrapper() -> T_Retval: + with claim_worker_thread("trio"): + return func(*args) + + # TODO: remove explicit context copying when trio 0.20 is the minimum requirement + context = copy_context() + context.run(sniffio.current_async_library_cvar.set, None) + return await run_sync( + context.run, wrapper, cancellable=cancellable, limiter=limiter + ) + + +# TODO: remove this workaround when trio 0.20 is the minimum requirement +def run_async_from_thread( + fn: Callable[..., Awaitable[T_Retval]], *args: Any +) -> T_Retval: + async def wrapper() -> T_Retval: + retval: T_Retval + + async def inner() -> None: + nonlocal retval + __tracebackhide__ = True + retval = await fn(*args) + + async with trio.open_nursery() as n: + context.run(n.start_soon, inner) + + __tracebackhide__ = True + return retval + + context = copy_context() + context.run(sniffio.current_async_library_cvar.set, "trio") + return trio.from_thread.run(wrapper) + + +def run_sync_from_thread(fn: Callable[..., T_Retval], *args: Any) -> T_Retval: + # TODO: remove explicit context copying when trio 0.20 is the minimum requirement + retval = trio.from_thread.run_sync(copy_context().run, fn, *args) + return cast(T_Retval, retval) + + +class BlockingPortal(abc.BlockingPortal): + def __new__(cls) -> "BlockingPortal": + return object.__new__(cls) + + def __init__(self) -> None: + super().__init__() + self._token = trio.lowlevel.current_trio_token() + + def _spawn_task_from_thread( + self, + func: Callable, + args: tuple, + kwargs: Dict[str, Any], + name: object, + future: Future, + ) -> None: + context = copy_context() + context.run(sniffio.current_async_library_cvar.set, "trio") + trio.from_thread.run_sync( + context.run, + partial(self._task_group.start_soon, name=name), + self._call_func, + func, + args, + kwargs, + future, + trio_token=self._token, + ) + + +# +# Subprocesses +# + + +@dataclass(eq=False) +class ReceiveStreamWrapper(abc.ByteReceiveStream): + _stream: trio.abc.ReceiveStream + + async def receive(self, max_bytes: Optional[int] = None) -> bytes: + try: + data = await self._stream.receive_some(max_bytes) + except trio.ClosedResourceError as exc: + raise ClosedResourceError from exc.__cause__ + except trio.BrokenResourceError as exc: + raise BrokenResourceError from exc.__cause__ + + if data: + return data + else: + raise EndOfStream + + async def aclose(self) -> None: + await self._stream.aclose() + + +@dataclass(eq=False) +class SendStreamWrapper(abc.ByteSendStream): + _stream: trio.abc.SendStream + + async def send(self, item: bytes) -> None: + try: + await self._stream.send_all(item) + except trio.ClosedResourceError as exc: + raise ClosedResourceError from exc.__cause__ + except trio.BrokenResourceError as exc: + raise BrokenResourceError from exc.__cause__ + + async def aclose(self) -> None: + await self._stream.aclose() + + +@dataclass(eq=False) +class Process(abc.Process): + _process: trio.Process + _stdin: Optional[abc.ByteSendStream] + _stdout: Optional[abc.ByteReceiveStream] + _stderr: Optional[abc.ByteReceiveStream] + + async def aclose(self) -> None: + if self._stdin: + await self._stdin.aclose() + if self._stdout: + await self._stdout.aclose() + if self._stderr: + await self._stderr.aclose() + + await self.wait() + + async def wait(self) -> int: + return await self._process.wait() + + def terminate(self) -> None: + self._process.terminate() + + def kill(self) -> None: + self._process.kill() + + def send_signal(self, signal: Signals) -> None: + self._process.send_signal(signal) + + @property + def pid(self) -> int: + return self._process.pid + + @property + def returncode(self) -> Optional[int]: + return self._process.returncode + + @property + def stdin(self) -> Optional[abc.ByteSendStream]: + return self._stdin + + @property + def stdout(self) -> Optional[abc.ByteReceiveStream]: + return self._stdout + + @property + def stderr(self) -> Optional[abc.ByteReceiveStream]: + return self._stderr + + +async def open_process( + command: Union[str, bytes, Sequence[Union[str, bytes]]], + *, + shell: bool, + stdin: Union[int, IO[Any], None], + stdout: Union[int, IO[Any], None], + stderr: Union[int, IO[Any], None], + cwd: Union[str, bytes, PathLike, None] = None, + env: Optional[Mapping[str, str]] = None, + start_new_session: bool = False, +) -> Process: + process = await trio_open_process( + command, + stdin=stdin, + stdout=stdout, + stderr=stderr, + shell=shell, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) + stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None + stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None + stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None + return Process(process, stdin_stream, stdout_stream, stderr_stream) + + +class _ProcessPoolShutdownInstrument(trio.abc.Instrument): + def after_run(self) -> None: + super().after_run() + + +current_default_worker_process_limiter: RunVar = RunVar( + "current_default_worker_process_limiter" +) + + +async def _shutdown_process_pool(workers: Set[Process]) -> None: + process: Process + try: + await sleep(math.inf) + except trio.Cancelled: + for process in workers: + if process.returncode is None: + process.kill() + + with CancelScope(shield=True): + for process in workers: + await process.aclose() + + +def setup_process_pool_exit_at_shutdown(workers: Set[Process]) -> None: + trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers) + + +# +# Sockets and networking +# + + +class _TrioSocketMixin(Generic[T_SockAddr]): + def __init__(self, trio_socket: TrioSocketType) -> None: + self._trio_socket = trio_socket + self._closed = False + + def _check_closed(self) -> None: + if self._closed: + raise ClosedResourceError + if self._trio_socket.fileno() < 0: + raise BrokenResourceError + + @property + def _raw_socket(self) -> socket.socket: + return self._trio_socket._sock # type: ignore[attr-defined] + + async def aclose(self) -> None: + if self._trio_socket.fileno() >= 0: + self._closed = True + self._trio_socket.close() + + def _convert_socket_error(self, exc: BaseException) -> "NoReturn": + if isinstance(exc, trio.ClosedResourceError): + raise ClosedResourceError from exc + elif self._trio_socket.fileno() < 0 and self._closed: + raise ClosedResourceError from None + elif isinstance(exc, OSError): + raise BrokenResourceError from exc + else: + raise exc + + +class SocketStream(_TrioSocketMixin, abc.SocketStream): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self, max_bytes: int = 65536) -> bytes: + with self._receive_guard: + try: + data = await self._trio_socket.recv(max_bytes) + except BaseException as exc: + self._convert_socket_error(exc) + + if data: + return data + else: + raise EndOfStream + + async def send(self, item: bytes) -> None: + with self._send_guard: + view = memoryview(item) + while view: + try: + bytes_sent = await self._trio_socket.send(view) + except BaseException as exc: + self._convert_socket_error(exc) + + view = view[bytes_sent:] + + async def send_eof(self) -> None: + self._trio_socket.shutdown(socket.SHUT_WR) + + +class UNIXSocketStream(SocketStream, abc.UNIXSocketStream): + async def receive_fds(self, msglen: int, maxfds: int) -> Tuple[bytes, List[int]]: + if not isinstance(msglen, int) or msglen < 0: + raise ValueError("msglen must be a non-negative integer") + if not isinstance(maxfds, int) or maxfds < 1: + raise ValueError("maxfds must be a positive integer") + + fds = array.array("i") + await checkpoint() + with self._receive_guard: + while True: + try: + message, ancdata, flags, addr = await self._trio_socket.recvmsg( + msglen, socket.CMSG_LEN(maxfds * fds.itemsize) + ) + except BaseException as exc: + self._convert_socket_error(exc) + else: + if not message and not ancdata: + raise EndOfStream + + break + + for cmsg_level, cmsg_type, cmsg_data in ancdata: + if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: + raise RuntimeError( + f"Received unexpected ancillary data; message = {message!r}, " + f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" + ) + + fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) + + return message, list(fds) + + async def send_fds( + self, message: bytes, fds: Collection[Union[int, IOBase]] + ) -> None: + if not message: + raise ValueError("message must not be empty") + if not fds: + raise ValueError("fds must not be empty") + + filenos: List[int] = [] + for fd in fds: + if isinstance(fd, int): + filenos.append(fd) + elif isinstance(fd, IOBase): + filenos.append(fd.fileno()) + + fdarray = array.array("i", filenos) + await checkpoint() + with self._send_guard: + while True: + try: + await self._trio_socket.sendmsg( + [message], + [ + ( + socket.SOL_SOCKET, + socket.SCM_RIGHTS, # type: ignore[list-item] + fdarray, + ) + ], + ) + break + except BaseException as exc: + self._convert_socket_error(exc) + + +class TCPSocketListener(_TrioSocketMixin, abc.SocketListener): + def __init__(self, raw_socket: socket.socket): + super().__init__(trio.socket.from_stdlib_socket(raw_socket)) + self._accept_guard = ResourceGuard("accepting connections from") + + async def accept(self) -> SocketStream: + with self._accept_guard: + try: + trio_socket, _addr = await self._trio_socket.accept() + except BaseException as exc: + self._convert_socket_error(exc) + + trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + return SocketStream(trio_socket) + + +class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener): + def __init__(self, raw_socket: socket.socket): + super().__init__(trio.socket.from_stdlib_socket(raw_socket)) + self._accept_guard = ResourceGuard("accepting connections from") + + async def accept(self) -> UNIXSocketStream: + with self._accept_guard: + try: + trio_socket, _addr = await self._trio_socket.accept() + except BaseException as exc: + self._convert_socket_error(exc) + + return UNIXSocketStream(trio_socket) + + +class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self) -> Tuple[bytes, IPSockAddrType]: + with self._receive_guard: + try: + data, addr = await self._trio_socket.recvfrom(65536) + return data, convert_ipv6_sockaddr(addr) + except BaseException as exc: + self._convert_socket_error(exc) + + async def send(self, item: UDPPacketType) -> None: + with self._send_guard: + try: + await self._trio_socket.sendto(*item) + except BaseException as exc: + self._convert_socket_error(exc) + + +class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self) -> bytes: + with self._receive_guard: + try: + return await self._trio_socket.recv(65536) + except BaseException as exc: + self._convert_socket_error(exc) + + async def send(self, item: bytes) -> None: + with self._send_guard: + try: + await self._trio_socket.send(item) + except BaseException as exc: + self._convert_socket_error(exc) + + +async def connect_tcp( + host: str, port: int, local_address: Optional[IPSockAddrType] = None +) -> SocketStream: + family = socket.AF_INET6 if ":" in host else socket.AF_INET + trio_socket = trio.socket.socket(family) + trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + if local_address: + await trio_socket.bind(local_address) + + try: + await trio_socket.connect((host, port)) + except BaseException: + trio_socket.close() + raise + + return SocketStream(trio_socket) + + +async def connect_unix(path: str) -> UNIXSocketStream: + trio_socket = trio.socket.socket(socket.AF_UNIX) + try: + await trio_socket.connect(path) + except BaseException: + trio_socket.close() + raise + + return UNIXSocketStream(trio_socket) + + +async def create_udp_socket( + family: socket.AddressFamily, + local_address: Optional[IPSockAddrType], + remote_address: Optional[IPSockAddrType], + reuse_port: bool, +) -> Union[UDPSocket, ConnectedUDPSocket]: + trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM) + + if reuse_port: + trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + + if local_address: + await trio_socket.bind(local_address) + + if remote_address: + await trio_socket.connect(remote_address) + return ConnectedUDPSocket(trio_socket) + else: + return UDPSocket(trio_socket) + + +getaddrinfo = trio.socket.getaddrinfo +getnameinfo = trio.socket.getnameinfo + + +async def wait_socket_readable(sock: socket.socket) -> None: + try: + await wait_readable(sock) + except trio.ClosedResourceError as exc: + raise ClosedResourceError().with_traceback(exc.__traceback__) from None + except trio.BusyResourceError: + raise BusyResourceError("reading from") from None + + +async def wait_socket_writable(sock: socket.socket) -> None: + try: + await wait_writable(sock) + except trio.ClosedResourceError as exc: + raise ClosedResourceError().with_traceback(exc.__traceback__) from None + except trio.BusyResourceError: + raise BusyResourceError("writing to") from None + + +# +# Synchronization +# + + +class Event(BaseEvent): + def __new__(cls) -> "Event": + return object.__new__(cls) + + def __init__(self) -> None: + self.__original = trio.Event() + + def is_set(self) -> bool: + return self.__original.is_set() + + async def wait(self) -> None: + return await self.__original.wait() + + def statistics(self) -> EventStatistics: + orig_statistics = self.__original.statistics() + return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting) + + def set(self) -> DeprecatedAwaitable: + self.__original.set() + return DeprecatedAwaitable(self.set) + + +class CapacityLimiter(BaseCapacityLimiter): + def __new__(cls, *args: object, **kwargs: object) -> "CapacityLimiter": + return object.__new__(cls) + + def __init__( + self, *args: Any, original: Optional[trio.CapacityLimiter] = None + ) -> None: + self.__original = original or trio.CapacityLimiter(*args) + + async def __aenter__(self) -> None: + return await self.__original.__aenter__() + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + return await self.__original.__aexit__(exc_type, exc_val, exc_tb) + + @property + def total_tokens(self) -> float: + return self.__original.total_tokens + + @total_tokens.setter + def total_tokens(self, value: float) -> None: + self.__original.total_tokens = value + + @property + def borrowed_tokens(self) -> int: + return self.__original.borrowed_tokens + + @property + def available_tokens(self) -> float: + return self.__original.available_tokens + + def acquire_nowait(self) -> DeprecatedAwaitable: + self.__original.acquire_nowait() + return DeprecatedAwaitable(self.acquire_nowait) + + def acquire_on_behalf_of_nowait(self, borrower: object) -> DeprecatedAwaitable: + self.__original.acquire_on_behalf_of_nowait(borrower) + return DeprecatedAwaitable(self.acquire_on_behalf_of_nowait) + + async def acquire(self) -> None: + await self.__original.acquire() + + async def acquire_on_behalf_of(self, borrower: object) -> None: + await self.__original.acquire_on_behalf_of(borrower) + + def release(self) -> None: + return self.__original.release() + + def release_on_behalf_of(self, borrower: object) -> None: + return self.__original.release_on_behalf_of(borrower) + + def statistics(self) -> CapacityLimiterStatistics: + orig = self.__original.statistics() + return CapacityLimiterStatistics( + borrowed_tokens=orig.borrowed_tokens, + total_tokens=orig.total_tokens, + borrowers=orig.borrowers, + tasks_waiting=orig.tasks_waiting, + ) + + +_capacity_limiter_wrapper: RunVar = RunVar("_capacity_limiter_wrapper") + + +def current_default_thread_limiter() -> CapacityLimiter: + try: + return _capacity_limiter_wrapper.get() + except LookupError: + limiter = CapacityLimiter( + original=trio.to_thread.current_default_thread_limiter() + ) + _capacity_limiter_wrapper.set(limiter) + return limiter + + +# +# Signal handling +# + + +class _SignalReceiver(DeprecatedAsyncContextManager[T]): + def __init__(self, cm: ContextManager[T]): + self._cm = cm + + def __enter__(self) -> T: + return self._cm.__enter__() + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + return self._cm.__exit__(exc_type, exc_val, exc_tb) + + +def open_signal_receiver(*signals: Signals) -> _SignalReceiver: + cm = trio.open_signal_receiver(*signals) + return _SignalReceiver(cm) + + +# +# Testing and debugging +# + + +def get_current_task() -> TaskInfo: + task = trio_lowlevel.current_task() + + parent_id = None + if task.parent_nursery and task.parent_nursery.parent_task: + parent_id = id(task.parent_nursery.parent_task) + + return TaskInfo(id(task), parent_id, task.name, task.coro) + + +def get_running_tasks() -> List[TaskInfo]: + root_task = trio_lowlevel.current_root_task() + task_infos = [TaskInfo(id(root_task), None, root_task.name, root_task.coro)] + nurseries = root_task.child_nurseries + while nurseries: + new_nurseries: List[trio.Nursery] = [] + for nursery in nurseries: + for task in nursery.child_tasks: + task_infos.append( + TaskInfo(id(task), id(nursery.parent_task), task.name, task.coro) + ) + new_nurseries.extend(task.child_nurseries) + + nurseries = new_nurseries + + return task_infos + + +def wait_all_tasks_blocked() -> Awaitable[None]: + import trio.testing + + return trio.testing.wait_all_tasks_blocked() + + +class TestRunner(abc.TestRunner): + def __init__(self, **options: Any) -> None: + from collections import deque + from queue import Queue + + self._call_queue: "Queue[Callable[..., object]]" = Queue() + self._result_queue: Deque[Outcome] = deque() + self._stop_event: Optional[trio.Event] = None + self._nursery: Optional[trio.Nursery] = None + self._options = options + + async def _trio_main(self) -> None: + self._stop_event = trio.Event() + async with trio.open_nursery() as self._nursery: + await self._stop_event.wait() + + async def _call_func( + self, func: Callable[..., Awaitable[object]], args: tuple, kwargs: dict + ) -> None: + try: + retval = await func(*args, **kwargs) + except BaseException as exc: + self._result_queue.append(Error(exc)) + else: + self._result_queue.append(Value(retval)) + + def _main_task_finished(self, outcome: object) -> None: + self._nursery = None + + def _get_nursery(self) -> trio.Nursery: + if self._nursery is None: + trio.lowlevel.start_guest_run( + self._trio_main, + run_sync_soon_threadsafe=self._call_queue.put, + done_callback=self._main_task_finished, + **self._options, + ) + while self._nursery is None: + self._call_queue.get()() + + return self._nursery + + def _call( + self, func: Callable[..., Awaitable[T_Retval]], *args: object, **kwargs: object + ) -> T_Retval: + self._get_nursery().start_soon(self._call_func, func, args, kwargs) + while not self._result_queue: + self._call_queue.get()() + + outcome = self._result_queue.pop() + return outcome.unwrap() + + def close(self) -> None: + if self._stop_event: + self._stop_event.set() + while self._nursery is not None: + self._call_queue.get()() + + def run_asyncgen_fixture( + self, + fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], + kwargs: Dict[str, Any], + ) -> Iterable[T_Retval]: + async def fixture_runner(*, task_status: "TaskStatus") -> None: + agen = fixture_func(**kwargs) + retval = await agen.asend(None) + task_status.started(retval) + await teardown_event.wait() + try: + await agen.asend(None) + except StopAsyncIteration: + pass + else: + await agen.aclose() + raise RuntimeError("Async generator fixture did not stop") + + teardown_event = trio.Event() + fixture_value = self._call(lambda: self._get_nursery().start(fixture_runner)) + yield fixture_value + teardown_event.set() + + def run_fixture( + self, + fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], + kwargs: Dict[str, Any], + ) -> T_Retval: + return self._call(fixture_func, **kwargs) + + def run_test( + self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: Dict[str, Any] + ) -> None: + self._call(test_func, **kwargs) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/__init__.py b/myenv/lib/python3.9/site-packages/anyio/_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_compat.py b/myenv/lib/python3.9/site-packages/anyio/_core/_compat.py new file mode 100644 index 0000000..7062be5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_compat.py @@ -0,0 +1,218 @@ +from abc import ABCMeta, abstractmethod +from contextlib import AbstractContextManager +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + AsyncContextManager, + Callable, + ContextManager, + Generator, + Generic, + Iterable, + List, + Optional, + Tuple, + Type, + TypeVar, + Union, + overload, +) +from warnings import warn + +if TYPE_CHECKING: + from ._testing import TaskInfo +else: + TaskInfo = object + +T = TypeVar("T") +AnyDeprecatedAwaitable = Union[ + "DeprecatedAwaitable", + "DeprecatedAwaitableFloat", + "DeprecatedAwaitableList[T]", + TaskInfo, +] + + +@overload +async def maybe_async(__obj: TaskInfo) -> TaskInfo: + ... + + +@overload +async def maybe_async(__obj: "DeprecatedAwaitableFloat") -> float: + ... + + +@overload +async def maybe_async(__obj: "DeprecatedAwaitableList[T]") -> List[T]: + ... + + +@overload +async def maybe_async(__obj: "DeprecatedAwaitable") -> None: + ... + + +async def maybe_async( + __obj: "AnyDeprecatedAwaitable[T]", +) -> Union[TaskInfo, float, List[T], None]: + """ + Await on the given object if necessary. + + This function is intended to bridge the gap between AnyIO 2.x and 3.x where some functions and + methods were converted from coroutine functions into regular functions. + + Do **not** try to use this for any other purpose! + + :return: the result of awaiting on the object if coroutine, or the object itself otherwise + + .. versionadded:: 2.2 + + """ + return __obj._unwrap() + + +class _ContextManagerWrapper: + def __init__(self, cm: ContextManager[T]): + self._cm = cm + + async def __aenter__(self) -> T: + return self._cm.__enter__() + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + return self._cm.__exit__(exc_type, exc_val, exc_tb) + + +def maybe_async_cm( + cm: Union[ContextManager[T], AsyncContextManager[T]] +) -> AsyncContextManager[T]: + """ + Wrap a regular context manager as an async one if necessary. + + This function is intended to bridge the gap between AnyIO 2.x and 3.x where some functions and + methods were changed to return regular context managers instead of async ones. + + :param cm: a regular or async context manager + :return: an async context manager + + .. versionadded:: 2.2 + + """ + if not isinstance(cm, AbstractContextManager): + raise TypeError("Given object is not an context manager") + + return _ContextManagerWrapper(cm) + + +def _warn_deprecation( + awaitable: "AnyDeprecatedAwaitable[Any]", stacklevel: int = 1 +) -> None: + warn( + f'Awaiting on {awaitable._name}() is deprecated. Use "await ' + f"anyio.maybe_async({awaitable._name}(...)) if you have to support both AnyIO 2.x " + f'and 3.x, or just remove the "await" if you are completely migrating to AnyIO 3+.', + DeprecationWarning, + stacklevel=stacklevel + 1, + ) + + +class DeprecatedAwaitable: + def __init__(self, func: Callable[..., "DeprecatedAwaitable"]): + self._name = f"{func.__module__}.{func.__qualname__}" + + def __await__(self) -> Generator[None, None, None]: + _warn_deprecation(self) + if False: + yield + + def __reduce__(self) -> Tuple[Type[None], Tuple[()]]: + return type(None), () + + def _unwrap(self) -> None: + return None + + +class DeprecatedAwaitableFloat(float): + def __new__( + cls, x: float, func: Callable[..., "DeprecatedAwaitableFloat"] + ) -> "DeprecatedAwaitableFloat": + return super().__new__(cls, x) + + def __init__(self, x: float, func: Callable[..., "DeprecatedAwaitableFloat"]): + self._name = f"{func.__module__}.{func.__qualname__}" + + def __await__(self) -> Generator[None, None, float]: + _warn_deprecation(self) + if False: + yield + + return float(self) + + def __reduce__(self) -> Tuple[Type[float], Tuple[float]]: + return float, (float(self),) + + def _unwrap(self) -> float: + return float(self) + + +class DeprecatedAwaitableList(List[T]): + def __init__( + self, + iterable: Iterable[T] = (), + *, + func: Callable[..., "DeprecatedAwaitableList[T]"], + ): + super().__init__(iterable) + self._name = f"{func.__module__}.{func.__qualname__}" + + def __await__(self) -> Generator[None, None, List[T]]: + _warn_deprecation(self) + if False: + yield + + return list(self) + + def __reduce__(self) -> Tuple[Type[List[T]], Tuple[List[T]]]: + return list, (list(self),) + + def _unwrap(self) -> List[T]: + return list(self) + + +class DeprecatedAsyncContextManager(Generic[T], metaclass=ABCMeta): + @abstractmethod + def __enter__(self) -> T: + pass + + @abstractmethod + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + pass + + async def __aenter__(self) -> T: + warn( + f"Using {self.__class__.__name__} as an async context manager has been deprecated. " + f'Use "async with anyio.maybe_async_cm(yourcontextmanager) as foo:" if you have to ' + f'support both AnyIO 2.x and 3.x, or just remove the "async" from "async with" if ' + f"you are completely migrating to AnyIO 3+.", + DeprecationWarning, + ) + return self.__enter__() + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + return self.__exit__(exc_type, exc_val, exc_tb) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_eventloop.py b/myenv/lib/python3.9/site-packages/anyio/_core/_eventloop.py new file mode 100644 index 0000000..f027ae5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_eventloop.py @@ -0,0 +1,155 @@ +import math +import sys +import threading +from contextlib import contextmanager +from importlib import import_module +from typing import ( + Any, + Callable, + Coroutine, + Dict, + Generator, + Optional, + Tuple, + Type, + TypeVar, +) + +import sniffio + +# This must be updated when new backends are introduced +from ._compat import DeprecatedAwaitableFloat + +BACKENDS = "asyncio", "trio" + +T_Retval = TypeVar("T_Retval") +threadlocals = threading.local() + + +def run( + func: Callable[..., Coroutine[Any, Any, T_Retval]], + *args: object, + backend: str = "asyncio", + backend_options: Optional[Dict[str, Any]] = None, +) -> T_Retval: + """ + Run the given coroutine function in an asynchronous event loop. + + The current thread must not be already running an event loop. + + :param func: a coroutine function + :param args: positional arguments to ``func`` + :param backend: name of the asynchronous event loop implementation – currently either + ``asyncio`` or ``trio`` + :param backend_options: keyword arguments to call the backend ``run()`` implementation with + (documented :ref:`here `) + :return: the return value of the coroutine function + :raises RuntimeError: if an asynchronous event loop is already running in this thread + :raises LookupError: if the named backend is not found + + """ + try: + asynclib_name = sniffio.current_async_library() + except sniffio.AsyncLibraryNotFoundError: + pass + else: + raise RuntimeError(f"Already running {asynclib_name} in this thread") + + try: + asynclib = import_module(f"..._backends._{backend}", package=__name__) + except ImportError as exc: + raise LookupError(f"No such backend: {backend}") from exc + + token = None + if sniffio.current_async_library_cvar.get(None) is None: + # Since we're in control of the event loop, we can cache the name of the async library + token = sniffio.current_async_library_cvar.set(backend) + + try: + backend_options = backend_options or {} + return asynclib.run(func, *args, **backend_options) + finally: + if token: + sniffio.current_async_library_cvar.reset(token) + + +async def sleep(delay: float) -> None: + """ + Pause the current task for the specified duration. + + :param delay: the duration, in seconds + + """ + return await get_asynclib().sleep(delay) + + +async def sleep_forever() -> None: + """ + Pause the current task until it's cancelled. + + This is a shortcut for ``sleep(math.inf)``. + + .. versionadded:: 3.1 + + """ + await sleep(math.inf) + + +async def sleep_until(deadline: float) -> None: + """ + Pause the current task until the given time. + + :param deadline: the absolute time to wake up at (according to the internal monotonic clock of + the event loop) + + .. versionadded:: 3.1 + + """ + now = current_time() + await sleep(max(deadline - now, 0)) + + +def current_time() -> DeprecatedAwaitableFloat: + """ + Return the current value of the event loop's internal clock. + + :return: the clock value (seconds) + + """ + return DeprecatedAwaitableFloat(get_asynclib().current_time(), current_time) + + +def get_all_backends() -> Tuple[str, ...]: + """Return a tuple of the names of all built-in backends.""" + return BACKENDS + + +def get_cancelled_exc_class() -> Type[BaseException]: + """Return the current async library's cancellation exception class.""" + return get_asynclib().CancelledError + + +# +# Private API +# + + +@contextmanager +def claim_worker_thread(backend: str) -> Generator[Any, None, None]: + module = sys.modules["anyio._backends._" + backend] + threadlocals.current_async_module = module + try: + yield + finally: + del threadlocals.current_async_module + + +def get_asynclib(asynclib_name: Optional[str] = None) -> Any: + if asynclib_name is None: + asynclib_name = sniffio.current_async_library() + + modulename = "anyio._backends._" + asynclib_name + try: + return sys.modules[modulename] + except KeyError: + return import_module(modulename) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_exceptions.py b/myenv/lib/python3.9/site-packages/anyio/_core/_exceptions.py new file mode 100644 index 0000000..db2bbcf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_exceptions.py @@ -0,0 +1,93 @@ +from traceback import format_exception +from typing import List + + +class BrokenResourceError(Exception): + """ + Raised when trying to use a resource that has been rendered unusable due to external causes + (e.g. a send stream whose peer has disconnected). + """ + + +class BrokenWorkerProcess(Exception): + """ + Raised by :func:`run_sync_in_process` if the worker process terminates abruptly or otherwise + misbehaves. + """ + + +class BusyResourceError(Exception): + """Raised when two tasks are trying to read from or write to the same resource concurrently.""" + + def __init__(self, action: str): + super().__init__(f"Another task is already {action} this resource") + + +class ClosedResourceError(Exception): + """Raised when trying to use a resource that has been closed.""" + + +class DelimiterNotFound(Exception): + """ + Raised during :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the + maximum number of bytes has been read without the delimiter being found. + """ + + def __init__(self, max_bytes: int) -> None: + super().__init__( + f"The delimiter was not found among the first {max_bytes} bytes" + ) + + +class EndOfStream(Exception): + """Raised when trying to read from a stream that has been closed from the other end.""" + + +class ExceptionGroup(BaseException): + """ + Raised when multiple exceptions have been raised in a task group. + + :var ~typing.Sequence[BaseException] exceptions: the sequence of exceptions raised together + """ + + SEPARATOR = "----------------------------\n" + + exceptions: List[BaseException] + + def __str__(self) -> str: + tracebacks = [ + "".join(format_exception(type(exc), exc, exc.__traceback__)) + for exc in self.exceptions + ] + return ( + f"{len(self.exceptions)} exceptions were raised in the task group:\n" + f"{self.SEPARATOR}{self.SEPARATOR.join(tracebacks)}" + ) + + def __repr__(self) -> str: + exception_reprs = ", ".join(repr(exc) for exc in self.exceptions) + return f"<{self.__class__.__name__}: {exception_reprs}>" + + +class IncompleteRead(Exception): + """ + Raised during :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or + :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the + connection is closed before the requested amount of bytes has been read. + """ + + def __init__(self) -> None: + super().__init__( + "The stream was closed before the read operation could be completed" + ) + + +class TypedAttributeLookupError(LookupError): + """ + Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute is not + found and no default value has been given. + """ + + +class WouldBlock(Exception): + """Raised by ``X_nowait`` functions if ``X()`` would block.""" diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_fileio.py b/myenv/lib/python3.9/site-packages/anyio/_core/_fileio.py new file mode 100644 index 0000000..19c1e83 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_fileio.py @@ -0,0 +1,607 @@ +import os +import pathlib +import sys +from dataclasses import dataclass +from functools import partial +from os import PathLike +from typing import ( + IO, + TYPE_CHECKING, + Any, + AnyStr, + AsyncIterator, + Callable, + Generic, + Iterable, + Iterator, + List, + Optional, + Sequence, + Tuple, + Union, + cast, + overload, +) + +from .. import to_thread +from ..abc import AsyncResource + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +if TYPE_CHECKING: + from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer +else: + ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object + + +class AsyncFile(AsyncResource, Generic[AnyStr]): + """ + An asynchronous file object. + + This class wraps a standard file object and provides async friendly versions of the following + blocking methods (where available on the original file object): + + * read + * read1 + * readline + * readlines + * readinto + * readinto1 + * write + * writelines + * truncate + * seek + * tell + * flush + + All other methods are directly passed through. + + This class supports the asynchronous context manager protocol which closes the underlying file + at the end of the context block. + + This class also supports asynchronous iteration:: + + async with await open_file(...) as f: + async for line in f: + print(line) + """ + + def __init__(self, fp: IO[AnyStr]) -> None: + self._fp: Any = fp + + def __getattr__(self, name: str) -> object: + return getattr(self._fp, name) + + @property + def wrapped(self) -> IO[AnyStr]: + """The wrapped file object.""" + return self._fp + + async def __aiter__(self) -> AsyncIterator[AnyStr]: + while True: + line = await self.readline() + if line: + yield line + else: + break + + async def aclose(self) -> None: + return await to_thread.run_sync(self._fp.close) + + async def read(self, size: int = -1) -> AnyStr: + return await to_thread.run_sync(self._fp.read, size) + + async def read1(self: "AsyncFile[bytes]", size: int = -1) -> bytes: + return await to_thread.run_sync(self._fp.read1, size) + + async def readline(self) -> AnyStr: + return await to_thread.run_sync(self._fp.readline) + + async def readlines(self) -> List[AnyStr]: + return await to_thread.run_sync(self._fp.readlines) + + async def readinto(self: "AsyncFile[bytes]", b: WriteableBuffer) -> bytes: + return await to_thread.run_sync(self._fp.readinto, b) + + async def readinto1(self: "AsyncFile[bytes]", b: WriteableBuffer) -> bytes: + return await to_thread.run_sync(self._fp.readinto1, b) + + @overload + async def write(self: "AsyncFile[bytes]", b: ReadableBuffer) -> int: + ... + + @overload + async def write(self: "AsyncFile[str]", b: str) -> int: + ... + + async def write(self, b: Union[ReadableBuffer, str]) -> int: + return await to_thread.run_sync(self._fp.write, b) + + @overload + async def writelines( + self: "AsyncFile[bytes]", lines: Iterable[ReadableBuffer] + ) -> None: + ... + + @overload + async def writelines(self: "AsyncFile[str]", lines: Iterable[str]) -> None: + ... + + async def writelines( + self, lines: Union[Iterable[ReadableBuffer], Iterable[str]] + ) -> None: + return await to_thread.run_sync(self._fp.writelines, lines) + + async def truncate(self, size: Optional[int] = None) -> int: + return await to_thread.run_sync(self._fp.truncate, size) + + async def seek(self, offset: int, whence: Optional[int] = os.SEEK_SET) -> int: + return await to_thread.run_sync(self._fp.seek, offset, whence) + + async def tell(self) -> int: + return await to_thread.run_sync(self._fp.tell) + + async def flush(self) -> None: + return await to_thread.run_sync(self._fp.flush) + + +@overload +async def open_file( + file: Union[str, "PathLike[str]", int], + mode: OpenBinaryMode, + buffering: int = ..., + encoding: Optional[str] = ..., + errors: Optional[str] = ..., + newline: Optional[str] = ..., + closefd: bool = ..., + opener: Optional[Callable[[str, int], int]] = ..., +) -> AsyncFile[bytes]: + ... + + +@overload +async def open_file( + file: Union[str, "PathLike[str]", int], + mode: OpenTextMode = ..., + buffering: int = ..., + encoding: Optional[str] = ..., + errors: Optional[str] = ..., + newline: Optional[str] = ..., + closefd: bool = ..., + opener: Optional[Callable[[str, int], int]] = ..., +) -> AsyncFile[str]: + ... + + +async def open_file( + file: Union[str, "PathLike[str]", int], + mode: str = "r", + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + closefd: bool = True, + opener: Optional[Callable[[str, int], int]] = None, +) -> AsyncFile[Any]: + """ + Open a file asynchronously. + + The arguments are exactly the same as for the builtin :func:`open`. + + :return: an asynchronous file object + + """ + fp = await to_thread.run_sync( + open, file, mode, buffering, encoding, errors, newline, closefd, opener + ) + return AsyncFile(fp) + + +def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]: + """ + Wrap an existing file as an asynchronous file. + + :param file: an existing file-like object + :return: an asynchronous file object + + """ + return AsyncFile(file) + + +@dataclass(eq=False) +class _PathIterator(AsyncIterator["Path"]): + iterator: Iterator["PathLike[str]"] + + async def __anext__(self) -> "Path": + nextval = await to_thread.run_sync(next, self.iterator, None, cancellable=True) + if nextval is None: + raise StopAsyncIteration from None + + return Path(cast("PathLike[str]", nextval)) + + +class Path: + """ + An asynchronous version of :class:`pathlib.Path`. + + This class cannot be substituted for :class:`pathlib.Path` or :class:`pathlib.PurePath`, but + it is compatible with the :class:`os.PathLike` interface. + + It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for the + deprecated :meth:`~pathlib.Path.link_to` method. + + Any methods that do disk I/O need to be awaited on. These methods are: + + * :meth:`~pathlib.Path.absolute` + * :meth:`~pathlib.Path.chmod` + * :meth:`~pathlib.Path.cwd` + * :meth:`~pathlib.Path.exists` + * :meth:`~pathlib.Path.expanduser` + * :meth:`~pathlib.Path.group` + * :meth:`~pathlib.Path.hardlink_to` + * :meth:`~pathlib.Path.home` + * :meth:`~pathlib.Path.is_block_device` + * :meth:`~pathlib.Path.is_char_device` + * :meth:`~pathlib.Path.is_dir` + * :meth:`~pathlib.Path.is_fifo` + * :meth:`~pathlib.Path.is_file` + * :meth:`~pathlib.Path.is_mount` + * :meth:`~pathlib.Path.lchmod` + * :meth:`~pathlib.Path.lstat` + * :meth:`~pathlib.Path.mkdir` + * :meth:`~pathlib.Path.open` + * :meth:`~pathlib.Path.owner` + * :meth:`~pathlib.Path.read_bytes` + * :meth:`~pathlib.Path.read_text` + * :meth:`~pathlib.Path.readlink` + * :meth:`~pathlib.Path.rename` + * :meth:`~pathlib.Path.replace` + * :meth:`~pathlib.Path.rmdir` + * :meth:`~pathlib.Path.samefile` + * :meth:`~pathlib.Path.stat` + * :meth:`~pathlib.Path.touch` + * :meth:`~pathlib.Path.unlink` + * :meth:`~pathlib.Path.write_bytes` + * :meth:`~pathlib.Path.write_text` + + Additionally, the following methods return an async iterator yielding :class:`~.Path` objects: + + * :meth:`~pathlib.Path.glob` + * :meth:`~pathlib.Path.iterdir` + * :meth:`~pathlib.Path.rglob` + """ + + __slots__ = "_path", "__weakref__" + + __weakref__: Any + + def __init__(self, *args: Union[str, "PathLike[str]"]) -> None: + self._path: Final[pathlib.Path] = pathlib.Path(*args) + + def __fspath__(self) -> str: + return self._path.__fspath__() + + def __str__(self) -> str: + return self._path.__str__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.as_posix()!r})" + + def __bytes__(self) -> bytes: + return self._path.__bytes__() + + def __hash__(self) -> int: + return self._path.__hash__() + + def __eq__(self, other: object) -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__eq__(target) + + def __lt__(self, other: "Path") -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__lt__(target) + + def __le__(self, other: "Path") -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__le__(target) + + def __gt__(self, other: "Path") -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__gt__(target) + + def __ge__(self, other: "Path") -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__ge__(target) + + def __truediv__(self, other: Any) -> "Path": + return Path(self._path / other) + + def __rtruediv__(self, other: Any) -> "Path": + return Path(other) / self + + @property + def parts(self) -> Tuple[str, ...]: + return self._path.parts + + @property + def drive(self) -> str: + return self._path.drive + + @property + def root(self) -> str: + return self._path.root + + @property + def anchor(self) -> str: + return self._path.anchor + + @property + def parents(self) -> Sequence["Path"]: + return tuple(Path(p) for p in self._path.parents) + + @property + def parent(self) -> "Path": + return Path(self._path.parent) + + @property + def name(self) -> str: + return self._path.name + + @property + def suffix(self) -> str: + return self._path.suffix + + @property + def suffixes(self) -> List[str]: + return self._path.suffixes + + @property + def stem(self) -> str: + return self._path.stem + + async def absolute(self) -> "Path": + path = await to_thread.run_sync(self._path.absolute) + return Path(path) + + def as_posix(self) -> str: + return self._path.as_posix() + + def as_uri(self) -> str: + return self._path.as_uri() + + def match(self, path_pattern: str) -> bool: + return self._path.match(path_pattern) + + def is_relative_to(self, *other: Union[str, "PathLike[str]"]) -> bool: + try: + self.relative_to(*other) + return True + except ValueError: + return False + + async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None: + func = partial(os.chmod, follow_symlinks=follow_symlinks) + return await to_thread.run_sync(func, self._path, mode) + + @classmethod + async def cwd(cls) -> "Path": + path = await to_thread.run_sync(pathlib.Path.cwd) + return cls(path) + + async def exists(self) -> bool: + return await to_thread.run_sync(self._path.exists, cancellable=True) + + async def expanduser(self) -> "Path": + return Path(await to_thread.run_sync(self._path.expanduser, cancellable=True)) + + def glob(self, pattern: str) -> AsyncIterator["Path"]: + gen = self._path.glob(pattern) + return _PathIterator(gen) + + async def group(self) -> str: + return await to_thread.run_sync(self._path.group, cancellable=True) + + async def hardlink_to(self, target: Union[str, pathlib.Path, "Path"]) -> None: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(os.link, target, self) + + @classmethod + async def home(cls) -> "Path": + home_path = await to_thread.run_sync(pathlib.Path.home) + return cls(home_path) + + def is_absolute(self) -> bool: + return self._path.is_absolute() + + async def is_block_device(self) -> bool: + return await to_thread.run_sync(self._path.is_block_device, cancellable=True) + + async def is_char_device(self) -> bool: + return await to_thread.run_sync(self._path.is_char_device, cancellable=True) + + async def is_dir(self) -> bool: + return await to_thread.run_sync(self._path.is_dir, cancellable=True) + + async def is_fifo(self) -> bool: + return await to_thread.run_sync(self._path.is_fifo, cancellable=True) + + async def is_file(self) -> bool: + return await to_thread.run_sync(self._path.is_file, cancellable=True) + + async def is_mount(self) -> bool: + return await to_thread.run_sync(os.path.ismount, self._path, cancellable=True) + + def is_reserved(self) -> bool: + return self._path.is_reserved() + + async def is_socket(self) -> bool: + return await to_thread.run_sync(self._path.is_socket, cancellable=True) + + async def is_symlink(self) -> bool: + return await to_thread.run_sync(self._path.is_symlink, cancellable=True) + + def iterdir(self) -> AsyncIterator["Path"]: + gen = self._path.iterdir() + return _PathIterator(gen) + + def joinpath(self, *args: Union[str, "PathLike[str]"]) -> "Path": + return Path(self._path.joinpath(*args)) + + async def lchmod(self, mode: int) -> None: + await to_thread.run_sync(self._path.lchmod, mode) + + async def lstat(self) -> os.stat_result: + return await to_thread.run_sync(self._path.lstat, cancellable=True) + + async def mkdir( + self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False + ) -> None: + await to_thread.run_sync(self._path.mkdir, mode, parents, exist_ok) + + @overload + async def open( + self, + mode: OpenBinaryMode, + buffering: int = ..., + encoding: Optional[str] = ..., + errors: Optional[str] = ..., + newline: Optional[str] = ..., + ) -> AsyncFile[bytes]: + ... + + @overload + async def open( + self, + mode: OpenTextMode = ..., + buffering: int = ..., + encoding: Optional[str] = ..., + errors: Optional[str] = ..., + newline: Optional[str] = ..., + ) -> AsyncFile[str]: + ... + + async def open( + self, + mode: str = "r", + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + ) -> AsyncFile[Any]: + fp = await to_thread.run_sync( + self._path.open, mode, buffering, encoding, errors, newline + ) + return AsyncFile(fp) + + async def owner(self) -> str: + return await to_thread.run_sync(self._path.owner, cancellable=True) + + async def read_bytes(self) -> bytes: + return await to_thread.run_sync(self._path.read_bytes) + + async def read_text( + self, encoding: Optional[str] = None, errors: Optional[str] = None + ) -> str: + return await to_thread.run_sync(self._path.read_text, encoding, errors) + + def relative_to(self, *other: Union[str, "PathLike[str]"]) -> "Path": + return Path(self._path.relative_to(*other)) + + async def readlink(self) -> "Path": + target = await to_thread.run_sync(os.readlink, self._path) + return Path(cast(str, target)) + + async def rename(self, target: Union[str, pathlib.PurePath, "Path"]) -> "Path": + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(self._path.rename, target) + return Path(target) + + async def replace(self, target: Union[str, pathlib.PurePath, "Path"]) -> "Path": + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(self._path.replace, target) + return Path(target) + + async def resolve(self, strict: bool = False) -> "Path": + func = partial(self._path.resolve, strict=strict) + return Path(await to_thread.run_sync(func, cancellable=True)) + + def rglob(self, pattern: str) -> AsyncIterator["Path"]: + gen = self._path.rglob(pattern) + return _PathIterator(gen) + + async def rmdir(self) -> None: + await to_thread.run_sync(self._path.rmdir) + + async def samefile( + self, other_path: Union[str, bytes, int, pathlib.Path, "Path"] + ) -> bool: + if isinstance(other_path, Path): + other_path = other_path._path + + return await to_thread.run_sync( + self._path.samefile, other_path, cancellable=True + ) + + async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result: + func = partial(os.stat, follow_symlinks=follow_symlinks) + return await to_thread.run_sync(func, self._path, cancellable=True) + + async def symlink_to( + self, + target: Union[str, pathlib.Path, "Path"], + target_is_directory: bool = False, + ) -> None: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(self._path.symlink_to, target, target_is_directory) + + async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None: + await to_thread.run_sync(self._path.touch, mode, exist_ok) + + async def unlink(self, missing_ok: bool = False) -> None: + try: + await to_thread.run_sync(self._path.unlink) + except FileNotFoundError: + if not missing_ok: + raise + + def with_name(self, name: str) -> "Path": + return Path(self._path.with_name(name)) + + def with_stem(self, stem: str) -> "Path": + return Path(self._path.with_name(stem + self._path.suffix)) + + def with_suffix(self, suffix: str) -> "Path": + return Path(self._path.with_suffix(suffix)) + + async def write_bytes(self, data: bytes) -> int: + return await to_thread.run_sync(self._path.write_bytes, data) + + async def write_text( + self, + data: str, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + ) -> int: + # Path.write_text() does not support the "newline" parameter before Python 3.10 + def sync_write_text() -> int: + with self._path.open( + "w", encoding=encoding, errors=errors, newline=newline + ) as fp: + return fp.write(data) + + return await to_thread.run_sync(sync_write_text) + + +PathLike.register(Path) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_resources.py b/myenv/lib/python3.9/site-packages/anyio/_core/_resources.py new file mode 100644 index 0000000..b9414f7 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_resources.py @@ -0,0 +1,16 @@ +from ..abc import AsyncResource +from ._tasks import CancelScope + + +async def aclose_forcefully(resource: AsyncResource) -> None: + """ + Close an asynchronous resource in a cancelled scope. + + Doing this closes the resource without waiting on anything. + + :param resource: the resource to close + + """ + with CancelScope() as scope: + scope.cancel() + await resource.aclose() diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_signals.py b/myenv/lib/python3.9/site-packages/anyio/_core/_signals.py new file mode 100644 index 0000000..02234fd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_signals.py @@ -0,0 +1,24 @@ +from typing import AsyncIterator + +from ._compat import DeprecatedAsyncContextManager +from ._eventloop import get_asynclib + + +def open_signal_receiver( + *signals: int, +) -> DeprecatedAsyncContextManager[AsyncIterator[int]]: + """ + Start receiving operating system signals. + + :param signals: signals to receive (e.g. ``signal.SIGINT``) + :return: an asynchronous context manager for an asynchronous iterator which yields signal + numbers + + .. warning:: Windows does not support signals natively so it is best to avoid relying on this + in cross-platform applications. + + .. warning:: On asyncio, this permanently replaces any previous signal handler for the given + signals, as set via :meth:`~asyncio.loop.add_signal_handler`. + + """ + return get_asynclib().open_signal_receiver(*signals) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_sockets.py b/myenv/lib/python3.9/site-packages/anyio/_core/_sockets.py new file mode 100644 index 0000000..ca85d30 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_sockets.py @@ -0,0 +1,587 @@ +import socket +import ssl +import sys +from ipaddress import IPv6Address, ip_address +from os import PathLike, chmod +from pathlib import Path +from socket import AddressFamily, SocketKind +from typing import Awaitable, List, Optional, Tuple, Union, cast, overload + +from .. import to_thread +from ..abc import ( + ConnectedUDPSocket, + IPAddressType, + IPSockAddrType, + SocketListener, + SocketStream, + UDPSocket, + UNIXSocketStream, +) +from ..streams.stapled import MultiListener +from ..streams.tls import TLSStream +from ._eventloop import get_asynclib +from ._resources import aclose_forcefully +from ._synchronization import Event +from ._tasks import create_task_group, move_on_after + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515 + +GetAddrInfoReturnType = List[ + Tuple[AddressFamily, SocketKind, int, str, Tuple[str, int]] +] +AnyIPAddressFamily = Literal[ + AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6 +] +IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6] + + +# tls_hostname given +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: Optional[IPAddressType] = ..., + ssl_context: Optional[ssl.SSLContext] = ..., + tls_standard_compatible: bool = ..., + tls_hostname: str, + happy_eyeballs_delay: float = ..., +) -> TLSStream: + ... + + +# ssl_context given +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: Optional[IPAddressType] = ..., + ssl_context: ssl.SSLContext, + tls_standard_compatible: bool = ..., + tls_hostname: Optional[str] = ..., + happy_eyeballs_delay: float = ..., +) -> TLSStream: + ... + + +# tls=True +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: Optional[IPAddressType] = ..., + tls: Literal[True], + ssl_context: Optional[ssl.SSLContext] = ..., + tls_standard_compatible: bool = ..., + tls_hostname: Optional[str] = ..., + happy_eyeballs_delay: float = ..., +) -> TLSStream: + ... + + +# tls=False +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: Optional[IPAddressType] = ..., + tls: Literal[False], + ssl_context: Optional[ssl.SSLContext] = ..., + tls_standard_compatible: bool = ..., + tls_hostname: Optional[str] = ..., + happy_eyeballs_delay: float = ..., +) -> SocketStream: + ... + + +# No TLS arguments +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: Optional[IPAddressType] = ..., + happy_eyeballs_delay: float = ..., +) -> SocketStream: + ... + + +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: Optional[IPAddressType] = None, + tls: bool = False, + ssl_context: Optional[ssl.SSLContext] = None, + tls_standard_compatible: bool = True, + tls_hostname: Optional[str] = None, + happy_eyeballs_delay: float = 0.25, +) -> Union[SocketStream, TLSStream]: + """ + Connect to a host using the TCP protocol. + + This function implements the stateless version of the Happy Eyeballs algorithm (RFC 6555). + If ``address`` is a host name that resolves to multiple IP addresses, each one is tried until + one connection attempt succeeds. If the first attempt does not connected within 250 + milliseconds, a second attempt is started using the next address in the list, and so on. + On IPv6 enabled systems, an IPv6 address (if available) is tried first. + + When the connection has been established, a TLS handshake will be done if either + ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``. + + :param remote_host: the IP address or host name to connect to + :param remote_port: port on the target host to connect to + :param local_host: the interface address or name to bind the socket to before connecting + :param tls: ``True`` to do a TLS handshake with the connected stream and return a + :class:`~anyio.streams.tls.TLSStream` instead + :param ssl_context: the SSL context object to use (if omitted, a default context is created) + :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake before closing + the stream and requires that the server does this as well. Otherwise, + :exc:`~ssl.SSLEOFError` may be raised during reads from the stream. + Some protocols, such as HTTP, require this option to be ``False``. + See :meth:`~ssl.SSLContext.wrap_socket` for details. + :param tls_hostname: host name to check the server certificate against (defaults to the value + of ``remote_host``) + :param happy_eyeballs_delay: delay (in seconds) before starting the next connection attempt + :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream + :raises OSError: if the connection attempt fails + + """ + # Placed here due to https://github.com/python/mypy/issues/7057 + connected_stream: Optional[SocketStream] = None + + async def try_connect(remote_host: str, event: Event) -> None: + nonlocal connected_stream + try: + stream = await asynclib.connect_tcp(remote_host, remote_port, local_address) + except OSError as exc: + oserrors.append(exc) + return + else: + if connected_stream is None: + connected_stream = stream + tg.cancel_scope.cancel() + else: + await stream.aclose() + finally: + event.set() + + asynclib = get_asynclib() + local_address: Optional[IPSockAddrType] = None + family = socket.AF_UNSPEC + if local_host: + gai_res = await getaddrinfo(str(local_host), None) + family, *_, local_address = gai_res[0] + + target_host = str(remote_host) + try: + addr_obj = ip_address(remote_host) + except ValueError: + # getaddrinfo() will raise an exception if name resolution fails + gai_res = await getaddrinfo( + target_host, remote_port, family=family, type=socket.SOCK_STREAM + ) + + # Organize the list so that the first address is an IPv6 address (if available) and the + # second one is an IPv4 addresses. The rest can be in whatever order. + v6_found = v4_found = False + target_addrs: List[Tuple[socket.AddressFamily, str]] = [] + for af, *rest, sa in gai_res: + if af == socket.AF_INET6 and not v6_found: + v6_found = True + target_addrs.insert(0, (af, sa[0])) + elif af == socket.AF_INET and not v4_found and v6_found: + v4_found = True + target_addrs.insert(1, (af, sa[0])) + else: + target_addrs.append((af, sa[0])) + else: + if isinstance(addr_obj, IPv6Address): + target_addrs = [(socket.AF_INET6, addr_obj.compressed)] + else: + target_addrs = [(socket.AF_INET, addr_obj.compressed)] + + oserrors: List[OSError] = [] + async with create_task_group() as tg: + for i, (af, addr) in enumerate(target_addrs): + event = Event() + tg.start_soon(try_connect, addr, event) + with move_on_after(happy_eyeballs_delay): + await event.wait() + + if connected_stream is None: + cause = oserrors[0] if len(oserrors) == 1 else asynclib.ExceptionGroup(oserrors) + raise OSError("All connection attempts failed") from cause + + if tls or tls_hostname or ssl_context: + try: + return await TLSStream.wrap( + connected_stream, + server_side=False, + hostname=tls_hostname or str(remote_host), + ssl_context=ssl_context, + standard_compatible=tls_standard_compatible, + ) + except BaseException: + await aclose_forcefully(connected_stream) + raise + + return connected_stream + + +async def connect_unix(path: Union[str, "PathLike[str]"]) -> UNIXSocketStream: + """ + Connect to the given UNIX socket. + + Not available on Windows. + + :param path: path to the socket + :return: a socket stream object + + """ + path = str(Path(path)) + return await get_asynclib().connect_unix(path) + + +async def create_tcp_listener( + *, + local_host: Optional[IPAddressType] = None, + local_port: int = 0, + family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC, + backlog: int = 65536, + reuse_port: bool = False, +) -> MultiListener[SocketStream]: + """ + Create a TCP socket listener. + + :param local_port: port number to listen on + :param local_host: IP address of the interface to listen on. If omitted, listen on all IPv4 + and IPv6 interfaces. To listen on all interfaces on a specific address family, use + ``0.0.0.0`` for IPv4 or ``::`` for IPv6. + :param family: address family (used if ``interface`` was omitted) + :param backlog: maximum number of queued incoming connections (up to a maximum of 2**16, or + 65536) + :param reuse_port: ``True`` to allow multiple sockets to bind to the same address/port + (not supported on Windows) + :return: a list of listener objects + + """ + asynclib = get_asynclib() + backlog = min(backlog, 65536) + local_host = str(local_host) if local_host is not None else None + gai_res = await getaddrinfo( + local_host, # type: ignore[arg-type] + local_port, + family=family, + type=socket.SOCK_STREAM, + flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, + ) + listeners: List[SocketListener] = [] + try: + # The set() is here to work around a glibc bug: + # https://sourceware.org/bugzilla/show_bug.cgi?id=14969 + for fam, *_, sockaddr in sorted(set(gai_res)): + raw_socket = socket.socket(fam) + raw_socket.setblocking(False) + + # For Windows, enable exclusive address use. For others, enable address reuse. + if sys.platform == "win32": + raw_socket.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) + else: + raw_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + if reuse_port: + raw_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + + # If only IPv6 was requested, disable dual stack operation + if fam == socket.AF_INET6: + raw_socket.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, 1) + + raw_socket.bind(sockaddr) + raw_socket.listen(backlog) + listener = asynclib.TCPSocketListener(raw_socket) + listeners.append(listener) + except BaseException: + for listener in listeners: + await listener.aclose() + + raise + + return MultiListener(listeners) + + +async def create_unix_listener( + path: Union[str, "PathLike[str]"], + *, + mode: Optional[int] = None, + backlog: int = 65536, +) -> SocketListener: + """ + Create a UNIX socket listener. + + Not available on Windows. + + :param path: path of the socket + :param mode: permissions to set on the socket + :param backlog: maximum number of queued incoming connections (up to a maximum of 2**16, or + 65536) + :return: a listener object + + .. versionchanged:: 3.0 + If a socket already exists on the file system in the given path, it will be removed first. + + """ + path_str = str(path) + path = Path(path) + if path.is_socket(): + path.unlink() + + backlog = min(backlog, 65536) + raw_socket = socket.socket(socket.AF_UNIX) + raw_socket.setblocking(False) + try: + await to_thread.run_sync(raw_socket.bind, path_str, cancellable=True) + if mode is not None: + await to_thread.run_sync(chmod, path_str, mode, cancellable=True) + + raw_socket.listen(backlog) + return get_asynclib().UNIXSocketListener(raw_socket) + except BaseException: + raw_socket.close() + raise + + +async def create_udp_socket( + family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, + *, + local_host: Optional[IPAddressType] = None, + local_port: int = 0, + reuse_port: bool = False, +) -> UDPSocket: + """ + Create a UDP socket. + + If ``port`` has been given, the socket will be bound to this port on the local machine, + making this socket suitable for providing UDP based services. + + :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically determined from + ``local_host`` if omitted + :param local_host: IP address or host name of the local interface to bind to + :param local_port: local port to bind to + :param reuse_port: ``True`` to allow multiple sockets to bind to the same address/port + (not supported on Windows) + :return: a UDP socket + + """ + if family is AddressFamily.AF_UNSPEC and not local_host: + raise ValueError('Either "family" or "local_host" must be given') + + if local_host: + gai_res = await getaddrinfo( + str(local_host), + local_port, + family=family, + type=socket.SOCK_DGRAM, + flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, + ) + family = cast(AnyIPAddressFamily, gai_res[0][0]) + local_address = gai_res[0][-1] + elif family is AddressFamily.AF_INET6: + local_address = ("::", 0) + else: + local_address = ("0.0.0.0", 0) + + return await get_asynclib().create_udp_socket( + family, local_address, None, reuse_port + ) + + +async def create_connected_udp_socket( + remote_host: IPAddressType, + remote_port: int, + *, + family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, + local_host: Optional[IPAddressType] = None, + local_port: int = 0, + reuse_port: bool = False, +) -> ConnectedUDPSocket: + """ + Create a connected UDP socket. + + Connected UDP sockets can only communicate with the specified remote host/port, and any packets + sent from other sources are dropped. + + :param remote_host: remote host to set as the default target + :param remote_port: port on the remote host to set as the default target + :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically determined from + ``local_host`` or ``remote_host`` if omitted + :param local_host: IP address or host name of the local interface to bind to + :param local_port: local port to bind to + :param reuse_port: ``True`` to allow multiple sockets to bind to the same address/port + (not supported on Windows) + :return: a connected UDP socket + + """ + local_address = None + if local_host: + gai_res = await getaddrinfo( + str(local_host), + local_port, + family=family, + type=socket.SOCK_DGRAM, + flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, + ) + family = cast(AnyIPAddressFamily, gai_res[0][0]) + local_address = gai_res[0][-1] + + gai_res = await getaddrinfo( + str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM + ) + family = cast(AnyIPAddressFamily, gai_res[0][0]) + remote_address = gai_res[0][-1] + + return await get_asynclib().create_udp_socket( + family, local_address, remote_address, reuse_port + ) + + +async def getaddrinfo( + host: Union[bytearray, bytes, str], + port: Union[str, int, None], + *, + family: Union[int, AddressFamily] = 0, + type: Union[int, SocketKind] = 0, + proto: int = 0, + flags: int = 0, +) -> GetAddrInfoReturnType: + """ + Look up a numeric IP address given a host name. + + Internationalized domain names are translated according to the (non-transitional) IDNA 2008 + standard. + + .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of + (host, port), unlike what :func:`socket.getaddrinfo` does. + + :param host: host name + :param port: port number + :param family: socket family (`'AF_INET``, ...) + :param type: socket type (``SOCK_STREAM``, ...) + :param proto: protocol number + :param flags: flags to pass to upstream ``getaddrinfo()`` + :return: list of tuples containing (family, type, proto, canonname, sockaddr) + + .. seealso:: :func:`socket.getaddrinfo` + + """ + # Handle unicode hostnames + if isinstance(host, str): + try: + encoded_host = host.encode("ascii") + except UnicodeEncodeError: + import idna + + encoded_host = idna.encode(host, uts46=True) + else: + encoded_host = host + + gai_res = await get_asynclib().getaddrinfo( + encoded_host, port, family=family, type=type, proto=proto, flags=flags + ) + return [ + (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr)) + for family, type, proto, canonname, sockaddr in gai_res + ] + + +def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[Tuple[str, str]]: + """ + Look up the host name of an IP address. + + :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4) + :param flags: flags to pass to upstream ``getnameinfo()`` + :return: a tuple of (host name, service name) + + .. seealso:: :func:`socket.getnameinfo` + + """ + return get_asynclib().getnameinfo(sockaddr, flags) + + +def wait_socket_readable(sock: socket.socket) -> Awaitable[None]: + """ + Wait until the given socket has data to be read. + + This does **NOT** work on Windows when using the asyncio backend with a proactor event loop + (default on py3.8+). + + .. warning:: Only use this on raw sockets that have not been wrapped by any higher level + constructs like socket streams! + + :param sock: a socket object + :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the + socket to become readable + :raises ~anyio.BusyResourceError: if another task is already waiting for the socket + to become readable + + """ + return get_asynclib().wait_socket_readable(sock) + + +def wait_socket_writable(sock: socket.socket) -> Awaitable[None]: + """ + Wait until the given socket can be written to. + + This does **NOT** work on Windows when using the asyncio backend with a proactor event loop + (default on py3.8+). + + .. warning:: Only use this on raw sockets that have not been wrapped by any higher level + constructs like socket streams! + + :param sock: a socket object + :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the + socket to become writable + :raises ~anyio.BusyResourceError: if another task is already waiting for the socket + to become writable + + """ + return get_asynclib().wait_socket_writable(sock) + + +# +# Private API +# + + +def convert_ipv6_sockaddr( + sockaddr: Union[Tuple[str, int, int, int], Tuple[str, int]] +) -> Tuple[str, int]: + """ + Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format. + + If the scope ID is nonzero, it is added to the address, separated with ``%``. + Otherwise the flow id and scope id are simply cut off from the tuple. + Any other kinds of socket addresses are returned as-is. + + :param sockaddr: the result of :meth:`~socket.socket.getsockname` + :return: the converted socket address + + """ + # This is more complicated than it should be because of MyPy + if isinstance(sockaddr, tuple) and len(sockaddr) == 4: + host, port, flowinfo, scope_id = cast(Tuple[str, int, int, int], sockaddr) + if scope_id: + # Add scope_id to the address + return f"{host}%{scope_id}", port + else: + return host, port + else: + return cast(Tuple[str, int], sockaddr) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_streams.py b/myenv/lib/python3.9/site-packages/anyio/_core/_streams.py new file mode 100644 index 0000000..58954a6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_streams.py @@ -0,0 +1,45 @@ +import math +from typing import Any, Optional, Tuple, Type, TypeVar, overload + +from ..streams.memory import ( + MemoryObjectReceiveStream, + MemoryObjectSendStream, + MemoryObjectStreamState, +) + +T_Item = TypeVar("T_Item") + + +@overload +def create_memory_object_stream( + max_buffer_size: float, item_type: Type[T_Item] +) -> Tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]: + ... + + +@overload +def create_memory_object_stream( + max_buffer_size: float = 0, +) -> Tuple[MemoryObjectSendStream[Any], MemoryObjectReceiveStream[Any]]: + ... + + +def create_memory_object_stream( + max_buffer_size: float = 0, item_type: Optional[Type[T_Item]] = None +) -> Tuple[MemoryObjectSendStream[Any], MemoryObjectReceiveStream[Any]]: + """ + Create a memory object stream. + + :param max_buffer_size: number of items held in the buffer until ``send()`` starts blocking + :param item_type: type of item, for marking the streams with the right generic type for + static typing (not used at run time) + :return: a tuple of (send stream, receive stream) + + """ + if max_buffer_size != math.inf and not isinstance(max_buffer_size, int): + raise ValueError("max_buffer_size must be either an integer or math.inf") + if max_buffer_size < 0: + raise ValueError("max_buffer_size cannot be negative") + + state: MemoryObjectStreamState = MemoryObjectStreamState(max_buffer_size) + return MemoryObjectSendStream(state), MemoryObjectReceiveStream(state) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_subprocesses.py b/myenv/lib/python3.9/site-packages/anyio/_core/_subprocesses.py new file mode 100644 index 0000000..43fa6b6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_subprocesses.py @@ -0,0 +1,136 @@ +from io import BytesIO +from os import PathLike +from subprocess import DEVNULL, PIPE, CalledProcessError, CompletedProcess +from typing import ( + IO, + Any, + AsyncIterable, + List, + Mapping, + Optional, + Sequence, + Union, + cast, +) + +from ..abc import Process +from ._eventloop import get_asynclib +from ._tasks import create_task_group + + +async def run_process( + command: Union[str, bytes, Sequence[Union[str, bytes]]], + *, + input: Optional[bytes] = None, + stdout: Union[int, IO[Any], None] = PIPE, + stderr: Union[int, IO[Any], None] = PIPE, + check: bool = True, + cwd: Union[str, bytes, "PathLike[str]", None] = None, + env: Optional[Mapping[str, str]] = None, + start_new_session: bool = False, +) -> "CompletedProcess[bytes]": + """ + Run an external command in a subprocess and wait until it completes. + + .. seealso:: :func:`subprocess.run` + + :param command: either a string to pass to the shell, or an iterable of strings containing the + executable name or path and its arguments + :param input: bytes passed to the standard input of the subprocess + :param stdout: either :data:`subprocess.PIPE` or :data:`subprocess.DEVNULL` + :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL` or + :data:`subprocess.STDOUT` + :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the process + terminates with a return code other than 0 + :param cwd: If not ``None``, change the working directory to this before running the command + :param env: if not ``None``, this mapping replaces the inherited environment variables from the + parent process + :param start_new_session: if ``true`` the setsid() system call will be made in the child + process prior to the execution of the subprocess. (POSIX only) + :return: an object representing the completed process + :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process exits with a + nonzero return code + + """ + + async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None: + buffer = BytesIO() + async for chunk in stream: + buffer.write(chunk) + + stream_contents[index] = buffer.getvalue() + + async with await open_process( + command, + stdin=PIPE if input else DEVNULL, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) as process: + stream_contents: List[Optional[bytes]] = [None, None] + try: + async with create_task_group() as tg: + if process.stdout: + tg.start_soon(drain_stream, process.stdout, 0) + if process.stderr: + tg.start_soon(drain_stream, process.stderr, 1) + if process.stdin and input: + await process.stdin.send(input) + await process.stdin.aclose() + + await process.wait() + except BaseException: + process.kill() + raise + + output, errors = stream_contents + if check and process.returncode != 0: + raise CalledProcessError(cast(int, process.returncode), command, output, errors) + + return CompletedProcess(command, cast(int, process.returncode), output, errors) + + +async def open_process( + command: Union[str, bytes, Sequence[Union[str, bytes]]], + *, + stdin: Union[int, IO[Any], None] = PIPE, + stdout: Union[int, IO[Any], None] = PIPE, + stderr: Union[int, IO[Any], None] = PIPE, + cwd: Union[str, bytes, "PathLike[str]", None] = None, + env: Optional[Mapping[str, str]] = None, + start_new_session: bool = False, +) -> Process: + """ + Start an external command in a subprocess. + + .. seealso:: :class:`subprocess.Popen` + + :param command: either a string to pass to the shell, or an iterable of strings containing the + executable name or path and its arguments + :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a + file-like object, or ``None`` + :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, + a file-like object, or ``None`` + :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, + :data:`subprocess.STDOUT`, a file-like object, or ``None`` + :param cwd: If not ``None``, the working directory is changed before executing + :param env: If env is not ``None``, it must be a mapping that defines the environment + variables for the new process + :param start_new_session: if ``true`` the setsid() system call will be made in the child + process prior to the execution of the subprocess. (POSIX only) + :return: an asynchronous process object + + """ + shell = isinstance(command, str) + return await get_asynclib().open_process( + command, + shell=shell, + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + start_new_session=start_new_session, + ) diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_synchronization.py b/myenv/lib/python3.9/site-packages/anyio/_core/_synchronization.py new file mode 100644 index 0000000..15d4afc --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_synchronization.py @@ -0,0 +1,595 @@ +from collections import deque +from dataclasses import dataclass +from types import TracebackType +from typing import Deque, Optional, Tuple, Type +from warnings import warn + +from ..lowlevel import cancel_shielded_checkpoint, checkpoint, checkpoint_if_cancelled +from ._compat import DeprecatedAwaitable +from ._eventloop import get_asynclib +from ._exceptions import BusyResourceError, WouldBlock +from ._tasks import CancelScope +from ._testing import TaskInfo, get_current_task + + +@dataclass(frozen=True) +class EventStatistics: + """ + :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait` + """ + + tasks_waiting: int + + +@dataclass(frozen=True) +class CapacityLimiterStatistics: + """ + :ivar int borrowed_tokens: number of tokens currently borrowed by tasks + :ivar float total_tokens: total number of available tokens + :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from this + limiter + :ivar int tasks_waiting: number of tasks waiting on :meth:`~.CapacityLimiter.acquire` or + :meth:`~.CapacityLimiter.acquire_on_behalf_of` + """ + + borrowed_tokens: int + total_tokens: float + borrowers: Tuple[object, ...] + tasks_waiting: int + + +@dataclass(frozen=True) +class LockStatistics: + """ + :ivar bool locked: flag indicating if this lock is locked or not + :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the lock is not + held by any task) + :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire` + """ + + locked: bool + owner: Optional[TaskInfo] + tasks_waiting: int + + +@dataclass(frozen=True) +class ConditionStatistics: + """ + :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait` + :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying :class:`~.Lock` + """ + + tasks_waiting: int + lock_statistics: LockStatistics + + +@dataclass(frozen=True) +class SemaphoreStatistics: + """ + :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire` + + """ + + tasks_waiting: int + + +class Event: + def __new__(cls) -> "Event": + return get_asynclib().Event() + + def set(self) -> DeprecatedAwaitable: + """Set the flag, notifying all listeners.""" + raise NotImplementedError + + def is_set(self) -> bool: + """Return ``True`` if the flag is set, ``False`` if not.""" + raise NotImplementedError + + async def wait(self) -> None: + """ + Wait until the flag has been set. + + If the flag has already been set when this method is called, it returns immediately. + + """ + raise NotImplementedError + + def statistics(self) -> EventStatistics: + """Return statistics about the current state of this event.""" + raise NotImplementedError + + +class Lock: + _owner_task: Optional[TaskInfo] = None + + def __init__(self) -> None: + self._waiters: Deque[Tuple[TaskInfo, Event]] = deque() + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.release() + + async def acquire(self) -> None: + """Acquire the lock.""" + await checkpoint_if_cancelled() + try: + self.acquire_nowait() + except WouldBlock: + task = get_current_task() + event = Event() + token = task, event + self._waiters.append(token) + try: + await event.wait() + except BaseException: + if not event.is_set(): + self._waiters.remove(token) + elif self._owner_task == task: + self.release() + + raise + + assert self._owner_task == task + else: + try: + await cancel_shielded_checkpoint() + except BaseException: + self.release() + raise + + def acquire_nowait(self) -> None: + """ + Acquire the lock, without blocking. + + :raises ~WouldBlock: if the operation would block + + """ + task = get_current_task() + if self._owner_task == task: + raise RuntimeError("Attempted to acquire an already held Lock") + + if self._owner_task is not None: + raise WouldBlock + + self._owner_task = task + + def release(self) -> DeprecatedAwaitable: + """Release the lock.""" + if self._owner_task != get_current_task(): + raise RuntimeError("The current task is not holding this lock") + + if self._waiters: + self._owner_task, event = self._waiters.popleft() + event.set() + else: + del self._owner_task + + return DeprecatedAwaitable(self.release) + + def locked(self) -> bool: + """Return True if the lock is currently held.""" + return self._owner_task is not None + + def statistics(self) -> LockStatistics: + """ + Return statistics about the current state of this lock. + + .. versionadded:: 3.0 + """ + return LockStatistics(self.locked(), self._owner_task, len(self._waiters)) + + +class Condition: + _owner_task: Optional[TaskInfo] = None + + def __init__(self, lock: Optional[Lock] = None): + self._lock = lock or Lock() + self._waiters: Deque[Event] = deque() + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.release() + + def _check_acquired(self) -> None: + if self._owner_task != get_current_task(): + raise RuntimeError("The current task is not holding the underlying lock") + + async def acquire(self) -> None: + """Acquire the underlying lock.""" + await self._lock.acquire() + self._owner_task = get_current_task() + + def acquire_nowait(self) -> None: + """ + Acquire the underlying lock, without blocking. + + :raises ~WouldBlock: if the operation would block + + """ + self._lock.acquire_nowait() + self._owner_task = get_current_task() + + def release(self) -> DeprecatedAwaitable: + """Release the underlying lock.""" + self._lock.release() + return DeprecatedAwaitable(self.release) + + def locked(self) -> bool: + """Return True if the lock is set.""" + return self._lock.locked() + + def notify(self, n: int = 1) -> None: + """Notify exactly n listeners.""" + self._check_acquired() + for _ in range(n): + try: + event = self._waiters.popleft() + except IndexError: + break + + event.set() + + def notify_all(self) -> None: + """Notify all the listeners.""" + self._check_acquired() + for event in self._waiters: + event.set() + + self._waiters.clear() + + async def wait(self) -> None: + """Wait for a notification.""" + await checkpoint() + event = Event() + self._waiters.append(event) + self.release() + try: + await event.wait() + except BaseException: + if not event.is_set(): + self._waiters.remove(event) + + raise + finally: + with CancelScope(shield=True): + await self.acquire() + + def statistics(self) -> ConditionStatistics: + """ + Return statistics about the current state of this condition. + + .. versionadded:: 3.0 + """ + return ConditionStatistics(len(self._waiters), self._lock.statistics()) + + +class Semaphore: + def __init__(self, initial_value: int, *, max_value: Optional[int] = None): + if not isinstance(initial_value, int): + raise TypeError("initial_value must be an integer") + if initial_value < 0: + raise ValueError("initial_value must be >= 0") + if max_value is not None: + if not isinstance(max_value, int): + raise TypeError("max_value must be an integer or None") + if max_value < initial_value: + raise ValueError( + "max_value must be equal to or higher than initial_value" + ) + + self._value = initial_value + self._max_value = max_value + self._waiters: Deque[Event] = deque() + + async def __aenter__(self) -> "Semaphore": + await self.acquire() + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.release() + + async def acquire(self) -> None: + """Decrement the semaphore value, blocking if necessary.""" + await checkpoint_if_cancelled() + try: + self.acquire_nowait() + except WouldBlock: + event = Event() + self._waiters.append(event) + try: + await event.wait() + except BaseException: + if not event.is_set(): + self._waiters.remove(event) + else: + self.release() + + raise + else: + try: + await cancel_shielded_checkpoint() + except BaseException: + self.release() + raise + + def acquire_nowait(self) -> None: + """ + Acquire the underlying lock, without blocking. + + :raises ~WouldBlock: if the operation would block + + """ + if self._value == 0: + raise WouldBlock + + self._value -= 1 + + def release(self) -> DeprecatedAwaitable: + """Increment the semaphore value.""" + if self._max_value is not None and self._value == self._max_value: + raise ValueError("semaphore released too many times") + + if self._waiters: + self._waiters.popleft().set() + else: + self._value += 1 + + return DeprecatedAwaitable(self.release) + + @property + def value(self) -> int: + """The current value of the semaphore.""" + return self._value + + @property + def max_value(self) -> Optional[int]: + """The maximum value of the semaphore.""" + return self._max_value + + def statistics(self) -> SemaphoreStatistics: + """ + Return statistics about the current state of this semaphore. + + .. versionadded:: 3.0 + """ + return SemaphoreStatistics(len(self._waiters)) + + +class CapacityLimiter: + def __new__(cls, total_tokens: float) -> "CapacityLimiter": + return get_asynclib().CapacityLimiter(total_tokens) + + async def __aenter__(self) -> None: + raise NotImplementedError + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + raise NotImplementedError + + @property + def total_tokens(self) -> float: + """ + The total number of tokens available for borrowing. + + This is a read-write property. If the total number of tokens is increased, the + proportionate number of tasks waiting on this limiter will be granted their tokens. + + .. versionchanged:: 3.0 + The property is now writable. + + """ + raise NotImplementedError + + @total_tokens.setter + def total_tokens(self, value: float) -> None: + raise NotImplementedError + + async def set_total_tokens(self, value: float) -> None: + warn( + "CapacityLimiter.set_total_tokens has been deprecated. Set the value of the" + '"total_tokens" attribute directly.', + DeprecationWarning, + ) + self.total_tokens = value + + @property + def borrowed_tokens(self) -> int: + """The number of tokens that have currently been borrowed.""" + raise NotImplementedError + + @property + def available_tokens(self) -> float: + """The number of tokens currently available to be borrowed""" + raise NotImplementedError + + def acquire_nowait(self) -> DeprecatedAwaitable: + """ + Acquire a token for the current task without waiting for one to become available. + + :raises ~anyio.WouldBlock: if there are no tokens available for borrowing + + """ + raise NotImplementedError + + def acquire_on_behalf_of_nowait(self, borrower: object) -> DeprecatedAwaitable: + """ + Acquire a token without waiting for one to become available. + + :param borrower: the entity borrowing a token + :raises ~anyio.WouldBlock: if there are no tokens available for borrowing + + """ + raise NotImplementedError + + async def acquire(self) -> None: + """ + Acquire a token for the current task, waiting if necessary for one to become available. + + """ + raise NotImplementedError + + async def acquire_on_behalf_of(self, borrower: object) -> None: + """ + Acquire a token, waiting if necessary for one to become available. + + :param borrower: the entity borrowing a token + + """ + raise NotImplementedError + + def release(self) -> None: + """ + Release the token held by the current task. + :raises RuntimeError: if the current task has not borrowed a token from this limiter. + + """ + raise NotImplementedError + + def release_on_behalf_of(self, borrower: object) -> None: + """ + Release the token held by the given borrower. + + :raises RuntimeError: if the borrower has not borrowed a token from this limiter. + + """ + raise NotImplementedError + + def statistics(self) -> CapacityLimiterStatistics: + """ + Return statistics about the current state of this limiter. + + .. versionadded:: 3.0 + + """ + raise NotImplementedError + + +def create_lock() -> Lock: + """ + Create an asynchronous lock. + + :return: a lock object + + .. deprecated:: 3.0 + Use :class:`~Lock` directly. + + """ + warn("create_lock() is deprecated -- use Lock() directly", DeprecationWarning) + return Lock() + + +def create_condition(lock: Optional[Lock] = None) -> Condition: + """ + Create an asynchronous condition. + + :param lock: the lock to base the condition object on + :return: a condition object + + .. deprecated:: 3.0 + Use :class:`~Condition` directly. + + """ + warn( + "create_condition() is deprecated -- use Condition() directly", + DeprecationWarning, + ) + return Condition(lock=lock) + + +def create_event() -> Event: + """ + Create an asynchronous event object. + + :return: an event object + + .. deprecated:: 3.0 + Use :class:`~Event` directly. + + """ + warn("create_event() is deprecated -- use Event() directly", DeprecationWarning) + return get_asynclib().Event() + + +def create_semaphore(value: int, *, max_value: Optional[int] = None) -> Semaphore: + """ + Create an asynchronous semaphore. + + :param value: the semaphore's initial value + :param max_value: if set, makes this a "bounded" semaphore that raises :exc:`ValueError` if the + semaphore's value would exceed this number + :return: a semaphore object + + .. deprecated:: 3.0 + Use :class:`~Semaphore` directly. + + """ + warn( + "create_semaphore() is deprecated -- use Semaphore() directly", + DeprecationWarning, + ) + return Semaphore(value, max_value=max_value) + + +def create_capacity_limiter(total_tokens: float) -> CapacityLimiter: + """ + Create a capacity limiter. + + :param total_tokens: the total number of tokens available for borrowing (can be an integer or + :data:`math.inf`) + :return: a capacity limiter object + + .. deprecated:: 3.0 + Use :class:`~CapacityLimiter` directly. + + """ + warn( + "create_capacity_limiter() is deprecated -- use CapacityLimiter() directly", + DeprecationWarning, + ) + return get_asynclib().CapacityLimiter(total_tokens) + + +class ResourceGuard: + __slots__ = "action", "_guarded" + + def __init__(self, action: str): + self.action = action + self._guarded = False + + def __enter__(self) -> None: + if self._guarded: + raise BusyResourceError(self.action) + + self._guarded = True + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + self._guarded = False + return None diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_tasks.py b/myenv/lib/python3.9/site-packages/anyio/_core/_tasks.py new file mode 100644 index 0000000..f24764c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_tasks.py @@ -0,0 +1,178 @@ +import math +from types import TracebackType +from typing import Optional, Type +from warnings import warn + +from ..abc._tasks import TaskGroup, TaskStatus +from ._compat import ( + DeprecatedAsyncContextManager, + DeprecatedAwaitable, + DeprecatedAwaitableFloat, +) +from ._eventloop import get_asynclib + + +class _IgnoredTaskStatus(TaskStatus): + def started(self, value: object = None) -> None: + pass + + +TASK_STATUS_IGNORED = _IgnoredTaskStatus() + + +class CancelScope(DeprecatedAsyncContextManager["CancelScope"]): + """ + Wraps a unit of work that can be made separately cancellable. + + :param deadline: The time (clock value) when this scope is cancelled automatically + :param shield: ``True`` to shield the cancel scope from external cancellation + """ + + def __new__( + cls, *, deadline: float = math.inf, shield: bool = False + ) -> "CancelScope": + return get_asynclib().CancelScope(shield=shield, deadline=deadline) + + def cancel(self) -> DeprecatedAwaitable: + """Cancel this scope immediately.""" + raise NotImplementedError + + @property + def deadline(self) -> float: + """ + The time (clock value) when this scope is cancelled automatically. + + Will be ``float('inf')`` if no timeout has been set. + + """ + raise NotImplementedError + + @deadline.setter + def deadline(self, value: float) -> None: + raise NotImplementedError + + @property + def cancel_called(self) -> bool: + """``True`` if :meth:`cancel` has been called.""" + raise NotImplementedError + + @property + def shield(self) -> bool: + """ + ``True`` if this scope is shielded from external cancellation. + + While a scope is shielded, it will not receive cancellations from outside. + + """ + raise NotImplementedError + + @shield.setter + def shield(self, value: bool) -> None: + raise NotImplementedError + + def __enter__(self) -> "CancelScope": + raise NotImplementedError + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + raise NotImplementedError + + +def open_cancel_scope(*, shield: bool = False) -> CancelScope: + """ + Open a cancel scope. + + :param shield: ``True`` to shield the cancel scope from external cancellation + :return: a cancel scope + + .. deprecated:: 3.0 + Use :class:`~CancelScope` directly. + + """ + warn( + "open_cancel_scope() is deprecated -- use CancelScope() directly", + DeprecationWarning, + ) + return get_asynclib().CancelScope(shield=shield) + + +class FailAfterContextManager(DeprecatedAsyncContextManager[CancelScope]): + def __init__(self, cancel_scope: CancelScope): + self._cancel_scope = cancel_scope + + def __enter__(self) -> CancelScope: + return self._cancel_scope.__enter__() + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + retval = self._cancel_scope.__exit__(exc_type, exc_val, exc_tb) + if self._cancel_scope.cancel_called: + raise TimeoutError + + return retval + + +def fail_after(delay: Optional[float], shield: bool = False) -> FailAfterContextManager: + """ + Create a context manager which raises a :class:`TimeoutError` if does not finish in time. + + :param delay: maximum allowed time (in seconds) before raising the exception, or ``None`` to + disable the timeout + :param shield: ``True`` to shield the cancel scope from external cancellation + :return: a context manager that yields a cancel scope + :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.abc.CancelScope`\\] + + """ + deadline = ( + (get_asynclib().current_time() + delay) if delay is not None else math.inf + ) + cancel_scope = get_asynclib().CancelScope(deadline=deadline, shield=shield) + return FailAfterContextManager(cancel_scope) + + +def move_on_after(delay: Optional[float], shield: bool = False) -> CancelScope: + """ + Create a cancel scope with a deadline that expires after the given delay. + + :param delay: maximum allowed time (in seconds) before exiting the context block, or ``None`` + to disable the timeout + :param shield: ``True`` to shield the cancel scope from external cancellation + :return: a cancel scope + + """ + deadline = ( + (get_asynclib().current_time() + delay) if delay is not None else math.inf + ) + return get_asynclib().CancelScope(deadline=deadline, shield=shield) + + +def current_effective_deadline() -> DeprecatedAwaitableFloat: + """ + Return the nearest deadline among all the cancel scopes effective for the current task. + + :return: a clock value from the event loop's internal clock (``float('inf')`` if there is no + deadline in effect) + :rtype: float + + """ + return DeprecatedAwaitableFloat( + get_asynclib().current_effective_deadline(), current_effective_deadline + ) + + +def create_task_group() -> "TaskGroup": + """ + Create a task group. + + :return: a task group + + """ + return get_asynclib().TaskGroup() diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_testing.py b/myenv/lib/python3.9/site-packages/anyio/_core/_testing.py new file mode 100644 index 0000000..4998753 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_testing.py @@ -0,0 +1,80 @@ +from typing import Any, Awaitable, Generator, Optional, Union + +from ._compat import DeprecatedAwaitableList, _warn_deprecation +from ._eventloop import get_asynclib + + +class TaskInfo: + """ + Represents an asynchronous task. + + :ivar int id: the unique identifier of the task + :ivar parent_id: the identifier of the parent task, if any + :vartype parent_id: Optional[int] + :ivar str name: the description of the task (if any) + :ivar ~collections.abc.Coroutine coro: the coroutine object of the task + """ + + __slots__ = "_name", "id", "parent_id", "name", "coro" + + def __init__( + self, + id: int, + parent_id: Optional[int], + name: Optional[str], + coro: Union[Generator, Awaitable[Any]], + ): + func = get_current_task + self._name = f"{func.__module__}.{func.__qualname__}" + self.id: int = id + self.parent_id: Optional[int] = parent_id + self.name: Optional[str] = name + self.coro: Union[Generator, Awaitable[Any]] = coro + + def __eq__(self, other: object) -> bool: + if isinstance(other, TaskInfo): + return self.id == other.id + + return NotImplemented + + def __hash__(self) -> int: + return hash(self.id) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})" + + def __await__(self) -> Generator[None, None, "TaskInfo"]: + _warn_deprecation(self) + if False: + yield + + return self + + def _unwrap(self) -> "TaskInfo": + return self + + +def get_current_task() -> TaskInfo: + """ + Return the current task. + + :return: a representation of the current task + + """ + return get_asynclib().get_current_task() + + +def get_running_tasks() -> DeprecatedAwaitableList[TaskInfo]: + """ + Return a list of running tasks in the current event loop. + + :return: a list of task info objects + + """ + tasks = get_asynclib().get_running_tasks() + return DeprecatedAwaitableList(tasks, func=get_running_tasks) + + +async def wait_all_tasks_blocked() -> None: + """Wait until all other tasks are waiting for something.""" + await get_asynclib().wait_all_tasks_blocked() diff --git a/myenv/lib/python3.9/site-packages/anyio/_core/_typedattr.py b/myenv/lib/python3.9/site-packages/anyio/_core/_typedattr.py new file mode 100644 index 0000000..424836a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/_core/_typedattr.py @@ -0,0 +1,81 @@ +import sys +from typing import Any, Callable, Dict, Mapping, TypeVar, Union, overload + +from ._exceptions import TypedAttributeLookupError + +if sys.version_info >= (3, 8): + from typing import final +else: + from typing_extensions import final + +T_Attr = TypeVar("T_Attr") +T_Default = TypeVar("T_Default") +undefined = object() + + +def typed_attribute() -> Any: + """Return a unique object, used to mark typed attributes.""" + return object() + + +class TypedAttributeSet: + """ + Superclass for typed attribute collections. + + Checks that every public attribute of every subclass has a type annotation. + """ + + def __init_subclass__(cls) -> None: + annotations: Dict[str, Any] = getattr(cls, "__annotations__", {}) + for attrname in dir(cls): + if not attrname.startswith("_") and attrname not in annotations: + raise TypeError( + f"Attribute {attrname!r} is missing its type annotation" + ) + + super().__init_subclass__() + + +class TypedAttributeProvider: + """Base class for classes that wish to provide typed extra attributes.""" + + @property + def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]: + """ + A mapping of the extra attributes to callables that return the corresponding values. + + If the provider wraps another provider, the attributes from that wrapper should also be + included in the returned mapping (but the wrapper may override the callables from the + wrapped instance). + + """ + return {} + + @overload + def extra(self, attribute: T_Attr) -> T_Attr: + ... + + @overload + def extra(self, attribute: T_Attr, default: T_Default) -> Union[T_Attr, T_Default]: + ... + + @final + def extra(self, attribute: Any, default: object = undefined) -> object: + """ + extra(attribute, default=undefined) + + Return the value of the given typed extra attribute. + + :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to look for + :param default: the value that should be returned if no value is found for the attribute + :raises ~anyio.TypedAttributeLookupError: if the search failed and no default value was + given + + """ + try: + return self.extra_attributes[attribute]() + except KeyError: + if default is undefined: + raise TypedAttributeLookupError("Attribute not found") from None + else: + return default diff --git a/myenv/lib/python3.9/site-packages/anyio/abc/__init__.py b/myenv/lib/python3.9/site-packages/anyio/abc/__init__.py new file mode 100644 index 0000000..72c4444 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/abc/__init__.py @@ -0,0 +1,88 @@ +__all__ = ( + "AsyncResource", + "IPAddressType", + "IPSockAddrType", + "SocketAttribute", + "SocketStream", + "SocketListener", + "UDPSocket", + "UNIXSocketStream", + "UDPPacketType", + "ConnectedUDPSocket", + "UnreliableObjectReceiveStream", + "UnreliableObjectSendStream", + "UnreliableObjectStream", + "ObjectReceiveStream", + "ObjectSendStream", + "ObjectStream", + "ByteReceiveStream", + "ByteSendStream", + "ByteStream", + "AnyUnreliableByteReceiveStream", + "AnyUnreliableByteSendStream", + "AnyUnreliableByteStream", + "AnyByteReceiveStream", + "AnyByteSendStream", + "AnyByteStream", + "Listener", + "Process", + "Event", + "Condition", + "Lock", + "Semaphore", + "CapacityLimiter", + "CancelScope", + "TaskGroup", + "TaskStatus", + "TestRunner", + "BlockingPortal", +) + +from typing import Any + +from ._resources import AsyncResource +from ._sockets import ( + ConnectedUDPSocket, + IPAddressType, + IPSockAddrType, + SocketAttribute, + SocketListener, + SocketStream, + UDPPacketType, + UDPSocket, + UNIXSocketStream, +) +from ._streams import ( + AnyByteReceiveStream, + AnyByteSendStream, + AnyByteStream, + AnyUnreliableByteReceiveStream, + AnyUnreliableByteSendStream, + AnyUnreliableByteStream, + ByteReceiveStream, + ByteSendStream, + ByteStream, + Listener, + ObjectReceiveStream, + ObjectSendStream, + ObjectStream, + UnreliableObjectReceiveStream, + UnreliableObjectSendStream, + UnreliableObjectStream, +) +from ._subprocesses import Process +from ._tasks import TaskGroup, TaskStatus +from ._testing import TestRunner + +# Re-exported here, for backwards compatibility +# isort: off +from .._core._synchronization import CapacityLimiter, Condition, Event, Lock, Semaphore +from .._core._tasks import CancelScope +from ..from_thread import BlockingPortal + +# Re-export imports so they look like they live directly in this package +key: str +value: Any +for key, value in list(locals().items()): + if getattr(value, "__module__", "").startswith("anyio.abc."): + value.__module__ = __name__ diff --git a/myenv/lib/python3.9/site-packages/anyio/abc/_resources.py b/myenv/lib/python3.9/site-packages/anyio/abc/_resources.py new file mode 100644 index 0000000..4f66c38 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/abc/_resources.py @@ -0,0 +1,29 @@ +from abc import ABCMeta, abstractmethod +from types import TracebackType +from typing import Optional, Type, TypeVar + +T = TypeVar("T") + + +class AsyncResource(metaclass=ABCMeta): + """ + Abstract base class for all closeable asynchronous resources. + + Works as an asynchronous context manager which returns the instance itself on enter, and calls + :meth:`aclose` on exit. + """ + + async def __aenter__(self: T) -> T: + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + await self.aclose() + + @abstractmethod + async def aclose(self) -> None: + """Close the resource.""" diff --git a/myenv/lib/python3.9/site-packages/anyio/abc/_sockets.py b/myenv/lib/python3.9/site-packages/anyio/abc/_sockets.py new file mode 100644 index 0000000..f73e795 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/abc/_sockets.py @@ -0,0 +1,183 @@ +import socket +from abc import abstractmethod +from io import IOBase +from ipaddress import IPv4Address, IPv6Address +from socket import AddressFamily +from types import TracebackType +from typing import ( + Any, + AsyncContextManager, + Callable, + Collection, + Dict, + List, + Mapping, + Optional, + Tuple, + Type, + TypeVar, + Union, +) + +from .._core._typedattr import ( + TypedAttributeProvider, + TypedAttributeSet, + typed_attribute, +) +from ._streams import ByteStream, Listener, T_Stream, UnreliableObjectStream +from ._tasks import TaskGroup + +IPAddressType = Union[str, IPv4Address, IPv6Address] +IPSockAddrType = Tuple[str, int] +SockAddrType = Union[IPSockAddrType, str] +UDPPacketType = Tuple[bytes, IPSockAddrType] +T_Retval = TypeVar("T_Retval") + + +class _NullAsyncContextManager: + async def __aenter__(self) -> None: + pass + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + return None + + +class SocketAttribute(TypedAttributeSet): + #: the address family of the underlying socket + family: AddressFamily = typed_attribute() + #: the local socket address of the underlying socket + local_address: SockAddrType = typed_attribute() + #: for IP addresses, the local port the underlying socket is bound to + local_port: int = typed_attribute() + #: the underlying stdlib socket object + raw_socket: socket.socket = typed_attribute() + #: the remote address the underlying socket is connected to + remote_address: SockAddrType = typed_attribute() + #: for IP addresses, the remote port the underlying socket is connected to + remote_port: int = typed_attribute() + + +class _SocketProvider(TypedAttributeProvider): + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + from .._core._sockets import convert_ipv6_sockaddr as convert + + attributes: Dict[Any, Callable[[], Any]] = { + SocketAttribute.family: lambda: self._raw_socket.family, + SocketAttribute.local_address: lambda: convert( + self._raw_socket.getsockname() + ), + SocketAttribute.raw_socket: lambda: self._raw_socket, + } + try: + peername: Optional[Tuple[str, int]] = convert( + self._raw_socket.getpeername() + ) + except OSError: + peername = None + + # Provide the remote address for connected sockets + if peername is not None: + attributes[SocketAttribute.remote_address] = lambda: peername + + # Provide local and remote ports for IP based sockets + if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6): + attributes[ + SocketAttribute.local_port + ] = lambda: self._raw_socket.getsockname()[1] + if peername is not None: + remote_port = peername[1] + attributes[SocketAttribute.remote_port] = lambda: remote_port + + return attributes + + @property + @abstractmethod + def _raw_socket(self) -> socket.socket: + pass + + +class SocketStream(ByteStream, _SocketProvider): + """ + Transports bytes over a socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + +class UNIXSocketStream(SocketStream): + @abstractmethod + async def send_fds( + self, message: bytes, fds: Collection[Union[int, IOBase]] + ) -> None: + """ + Send file descriptors along with a message to the peer. + + :param message: a non-empty bytestring + :param fds: a collection of files (either numeric file descriptors or open file or socket + objects) + """ + + @abstractmethod + async def receive_fds(self, msglen: int, maxfds: int) -> Tuple[bytes, List[int]]: + """ + Receive file descriptors along with a message from the peer. + + :param msglen: length of the message to expect from the peer + :param maxfds: maximum number of file descriptors to expect from the peer + :return: a tuple of (message, file descriptors) + """ + + +class SocketListener(Listener[SocketStream], _SocketProvider): + """ + Listens to incoming socket connections. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + @abstractmethod + async def accept(self) -> SocketStream: + """Accept an incoming connection.""" + + async def serve( + self, handler: Callable[[T_Stream], Any], task_group: Optional[TaskGroup] = None + ) -> None: + from .. import create_task_group + + context_manager: AsyncContextManager + if task_group is None: + task_group = context_manager = create_task_group() + else: + # Can be replaced with AsyncExitStack once on py3.7+ + context_manager = _NullAsyncContextManager() + + async with context_manager: + while True: + stream = await self.accept() + task_group.start_soon(handler, stream) + + +class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider): + """ + Represents an unconnected UDP socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + async def sendto(self, data: bytes, host: str, port: int) -> None: + """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))).""" + return await self.send((data, (host, port))) + + +class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider): + """ + Represents an connected UDP socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ diff --git a/myenv/lib/python3.9/site-packages/anyio/abc/_streams.py b/myenv/lib/python3.9/site-packages/anyio/abc/_streams.py new file mode 100644 index 0000000..4980ef4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/abc/_streams.py @@ -0,0 +1,198 @@ +from abc import abstractmethod +from typing import Any, Callable, Generic, Optional, TypeVar, Union + +from .._core._exceptions import EndOfStream +from .._core._typedattr import TypedAttributeProvider +from ._resources import AsyncResource +from ._tasks import TaskGroup + +T_Item = TypeVar("T_Item") +T_Stream = TypeVar("T_Stream") + + +class UnreliableObjectReceiveStream( + Generic[T_Item], AsyncResource, TypedAttributeProvider +): + """ + An interface for receiving objects. + + This interface makes no guarantees that the received messages arrive in the order in which they + were sent, or that no messages are missed. + + Asynchronously iterating over objects of this type will yield objects matching the given type + parameter. + """ + + def __aiter__(self) -> "UnreliableObjectReceiveStream[T_Item]": + return self + + async def __anext__(self) -> T_Item: + try: + return await self.receive() + except EndOfStream: + raise StopAsyncIteration + + @abstractmethod + async def receive(self) -> T_Item: + """ + Receive the next item. + + :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly + closed + :raises ~anyio.EndOfStream: if this stream has been closed from the other end + :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable + due to external causes + """ + + +class UnreliableObjectSendStream( + Generic[T_Item], AsyncResource, TypedAttributeProvider +): + """ + An interface for sending objects. + + This interface makes no guarantees that the messages sent will reach the recipient(s) in the + same order in which they were sent, or at all. + """ + + @abstractmethod + async def send(self, item: T_Item) -> None: + """ + Send an item to the peer(s). + + :param item: the item to send + :raises ~anyio.ClosedResourceError: if the send stream has been explicitly + closed + :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable + due to external causes + """ + + +class UnreliableObjectStream( + UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item] +): + """ + A bidirectional message stream which does not guarantee the order or reliability of message + delivery. + """ + + +class ObjectReceiveStream(UnreliableObjectReceiveStream[T_Item]): + """ + A receive message stream which guarantees that messages are received in the same order in + which they were sent, and that no messages are missed. + """ + + +class ObjectSendStream(UnreliableObjectSendStream[T_Item]): + """ + A send message stream which guarantees that messages are delivered in the same order in which + they were sent, without missing any messages in the middle. + """ + + +class ObjectStream( + ObjectReceiveStream[T_Item], + ObjectSendStream[T_Item], + UnreliableObjectStream[T_Item], +): + """ + A bidirectional message stream which guarantees the order and reliability of message delivery. + """ + + @abstractmethod + async def send_eof(self) -> None: + """ + Send an end-of-file indication to the peer. + + You should not try to send any further data to this stream after calling this method. + This method is idempotent (does nothing on successive calls). + """ + + +class ByteReceiveStream(AsyncResource, TypedAttributeProvider): + """ + An interface for receiving bytes from a single peer. + + Iterating this byte stream will yield a byte string of arbitrary length, but no more than + 65536 bytes. + """ + + def __aiter__(self) -> "ByteReceiveStream": + return self + + async def __anext__(self) -> bytes: + try: + return await self.receive() + except EndOfStream: + raise StopAsyncIteration + + @abstractmethod + async def receive(self, max_bytes: int = 65536) -> bytes: + """ + Receive at most ``max_bytes`` bytes from the peer. + + .. note:: Implementors of this interface should not return an empty :class:`bytes` object, + and users should ignore them. + + :param max_bytes: maximum number of bytes to receive + :return: the received bytes + :raises ~anyio.EndOfStream: if this stream has been closed from the other end + """ + + +class ByteSendStream(AsyncResource, TypedAttributeProvider): + """An interface for sending bytes to a single peer.""" + + @abstractmethod + async def send(self, item: bytes) -> None: + """ + Send the given bytes to the peer. + + :param item: the bytes to send + """ + + +class ByteStream(ByteReceiveStream, ByteSendStream): + """A bidirectional byte stream.""" + + @abstractmethod + async def send_eof(self) -> None: + """ + Send an end-of-file indication to the peer. + + You should not try to send any further data to this stream after calling this method. + This method is idempotent (does nothing on successive calls). + """ + + +#: Type alias for all unreliable bytes-oriented receive streams. +AnyUnreliableByteReceiveStream = Union[ + UnreliableObjectReceiveStream[bytes], ByteReceiveStream +] +#: Type alias for all unreliable bytes-oriented send streams. +AnyUnreliableByteSendStream = Union[UnreliableObjectSendStream[bytes], ByteSendStream] +#: Type alias for all unreliable bytes-oriented streams. +AnyUnreliableByteStream = Union[UnreliableObjectStream[bytes], ByteStream] +#: Type alias for all bytes-oriented receive streams. +AnyByteReceiveStream = Union[ObjectReceiveStream[bytes], ByteReceiveStream] +#: Type alias for all bytes-oriented send streams. +AnyByteSendStream = Union[ObjectSendStream[bytes], ByteSendStream] +#: Type alias for all bytes-oriented streams. +AnyByteStream = Union[ObjectStream[bytes], ByteStream] + + +class Listener(Generic[T_Stream], AsyncResource, TypedAttributeProvider): + """An interface for objects that let you accept incoming connections.""" + + @abstractmethod + async def serve( + self, handler: Callable[[T_Stream], Any], task_group: Optional[TaskGroup] = None + ) -> None: + """ + Accept incoming connections as they come in and start tasks to handle them. + + :param handler: a callable that will be used to handle each accepted connection + :param task_group: the task group that will be used to start tasks for handling each + accepted connection (if omitted, an ad-hoc task group will be created) + """ diff --git a/myenv/lib/python3.9/site-packages/anyio/abc/_subprocesses.py b/myenv/lib/python3.9/site-packages/anyio/abc/_subprocesses.py new file mode 100644 index 0000000..1e633fb --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/abc/_subprocesses.py @@ -0,0 +1,78 @@ +from abc import abstractmethod +from signal import Signals +from typing import Optional + +from ._resources import AsyncResource +from ._streams import ByteReceiveStream, ByteSendStream + + +class Process(AsyncResource): + """An asynchronous version of :class:`subprocess.Popen`.""" + + @abstractmethod + async def wait(self) -> int: + """ + Wait until the process exits. + + :return: the exit code of the process + """ + + @abstractmethod + def terminate(self) -> None: + """ + Terminates the process, gracefully if possible. + + On Windows, this calls ``TerminateProcess()``. + On POSIX systems, this sends ``SIGTERM`` to the process. + + .. seealso:: :meth:`subprocess.Popen.terminate` + """ + + @abstractmethod + def kill(self) -> None: + """ + Kills the process. + + On Windows, this calls ``TerminateProcess()``. + On POSIX systems, this sends ``SIGKILL`` to the process. + + .. seealso:: :meth:`subprocess.Popen.kill` + """ + + @abstractmethod + def send_signal(self, signal: Signals) -> None: + """ + Send a signal to the subprocess. + + .. seealso:: :meth:`subprocess.Popen.send_signal` + + :param signal: the signal number (e.g. :data:`signal.SIGHUP`) + """ + + @property + @abstractmethod + def pid(self) -> int: + """The process ID of the process.""" + + @property + @abstractmethod + def returncode(self) -> Optional[int]: + """ + The return code of the process. If the process has not yet terminated, this will be + ``None``. + """ + + @property + @abstractmethod + def stdin(self) -> Optional[ByteSendStream]: + """The stream for the standard input of the process.""" + + @property + @abstractmethod + def stdout(self) -> Optional[ByteReceiveStream]: + """The stream for the standard output of the process.""" + + @property + @abstractmethod + def stderr(self) -> Optional[ByteReceiveStream]: + """The stream for the standard error output of the process.""" diff --git a/myenv/lib/python3.9/site-packages/anyio/abc/_tasks.py b/myenv/lib/python3.9/site-packages/anyio/abc/_tasks.py new file mode 100644 index 0000000..99928a1 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/abc/_tasks.py @@ -0,0 +1,104 @@ +import typing +from abc import ABCMeta, abstractmethod +from types import TracebackType +from typing import Any, Callable, Coroutine, Optional, Type, TypeVar +from warnings import warn + +if typing.TYPE_CHECKING: + from anyio._core._tasks import CancelScope + +T_Retval = TypeVar("T_Retval") + + +class TaskStatus(metaclass=ABCMeta): + @abstractmethod + def started(self, value: object = None) -> None: + """ + Signal that the task has started. + + :param value: object passed back to the starter of the task + """ + + +class TaskGroup(metaclass=ABCMeta): + """ + Groups several asynchronous tasks together. + + :ivar cancel_scope: the cancel scope inherited by all child tasks + :vartype cancel_scope: CancelScope + """ + + cancel_scope: "CancelScope" + + async def spawn( + self, + func: Callable[..., Coroutine[Any, Any, Any]], + *args: object, + name: object = None + ) -> None: + """ + Start a new task in this task group. + + :param func: a coroutine function + :param args: positional arguments to call the function with + :param name: name of the task, for the purposes of introspection and debugging + + .. deprecated:: 3.0 + Use :meth:`start_soon` instead. If your code needs AnyIO 2 compatibility, you + can keep using this until AnyIO 4. + + """ + warn( + 'spawn() is deprecated -- use start_soon() (without the "await") instead', + DeprecationWarning, + ) + self.start_soon(func, *args, name=name) + + @abstractmethod + def start_soon( + self, + func: Callable[..., Coroutine[Any, Any, Any]], + *args: object, + name: object = None + ) -> None: + """ + Start a new task in this task group. + + :param func: a coroutine function + :param args: positional arguments to call the function with + :param name: name of the task, for the purposes of introspection and debugging + + .. versionadded:: 3.0 + """ + + @abstractmethod + async def start( + self, + func: Callable[..., Coroutine[Any, Any, Any]], + *args: object, + name: object = None + ) -> object: + """ + Start a new task and wait until it signals for readiness. + + :param func: a coroutine function + :param args: positional arguments to call the function with + :param name: name of the task, for the purposes of introspection and debugging + :return: the value passed to ``task_status.started()`` + :raises RuntimeError: if the task finishes without calling ``task_status.started()`` + + .. versionadded:: 3.0 + """ + + @abstractmethod + async def __aenter__(self) -> "TaskGroup": + """Enter the task group context and allow starting new tasks.""" + + @abstractmethod + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + """Exit the task group context waiting for all tasks to finish.""" diff --git a/myenv/lib/python3.9/site-packages/anyio/abc/_testing.py b/myenv/lib/python3.9/site-packages/anyio/abc/_testing.py new file mode 100644 index 0000000..4e3621d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/abc/_testing.py @@ -0,0 +1,68 @@ +import types +from abc import ABCMeta, abstractmethod +from collections.abc import AsyncGenerator, Iterable +from typing import Any, Callable, Coroutine, Dict, Optional, Type, TypeVar + +_T = TypeVar("_T") + + +class TestRunner(metaclass=ABCMeta): + """ + Encapsulates a running event loop. Every call made through this object will use the same event + loop. + """ + + def __enter__(self) -> "TestRunner": + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[types.TracebackType], + ) -> Optional[bool]: + self.close() + return None + + @abstractmethod + def close(self) -> None: + """Close the event loop.""" + + @abstractmethod + def run_asyncgen_fixture( + self, + fixture_func: Callable[..., "AsyncGenerator[_T, Any]"], + kwargs: Dict[str, Any], + ) -> "Iterable[_T]": + """ + Run an async generator fixture. + + :param fixture_func: the fixture function + :param kwargs: keyword arguments to call the fixture function with + :return: an iterator yielding the value yielded from the async generator + """ + + @abstractmethod + def run_fixture( + self, + fixture_func: Callable[..., Coroutine[Any, Any, _T]], + kwargs: Dict[str, Any], + ) -> _T: + """ + Run an async fixture. + + :param fixture_func: the fixture function + :param kwargs: keyword arguments to call the fixture function with + :return: the return value of the fixture function + """ + + @abstractmethod + def run_test( + self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: Dict[str, Any] + ) -> None: + """ + Run an async test function. + + :param test_func: the test function + :param kwargs: keyword arguments to call the test function with + """ diff --git a/myenv/lib/python3.9/site-packages/anyio/from_thread.py b/myenv/lib/python3.9/site-packages/anyio/from_thread.py new file mode 100644 index 0000000..e4f871f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/from_thread.py @@ -0,0 +1,502 @@ +import threading +from asyncio import iscoroutine +from concurrent.futures import FIRST_COMPLETED, Future, ThreadPoolExecutor, wait +from contextlib import AbstractContextManager, contextmanager +from types import TracebackType +from typing import ( + Any, + AsyncContextManager, + Callable, + ContextManager, + Coroutine, + Dict, + Generator, + Iterable, + Optional, + Tuple, + Type, + TypeVar, + Union, + cast, + overload, +) +from warnings import warn + +from ._core import _eventloop +from ._core._eventloop import get_asynclib, get_cancelled_exc_class, threadlocals +from ._core._synchronization import Event +from ._core._tasks import CancelScope, create_task_group +from .abc._tasks import TaskStatus + +T_Retval = TypeVar("T_Retval") +T_co = TypeVar("T_co") + + +def run(func: Callable[..., Coroutine[Any, Any, T_Retval]], *args: object) -> T_Retval: + """ + Call a coroutine function from a worker thread. + + :param func: a coroutine function + :param args: positional arguments for the callable + :return: the return value of the coroutine function + + """ + try: + asynclib = threadlocals.current_async_module + except AttributeError: + raise RuntimeError("This function can only be run from an AnyIO worker thread") + + return asynclib.run_async_from_thread(func, *args) + + +def run_async_from_thread( + func: Callable[..., Coroutine[Any, Any, T_Retval]], *args: object +) -> T_Retval: + warn( + "run_async_from_thread() has been deprecated, use anyio.from_thread.run() instead", + DeprecationWarning, + ) + return run(func, *args) + + +def run_sync(func: Callable[..., T_Retval], *args: object) -> T_Retval: + """ + Call a function in the event loop thread from a worker thread. + + :param func: a callable + :param args: positional arguments for the callable + :return: the return value of the callable + + """ + try: + asynclib = threadlocals.current_async_module + except AttributeError: + raise RuntimeError("This function can only be run from an AnyIO worker thread") + + return asynclib.run_sync_from_thread(func, *args) + + +def run_sync_from_thread(func: Callable[..., T_Retval], *args: object) -> T_Retval: + warn( + "run_sync_from_thread() has been deprecated, use anyio.from_thread.run_sync() instead", + DeprecationWarning, + ) + return run_sync(func, *args) + + +class _BlockingAsyncContextManager(AbstractContextManager): + _enter_future: Future + _exit_future: Future + _exit_event: Event + _exit_exc_info: Tuple[ + Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType] + ] = (None, None, None) + + def __init__(self, async_cm: AsyncContextManager[T_co], portal: "BlockingPortal"): + self._async_cm = async_cm + self._portal = portal + + async def run_async_cm(self) -> Optional[bool]: + try: + self._exit_event = Event() + value = await self._async_cm.__aenter__() + except BaseException as exc: + self._enter_future.set_exception(exc) + raise + else: + self._enter_future.set_result(value) + + try: + # Wait for the sync context manager to exit. + # This next statement can raise `get_cancelled_exc_class()` if + # something went wrong in a task group in this async context + # manager. + await self._exit_event.wait() + finally: + # In case of cancellation, it could be that we end up here before + # `_BlockingAsyncContextManager.__exit__` is called, and an + # `_exit_exc_info` has been set. + result = await self._async_cm.__aexit__(*self._exit_exc_info) + return result + + def __enter__(self) -> T_co: + self._enter_future = Future() + self._exit_future = self._portal.start_task_soon(self.run_async_cm) + cm = self._enter_future.result() + return cast(T_co, cm) + + def __exit__( + self, + __exc_type: Optional[Type[BaseException]], + __exc_value: Optional[BaseException], + __traceback: Optional[TracebackType], + ) -> Optional[bool]: + self._exit_exc_info = __exc_type, __exc_value, __traceback + self._portal.call(self._exit_event.set) + return self._exit_future.result() + + +class _BlockingPortalTaskStatus(TaskStatus): + def __init__(self, future: Future): + self._future = future + + def started(self, value: object = None) -> None: + self._future.set_result(value) + + +class BlockingPortal: + """An object that lets external threads run code in an asynchronous event loop.""" + + def __new__(cls) -> "BlockingPortal": + return get_asynclib().BlockingPortal() + + def __init__(self) -> None: + self._event_loop_thread_id: Optional[int] = threading.get_ident() + self._stop_event = Event() + self._task_group = create_task_group() + self._cancelled_exc_class = get_cancelled_exc_class() + + async def __aenter__(self) -> "BlockingPortal": + await self._task_group.__aenter__() + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> Optional[bool]: + await self.stop() + return await self._task_group.__aexit__(exc_type, exc_val, exc_tb) + + def _check_running(self) -> None: + if self._event_loop_thread_id is None: + raise RuntimeError("This portal is not running") + if self._event_loop_thread_id == threading.get_ident(): + raise RuntimeError( + "This method cannot be called from the event loop thread" + ) + + async def sleep_until_stopped(self) -> None: + """Sleep until :meth:`stop` is called.""" + await self._stop_event.wait() + + async def stop(self, cancel_remaining: bool = False) -> None: + """ + Signal the portal to shut down. + + This marks the portal as no longer accepting new calls and exits from + :meth:`sleep_until_stopped`. + + :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False`` to let them + finish before returning + + """ + self._event_loop_thread_id = None + self._stop_event.set() + if cancel_remaining: + self._task_group.cancel_scope.cancel() + + async def _call_func( + self, func: Callable, args: tuple, kwargs: Dict[str, Any], future: Future + ) -> None: + def callback(f: Future) -> None: + if f.cancelled() and self._event_loop_thread_id not in ( + None, + threading.get_ident(), + ): + self.call(scope.cancel) + + try: + retval = func(*args, **kwargs) + if iscoroutine(retval): + with CancelScope() as scope: + if future.cancelled(): + scope.cancel() + else: + future.add_done_callback(callback) + + retval = await retval + except self._cancelled_exc_class: + future.cancel() + except BaseException as exc: + if not future.cancelled(): + future.set_exception(exc) + + # Let base exceptions fall through + if not isinstance(exc, Exception): + raise + else: + if not future.cancelled(): + future.set_result(retval) + finally: + scope = None # type: ignore[assignment] + + def _spawn_task_from_thread( + self, + func: Callable, + args: tuple, + kwargs: Dict[str, Any], + name: object, + future: Future, + ) -> None: + """ + Spawn a new task using the given callable. + + Implementors must ensure that the future is resolved when the task finishes. + + :param func: a callable + :param args: positional arguments to be passed to the callable + :param kwargs: keyword arguments to be passed to the callable + :param name: name of the task (will be coerced to a string if not ``None``) + :param future: a future that will resolve to the return value of the callable, or the + exception raised during its execution + + """ + raise NotImplementedError + + @overload + def call( + self, func: Callable[..., Coroutine[Any, Any, T_Retval]], *args: object + ) -> T_Retval: + ... + + @overload + def call(self, func: Callable[..., T_Retval], *args: object) -> T_Retval: + ... + + def call( + self, + func: Callable[..., Union[Coroutine[Any, Any, T_Retval], T_Retval]], + *args: object + ) -> T_Retval: + """ + Call the given function in the event loop thread. + + If the callable returns a coroutine object, it is awaited on. + + :param func: any callable + :raises RuntimeError: if the portal is not running or if this method is called from within + the event loop thread + + """ + return cast(T_Retval, self.start_task_soon(func, *args).result()) + + @overload + def spawn_task( + self, + func: Callable[..., Coroutine[Any, Any, T_Retval]], + *args: object, + name: object = None + ) -> "Future[T_Retval]": + ... + + @overload + def spawn_task( + self, func: Callable[..., T_Retval], *args: object, name: object = None + ) -> "Future[T_Retval]": + ... + + def spawn_task( + self, + func: Callable[..., Union[Coroutine[Any, Any, T_Retval], T_Retval]], + *args: object, + name: object = None + ) -> "Future[T_Retval]": + """ + Start a task in the portal's task group. + + :param func: the target coroutine function + :param args: positional arguments passed to ``func`` + :param name: name of the task (will be coerced to a string if not ``None``) + :return: a future that resolves with the return value of the callable if the task completes + successfully, or with the exception raised in the task + :raises RuntimeError: if the portal is not running or if this method is called from within + the event loop thread + + .. versionadded:: 2.1 + .. deprecated:: 3.0 + Use :meth:`start_task_soon` instead. If your code needs AnyIO 2 compatibility, you + can keep using this until AnyIO 4. + + """ + warn( + "spawn_task() is deprecated -- use start_task_soon() instead", + DeprecationWarning, + ) + return self.start_task_soon(func, *args, name=name) # type: ignore[arg-type] + + @overload + def start_task_soon( + self, + func: Callable[..., Coroutine[Any, Any, T_Retval]], + *args: object, + name: object = None + ) -> "Future[T_Retval]": + ... + + @overload + def start_task_soon( + self, func: Callable[..., T_Retval], *args: object, name: object = None + ) -> "Future[T_Retval]": + ... + + def start_task_soon( + self, + func: Callable[..., Union[Coroutine[Any, Any, T_Retval], T_Retval]], + *args: object, + name: object = None + ) -> "Future[T_Retval]": + """ + Start a task in the portal's task group. + + The task will be run inside a cancel scope which can be cancelled by cancelling the + returned future. + + :param func: the target coroutine function + :param args: positional arguments passed to ``func`` + :param name: name of the task (will be coerced to a string if not ``None``) + :return: a future that resolves with the return value of the callable if the task completes + successfully, or with the exception raised in the task + :raises RuntimeError: if the portal is not running or if this method is called from within + the event loop thread + + .. versionadded:: 3.0 + + """ + self._check_running() + f: Future = Future() + self._spawn_task_from_thread(func, args, {}, name, f) + return f + + def start_task( + self, + func: Callable[..., Coroutine[Any, Any, Any]], + *args: object, + name: object = None + ) -> Tuple["Future[Any]", Any]: + """ + Start a task in the portal's task group and wait until it signals for readiness. + + This method works the same way as :meth:`TaskGroup.start`. + + :param func: the target coroutine function + :param args: positional arguments passed to ``func`` + :param name: name of the task (will be coerced to a string if not ``None``) + :return: a tuple of (future, task_status_value) where the ``task_status_value`` is the + value passed to ``task_status.started()`` from within the target function + + .. versionadded:: 3.0 + + """ + + def task_done(future: Future) -> None: + if not task_status_future.done(): + if future.cancelled(): + task_status_future.cancel() + elif future.exception(): + task_status_future.set_exception(future.exception()) + else: + exc = RuntimeError( + "Task exited without calling task_status.started()" + ) + task_status_future.set_exception(exc) + + self._check_running() + task_status_future: Future = Future() + task_status = _BlockingPortalTaskStatus(task_status_future) + f: Future = Future() + f.add_done_callback(task_done) + self._spawn_task_from_thread(func, args, {"task_status": task_status}, name, f) + return f, task_status_future.result() + + def wrap_async_context_manager( + self, cm: AsyncContextManager[T_co] + ) -> ContextManager[T_co]: + """ + Wrap an async context manager as a synchronous context manager via this portal. + + Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping in the + middle until the synchronous context manager exits. + + :param cm: an asynchronous context manager + :return: a synchronous context manager + + .. versionadded:: 2.1 + + """ + return _BlockingAsyncContextManager(cm, self) + + +def create_blocking_portal() -> BlockingPortal: + """ + Create a portal for running functions in the event loop thread from external threads. + + Use this function in asynchronous code when you need to allow external threads access to the + event loop where your asynchronous code is currently running. + + .. deprecated:: 3.0 + Use :class:`.BlockingPortal` directly. + + """ + warn( + "create_blocking_portal() has been deprecated -- use anyio.from_thread.BlockingPortal() " + "directly", + DeprecationWarning, + ) + return BlockingPortal() + + +@contextmanager +def start_blocking_portal( + backend: str = "asyncio", backend_options: Optional[Dict[str, Any]] = None +) -> Generator[BlockingPortal, Any, None]: + """ + Start a new event loop in a new thread and run a blocking portal in its main task. + + The parameters are the same as for :func:`~anyio.run`. + + :param backend: name of the backend + :param backend_options: backend options + :return: a context manager that yields a blocking portal + + .. versionchanged:: 3.0 + Usage as a context manager is now required. + + """ + + async def run_portal() -> None: + async with BlockingPortal() as portal_: + if future.set_running_or_notify_cancel(): + future.set_result(portal_) + await portal_.sleep_until_stopped() + + future: Future[BlockingPortal] = Future() + with ThreadPoolExecutor(1) as executor: + run_future = executor.submit( + _eventloop.run, + run_portal, # type: ignore[arg-type] + backend=backend, + backend_options=backend_options, + ) + try: + wait( + cast(Iterable[Future], [run_future, future]), + return_when=FIRST_COMPLETED, + ) + except BaseException: + future.cancel() + run_future.cancel() + raise + + if future.done(): + portal = future.result() + try: + yield portal + except BaseException: + portal.call(portal.stop, True) + raise + + portal.call(portal.stop, False) + + run_future.result() diff --git a/myenv/lib/python3.9/site-packages/anyio/lowlevel.py b/myenv/lib/python3.9/site-packages/anyio/lowlevel.py new file mode 100644 index 0000000..c1da8fa --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/lowlevel.py @@ -0,0 +1,170 @@ +import enum +import sys +from dataclasses import dataclass +from typing import Any, Dict, Generic, Set, TypeVar, Union, overload +from weakref import WeakKeyDictionary + +from ._core._eventloop import get_asynclib + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +T = TypeVar("T") +D = TypeVar("D") + + +async def checkpoint() -> None: + """ + Check for cancellation and allow the scheduler to switch to another task. + + Equivalent to (but more efficient than):: + + await checkpoint_if_cancelled() + await cancel_shielded_checkpoint() + + .. versionadded:: 3.0 + + """ + await get_asynclib().checkpoint() + + +async def checkpoint_if_cancelled() -> None: + """ + Enter a checkpoint if the enclosing cancel scope has been cancelled. + + This does not allow the scheduler to switch to a different task. + + .. versionadded:: 3.0 + + """ + await get_asynclib().checkpoint_if_cancelled() + + +async def cancel_shielded_checkpoint() -> None: + """ + Allow the scheduler to switch to another task but without checking for cancellation. + + Equivalent to (but potentially more efficient than):: + + with CancelScope(shield=True): + await checkpoint() + + .. versionadded:: 3.0 + + """ + await get_asynclib().cancel_shielded_checkpoint() + + +def current_token() -> object: + """Return a backend specific token object that can be used to get back to the event loop.""" + return get_asynclib().current_token() + + +_run_vars = WeakKeyDictionary() # type: WeakKeyDictionary[Any, Dict[str, Any]] +_token_wrappers: Dict[Any, "_TokenWrapper"] = {} + + +@dataclass(frozen=True) +class _TokenWrapper: + __slots__ = "_token", "__weakref__" + _token: object + + +class _NoValueSet(enum.Enum): + NO_VALUE_SET = enum.auto() + + +class RunvarToken(Generic[T]): + __slots__ = "_var", "_value", "_redeemed" + + def __init__( + self, var: "RunVar[T]", value: Union[T, Literal[_NoValueSet.NO_VALUE_SET]] + ): + self._var = var + self._value: Union[T, Literal[_NoValueSet.NO_VALUE_SET]] = value + self._redeemed = False + + +class RunVar(Generic[T]): + """Like a :class:`~contextvars.ContextVar`, expect scoped to the running event loop.""" + + __slots__ = "_name", "_default" + + NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET + + _token_wrappers: Set[_TokenWrapper] = set() + + def __init__( + self, + name: str, + default: Union[T, Literal[_NoValueSet.NO_VALUE_SET]] = NO_VALUE_SET, + ): + self._name = name + self._default = default + + @property + def _current_vars(self) -> Dict[str, T]: + token = current_token() + while True: + try: + return _run_vars[token] + except TypeError: + # Happens when token isn't weak referable (TrioToken). + # This workaround does mean that some memory will leak on Trio until the problem + # is fixed on their end. + token = _TokenWrapper(token) + self._token_wrappers.add(token) + except KeyError: + run_vars = _run_vars[token] = {} + return run_vars + + @overload + def get(self, default: D) -> Union[T, D]: + ... + + @overload + def get(self) -> T: + ... + + def get( + self, default: Union[D, Literal[_NoValueSet.NO_VALUE_SET]] = NO_VALUE_SET + ) -> Union[T, D]: + try: + return self._current_vars[self._name] + except KeyError: + if default is not RunVar.NO_VALUE_SET: + return default + elif self._default is not RunVar.NO_VALUE_SET: + return self._default + + raise LookupError( + f'Run variable "{self._name}" has no value and no default set' + ) + + def set(self, value: T) -> RunvarToken[T]: + current_vars = self._current_vars + token = RunvarToken(self, current_vars.get(self._name, RunVar.NO_VALUE_SET)) + current_vars[self._name] = value + return token + + def reset(self, token: RunvarToken[T]) -> None: + if token._var is not self: + raise ValueError("This token does not belong to this RunVar") + + if token._redeemed: + raise ValueError("This token has already been used") + + if token._value is _NoValueSet.NO_VALUE_SET: + try: + del self._current_vars[self._name] + except KeyError: + pass + else: + self._current_vars[self._name] = token._value + + token._redeemed = True + + def __repr__(self) -> str: + return f"" diff --git a/myenv/lib/python3.9/site-packages/anyio/py.typed b/myenv/lib/python3.9/site-packages/anyio/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/anyio/pytest_plugin.py b/myenv/lib/python3.9/site-packages/anyio/pytest_plugin.py new file mode 100644 index 0000000..432eee3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/pytest_plugin.py @@ -0,0 +1,144 @@ +from contextlib import contextmanager +from inspect import isasyncgenfunction, iscoroutinefunction +from typing import TYPE_CHECKING, Any, Dict, Generator, Optional, Tuple, cast + +import pytest +import sniffio +from _pytest.fixtures import FixtureRequest + +from ._core._eventloop import get_all_backends, get_asynclib +from .abc import TestRunner + +if TYPE_CHECKING: + from _pytest.config import Config + +_current_runner: Optional[TestRunner] = None + + +def extract_backend_and_options(backend: object) -> Tuple[str, Dict[str, Any]]: + if isinstance(backend, str): + return backend, {} + elif isinstance(backend, tuple) and len(backend) == 2: + if isinstance(backend[0], str) and isinstance(backend[1], dict): + return cast(Tuple[str, Dict[str, Any]], backend) + + raise TypeError("anyio_backend must be either a string or tuple of (string, dict)") + + +@contextmanager +def get_runner( + backend_name: str, backend_options: Dict[str, Any] +) -> Generator[TestRunner, object, None]: + global _current_runner + if _current_runner: + yield _current_runner + return + + asynclib = get_asynclib(backend_name) + token = None + if sniffio.current_async_library_cvar.get(None) is None: + # Since we're in control of the event loop, we can cache the name of the async library + token = sniffio.current_async_library_cvar.set(backend_name) + + try: + backend_options = backend_options or {} + with asynclib.TestRunner(**backend_options) as runner: + _current_runner = runner + yield runner + finally: + _current_runner = None + if token: + sniffio.current_async_library_cvar.reset(token) + + +def pytest_configure(config: "Config") -> None: + config.addinivalue_line( + "markers", + "anyio: mark the (coroutine function) test to be run " + "asynchronously via anyio.", + ) + + +def pytest_fixture_setup(fixturedef: Any, request: FixtureRequest) -> None: + def wrapper(*args, anyio_backend, **kwargs): # type: ignore[no-untyped-def] + backend_name, backend_options = extract_backend_and_options(anyio_backend) + if has_backend_arg: + kwargs["anyio_backend"] = anyio_backend + + with get_runner(backend_name, backend_options) as runner: + if isasyncgenfunction(func): + yield from runner.run_asyncgen_fixture(func, kwargs) + else: + yield runner.run_fixture(func, kwargs) + + # Only apply this to coroutine functions and async generator functions in requests that involve + # the anyio_backend fixture + func = fixturedef.func + if isasyncgenfunction(func) or iscoroutinefunction(func): + if "anyio_backend" in request.fixturenames: + has_backend_arg = "anyio_backend" in fixturedef.argnames + fixturedef.func = wrapper + if not has_backend_arg: + fixturedef.argnames += ("anyio_backend",) + + +@pytest.hookimpl(tryfirst=True) +def pytest_pycollect_makeitem(collector: Any, name: Any, obj: Any) -> None: + if collector.istestfunction(obj, name): + inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj + if iscoroutinefunction(inner_func): + marker = collector.get_closest_marker("anyio") + own_markers = getattr(obj, "pytestmark", ()) + if marker or any(marker.name == "anyio" for marker in own_markers): + pytest.mark.usefixtures("anyio_backend")(obj) + + +@pytest.hookimpl(tryfirst=True) +def pytest_pyfunc_call(pyfuncitem: Any) -> Optional[bool]: + def run_with_hypothesis(**kwargs: Any) -> None: + with get_runner(backend_name, backend_options) as runner: + runner.run_test(original_func, kwargs) + + backend = pyfuncitem.funcargs.get("anyio_backend") + if backend: + backend_name, backend_options = extract_backend_and_options(backend) + + if hasattr(pyfuncitem.obj, "hypothesis"): + # Wrap the inner test function unless it's already wrapped + original_func = pyfuncitem.obj.hypothesis.inner_test + if original_func.__qualname__ != run_with_hypothesis.__qualname__: + if iscoroutinefunction(original_func): + pyfuncitem.obj.hypothesis.inner_test = run_with_hypothesis + + return None + + if iscoroutinefunction(pyfuncitem.obj): + funcargs = pyfuncitem.funcargs + testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} + with get_runner(backend_name, backend_options) as runner: + runner.run_test(pyfuncitem.obj, testargs) + + return True + + return None + + +@pytest.fixture(params=get_all_backends()) +def anyio_backend(request: Any) -> Any: + return request.param + + +@pytest.fixture +def anyio_backend_name(anyio_backend: Any) -> str: + if isinstance(anyio_backend, str): + return anyio_backend + else: + return anyio_backend[0] + + +@pytest.fixture +def anyio_backend_options(anyio_backend: Any) -> Dict[str, Any]: + if isinstance(anyio_backend, str): + return {} + else: + return anyio_backend[1] diff --git a/myenv/lib/python3.9/site-packages/anyio/streams/__init__.py b/myenv/lib/python3.9/site-packages/anyio/streams/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/anyio/streams/buffered.py b/myenv/lib/python3.9/site-packages/anyio/streams/buffered.py new file mode 100644 index 0000000..1503b3e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/streams/buffered.py @@ -0,0 +1,116 @@ +from dataclasses import dataclass, field +from typing import Any, Callable, Mapping + +from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead +from ..abc import AnyByteReceiveStream, ByteReceiveStream + + +@dataclass(eq=False) +class BufferedByteReceiveStream(ByteReceiveStream): + """ + Wraps any bytes-based receive stream and uses a buffer to provide sophisticated receiving + capabilities in the form of a byte stream. + """ + + receive_stream: AnyByteReceiveStream + _buffer: bytearray = field(init=False, default_factory=bytearray) + _closed: bool = field(init=False, default=False) + + async def aclose(self) -> None: + await self.receive_stream.aclose() + self._closed = True + + @property + def buffer(self) -> bytes: + """The bytes currently in the buffer.""" + return bytes(self._buffer) + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return self.receive_stream.extra_attributes + + async def receive(self, max_bytes: int = 65536) -> bytes: + if self._closed: + raise ClosedResourceError + + if self._buffer: + chunk = bytes(self._buffer[:max_bytes]) + del self._buffer[:max_bytes] + return chunk + elif isinstance(self.receive_stream, ByteReceiveStream): + return await self.receive_stream.receive(max_bytes) + else: + # With a bytes-oriented object stream, we need to handle any surplus bytes we get from + # the receive() call + chunk = await self.receive_stream.receive() + if len(chunk) > max_bytes: + # Save the surplus bytes in the buffer + self._buffer.extend(chunk[max_bytes:]) + return chunk[:max_bytes] + else: + return chunk + + async def receive_exactly(self, nbytes: int) -> bytes: + """ + Read exactly the given amount of bytes from the stream. + + :param nbytes: the number of bytes to read + :return: the bytes read + :raises ~anyio.IncompleteRead: if the stream was closed before the requested + amount of bytes could be read from the stream + + """ + while True: + remaining = nbytes - len(self._buffer) + if remaining <= 0: + retval = self._buffer[:nbytes] + del self._buffer[:nbytes] + return bytes(retval) + + try: + if isinstance(self.receive_stream, ByteReceiveStream): + chunk = await self.receive_stream.receive(remaining) + else: + chunk = await self.receive_stream.receive() + except EndOfStream as exc: + raise IncompleteRead from exc + + self._buffer.extend(chunk) + + async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes: + """ + Read from the stream until the delimiter is found or max_bytes have been read. + + :param delimiter: the marker to look for in the stream + :param max_bytes: maximum number of bytes that will be read before raising + :exc:`~anyio.DelimiterNotFound` + :return: the bytes read (not including the delimiter) + :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter + was found + :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the + bytes read up to the maximum allowed + + """ + delimiter_size = len(delimiter) + offset = 0 + while True: + # Check if the delimiter can be found in the current buffer + index = self._buffer.find(delimiter, offset) + if index >= 0: + found = self._buffer[:index] + del self._buffer[: index + len(delimiter) :] + return bytes(found) + + # Check if the buffer is already at or over the limit + if len(self._buffer) >= max_bytes: + raise DelimiterNotFound(max_bytes) + + # Read more data into the buffer from the socket + try: + data = await self.receive_stream.receive() + except EndOfStream as exc: + raise IncompleteRead from exc + + # Move the offset forward and add the new data to the buffer + offset = max(len(self._buffer) - delimiter_size + 1, 0) + self._buffer.extend(data) diff --git a/myenv/lib/python3.9/site-packages/anyio/streams/file.py b/myenv/lib/python3.9/site-packages/anyio/streams/file.py new file mode 100644 index 0000000..938d1da --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/streams/file.py @@ -0,0 +1,145 @@ +from io import SEEK_SET, UnsupportedOperation +from os import PathLike +from pathlib import Path +from typing import Any, BinaryIO, Callable, Dict, Mapping, Union, cast + +from .. import ( + BrokenResourceError, + ClosedResourceError, + EndOfStream, + TypedAttributeSet, + to_thread, + typed_attribute, +) +from ..abc import ByteReceiveStream, ByteSendStream + + +class FileStreamAttribute(TypedAttributeSet): + #: the open file descriptor + file: BinaryIO = typed_attribute() + #: the path of the file on the file system, if available (file must be a real file) + path: Path = typed_attribute() + #: the file number, if available (file must be a real file or a TTY) + fileno: int = typed_attribute() + + +class _BaseFileStream: + def __init__(self, file: BinaryIO): + self._file = file + + async def aclose(self) -> None: + await to_thread.run_sync(self._file.close) + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + attributes: Dict[Any, Callable[[], Any]] = { + FileStreamAttribute.file: lambda: self._file, + } + + if hasattr(self._file, "name"): + attributes[FileStreamAttribute.path] = lambda: Path(self._file.name) + + try: + self._file.fileno() + except UnsupportedOperation: + pass + else: + attributes[FileStreamAttribute.fileno] = lambda: self._file.fileno() + + return attributes + + +class FileReadStream(_BaseFileStream, ByteReceiveStream): + """ + A byte stream that reads from a file in the file system. + + :param file: a file that has been opened for reading in binary mode + + .. versionadded:: 3.0 + """ + + @classmethod + async def from_path(cls, path: Union[str, "PathLike[str]"]) -> "FileReadStream": + """ + Create a file read stream by opening the given file. + + :param path: path of the file to read from + + """ + file = await to_thread.run_sync(Path(path).open, "rb") + return cls(cast(BinaryIO, file)) + + async def receive(self, max_bytes: int = 65536) -> bytes: + try: + data = await to_thread.run_sync(self._file.read, max_bytes) + except ValueError: + raise ClosedResourceError from None + except OSError as exc: + raise BrokenResourceError from exc + + if data: + return data + else: + raise EndOfStream + + async def seek(self, position: int, whence: int = SEEK_SET) -> int: + """ + Seek the file to the given position. + + .. seealso:: :meth:`io.IOBase.seek` + + .. note:: Not all file descriptors are seekable. + + :param position: position to seek the file to + :param whence: controls how ``position`` is interpreted + :return: the new absolute position + :raises OSError: if the file is not seekable + + """ + return await to_thread.run_sync(self._file.seek, position, whence) + + async def tell(self) -> int: + """ + Return the current stream position. + + .. note:: Not all file descriptors are seekable. + + :return: the current absolute position + :raises OSError: if the file is not seekable + + """ + return await to_thread.run_sync(self._file.tell) + + +class FileWriteStream(_BaseFileStream, ByteSendStream): + """ + A byte stream that writes to a file in the file system. + + :param file: a file that has been opened for writing in binary mode + + .. versionadded:: 3.0 + """ + + @classmethod + async def from_path( + cls, path: Union[str, "PathLike[str]"], append: bool = False + ) -> "FileWriteStream": + """ + Create a file write stream by opening the given file for writing. + + :param path: path of the file to write to + :param append: if ``True``, open the file for appending; if ``False``, any existing file + at the given path will be truncated + + """ + mode = "ab" if append else "wb" + file = await to_thread.run_sync(Path(path).open, mode) + return cls(cast(BinaryIO, file)) + + async def send(self, item: bytes) -> None: + try: + await to_thread.run_sync(self._file.write, item) + except ValueError: + raise ClosedResourceError from None + except OSError as exc: + raise BrokenResourceError from exc diff --git a/myenv/lib/python3.9/site-packages/anyio/streams/memory.py b/myenv/lib/python3.9/site-packages/anyio/streams/memory.py new file mode 100644 index 0000000..d8a958c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/streams/memory.py @@ -0,0 +1,275 @@ +from collections import OrderedDict, deque +from dataclasses import dataclass, field +from types import TracebackType +from typing import Deque, Generic, List, NamedTuple, Optional, Type, TypeVar + +from .. import ( + BrokenResourceError, + ClosedResourceError, + EndOfStream, + WouldBlock, + get_cancelled_exc_class, +) +from .._core._compat import DeprecatedAwaitable +from ..abc import Event, ObjectReceiveStream, ObjectSendStream +from ..lowlevel import checkpoint + +T_Item = TypeVar("T_Item") + + +class MemoryObjectStreamStatistics(NamedTuple): + current_buffer_used: int #: number of items stored in the buffer + #: maximum number of items that can be stored on this stream (or :data:`math.inf`) + max_buffer_size: float + open_send_streams: int #: number of unclosed clones of the send stream + open_receive_streams: int #: number of unclosed clones of the receive stream + tasks_waiting_send: int #: number of tasks blocked on :meth:`MemoryObjectSendStream.send` + #: number of tasks blocked on :meth:`MemoryObjectReceiveStream.receive` + tasks_waiting_receive: int + + +@dataclass(eq=False) +class MemoryObjectStreamState(Generic[T_Item]): + max_buffer_size: float = field() + buffer: Deque[T_Item] = field(init=False, default_factory=deque) + open_send_channels: int = field(init=False, default=0) + open_receive_channels: int = field(init=False, default=0) + waiting_receivers: "OrderedDict[Event, List[T_Item]]" = field( + init=False, default_factory=OrderedDict + ) + waiting_senders: "OrderedDict[Event, T_Item]" = field( + init=False, default_factory=OrderedDict + ) + + def statistics(self) -> MemoryObjectStreamStatistics: + return MemoryObjectStreamStatistics( + len(self.buffer), + self.max_buffer_size, + self.open_send_channels, + self.open_receive_channels, + len(self.waiting_senders), + len(self.waiting_receivers), + ) + + +@dataclass(eq=False) +class MemoryObjectReceiveStream(Generic[T_Item], ObjectReceiveStream[T_Item]): + _state: MemoryObjectStreamState[T_Item] + _closed: bool = field(init=False, default=False) + + def __post_init__(self) -> None: + self._state.open_receive_channels += 1 + + def receive_nowait(self) -> T_Item: + """ + Receive the next item if it can be done without waiting. + + :return: the received item + :raises ~anyio.ClosedResourceError: if this send stream has been closed + :raises ~anyio.EndOfStream: if the buffer is empty and this stream has been + closed from the sending end + :raises ~anyio.WouldBlock: if there are no items in the buffer and no tasks + waiting to send + + """ + if self._closed: + raise ClosedResourceError + + if self._state.waiting_senders: + # Get the item from the next sender + send_event, item = self._state.waiting_senders.popitem(last=False) + self._state.buffer.append(item) + send_event.set() + + if self._state.buffer: + return self._state.buffer.popleft() + elif not self._state.open_send_channels: + raise EndOfStream + + raise WouldBlock + + async def receive(self) -> T_Item: + await checkpoint() + try: + return self.receive_nowait() + except WouldBlock: + # Add ourselves in the queue + receive_event = Event() + container: List[T_Item] = [] + self._state.waiting_receivers[receive_event] = container + + try: + await receive_event.wait() + except get_cancelled_exc_class(): + # Ignore the immediate cancellation if we already received an item, so as not to + # lose it + if not container: + raise + finally: + self._state.waiting_receivers.pop(receive_event, None) + + if container: + return container[0] + else: + raise EndOfStream + + def clone(self) -> "MemoryObjectReceiveStream[T_Item]": + """ + Create a clone of this receive stream. + + Each clone can be closed separately. Only when all clones have been closed will the + receiving end of the memory stream be considered closed by the sending ends. + + :return: the cloned stream + + """ + if self._closed: + raise ClosedResourceError + + return MemoryObjectReceiveStream(_state=self._state) + + def close(self) -> None: + """ + Close the stream. + + This works the exact same way as :meth:`aclose`, but is provided as a special case for the + benefit of synchronous callbacks. + + """ + if not self._closed: + self._closed = True + self._state.open_receive_channels -= 1 + if self._state.open_receive_channels == 0: + send_events = list(self._state.waiting_senders.keys()) + for event in send_events: + event.set() + + async def aclose(self) -> None: + self.close() + + def statistics(self) -> MemoryObjectStreamStatistics: + """ + Return statistics about the current state of this stream. + + .. versionadded:: 3.0 + """ + return self._state.statistics() + + def __enter__(self) -> "MemoryObjectReceiveStream[T_Item]": + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.close() + + +@dataclass(eq=False) +class MemoryObjectSendStream(Generic[T_Item], ObjectSendStream[T_Item]): + _state: MemoryObjectStreamState[T_Item] + _closed: bool = field(init=False, default=False) + + def __post_init__(self) -> None: + self._state.open_send_channels += 1 + + def send_nowait(self, item: T_Item) -> DeprecatedAwaitable: + """ + Send an item immediately if it can be done without waiting. + + :param item: the item to send + :raises ~anyio.ClosedResourceError: if this send stream has been closed + :raises ~anyio.BrokenResourceError: if the stream has been closed from the + receiving end + :raises ~anyio.WouldBlock: if the buffer is full and there are no tasks waiting + to receive + + """ + if self._closed: + raise ClosedResourceError + if not self._state.open_receive_channels: + raise BrokenResourceError + + if self._state.waiting_receivers: + receive_event, container = self._state.waiting_receivers.popitem(last=False) + container.append(item) + receive_event.set() + elif len(self._state.buffer) < self._state.max_buffer_size: + self._state.buffer.append(item) + else: + raise WouldBlock + + return DeprecatedAwaitable(self.send_nowait) + + async def send(self, item: T_Item) -> None: + await checkpoint() + try: + self.send_nowait(item) + except WouldBlock: + # Wait until there's someone on the receiving end + send_event = Event() + self._state.waiting_senders[send_event] = item + try: + await send_event.wait() + except BaseException: + self._state.waiting_senders.pop(send_event, None) # type: ignore[arg-type] + raise + + if self._state.waiting_senders.pop(send_event, None): # type: ignore[arg-type] + raise BrokenResourceError + + def clone(self) -> "MemoryObjectSendStream[T_Item]": + """ + Create a clone of this send stream. + + Each clone can be closed separately. Only when all clones have been closed will the + sending end of the memory stream be considered closed by the receiving ends. + + :return: the cloned stream + + """ + if self._closed: + raise ClosedResourceError + + return MemoryObjectSendStream(_state=self._state) + + def close(self) -> None: + """ + Close the stream. + + This works the exact same way as :meth:`aclose`, but is provided as a special case for the + benefit of synchronous callbacks. + + """ + if not self._closed: + self._closed = True + self._state.open_send_channels -= 1 + if self._state.open_send_channels == 0: + receive_events = list(self._state.waiting_receivers.keys()) + self._state.waiting_receivers.clear() + for event in receive_events: + event.set() + + async def aclose(self) -> None: + self.close() + + def statistics(self) -> MemoryObjectStreamStatistics: + """ + Return statistics about the current state of this stream. + + .. versionadded:: 3.0 + """ + return self._state.statistics() + + def __enter__(self) -> "MemoryObjectSendStream[T_Item]": + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.close() diff --git a/myenv/lib/python3.9/site-packages/anyio/streams/stapled.py b/myenv/lib/python3.9/site-packages/anyio/streams/stapled.py new file mode 100644 index 0000000..a71ffb0 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/streams/stapled.py @@ -0,0 +1,138 @@ +from dataclasses import dataclass +from typing import Any, Callable, Generic, List, Mapping, Optional, Sequence, TypeVar + +from ..abc import ( + ByteReceiveStream, + ByteSendStream, + ByteStream, + Listener, + ObjectReceiveStream, + ObjectSendStream, + ObjectStream, + TaskGroup, +) + +T_Item = TypeVar("T_Item") +T_Stream = TypeVar("T_Stream") + + +@dataclass(eq=False) +class StapledByteStream(ByteStream): + """ + Combines two byte streams into a single, bidirectional byte stream. + + Extra attributes will be provided from both streams, with the receive stream providing the + values in case of a conflict. + + :param ByteSendStream send_stream: the sending byte stream + :param ByteReceiveStream receive_stream: the receiving byte stream + """ + + send_stream: ByteSendStream + receive_stream: ByteReceiveStream + + async def receive(self, max_bytes: int = 65536) -> bytes: + return await self.receive_stream.receive(max_bytes) + + async def send(self, item: bytes) -> None: + await self.send_stream.send(item) + + async def send_eof(self) -> None: + await self.send_stream.aclose() + + async def aclose(self) -> None: + await self.send_stream.aclose() + await self.receive_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self.send_stream.extra_attributes, + **self.receive_stream.extra_attributes, + } + + +@dataclass(eq=False) +class StapledObjectStream(Generic[T_Item], ObjectStream[T_Item]): + """ + Combines two object streams into a single, bidirectional object stream. + + Extra attributes will be provided from both streams, with the receive stream providing the + values in case of a conflict. + + :param ObjectSendStream send_stream: the sending object stream + :param ObjectReceiveStream receive_stream: the receiving object stream + """ + + send_stream: ObjectSendStream[T_Item] + receive_stream: ObjectReceiveStream[T_Item] + + async def receive(self) -> T_Item: + return await self.receive_stream.receive() + + async def send(self, item: T_Item) -> None: + await self.send_stream.send(item) + + async def send_eof(self) -> None: + await self.send_stream.aclose() + + async def aclose(self) -> None: + await self.send_stream.aclose() + await self.receive_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self.send_stream.extra_attributes, + **self.receive_stream.extra_attributes, + } + + +@dataclass(eq=False) +class MultiListener(Generic[T_Stream], Listener[T_Stream]): + """ + Combines multiple listeners into one, serving connections from all of them at once. + + Any MultiListeners in the given collection of listeners will have their listeners moved into + this one. + + Extra attributes are provided from each listener, with each successive listener overriding any + conflicting attributes from the previous one. + + :param listeners: listeners to serve + :type listeners: Sequence[Listener[T_Stream]] + """ + + listeners: Sequence[Listener[T_Stream]] + + def __post_init__(self) -> None: + listeners: List[Listener[T_Stream]] = [] + for listener in self.listeners: + if isinstance(listener, MultiListener): + listeners.extend(listener.listeners) + del listener.listeners[:] # type: ignore[attr-defined] + else: + listeners.append(listener) + + self.listeners = listeners + + async def serve( + self, handler: Callable[[T_Stream], Any], task_group: Optional[TaskGroup] = None + ) -> None: + from .. import create_task_group + + async with create_task_group() as tg: + for listener in self.listeners: + tg.start_soon(listener.serve, handler, task_group) + + async def aclose(self) -> None: + for listener in self.listeners: + await listener.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + attributes: dict = {} + for listener in self.listeners: + attributes.update(listener.extra_attributes) + + return attributes diff --git a/myenv/lib/python3.9/site-packages/anyio/streams/text.py b/myenv/lib/python3.9/site-packages/anyio/streams/text.py new file mode 100644 index 0000000..ccb683c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/streams/text.py @@ -0,0 +1,141 @@ +import codecs +from dataclasses import InitVar, dataclass, field +from typing import Any, Callable, Mapping, Tuple + +from ..abc import ( + AnyByteReceiveStream, + AnyByteSendStream, + AnyByteStream, + ObjectReceiveStream, + ObjectSendStream, + ObjectStream, +) + + +@dataclass(eq=False) +class TextReceiveStream(ObjectReceiveStream[str]): + """ + Stream wrapper that decodes bytes to strings using the given encoding. + + Decoding is done using :class:`~codecs.IncrementalDecoder` which returns any completely + received unicode characters as soon as they come in. + + :param transport_stream: any bytes-based receive stream + :param encoding: character encoding to use for decoding bytes to strings (defaults to + ``utf-8``) + :param errors: handling scheme for decoding errors (defaults to ``strict``; see the + `codecs module documentation`_ for a comprehensive list of options) + + .. _codecs module documentation: https://docs.python.org/3/library/codecs.html#codec-objects + """ + + transport_stream: AnyByteReceiveStream + encoding: InitVar[str] = "utf-8" + errors: InitVar[str] = "strict" + _decoder: codecs.IncrementalDecoder = field(init=False) + + def __post_init__(self, encoding: str, errors: str) -> None: + decoder_class = codecs.getincrementaldecoder(encoding) + self._decoder = decoder_class(errors=errors) + + async def receive(self) -> str: + while True: + chunk = await self.transport_stream.receive() + decoded = self._decoder.decode(chunk) + if decoded: + return decoded + + async def aclose(self) -> None: + await self.transport_stream.aclose() + self._decoder.reset() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return self.transport_stream.extra_attributes + + +@dataclass(eq=False) +class TextSendStream(ObjectSendStream[str]): + """ + Sends strings to the wrapped stream as bytes using the given encoding. + + :param AnyByteSendStream transport_stream: any bytes-based send stream + :param str encoding: character encoding to use for encoding strings to bytes (defaults to + ``utf-8``) + :param str errors: handling scheme for encoding errors (defaults to ``strict``; see the + `codecs module documentation`_ for a comprehensive list of options) + + .. _codecs module documentation: https://docs.python.org/3/library/codecs.html#codec-objects + """ + + transport_stream: AnyByteSendStream + encoding: InitVar[str] = "utf-8" + errors: str = "strict" + _encoder: Callable[..., Tuple[bytes, int]] = field(init=False) + + def __post_init__(self, encoding: str) -> None: + self._encoder = codecs.getencoder(encoding) + + async def send(self, item: str) -> None: + encoded = self._encoder(item, self.errors)[0] + await self.transport_stream.send(encoded) + + async def aclose(self) -> None: + await self.transport_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return self.transport_stream.extra_attributes + + +@dataclass(eq=False) +class TextStream(ObjectStream[str]): + """ + A bidirectional stream that decodes bytes to strings on receive and encodes strings to bytes on + send. + + Extra attributes will be provided from both streams, with the receive stream providing the + values in case of a conflict. + + :param AnyByteStream transport_stream: any bytes-based stream + :param str encoding: character encoding to use for encoding/decoding strings to/from bytes + (defaults to ``utf-8``) + :param str errors: handling scheme for encoding errors (defaults to ``strict``; see the + `codecs module documentation`_ for a comprehensive list of options) + + .. _codecs module documentation: https://docs.python.org/3/library/codecs.html#codec-objects + """ + + transport_stream: AnyByteStream + encoding: InitVar[str] = "utf-8" + errors: InitVar[str] = "strict" + _receive_stream: TextReceiveStream = field(init=False) + _send_stream: TextSendStream = field(init=False) + + def __post_init__(self, encoding: str, errors: str) -> None: + self._receive_stream = TextReceiveStream( + self.transport_stream, encoding=encoding, errors=errors + ) + self._send_stream = TextSendStream( + self.transport_stream, encoding=encoding, errors=errors + ) + + async def receive(self) -> str: + return await self._receive_stream.receive() + + async def send(self, item: str) -> None: + await self._send_stream.send(item) + + async def send_eof(self) -> None: + await self.transport_stream.send_eof() + + async def aclose(self) -> None: + await self._send_stream.aclose() + await self._receive_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self._send_stream.extra_attributes, + **self._receive_stream.extra_attributes, + } diff --git a/myenv/lib/python3.9/site-packages/anyio/streams/tls.py b/myenv/lib/python3.9/site-packages/anyio/streams/tls.py new file mode 100644 index 0000000..c8e19e2 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/streams/tls.py @@ -0,0 +1,317 @@ +import logging +import re +import ssl +from dataclasses import dataclass +from functools import wraps +from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, TypeVar, Union + +from .. import ( + BrokenResourceError, + EndOfStream, + aclose_forcefully, + get_cancelled_exc_class, +) +from .._core._typedattr import TypedAttributeSet, typed_attribute +from ..abc import AnyByteStream, ByteStream, Listener, TaskGroup + +T_Retval = TypeVar("T_Retval") +_PCTRTT = Tuple[Tuple[str, str], ...] +_PCTRTTT = Tuple[_PCTRTT, ...] + + +class TLSAttribute(TypedAttributeSet): + """Contains Transport Layer Security related attributes.""" + + #: the selected ALPN protocol + alpn_protocol: Optional[str] = typed_attribute() + #: the channel binding for type ``tls-unique`` + channel_binding_tls_unique: bytes = typed_attribute() + #: the selected cipher + cipher: Tuple[str, str, int] = typed_attribute() + #: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert` for more + #: information) + peer_certificate: Optional[ + Dict[str, Union[str, _PCTRTTT, _PCTRTT]] + ] = typed_attribute() + #: the peer certificate in binary form + peer_certificate_binary: Optional[bytes] = typed_attribute() + #: ``True`` if this is the server side of the connection + server_side: bool = typed_attribute() + #: ciphers shared between both ends of the TLS connection + shared_ciphers: List[Tuple[str, str, int]] = typed_attribute() + #: the :class:`~ssl.SSLObject` used for encryption + ssl_object: ssl.SSLObject = typed_attribute() + #: ``True`` if this stream does (and expects) a closing TLS handshake when the stream is being + #: closed + standard_compatible: bool = typed_attribute() + #: the TLS protocol version (e.g. ``TLSv1.2``) + tls_version: str = typed_attribute() + + +@dataclass(eq=False) +class TLSStream(ByteStream): + """ + A stream wrapper that encrypts all sent data and decrypts received data. + + This class has no public initializer; use :meth:`wrap` instead. + All extra attributes from :class:`~TLSAttribute` are supported. + + :var AnyByteStream transport_stream: the wrapped stream + + """ + + transport_stream: AnyByteStream + standard_compatible: bool + _ssl_object: ssl.SSLObject + _read_bio: ssl.MemoryBIO + _write_bio: ssl.MemoryBIO + + @classmethod + async def wrap( + cls, + transport_stream: AnyByteStream, + *, + server_side: Optional[bool] = None, + hostname: Optional[str] = None, + ssl_context: Optional[ssl.SSLContext] = None, + standard_compatible: bool = True, + ) -> "TLSStream": + """ + Wrap an existing stream with Transport Layer Security. + + This performs a TLS handshake with the peer. + + :param transport_stream: a bytes-transporting stream to wrap + :param server_side: ``True`` if this is the server side of the connection, ``False`` if + this is the client side (if omitted, will be set to ``False`` if ``hostname`` has been + provided, ``False`` otherwise). Used only to create a default context when an explicit + context has not been provided. + :param hostname: host name of the peer (if host name checking is desired) + :param ssl_context: the SSLContext object to use (if not provided, a secure default will be + created) + :param standard_compatible: if ``False``, skip the closing handshake when closing the + connection, and don't raise an exception if the peer does the same + :raises ~ssl.SSLError: if the TLS handshake fails + + """ + if server_side is None: + server_side = not hostname + + if not ssl_context: + purpose = ( + ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH + ) + ssl_context = ssl.create_default_context(purpose) + + # Re-enable detection of unexpected EOFs if it was disabled by Python + if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"): + ssl_context.options ^= ssl.OP_IGNORE_UNEXPECTED_EOF # type: ignore[attr-defined] + + bio_in = ssl.MemoryBIO() + bio_out = ssl.MemoryBIO() + ssl_object = ssl_context.wrap_bio( + bio_in, bio_out, server_side=server_side, server_hostname=hostname + ) + wrapper = cls( + transport_stream=transport_stream, + standard_compatible=standard_compatible, + _ssl_object=ssl_object, + _read_bio=bio_in, + _write_bio=bio_out, + ) + await wrapper._call_sslobject_method(ssl_object.do_handshake) + return wrapper + + async def _call_sslobject_method( + self, func: Callable[..., T_Retval], *args: object + ) -> T_Retval: + while True: + try: + result = func(*args) + except ssl.SSLWantReadError: + try: + # Flush any pending writes first + if self._write_bio.pending: + await self.transport_stream.send(self._write_bio.read()) + + data = await self.transport_stream.receive() + except EndOfStream: + self._read_bio.write_eof() + except OSError as exc: + self._read_bio.write_eof() + self._write_bio.write_eof() + raise BrokenResourceError from exc + else: + self._read_bio.write(data) + except ssl.SSLWantWriteError: + await self.transport_stream.send(self._write_bio.read()) + except ssl.SSLSyscallError as exc: + self._read_bio.write_eof() + self._write_bio.write_eof() + raise BrokenResourceError from exc + except ssl.SSLError as exc: + self._read_bio.write_eof() + self._write_bio.write_eof() + if ( + isinstance(exc, ssl.SSLEOFError) + or "UNEXPECTED_EOF_WHILE_READING" in exc.strerror + ): + if self.standard_compatible: + raise BrokenResourceError from exc + else: + raise EndOfStream from None + + raise + else: + # Flush any pending writes first + if self._write_bio.pending: + await self.transport_stream.send(self._write_bio.read()) + + return result + + async def unwrap(self) -> Tuple[AnyByteStream, bytes]: + """ + Does the TLS closing handshake. + + :return: a tuple of (wrapped byte stream, bytes left in the read buffer) + + """ + await self._call_sslobject_method(self._ssl_object.unwrap) + self._read_bio.write_eof() + self._write_bio.write_eof() + return self.transport_stream, self._read_bio.read() + + async def aclose(self) -> None: + if self.standard_compatible: + try: + await self.unwrap() + except BaseException: + await aclose_forcefully(self.transport_stream) + raise + + await self.transport_stream.aclose() + + async def receive(self, max_bytes: int = 65536) -> bytes: + data = await self._call_sslobject_method(self._ssl_object.read, max_bytes) + if not data: + raise EndOfStream + + return data + + async def send(self, item: bytes) -> None: + await self._call_sslobject_method(self._ssl_object.write, item) + + async def send_eof(self) -> None: + tls_version = self.extra(TLSAttribute.tls_version) + match = re.match(r"TLSv(\d+)(?:\.(\d+))?", tls_version) + if match: + major, minor = int(match.group(1)), int(match.group(2) or 0) + if (major, minor) < (1, 3): + raise NotImplementedError( + f"send_eof() requires at least TLSv1.3; current " + f"session uses {tls_version}" + ) + + raise NotImplementedError( + "send_eof() has not yet been implemented for TLS streams" + ) + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self.transport_stream.extra_attributes, + TLSAttribute.alpn_protocol: self._ssl_object.selected_alpn_protocol, + TLSAttribute.channel_binding_tls_unique: self._ssl_object.get_channel_binding, + TLSAttribute.cipher: self._ssl_object.cipher, + TLSAttribute.peer_certificate: lambda: self._ssl_object.getpeercert(False), + TLSAttribute.peer_certificate_binary: lambda: self._ssl_object.getpeercert( + True + ), + TLSAttribute.server_side: lambda: self._ssl_object.server_side, + TLSAttribute.shared_ciphers: lambda: self._ssl_object.shared_ciphers(), + TLSAttribute.standard_compatible: lambda: self.standard_compatible, + TLSAttribute.ssl_object: lambda: self._ssl_object, + TLSAttribute.tls_version: self._ssl_object.version, + } + + +@dataclass(eq=False) +class TLSListener(Listener[TLSStream]): + """ + A convenience listener that wraps another listener and auto-negotiates a TLS session on every + accepted connection. + + If the TLS handshake times out or raises an exception, :meth:`handle_handshake_error` is + called to do whatever post-mortem processing is deemed necessary. + + Supports only the :attr:`~TLSAttribute.standard_compatible` extra attribute. + + :param Listener listener: the listener to wrap + :param ssl_context: the SSL context object + :param standard_compatible: a flag passed through to :meth:`TLSStream.wrap` + :param handshake_timeout: time limit for the TLS handshake + (passed to :func:`~anyio.fail_after`) + """ + + listener: Listener[Any] + ssl_context: ssl.SSLContext + standard_compatible: bool = True + handshake_timeout: float = 30 + + @staticmethod + async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None: + f""" + Handle an exception raised during the TLS handshake. + + This method does 3 things: + + #. Forcefully closes the original stream + #. Logs the exception (unless it was a cancellation exception) using the ``{__name__}`` + logger + #. Reraises the exception if it was a base exception or a cancellation exception + + :param exc: the exception + :param stream: the original stream + + """ + await aclose_forcefully(stream) + + # Log all except cancellation exceptions + if not isinstance(exc, get_cancelled_exc_class()): + logging.getLogger(__name__).exception("Error during TLS handshake") + + # Only reraise base exceptions and cancellation exceptions + if not isinstance(exc, Exception) or isinstance(exc, get_cancelled_exc_class()): + raise + + async def serve( + self, + handler: Callable[[TLSStream], Any], + task_group: Optional[TaskGroup] = None, + ) -> None: + @wraps(handler) + async def handler_wrapper(stream: AnyByteStream) -> None: + from .. import fail_after + + try: + with fail_after(self.handshake_timeout): + wrapped_stream = await TLSStream.wrap( + stream, + ssl_context=self.ssl_context, + standard_compatible=self.standard_compatible, + ) + except BaseException as exc: + await self.handle_handshake_error(exc, stream) + else: + await handler(wrapped_stream) + + await self.listener.serve(handler_wrapper, task_group) + + async def aclose(self) -> None: + await self.listener.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + TLSAttribute.standard_compatible: lambda: self.standard_compatible, + } diff --git a/myenv/lib/python3.9/site-packages/anyio/to_process.py b/myenv/lib/python3.9/site-packages/anyio/to_process.py new file mode 100644 index 0000000..39a3173 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/to_process.py @@ -0,0 +1,247 @@ +import os +import pickle +import subprocess +import sys +from collections import deque +from importlib.util import module_from_spec, spec_from_file_location +from typing import Callable, Deque, List, Optional, Set, Tuple, TypeVar, cast + +from ._core._eventloop import current_time, get_asynclib, get_cancelled_exc_class +from ._core._exceptions import BrokenWorkerProcess +from ._core._subprocesses import open_process +from ._core._synchronization import CapacityLimiter +from ._core._tasks import CancelScope, fail_after +from .abc import ByteReceiveStream, ByteSendStream, Process +from .lowlevel import RunVar, checkpoint_if_cancelled +from .streams.buffered import BufferedByteReceiveStream + +WORKER_MAX_IDLE_TIME = 300 # 5 minutes + +T_Retval = TypeVar("T_Retval") +_process_pool_workers: RunVar[Set[Process]] = RunVar("_process_pool_workers") +_process_pool_idle_workers: RunVar[Deque[Tuple[Process, float]]] = RunVar( + "_process_pool_idle_workers" +) +_default_process_limiter: RunVar[CapacityLimiter] = RunVar("_default_process_limiter") + + +async def run_sync( + func: Callable[..., T_Retval], + *args: object, + cancellable: bool = False, + limiter: Optional[CapacityLimiter] = None, +) -> T_Retval: + """ + Call the given function with the given arguments in a worker process. + + If the ``cancellable`` option is enabled and the task waiting for its completion is cancelled, + the worker process running it will be abruptly terminated using SIGKILL (or + ``terminateProcess()`` on Windows). + + :param func: a callable + :param args: positional arguments for the callable + :param cancellable: ``True`` to allow cancellation of the operation while it's running + :param limiter: capacity limiter to use to limit the total amount of processes running + (if omitted, the default limiter is used) + :return: an awaitable that yields the return value of the function. + + """ + + async def send_raw_command(pickled_cmd: bytes) -> object: + try: + await stdin.send(pickled_cmd) + response = await buffered.receive_until(b"\n", 50) + status, length = response.split(b" ") + if status not in (b"RETURN", b"EXCEPTION"): + raise RuntimeError( + f"Worker process returned unexpected response: {response!r}" + ) + + pickled_response = await buffered.receive_exactly(int(length)) + except BaseException as exc: + workers.discard(process) + try: + process.kill() + with CancelScope(shield=True): + await process.aclose() + except ProcessLookupError: + pass + + if isinstance(exc, get_cancelled_exc_class()): + raise + else: + raise BrokenWorkerProcess from exc + + retval = pickle.loads(pickled_response) + if status == b"EXCEPTION": + assert isinstance(retval, BaseException) + raise retval + else: + return retval + + # First pickle the request before trying to reserve a worker process + await checkpoint_if_cancelled() + request = pickle.dumps(("run", func, args), protocol=pickle.HIGHEST_PROTOCOL) + + # If this is the first run in this event loop thread, set up the necessary variables + try: + workers = _process_pool_workers.get() + idle_workers = _process_pool_idle_workers.get() + except LookupError: + workers = set() + idle_workers = deque() + _process_pool_workers.set(workers) + _process_pool_idle_workers.set(idle_workers) + get_asynclib().setup_process_pool_exit_at_shutdown(workers) + + async with (limiter or current_default_process_limiter()): + # Pop processes from the pool (starting from the most recently used) until we find one that + # hasn't exited yet + process: Process + while idle_workers: + process, idle_since = idle_workers.pop() + if process.returncode is None: + stdin = cast(ByteSendStream, process.stdin) + buffered = BufferedByteReceiveStream( + cast(ByteReceiveStream, process.stdout) + ) + + # Prune any other workers that have been idle for WORKER_MAX_IDLE_TIME seconds or + # longer + now = current_time() + killed_processes: List[Process] = [] + while idle_workers: + if now - idle_workers[0][1] < WORKER_MAX_IDLE_TIME: + break + + process, idle_since = idle_workers.popleft() + process.kill() + workers.remove(process) + killed_processes.append(process) + + with CancelScope(shield=True): + for process in killed_processes: + await process.aclose() + + break + + workers.remove(process) + else: + command = [sys.executable, "-u", "-m", __name__] + process = await open_process( + command, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) + try: + stdin = cast(ByteSendStream, process.stdin) + buffered = BufferedByteReceiveStream( + cast(ByteReceiveStream, process.stdout) + ) + with fail_after(20): + message = await buffered.receive(6) + + if message != b"READY\n": + raise BrokenWorkerProcess( + f"Worker process returned unexpected response: {message!r}" + ) + + main_module_path = getattr(sys.modules["__main__"], "__file__", None) + pickled = pickle.dumps( + ("init", sys.path, main_module_path), + protocol=pickle.HIGHEST_PROTOCOL, + ) + await send_raw_command(pickled) + except (BrokenWorkerProcess, get_cancelled_exc_class()): + raise + except BaseException as exc: + process.kill() + raise BrokenWorkerProcess( + "Error during worker process initialization" + ) from exc + + workers.add(process) + + with CancelScope(shield=not cancellable): + try: + return cast(T_Retval, await send_raw_command(request)) + finally: + if process in workers: + idle_workers.append((process, current_time())) + + +def current_default_process_limiter() -> CapacityLimiter: + """ + Return the capacity limiter that is used by default to limit the number of worker processes. + + :return: a capacity limiter object + + """ + try: + return _default_process_limiter.get() + except LookupError: + limiter = CapacityLimiter(os.cpu_count() or 2) + _default_process_limiter.set(limiter) + return limiter + + +def process_worker() -> None: + # Redirect standard streams to os.devnull so that user code won't interfere with the + # parent-worker communication + stdin = sys.stdin + stdout = sys.stdout + sys.stdin = open(os.devnull) + sys.stdout = open(os.devnull, "w") + + stdout.buffer.write(b"READY\n") + while True: + retval = exception = None + try: + command, *args = pickle.load(stdin.buffer) + except EOFError: + return + except BaseException as exc: + exception = exc + else: + if command == "run": + func, args = args + try: + retval = func(*args) + except BaseException as exc: + exception = exc + elif command == "init": + main_module_path: Optional[str] + sys.path, main_module_path = args + del sys.modules["__main__"] + if main_module_path: + # Load the parent's main module but as __mp_main__ instead of __main__ + # (like multiprocessing does) to avoid infinite recursion + try: + spec = spec_from_file_location("__mp_main__", main_module_path) + if spec and spec.loader: + main = module_from_spec(spec) + spec.loader.exec_module(main) + sys.modules["__main__"] = main + except BaseException as exc: + exception = exc + + try: + if exception is not None: + status = b"EXCEPTION" + pickled = pickle.dumps(exception, pickle.HIGHEST_PROTOCOL) + else: + status = b"RETURN" + pickled = pickle.dumps(retval, pickle.HIGHEST_PROTOCOL) + except BaseException as exc: + exception = exc + status = b"EXCEPTION" + pickled = pickle.dumps(exc, pickle.HIGHEST_PROTOCOL) + + stdout.buffer.write(b"%s %d\n" % (status, len(pickled))) + stdout.buffer.write(pickled) + + # Respect SIGTERM + if isinstance(exception, SystemExit): + raise exception + + +if __name__ == "__main__": + process_worker() diff --git a/myenv/lib/python3.9/site-packages/anyio/to_thread.py b/myenv/lib/python3.9/site-packages/anyio/to_thread.py new file mode 100644 index 0000000..a2fd42f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/anyio/to_thread.py @@ -0,0 +1,65 @@ +from typing import Callable, Optional, TypeVar +from warnings import warn + +from ._core._eventloop import get_asynclib +from .abc import CapacityLimiter + +T_Retval = TypeVar("T_Retval") + + +async def run_sync( + func: Callable[..., T_Retval], + *args: object, + cancellable: bool = False, + limiter: Optional[CapacityLimiter] = None +) -> T_Retval: + """ + Call the given function with the given arguments in a worker thread. + + If the ``cancellable`` option is enabled and the task waiting for its completion is cancelled, + the thread will still run its course but its return value (or any raised exception) will be + ignored. + + :param func: a callable + :param args: positional arguments for the callable + :param cancellable: ``True`` to allow cancellation of the operation + :param limiter: capacity limiter to use to limit the total amount of threads running + (if omitted, the default limiter is used) + :return: an awaitable that yields the return value of the function. + + """ + return await get_asynclib().run_sync_in_worker_thread( + func, *args, cancellable=cancellable, limiter=limiter + ) + + +async def run_sync_in_worker_thread( + func: Callable[..., T_Retval], + *args: object, + cancellable: bool = False, + limiter: Optional[CapacityLimiter] = None +) -> T_Retval: + warn( + "run_sync_in_worker_thread() has been deprecated, use anyio.to_thread.run_sync() instead", + DeprecationWarning, + ) + return await run_sync(func, *args, cancellable=cancellable, limiter=limiter) + + +def current_default_thread_limiter() -> CapacityLimiter: + """ + Return the capacity limiter that is used by default to limit the number of concurrent threads. + + :return: a capacity limiter object + + """ + return get_asynclib().current_default_thread_limiter() + + +def current_default_worker_thread_limiter() -> CapacityLimiter: + warn( + "current_default_worker_thread_limiter() has been deprecated, " + "use anyio.to_thread.current_default_thread_limiter() instead", + DeprecationWarning, + ) + return current_default_thread_limiter() diff --git a/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/LICENSE new file mode 100644 index 0000000..5f4f225 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Django Software Foundation and individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of Django nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/METADATA b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/METADATA new file mode 100644 index 0000000..48f0b33 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/METADATA @@ -0,0 +1,245 @@ +Metadata-Version: 2.1 +Name: asgiref +Version: 3.5.2 +Summary: ASGI specs, helper code, and adapters +Home-page: https://github.com/django/asgiref/ +Author: Django Software Foundation +Author-email: foundation@djangoproject.com +License: BSD +Project-URL: Documentation, https://asgi.readthedocs.io/ +Project-URL: Further Documentation, https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions +Project-URL: Changelog, https://github.com/django/asgiref/blob/master/CHANGELOG.txt +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.7 +License-File: LICENSE +Requires-Dist: typing-extensions ; python_version < "3.8" +Provides-Extra: tests +Requires-Dist: pytest ; extra == 'tests' +Requires-Dist: pytest-asyncio ; extra == 'tests' +Requires-Dist: mypy (>=0.800) ; extra == 'tests' + +asgiref +======= + +.. image:: https://api.travis-ci.org/django/asgiref.svg + :target: https://travis-ci.org/django/asgiref + +.. image:: https://img.shields.io/pypi/v/asgiref.svg + :target: https://pypi.python.org/pypi/asgiref + +ASGI is a standard for Python asynchronous web apps and servers to communicate +with each other, and positioned as an asynchronous successor to WSGI. You can +read more at https://asgi.readthedocs.io/en/latest/ + +This package includes ASGI base libraries, such as: + +* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync`` +* Server base classes, ``asgiref.server`` +* A WSGI-to-ASGI adapter, in ``asgiref.wsgi`` + + +Function wrappers +----------------- + +These allow you to wrap or decorate async or sync functions to call them from +the other style (so you can call async functions from a synchronous thread, +or vice-versa). + +In particular: + +* AsyncToSync lets a synchronous subthread stop and wait while the async + function is called on the main thread's event loop, and then control is + returned to the thread when the async function is finished. + +* SyncToAsync lets async code call a synchronous function, which is run in + a threadpool and control returned to the async coroutine when the synchronous + function completes. + +The idea is to make it easier to call synchronous APIs from async code and +asynchronous APIs from synchronous code so it's easier to transition code from +one style to the other. In the case of Channels, we wrap the (synchronous) +Django view system with SyncToAsync to allow it to run inside the (asynchronous) +ASGI server. + +Note that exactly what threads things run in is very specific, and aimed to +keep maximum compatibility with old synchronous code. See +"Synchronous code & Threads" below for a full explanation. By default, +``sync_to_async`` will run all synchronous code in the program in the same +thread for safety reasons; you can disable this for more performance with +``@sync_to_async(thread_sensitive=False)``, but make sure that your code does +not rely on anything bound to threads (like database connections) when you do. + + +Threadlocal replacement +----------------------- + +This is a drop-in replacement for ``threading.local`` that works with both +threads and asyncio Tasks. Even better, it will proxy values through from a +task-local context to a thread-local context when you use ``sync_to_async`` +to run things in a threadpool, and vice-versa for ``async_to_sync``. + +If you instead want true thread- and task-safety, you can set +``thread_critical`` on the Local object to ensure this instead. + + +Server base classes +------------------- + +Includes a ``StatelessServer`` class which provides all the hard work of +writing a stateless server (as in, does not handle direct incoming sockets +but instead consumes external streams or sockets to work out what is happening). + +An example of such a server would be a chatbot server that connects out to +a central chat server and provides a "connection scope" per user chatting to +it. There's only one actual connection, but the server has to separate things +into several scopes for easier writing of the code. + +You can see an example of this being used in `frequensgi `_. + + +WSGI-to-ASGI adapter +-------------------- + +Allows you to wrap a WSGI application so it appears as a valid ASGI application. + +Simply wrap it around your WSGI application like so:: + + asgi_application = WsgiToAsgi(wsgi_application) + +The WSGI application will be run in a synchronous threadpool, and the wrapped +ASGI application will be one that accepts ``http`` class messages. + +Please note that not all extended features of WSGI may be supported (such as +file handles for incoming POST bodies). + + +Dependencies +------------ + +``asgiref`` requires Python 3.7 or higher. + + +Contributing +------------ + +Please refer to the +`main Channels contributing docs `_. + + +Testing +''''''' + +To run tests, make sure you have installed the ``tests`` extra with the package:: + + cd asgiref/ + pip install -e .[tests] + pytest + + +Building the documentation +'''''''''''''''''''''''''' + +The documentation uses `Sphinx `_:: + + cd asgiref/docs/ + pip install sphinx + +To build the docs, you can use the default tools:: + + sphinx-build -b html . _build/html # or `make html`, if you've got make set up + cd _build/html + python -m http.server + +...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload +your documentation changes automatically:: + + pip install sphinx-autobuild + sphinx-autobuild . _build/html + + +Releasing +''''''''' + +To release, first add details to CHANGELOG.txt and update the version number in ``asgiref/__init__.py``. + +Then, build and push the packages:: + + python -m build + twine upload dist/* + rm -r build/ dist/ + + +Implementation Details +---------------------- + +Synchronous code & threads +'''''''''''''''''''''''''' + +The ``asgiref.sync`` module provides two wrappers that let you go between +asynchronous and synchronous code at will, while taking care of the rough edges +for you. + +Unfortunately, the rough edges are numerous, and the code has to work especially +hard to keep things in the same thread as much as possible. Notably, the +restrictions we are working with are: + +* All synchronous code called through ``SyncToAsync`` and marked with + ``thread_sensitive`` should run in the same thread as each other (and if the + outer layer of the program is synchronous, the main thread) + +* If a thread already has a running async loop, ``AsyncToSync`` can't run things + on that loop if it's blocked on synchronous code that is above you in the + call stack. + +The first compromise you get to might be that ``thread_sensitive`` code should +just run in the same thread and not spawn in a sub-thread, fulfilling the first +restriction, but that immediately runs you into the second restriction. + +The only real solution is to essentially have a variant of ThreadPoolExecutor +that executes any ``thread_sensitive`` code on the outermost synchronous +thread - either the main thread, or a single spawned subthread. + +This means you now have two basic states: + +* If the outermost layer of your program is synchronous, then all async code + run through ``AsyncToSync`` will run in a per-call event loop in arbitrary + sub-threads, while all ``thread_sensitive`` code will run in the main thread. + +* If the outermost layer of your program is asynchronous, then all async code + runs on the main thread's event loop, and all ``thread_sensitive`` synchronous + code will run in a single shared sub-thread. + +Crucially, this means that in both cases there is a thread which is a shared +resource that all ``thread_sensitive`` code must run on, and there is a chance +that this thread is currently blocked on its own ``AsyncToSync`` call. Thus, +``AsyncToSync`` needs to act as an executor for thread code while it's blocking. + +The ``CurrentThreadExecutor`` class provides this functionality; rather than +simply waiting on a Future, you can call its ``run_until_future`` method and +it will run submitted code until that Future is done. This means that code +inside the call can then run code on your thread. + + +Maintenance and Security +------------------------ + +To report security issues, please contact security@djangoproject.com. For GPG +signatures and more security process information, see +https://docs.djangoproject.com/en/dev/internals/security/. + +To report bugs or request new features, please open a new GitHub issue. + +This repository is part of the Channels project. For the shepherd and maintenance team, please see the +`main Channels readme `_. diff --git a/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/RECORD b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/RECORD new file mode 100644 index 0000000..83e51b9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/RECORD @@ -0,0 +1,17 @@ +asgiref/__init__.py,sha256=LtYJ5AVwuiAlsrJUQwzHZMrGMIRn7cuIoIt4OznYy6c,22 +asgiref/compatibility.py,sha256=MVH2bEdiCMMVTLbE-1V6KiU7q4LwqzP7PIufeXa-njM,1598 +asgiref/current_thread_executor.py,sha256=oeH8zv2tTmcbpxdUmOSMzbEXzeY5nJzIMFvzprE95gA,2801 +asgiref/local.py,sha256=nx5RqVFLYgUJVaxzApuQUW7dd9y21sruMYdgISoRs1k,4854 +asgiref/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +asgiref/server.py,sha256=egTQhZo1k4G0F7SSBQNp_VOekpGcjBJZU2kkCoiGC_M,6005 +asgiref/sync.py,sha256=3P813NHl3EHPMtzPEjaBelmjV_JUw97zYbtx-MmLUiw,20185 +asgiref/testing.py,sha256=3byNRV7Oto_Fg8Z-fErQJ3yGf7OQlcUexbN_cDQugzQ,3119 +asgiref/timeout.py,sha256=5Ekbmn3X1HPR55qgx-hPJMPEu_-YoivHqNhFEitiSYE,3440 +asgiref/typing.py,sha256=MZ7vbJY1F7EQqo9gL9pMSFRMw9b_SQrQQsnvlJQ2iP4,5603 +asgiref/wsgi.py,sha256=-L0eo_uK_dq7EPjv1meW1BRGytURaO9NPESxnJc9CtA,6575 +asgiref-3.5.2.dist-info/LICENSE,sha256=uEZBXRtRTpwd_xSiLeuQbXlLxUbKYSn5UKGM0JHipmk,1552 +asgiref-3.5.2.dist-info/METADATA,sha256=3JU5Zw-j9qCKPcuf3cJZ5dVispB_b7UXU0fnQVp9DDA,9143 +asgiref-3.5.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +asgiref-3.5.2.dist-info/top_level.txt,sha256=bokQjCzwwERhdBiPdvYEZa4cHxT4NCeAffQNUqJ8ssg,8 +asgiref-3.5.2.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +asgiref-3.5.2.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/top_level.txt new file mode 100644 index 0000000..ddf99d3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref-3.5.2.dist-info/top_level.txt @@ -0,0 +1 @@ +asgiref diff --git a/myenv/lib/python3.9/site-packages/asgiref/__init__.py b/myenv/lib/python3.9/site-packages/asgiref/__init__.py new file mode 100644 index 0000000..dae42b1 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/__init__.py @@ -0,0 +1 @@ +__version__ = "3.5.2" diff --git a/myenv/lib/python3.9/site-packages/asgiref/compatibility.py b/myenv/lib/python3.9/site-packages/asgiref/compatibility.py new file mode 100644 index 0000000..eccaee0 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/compatibility.py @@ -0,0 +1,47 @@ +import asyncio +import inspect + + +def is_double_callable(application): + """ + Tests to see if an application is a legacy-style (double-callable) application. + """ + # Look for a hint on the object first + if getattr(application, "_asgi_single_callable", False): + return False + if getattr(application, "_asgi_double_callable", False): + return True + # Uninstanted classes are double-callable + if inspect.isclass(application): + return True + # Instanted classes depend on their __call__ + if hasattr(application, "__call__"): + # We only check to see if its __call__ is a coroutine function - + # if it's not, it still might be a coroutine function itself. + if asyncio.iscoroutinefunction(application.__call__): + return False + # Non-classes we just check directly + return not asyncio.iscoroutinefunction(application) + + +def double_to_single_callable(application): + """ + Transforms a double-callable ASGI application into a single-callable one. + """ + + async def new_application(scope, receive, send): + instance = application(scope) + return await instance(receive, send) + + return new_application + + +def guarantee_single_callable(application): + """ + Takes either a single- or double-callable application and always returns it + in single-callable style. Use this to add backwards compatibility for ASGI + 2.0 applications to your server/test harness/etc. + """ + if is_double_callable(application): + application = double_to_single_callable(application) + return application diff --git a/myenv/lib/python3.9/site-packages/asgiref/current_thread_executor.py b/myenv/lib/python3.9/site-packages/asgiref/current_thread_executor.py new file mode 100644 index 0000000..a7898f8 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/current_thread_executor.py @@ -0,0 +1,81 @@ +import queue +import threading +from concurrent.futures import Executor, Future + + +class _WorkItem: + """ + Represents an item needing to be run in the executor. + Copied from ThreadPoolExecutor (but it's private, so we're not going to rely on importing it) + """ + + def __init__(self, future, fn, args, kwargs): + self.future = future + self.fn = fn + self.args = args + self.kwargs = kwargs + + def run(self): + if not self.future.set_running_or_notify_cancel(): + return + try: + result = self.fn(*self.args, **self.kwargs) + except BaseException as exc: + self.future.set_exception(exc) + # Break a reference cycle with the exception 'exc' + self = None + else: + self.future.set_result(result) + + +class CurrentThreadExecutor(Executor): + """ + An Executor that actually runs code in the thread it is instantiated in. + Passed to other threads running async code, so they can run sync code in + the thread they came from. + """ + + def __init__(self): + self._work_thread = threading.current_thread() + self._work_queue = queue.Queue() + self._broken = False + + def run_until_future(self, future): + """ + Runs the code in the work queue until a result is available from the future. + Should be run from the thread the executor is initialised in. + """ + # Check we're in the right thread + if threading.current_thread() != self._work_thread: + raise RuntimeError( + "You cannot run CurrentThreadExecutor from a different thread" + ) + future.add_done_callback(self._work_queue.put) + # Keep getting and running work items until we get the future we're waiting for + # back via the future's done callback. + try: + while True: + # Get a work item and run it + work_item = self._work_queue.get() + if work_item is future: + return + work_item.run() + del work_item + finally: + self._broken = True + + def submit(self, fn, *args, **kwargs): + # Check they're not submitting from the same thread + if threading.current_thread() == self._work_thread: + raise RuntimeError( + "You cannot submit onto CurrentThreadExecutor from its own thread" + ) + # Check they're not too late or the executor errored + if self._broken: + raise RuntimeError("CurrentThreadExecutor already quit or is broken") + # Add to work queue + f = Future() + work_item = _WorkItem(f, fn, args, kwargs) + self._work_queue.put(work_item) + # Return the future + return f diff --git a/myenv/lib/python3.9/site-packages/asgiref/local.py b/myenv/lib/python3.9/site-packages/asgiref/local.py new file mode 100644 index 0000000..17314d4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/local.py @@ -0,0 +1,120 @@ +import random +import string +import sys +import threading +import weakref + + +class Local: + """ + A drop-in replacement for threading.locals that also works with asyncio + Tasks (via the current_task asyncio method), and passes locals through + sync_to_async and async_to_sync. + + Specifically: + - Locals work per-coroutine on any thread not spawned using asgiref + - Locals work per-thread on any thread not spawned using asgiref + - Locals are shared with the parent coroutine when using sync_to_async + - Locals are shared with the parent thread when using async_to_sync + (and if that thread was launched using sync_to_async, with its parent + coroutine as well, with this working for indefinite levels of nesting) + + Set thread_critical to True to not allow locals to pass from an async Task + to a thread it spawns. This is needed for code that truly needs + thread-safety, as opposed to things used for helpful context (e.g. sqlite + does not like being called from a different thread to the one it is from). + Thread-critical code will still be differentiated per-Task within a thread + as it is expected it does not like concurrent access. + + This doesn't use contextvars as it needs to support 3.6. Once it can support + 3.7 only, we can then reimplement the storage more nicely. + """ + + def __init__(self, thread_critical: bool = False) -> None: + self._thread_critical = thread_critical + self._thread_lock = threading.RLock() + self._context_refs: "weakref.WeakSet[object]" = weakref.WeakSet() + # Random suffixes stop accidental reuse between different Locals, + # though we try to force deletion as well. + self._attr_name = "_asgiref_local_impl_{}_{}".format( + id(self), + "".join(random.choice(string.ascii_letters) for i in range(8)), + ) + + def _get_context_id(self): + """ + Get the ID we should use for looking up variables + """ + # Prevent a circular reference + from .sync import AsyncToSync, SyncToAsync + + # First, pull the current task if we can + context_id = SyncToAsync.get_current_task() + context_is_async = True + # OK, let's try for a thread ID + if context_id is None: + context_id = threading.current_thread() + context_is_async = False + # If we're thread-critical, we stop here, as we can't share contexts. + if self._thread_critical: + return context_id + # Now, take those and see if we can resolve them through the launch maps + for i in range(sys.getrecursionlimit()): + try: + if context_is_async: + # Tasks have a source thread in AsyncToSync + context_id = AsyncToSync.launch_map[context_id] + context_is_async = False + else: + # Threads have a source task in SyncToAsync + context_id = SyncToAsync.launch_map[context_id] + context_is_async = True + except KeyError: + break + else: + # Catch infinite loops (they happen if you are screwing around + # with AsyncToSync implementations) + raise RuntimeError("Infinite launch_map loops") + return context_id + + def _get_storage(self): + context_obj = self._get_context_id() + if not hasattr(context_obj, self._attr_name): + setattr(context_obj, self._attr_name, {}) + self._context_refs.add(context_obj) + return getattr(context_obj, self._attr_name) + + def __del__(self): + try: + for context_obj in self._context_refs: + try: + delattr(context_obj, self._attr_name) + except AttributeError: + pass + except TypeError: + # WeakSet.__iter__ can crash when interpreter is shutting down due + # to _IterationGuard being None. + pass + + def __getattr__(self, key): + with self._thread_lock: + storage = self._get_storage() + if key in storage: + return storage[key] + else: + raise AttributeError(f"{self!r} object has no attribute {key!r}") + + def __setattr__(self, key, value): + if key in ("_context_refs", "_thread_critical", "_thread_lock", "_attr_name"): + return super().__setattr__(key, value) + with self._thread_lock: + storage = self._get_storage() + storage[key] = value + + def __delattr__(self, key): + with self._thread_lock: + storage = self._get_storage() + if key in storage: + del storage[key] + else: + raise AttributeError(f"{self!r} object has no attribute {key!r}") diff --git a/myenv/lib/python3.9/site-packages/asgiref/py.typed b/myenv/lib/python3.9/site-packages/asgiref/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/asgiref/server.py b/myenv/lib/python3.9/site-packages/asgiref/server.py new file mode 100644 index 0000000..43c28c6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/server.py @@ -0,0 +1,157 @@ +import asyncio +import logging +import time +import traceback + +from .compatibility import guarantee_single_callable + +logger = logging.getLogger(__name__) + + +class StatelessServer: + """ + Base server class that handles basic concepts like application instance + creation/pooling, exception handling, and similar, for stateless protocols + (i.e. ones without actual incoming connections to the process) + + Your code should override the handle() method, doing whatever it needs to, + and calling get_or_create_application_instance with a unique `scope_id` + and `scope` for the scope it wants to get. + + If an application instance is found with the same `scope_id`, you are + given its input queue, otherwise one is made for you with the scope provided + and you are given that fresh new input queue. Either way, you should do + something like: + + input_queue = self.get_or_create_application_instance( + "user-123456", + {"type": "testprotocol", "user_id": "123456", "username": "andrew"}, + ) + input_queue.put_nowait(message) + + If you try and create an application instance and there are already + `max_application` instances, the oldest/least recently used one will be + reclaimed and shut down to make space. + + Application coroutines that error will be found periodically (every 100ms + by default) and have their exceptions printed to the console. Override + application_exception() if you want to do more when this happens. + + If you override run(), make sure you handle things like launching the + application checker. + """ + + application_checker_interval = 0.1 + + def __init__(self, application, max_applications=1000): + # Parameters + self.application = application + self.max_applications = max_applications + # Initialisation + self.application_instances = {} + + ### Mainloop and handling + + def run(self): + """ + Runs the asyncio event loop with our handler loop. + """ + event_loop = asyncio.get_event_loop() + asyncio.ensure_future(self.application_checker()) + try: + event_loop.run_until_complete(self.handle()) + except KeyboardInterrupt: + logger.info("Exiting due to Ctrl-C/interrupt") + + async def handle(self): + raise NotImplementedError("You must implement handle()") + + async def application_send(self, scope, message): + """ + Receives outbound sends from applications and handles them. + """ + raise NotImplementedError("You must implement application_send()") + + ### Application instance management + + def get_or_create_application_instance(self, scope_id, scope): + """ + Creates an application instance and returns its queue. + """ + if scope_id in self.application_instances: + self.application_instances[scope_id]["last_used"] = time.time() + return self.application_instances[scope_id]["input_queue"] + # See if we need to delete an old one + while len(self.application_instances) > self.max_applications: + self.delete_oldest_application_instance() + # Make an instance of the application + input_queue = asyncio.Queue() + application_instance = guarantee_single_callable(self.application) + # Run it, and stash the future for later checking + future = asyncio.ensure_future( + application_instance( + scope=scope, + receive=input_queue.get, + send=lambda message: self.application_send(scope, message), + ), + ) + self.application_instances[scope_id] = { + "input_queue": input_queue, + "future": future, + "scope": scope, + "last_used": time.time(), + } + return input_queue + + def delete_oldest_application_instance(self): + """ + Finds and deletes the oldest application instance + """ + oldest_time = min( + details["last_used"] for details in self.application_instances.values() + ) + for scope_id, details in self.application_instances.items(): + if details["last_used"] == oldest_time: + self.delete_application_instance(scope_id) + # Return to make sure we only delete one in case two have + # the same oldest time + return + + def delete_application_instance(self, scope_id): + """ + Removes an application instance (makes sure its task is stopped, + then removes it from the current set) + """ + details = self.application_instances[scope_id] + del self.application_instances[scope_id] + if not details["future"].done(): + details["future"].cancel() + + async def application_checker(self): + """ + Goes through the set of current application instance Futures and cleans up + any that are done/prints exceptions for any that errored. + """ + while True: + await asyncio.sleep(self.application_checker_interval) + for scope_id, details in list(self.application_instances.items()): + if details["future"].done(): + exception = details["future"].exception() + if exception: + await self.application_exception(exception, details) + try: + del self.application_instances[scope_id] + except KeyError: + # Exception handling might have already got here before us. That's fine. + pass + + async def application_exception(self, exception, application_details): + """ + Called whenever an application coroutine has an exception. + """ + logging.error( + "Exception inside application: %s\n%s%s", + exception, + "".join(traceback.format_tb(exception.__traceback__)), + f" {exception}", + ) diff --git a/myenv/lib/python3.9/site-packages/asgiref/sync.py b/myenv/lib/python3.9/site-packages/asgiref/sync.py new file mode 100644 index 0000000..6247043 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/sync.py @@ -0,0 +1,532 @@ +import asyncio +import asyncio.coroutines +import contextvars +import functools +import inspect +import os +import sys +import threading +import warnings +import weakref +from concurrent.futures import Future, ThreadPoolExecutor +from typing import Any, Callable, Dict, Optional, overload + +from .current_thread_executor import CurrentThreadExecutor +from .local import Local + + +def _restore_context(context): + # Check for changes in contextvars, and set them to the current + # context for downstream consumers + for cvar in context: + try: + if cvar.get() != context.get(cvar): + cvar.set(context.get(cvar)) + except LookupError: + cvar.set(context.get(cvar)) + + +def _iscoroutinefunction_or_partial(func: Any) -> bool: + # Python < 3.8 does not correctly determine partially wrapped + # coroutine functions are coroutine functions, hence the need for + # this to exist. Code taken from CPython. + if sys.version_info >= (3, 8): + return asyncio.iscoroutinefunction(func) + else: + while inspect.ismethod(func): + func = func.__func__ + while isinstance(func, functools.partial): + func = func.func + + return asyncio.iscoroutinefunction(func) + + +class ThreadSensitiveContext: + """Async context manager to manage context for thread sensitive mode + + This context manager controls which thread pool executor is used when in + thread sensitive mode. By default, a single thread pool executor is shared + within a process. + + In Python 3.7+, the ThreadSensitiveContext() context manager may be used to + specify a thread pool per context. + + This context manager is re-entrant, so only the outer-most call to + ThreadSensitiveContext will set the context. + + Usage: + + >>> import time + >>> async with ThreadSensitiveContext(): + ... await sync_to_async(time.sleep, 1)() + """ + + def __init__(self): + self.token = None + + async def __aenter__(self): + try: + SyncToAsync.thread_sensitive_context.get() + except LookupError: + self.token = SyncToAsync.thread_sensitive_context.set(self) + + return self + + async def __aexit__(self, exc, value, tb): + if not self.token: + return + + executor = SyncToAsync.context_to_thread_executor.pop(self, None) + if executor: + executor.shutdown() + SyncToAsync.thread_sensitive_context.reset(self.token) + + +class AsyncToSync: + """ + Utility class which turns an awaitable that only works on the thread with + the event loop into a synchronous callable that works in a subthread. + + If the call stack contains an async loop, the code runs there. + Otherwise, the code runs in a new loop in a new thread. + + Either way, this thread then pauses and waits to run any thread_sensitive + code called from further down the call stack using SyncToAsync, before + finally exiting once the async task returns. + """ + + # Maps launched Tasks to the threads that launched them (for locals impl) + launch_map: "Dict[asyncio.Task[object], threading.Thread]" = {} + + # Keeps track of which CurrentThreadExecutor to use. This uses an asgiref + # Local, not a threadlocal, so that tasks can work out what their parent used. + executors = Local() + + # When we can't find a CurrentThreadExecutor from the context, such as + # inside create_task, we'll look it up here from the running event loop. + loop_thread_executors: "Dict[asyncio.AbstractEventLoop, CurrentThreadExecutor]" = {} + + def __init__(self, awaitable, force_new_loop=False): + if not callable(awaitable) or ( + not _iscoroutinefunction_or_partial(awaitable) + and not _iscoroutinefunction_or_partial( + getattr(awaitable, "__call__", awaitable) + ) + ): + # Python does not have very reliable detection of async functions + # (lots of false negatives) so this is just a warning. + warnings.warn( + "async_to_sync was passed a non-async-marked callable", stacklevel=2 + ) + self.awaitable = awaitable + try: + self.__self__ = self.awaitable.__self__ + except AttributeError: + pass + if force_new_loop: + # They have asked that we always run in a new sub-loop. + self.main_event_loop = None + else: + try: + self.main_event_loop = asyncio.get_running_loop() + except RuntimeError: + # There's no event loop in this thread. Look for the threadlocal if + # we're inside SyncToAsync + main_event_loop_pid = getattr( + SyncToAsync.threadlocal, "main_event_loop_pid", None + ) + # We make sure the parent loop is from the same process - if + # they've forked, this is not going to be valid any more (#194) + if main_event_loop_pid and main_event_loop_pid == os.getpid(): + self.main_event_loop = getattr( + SyncToAsync.threadlocal, "main_event_loop", None + ) + else: + self.main_event_loop = None + + def __call__(self, *args, **kwargs): + # You can't call AsyncToSync from a thread with a running event loop + try: + event_loop = asyncio.get_running_loop() + except RuntimeError: + pass + else: + if event_loop.is_running(): + raise RuntimeError( + "You cannot use AsyncToSync in the same thread as an async event loop - " + "just await the async function directly." + ) + + # Wrapping context in list so it can be reassigned from within + # `main_wrap`. + context = [contextvars.copy_context()] + + # Make a future for the return information + call_result = Future() + # Get the source thread + source_thread = threading.current_thread() + # Make a CurrentThreadExecutor we'll use to idle in this thread - we + # need one for every sync frame, even if there's one above us in the + # same thread. + if hasattr(self.executors, "current"): + old_current_executor = self.executors.current + else: + old_current_executor = None + current_executor = CurrentThreadExecutor() + self.executors.current = current_executor + loop = None + # Use call_soon_threadsafe to schedule a synchronous callback on the + # main event loop's thread if it's there, otherwise make a new loop + # in this thread. + try: + awaitable = self.main_wrap( + args, kwargs, call_result, source_thread, sys.exc_info(), context + ) + + if not (self.main_event_loop and self.main_event_loop.is_running()): + # Make our own event loop - in a new thread - and run inside that. + loop = asyncio.new_event_loop() + self.loop_thread_executors[loop] = current_executor + loop_executor = ThreadPoolExecutor(max_workers=1) + loop_future = loop_executor.submit( + self._run_event_loop, loop, awaitable + ) + if current_executor: + # Run the CurrentThreadExecutor until the future is done + current_executor.run_until_future(loop_future) + # Wait for future and/or allow for exception propagation + loop_future.result() + else: + # Call it inside the existing loop + self.main_event_loop.call_soon_threadsafe( + self.main_event_loop.create_task, awaitable + ) + if current_executor: + # Run the CurrentThreadExecutor until the future is done + current_executor.run_until_future(call_result) + finally: + # Clean up any executor we were running + if loop is not None: + del self.loop_thread_executors[loop] + if hasattr(self.executors, "current"): + del self.executors.current + if old_current_executor: + self.executors.current = old_current_executor + _restore_context(context[0]) + + # Wait for results from the future. + return call_result.result() + + def _run_event_loop(self, loop, coro): + """ + Runs the given event loop (designed to be called in a thread). + """ + asyncio.set_event_loop(loop) + try: + loop.run_until_complete(coro) + finally: + try: + # mimic asyncio.run() behavior + # cancel unexhausted async generators + tasks = asyncio.all_tasks(loop) + for task in tasks: + task.cancel() + + async def gather(): + await asyncio.gather(*tasks, return_exceptions=True) + + loop.run_until_complete(gather()) + for task in tasks: + if task.cancelled(): + continue + if task.exception() is not None: + loop.call_exception_handler( + { + "message": "unhandled exception during loop shutdown", + "exception": task.exception(), + "task": task, + } + ) + if hasattr(loop, "shutdown_asyncgens"): + loop.run_until_complete(loop.shutdown_asyncgens()) + finally: + loop.close() + asyncio.set_event_loop(self.main_event_loop) + + def __get__(self, parent, objtype): + """ + Include self for methods + """ + func = functools.partial(self.__call__, parent) + return functools.update_wrapper(func, self.awaitable) + + async def main_wrap( + self, args, kwargs, call_result, source_thread, exc_info, context + ): + """ + Wraps the awaitable with something that puts the result into the + result/exception future. + """ + if context is not None: + _restore_context(context[0]) + + current_task = SyncToAsync.get_current_task() + self.launch_map[current_task] = source_thread + try: + # If we have an exception, run the function inside the except block + # after raising it so exc_info is correctly populated. + if exc_info[1]: + try: + raise exc_info[1] + except BaseException: + result = await self.awaitable(*args, **kwargs) + else: + result = await self.awaitable(*args, **kwargs) + except BaseException as e: + call_result.set_exception(e) + else: + call_result.set_result(result) + finally: + del self.launch_map[current_task] + + context[0] = contextvars.copy_context() + + +class SyncToAsync: + """ + Utility class which turns a synchronous callable into an awaitable that + runs in a threadpool. It also sets a threadlocal inside the thread so + calls to AsyncToSync can escape it. + + If thread_sensitive is passed, the code will run in the same thread as any + outer code. This is needed for underlying Python code that is not + threadsafe (for example, code which handles SQLite database connections). + + If the outermost program is async (i.e. SyncToAsync is outermost), then + this will be a dedicated single sub-thread that all sync code runs in, + one after the other. If the outermost program is sync (i.e. AsyncToSync is + outermost), this will just be the main thread. This is achieved by idling + with a CurrentThreadExecutor while AsyncToSync is blocking its sync parent, + rather than just blocking. + + If executor is passed in, that will be used instead of the loop's default executor. + In order to pass in an executor, thread_sensitive must be set to False, otherwise + a TypeError will be raised. + """ + + # If they've set ASGI_THREADS, update the default asyncio executor for now + if "ASGI_THREADS" in os.environ: + # We use get_event_loop here - not get_running_loop - as this will + # be run at import time, and we want to update the main thread's loop. + loop = asyncio.get_event_loop() + loop.set_default_executor( + ThreadPoolExecutor(max_workers=int(os.environ["ASGI_THREADS"])) + ) + + # Maps launched threads to the coroutines that spawned them + launch_map: "Dict[threading.Thread, asyncio.Task[object]]" = {} + + # Storage for main event loop references + threadlocal = threading.local() + + # Single-thread executor for thread-sensitive code + single_thread_executor = ThreadPoolExecutor(max_workers=1) + + # Maintain a contextvar for the current execution context. Optionally used + # for thread sensitive mode. + thread_sensitive_context: "contextvars.ContextVar[str]" = contextvars.ContextVar( + "thread_sensitive_context" + ) + + # Contextvar that is used to detect if the single thread executor + # would be awaited on while already being used in the same context + deadlock_context: "contextvars.ContextVar[bool]" = contextvars.ContextVar( + "deadlock_context" + ) + + # Maintaining a weak reference to the context ensures that thread pools are + # erased once the context goes out of scope. This terminates the thread pool. + context_to_thread_executor: "weakref.WeakKeyDictionary[object, ThreadPoolExecutor]" = ( + weakref.WeakKeyDictionary() + ) + + def __init__( + self, + func: Callable[..., Any], + thread_sensitive: bool = True, + executor: Optional["ThreadPoolExecutor"] = None, + ) -> None: + if ( + not callable(func) + or _iscoroutinefunction_or_partial(func) + or _iscoroutinefunction_or_partial(getattr(func, "__call__", func)) + ): + raise TypeError("sync_to_async can only be applied to sync functions.") + self.func = func + functools.update_wrapper(self, func) + self._thread_sensitive = thread_sensitive + self._is_coroutine = asyncio.coroutines._is_coroutine # type: ignore + if thread_sensitive and executor is not None: + raise TypeError("executor must not be set when thread_sensitive is True") + self._executor = executor + try: + self.__self__ = func.__self__ # type: ignore + except AttributeError: + pass + + async def __call__(self, *args, **kwargs): + loop = asyncio.get_running_loop() + + # Work out what thread to run the code in + if self._thread_sensitive: + if hasattr(AsyncToSync.executors, "current"): + # If we have a parent sync thread above somewhere, use that + executor = AsyncToSync.executors.current + elif self.thread_sensitive_context and self.thread_sensitive_context.get( + None + ): + # If we have a way of retrieving the current context, attempt + # to use a per-context thread pool executor + thread_sensitive_context = self.thread_sensitive_context.get() + + if thread_sensitive_context in self.context_to_thread_executor: + # Re-use thread executor in current context + executor = self.context_to_thread_executor[thread_sensitive_context] + else: + # Create new thread executor in current context + executor = ThreadPoolExecutor(max_workers=1) + self.context_to_thread_executor[thread_sensitive_context] = executor + elif loop in AsyncToSync.loop_thread_executors: + # Re-use thread executor for running loop + executor = AsyncToSync.loop_thread_executors[loop] + elif self.deadlock_context and self.deadlock_context.get(False): + raise RuntimeError( + "Single thread executor already being used, would deadlock" + ) + else: + # Otherwise, we run it in a fixed single thread + executor = self.single_thread_executor + if self.deadlock_context: + self.deadlock_context.set(True) + else: + # Use the passed in executor, or the loop's default if it is None + executor = self._executor + + context = contextvars.copy_context() + child = functools.partial(self.func, *args, **kwargs) + func = context.run + args = (child,) + kwargs = {} + + try: + # Run the code in the right thread + future = loop.run_in_executor( + executor, + functools.partial( + self.thread_handler, + loop, + self.get_current_task(), + sys.exc_info(), + func, + *args, + **kwargs, + ), + ) + ret = await asyncio.wait_for(future, timeout=None) + + finally: + _restore_context(context) + if self.deadlock_context: + self.deadlock_context.set(False) + + return ret + + def __get__(self, parent, objtype): + """ + Include self for methods + """ + return functools.partial(self.__call__, parent) + + def thread_handler(self, loop, source_task, exc_info, func, *args, **kwargs): + """ + Wraps the sync application with exception handling. + """ + # Set the threadlocal for AsyncToSync + self.threadlocal.main_event_loop = loop + self.threadlocal.main_event_loop_pid = os.getpid() + # Set the task mapping (used for the locals module) + current_thread = threading.current_thread() + if AsyncToSync.launch_map.get(source_task) == current_thread: + # Our parent task was launched from this same thread, so don't make + # a launch map entry - let it shortcut over us! (and stop infinite loops) + parent_set = False + else: + self.launch_map[current_thread] = source_task + parent_set = True + # Run the function + try: + # If we have an exception, run the function inside the except block + # after raising it so exc_info is correctly populated. + if exc_info[1]: + try: + raise exc_info[1] + except BaseException: + return func(*args, **kwargs) + else: + return func(*args, **kwargs) + finally: + # Only delete the launch_map parent if we set it, otherwise it is + # from someone else. + if parent_set: + del self.launch_map[current_thread] + + @staticmethod + def get_current_task(): + """ + Implementation of asyncio.current_task() + that returns None if there is no task. + """ + try: + return asyncio.current_task() + except RuntimeError: + return None + + +# Lowercase aliases (and decorator friendliness) +async_to_sync = AsyncToSync + + +@overload +def sync_to_async( + func: None = None, + thread_sensitive: bool = True, + executor: Optional["ThreadPoolExecutor"] = None, +) -> Callable[[Callable[..., Any]], SyncToAsync]: + ... + + +@overload +def sync_to_async( + func: Callable[..., Any], + thread_sensitive: bool = True, + executor: Optional["ThreadPoolExecutor"] = None, +) -> SyncToAsync: + ... + + +def sync_to_async( + func=None, + thread_sensitive=True, + executor=None, +): + if func is None: + return lambda f: SyncToAsync( + f, + thread_sensitive=thread_sensitive, + executor=executor, + ) + return SyncToAsync( + func, + thread_sensitive=thread_sensitive, + executor=executor, + ) diff --git a/myenv/lib/python3.9/site-packages/asgiref/testing.py b/myenv/lib/python3.9/site-packages/asgiref/testing.py new file mode 100644 index 0000000..6624317 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/testing.py @@ -0,0 +1,97 @@ +import asyncio +import time + +from .compatibility import guarantee_single_callable +from .timeout import timeout as async_timeout + + +class ApplicationCommunicator: + """ + Runs an ASGI application in a test mode, allowing sending of + messages to it and retrieval of messages it sends. + """ + + def __init__(self, application, scope): + self.application = guarantee_single_callable(application) + self.scope = scope + self.input_queue = asyncio.Queue() + self.output_queue = asyncio.Queue() + self.future = asyncio.ensure_future( + self.application(scope, self.input_queue.get, self.output_queue.put) + ) + + async def wait(self, timeout=1): + """ + Waits for the application to stop itself and returns any exceptions. + """ + try: + async with async_timeout(timeout): + try: + await self.future + self.future.result() + except asyncio.CancelledError: + pass + finally: + if not self.future.done(): + self.future.cancel() + try: + await self.future + except asyncio.CancelledError: + pass + + def stop(self, exceptions=True): + if not self.future.done(): + self.future.cancel() + elif exceptions: + # Give a chance to raise any exceptions + self.future.result() + + def __del__(self): + # Clean up on deletion + try: + self.stop(exceptions=False) + except RuntimeError: + # Event loop already stopped + pass + + async def send_input(self, message): + """ + Sends a single message to the application + """ + # Give it the message + await self.input_queue.put(message) + + async def receive_output(self, timeout=1): + """ + Receives a single message from the application, with optional timeout. + """ + # Make sure there's not an exception to raise from the task + if self.future.done(): + self.future.result() + # Wait and receive the message + try: + async with async_timeout(timeout): + return await self.output_queue.get() + except asyncio.TimeoutError as e: + # See if we have another error to raise inside + if self.future.done(): + self.future.result() + else: + self.future.cancel() + try: + await self.future + except asyncio.CancelledError: + pass + raise e + + async def receive_nothing(self, timeout=0.1, interval=0.01): + """ + Checks that there is no message to receive in the given time. + """ + # `interval` has precedence over `timeout` + start = time.monotonic() + while time.monotonic() - start < timeout: + if not self.output_queue.empty(): + return False + await asyncio.sleep(interval) + return self.output_queue.empty() diff --git a/myenv/lib/python3.9/site-packages/asgiref/timeout.py b/myenv/lib/python3.9/site-packages/asgiref/timeout.py new file mode 100644 index 0000000..65932d1 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/timeout.py @@ -0,0 +1,112 @@ +# This code is originally sourced from the aio-libs project "async_timeout", +# under the Apache 2.0 license. You may see the original project at +# https://github.com/aio-libs/async-timeout + +# It is vendored here to reduce chain-dependencies on this library, and +# modified slightly to remove some features we don't use. + + +import asyncio +from types import TracebackType +from typing import Any, Optional, Type + + +class timeout: + """timeout context manager. + + Useful in cases when you want to apply timeout logic around block + of code or in cases when asyncio.wait_for is not suitable. For example: + + >>> with timeout(0.001): + ... async with aiohttp.get('https://github.com') as r: + ... await r.text() + + + timeout - value in seconds or None to disable timeout logic + loop - asyncio compatible event loop + """ + + def __init__( + self, + timeout: Optional[float], + *, + loop: Optional[asyncio.AbstractEventLoop] = None, + ) -> None: + self._timeout = timeout + if loop is None: + loop = asyncio.get_event_loop() + self._loop = loop + self._task = None # type: Optional[asyncio.Task[Any]] + self._cancelled = False + self._cancel_handler = None # type: Optional[asyncio.Handle] + self._cancel_at = None # type: Optional[float] + + def __enter__(self) -> "timeout": + return self._do_enter() + + def __exit__( + self, + exc_type: Type[BaseException], + exc_val: BaseException, + exc_tb: TracebackType, + ) -> Optional[bool]: + self._do_exit(exc_type) + return None + + async def __aenter__(self) -> "timeout": + return self._do_enter() + + async def __aexit__( + self, + exc_type: Type[BaseException], + exc_val: BaseException, + exc_tb: TracebackType, + ) -> None: + self._do_exit(exc_type) + + @property + def expired(self) -> bool: + return self._cancelled + + @property + def remaining(self) -> Optional[float]: + if self._cancel_at is not None: + return max(self._cancel_at - self._loop.time(), 0.0) + else: + return None + + def _do_enter(self) -> "timeout": + # Support Tornado 5- without timeout + # Details: https://github.com/python/asyncio/issues/392 + if self._timeout is None: + return self + + self._task = asyncio.current_task(self._loop) + if self._task is None: + raise RuntimeError( + "Timeout context manager should be used " "inside a task" + ) + + if self._timeout <= 0: + self._loop.call_soon(self._cancel_task) + return self + + self._cancel_at = self._loop.time() + self._timeout + self._cancel_handler = self._loop.call_at(self._cancel_at, self._cancel_task) + return self + + def _do_exit(self, exc_type: Type[BaseException]) -> None: + if exc_type is asyncio.CancelledError and self._cancelled: + self._cancel_handler = None + self._task = None + raise asyncio.TimeoutError + if self._timeout is not None and self._cancel_handler is not None: + self._cancel_handler.cancel() + self._cancel_handler = None + self._task = None + return None + + def _cancel_task(self) -> None: + if self._task is not None: + self._task.cancel() + self._cancelled = True diff --git a/myenv/lib/python3.9/site-packages/asgiref/typing.py b/myenv/lib/python3.9/site-packages/asgiref/typing.py new file mode 100644 index 0000000..c7d7576 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/typing.py @@ -0,0 +1,242 @@ +import sys +from typing import Awaitable, Callable, Dict, Iterable, Optional, Tuple, Type, Union + +if sys.version_info >= (3, 8): + from typing import Literal, Protocol, TypedDict +else: + from typing_extensions import Literal, Protocol, TypedDict + +__all__ = ( + "ASGIVersions", + "HTTPScope", + "WebSocketScope", + "LifespanScope", + "WWWScope", + "Scope", + "HTTPRequestEvent", + "HTTPResponseStartEvent", + "HTTPResponseBodyEvent", + "HTTPServerPushEvent", + "HTTPDisconnectEvent", + "WebSocketConnectEvent", + "WebSocketAcceptEvent", + "WebSocketReceiveEvent", + "WebSocketSendEvent", + "WebSocketResponseStartEvent", + "WebSocketResponseBodyEvent", + "WebSocketDisconnectEvent", + "WebSocketCloseEvent", + "LifespanStartupEvent", + "LifespanShutdownEvent", + "LifespanStartupCompleteEvent", + "LifespanStartupFailedEvent", + "LifespanShutdownCompleteEvent", + "LifespanShutdownFailedEvent", + "ASGIReceiveEvent", + "ASGISendEvent", + "ASGIReceiveCallable", + "ASGISendCallable", + "ASGI2Protocol", + "ASGI2Application", + "ASGI3Application", + "ASGIApplication", +) + + +class ASGIVersions(TypedDict): + spec_version: str + version: Union[Literal["2.0"], Literal["3.0"]] + + +class HTTPScope(TypedDict): + type: Literal["http"] + asgi: ASGIVersions + http_version: str + method: str + scheme: str + path: str + raw_path: bytes + query_string: bytes + root_path: str + headers: Iterable[Tuple[bytes, bytes]] + client: Optional[Tuple[str, int]] + server: Optional[Tuple[str, Optional[int]]] + extensions: Optional[Dict[str, Dict[object, object]]] + + +class WebSocketScope(TypedDict): + type: Literal["websocket"] + asgi: ASGIVersions + http_version: str + scheme: str + path: str + raw_path: bytes + query_string: bytes + root_path: str + headers: Iterable[Tuple[bytes, bytes]] + client: Optional[Tuple[str, int]] + server: Optional[Tuple[str, Optional[int]]] + subprotocols: Iterable[str] + extensions: Optional[Dict[str, Dict[object, object]]] + + +class LifespanScope(TypedDict): + type: Literal["lifespan"] + asgi: ASGIVersions + + +WWWScope = Union[HTTPScope, WebSocketScope] +Scope = Union[HTTPScope, WebSocketScope, LifespanScope] + + +class HTTPRequestEvent(TypedDict): + type: Literal["http.request"] + body: bytes + more_body: bool + + +class HTTPResponseStartEvent(TypedDict): + type: Literal["http.response.start"] + status: int + headers: Iterable[Tuple[bytes, bytes]] + + +class HTTPResponseBodyEvent(TypedDict): + type: Literal["http.response.body"] + body: bytes + more_body: bool + + +class HTTPServerPushEvent(TypedDict): + type: Literal["http.response.push"] + path: str + headers: Iterable[Tuple[bytes, bytes]] + + +class HTTPDisconnectEvent(TypedDict): + type: Literal["http.disconnect"] + + +class WebSocketConnectEvent(TypedDict): + type: Literal["websocket.connect"] + + +class WebSocketAcceptEvent(TypedDict): + type: Literal["websocket.accept"] + subprotocol: Optional[str] + headers: Iterable[Tuple[bytes, bytes]] + + +class WebSocketReceiveEvent(TypedDict): + type: Literal["websocket.receive"] + bytes: Optional[bytes] + text: Optional[str] + + +class WebSocketSendEvent(TypedDict): + type: Literal["websocket.send"] + bytes: Optional[bytes] + text: Optional[str] + + +class WebSocketResponseStartEvent(TypedDict): + type: Literal["websocket.http.response.start"] + status: int + headers: Iterable[Tuple[bytes, bytes]] + + +class WebSocketResponseBodyEvent(TypedDict): + type: Literal["websocket.http.response.body"] + body: bytes + more_body: bool + + +class WebSocketDisconnectEvent(TypedDict): + type: Literal["websocket.disconnect"] + code: int + + +class WebSocketCloseEvent(TypedDict): + type: Literal["websocket.close"] + code: int + reason: Optional[str] + + +class LifespanStartupEvent(TypedDict): + type: Literal["lifespan.startup"] + + +class LifespanShutdownEvent(TypedDict): + type: Literal["lifespan.shutdown"] + + +class LifespanStartupCompleteEvent(TypedDict): + type: Literal["lifespan.startup.complete"] + + +class LifespanStartupFailedEvent(TypedDict): + type: Literal["lifespan.startup.failed"] + message: str + + +class LifespanShutdownCompleteEvent(TypedDict): + type: Literal["lifespan.shutdown.complete"] + + +class LifespanShutdownFailedEvent(TypedDict): + type: Literal["lifespan.shutdown.failed"] + message: str + + +ASGIReceiveEvent = Union[ + HTTPRequestEvent, + HTTPDisconnectEvent, + WebSocketConnectEvent, + WebSocketReceiveEvent, + WebSocketDisconnectEvent, + LifespanStartupEvent, + LifespanShutdownEvent, +] + + +ASGISendEvent = Union[ + HTTPResponseStartEvent, + HTTPResponseBodyEvent, + HTTPServerPushEvent, + HTTPDisconnectEvent, + WebSocketAcceptEvent, + WebSocketSendEvent, + WebSocketResponseStartEvent, + WebSocketResponseBodyEvent, + WebSocketCloseEvent, + LifespanStartupCompleteEvent, + LifespanStartupFailedEvent, + LifespanShutdownCompleteEvent, + LifespanShutdownFailedEvent, +] + + +ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]] +ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]] + + +class ASGI2Protocol(Protocol): + def __init__(self, scope: Scope) -> None: + ... + + async def __call__( + self, receive: ASGIReceiveCallable, send: ASGISendCallable + ) -> None: + ... + + +ASGI2Application = Type[ASGI2Protocol] +ASGI3Application = Callable[ + [ + Scope, + ASGIReceiveCallable, + ASGISendCallable, + ], + Awaitable[None], +] +ASGIApplication = Union[ASGI2Application, ASGI3Application] diff --git a/myenv/lib/python3.9/site-packages/asgiref/wsgi.py b/myenv/lib/python3.9/site-packages/asgiref/wsgi.py new file mode 100644 index 0000000..40fba20 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/asgiref/wsgi.py @@ -0,0 +1,162 @@ +from io import BytesIO +from tempfile import SpooledTemporaryFile + +from asgiref.sync import AsyncToSync, sync_to_async + + +class WsgiToAsgi: + """ + Wraps a WSGI application to make it into an ASGI application. + """ + + def __init__(self, wsgi_application): + self.wsgi_application = wsgi_application + + async def __call__(self, scope, receive, send): + """ + ASGI application instantiation point. + We return a new WsgiToAsgiInstance here with the WSGI app + and the scope, ready to respond when it is __call__ed. + """ + await WsgiToAsgiInstance(self.wsgi_application)(scope, receive, send) + + +class WsgiToAsgiInstance: + """ + Per-socket instance of a wrapped WSGI application + """ + + def __init__(self, wsgi_application): + self.wsgi_application = wsgi_application + self.response_started = False + self.response_content_length = None + + async def __call__(self, scope, receive, send): + if scope["type"] != "http": + raise ValueError("WSGI wrapper received a non-HTTP scope") + self.scope = scope + with SpooledTemporaryFile(max_size=65536) as body: + # Alright, wait for the http.request messages + while True: + message = await receive() + if message["type"] != "http.request": + raise ValueError("WSGI wrapper received a non-HTTP-request message") + body.write(message.get("body", b"")) + if not message.get("more_body"): + break + body.seek(0) + # Wrap send so it can be called from the subthread + self.sync_send = AsyncToSync(send) + # Call the WSGI app + await self.run_wsgi_app(body) + + def build_environ(self, scope, body): + """ + Builds a scope and request body into a WSGI environ object. + """ + environ = { + "REQUEST_METHOD": scope["method"], + "SCRIPT_NAME": scope.get("root_path", "").encode("utf8").decode("latin1"), + "PATH_INFO": scope["path"].encode("utf8").decode("latin1"), + "QUERY_STRING": scope["query_string"].decode("ascii"), + "SERVER_PROTOCOL": "HTTP/%s" % scope["http_version"], + "wsgi.version": (1, 0), + "wsgi.url_scheme": scope.get("scheme", "http"), + "wsgi.input": body, + "wsgi.errors": BytesIO(), + "wsgi.multithread": True, + "wsgi.multiprocess": True, + "wsgi.run_once": False, + } + # Get server name and port - required in WSGI, not in ASGI + if "server" in scope: + environ["SERVER_NAME"] = scope["server"][0] + environ["SERVER_PORT"] = str(scope["server"][1]) + else: + environ["SERVER_NAME"] = "localhost" + environ["SERVER_PORT"] = "80" + + if "client" in scope: + environ["REMOTE_ADDR"] = scope["client"][0] + + # Go through headers and make them into environ entries + for name, value in self.scope.get("headers", []): + name = name.decode("latin1") + if name == "content-length": + corrected_name = "CONTENT_LENGTH" + elif name == "content-type": + corrected_name = "CONTENT_TYPE" + else: + corrected_name = "HTTP_%s" % name.upper().replace("-", "_") + # HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in case + value = value.decode("latin1") + if corrected_name in environ: + value = environ[corrected_name] + "," + value + environ[corrected_name] = value + return environ + + def start_response(self, status, response_headers, exc_info=None): + """ + WSGI start_response callable. + """ + # Don't allow re-calling once response has begun + if self.response_started: + raise exc_info[1].with_traceback(exc_info[2]) + # Don't allow re-calling without exc_info + if hasattr(self, "response_start") and exc_info is None: + raise ValueError( + "You cannot call start_response a second time without exc_info" + ) + # Extract status code + status_code, _ = status.split(" ", 1) + status_code = int(status_code) + # Extract headers + headers = [ + (name.lower().encode("ascii"), value.encode("ascii")) + for name, value in response_headers + ] + # Extract content-length + self.response_content_length = None + for name, value in response_headers: + if name.lower() == "content-length": + self.response_content_length = int(value) + # Build and send response start message. + self.response_start = { + "type": "http.response.start", + "status": status_code, + "headers": headers, + } + + @sync_to_async + def run_wsgi_app(self, body): + """ + Called in a subthread to run the WSGI app. We encapsulate like + this so that the start_response callable is called in the same thread. + """ + # Translate the scope and incoming request body into a WSGI environ + environ = self.build_environ(self.scope, body) + # Run the WSGI app + bytes_sent = 0 + for output in self.wsgi_application(environ, self.start_response): + # If this is the first response, include the response headers + if not self.response_started: + self.response_started = True + self.sync_send(self.response_start) + # If the application supplies a Content-Length header + if self.response_content_length is not None: + # The server should not transmit more bytes to the client than the header allows + bytes_allowed = self.response_content_length - bytes_sent + if len(output) > bytes_allowed: + output = output[:bytes_allowed] + self.sync_send( + {"type": "http.response.body", "body": output, "more_body": True} + ) + bytes_sent += len(output) + # The server should stop iterating over the response when enough data has been sent + if bytes_sent == self.response_content_length: + break + # Close connection + if not self.response_started: + self.response_started = True + self.sync_send(self.response_start) + self.sync_send({"type": "http.response.body"}) diff --git a/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/CONTRIBUTORS.txt b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/CONTRIBUTORS.txt new file mode 100644 index 0000000..0fb15ad --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/CONTRIBUTORS.txt @@ -0,0 +1,175 @@ +# This file is autocompleted by 'contributors-txt', +# using the configuration in 'script/.contributors_aliases.json'. +# Do not add new persons manually and only add information without +# using '-' as the line first character. +# Please verify that your change are stable if you modify manually. + +Ex-maintainers +-------------- +- Claudiu Popa +- Sylvain Thénault +- Torsten Marek + + +Maintainers +----------- +- Pierre Sassoulas +- Hippo91 +- Marc Mueller <30130371+cdce8p@users.noreply.github.com> +- Daniël van Noord <13665637+DanielNoord@users.noreply.github.com> +- Bryce Guinta +- Ceridwen +- Łukasz Rogalski +- Florian Bruhin +- Ashley Whetter +- Jacob Walls +- Dimitri Prybysh +- Areveny + + +Contributors +------------ +- LOGILAB S.A. (Paris, FRANCE) +- Nick Drozd +- Andrew Haigh +- David Liu +- Eevee (Alex Munroe) +- David Gilman +- Julien Jehannet +- Calen Pennington +- Phil Schaf +- Hugo van Kemenade +- Alex Hall +- Tushar Sadhwani <86737547+tushar-deepsource@users.noreply.github.com> +- Tim Martin +- Raphael Gaschignard +- Radosław Ganczarek +- Paligot Gérard +- Ioana Tagirta +- Derek Gustafson +- David Shea +- Daniel Harding +- Ville Skyttä +- Rene Zhang +- Philip Lorenz +- Mario Corchero +- Marien Zwart +- FELD Boris +- Enji Cooper +- doranid +- brendanator +- Tomas Gavenciak +- Thomas Hisch +- Stefan Scherfke +- Sergei Lebedev <185856+superbobry@users.noreply.github.com> +- Ram Rachum +- Peter Pentchev +- Peter Kolbus +- Omer Katz +- Moises Lopez +- Keichi Takahashi +- Kavins Singh +- Karthikeyan Singaravelan +- Joshua Cannon +- John Vandenberg +- Jacob Bogdanov +- Google, Inc. +- David Euresti +- David Cain +- Anthony Sottile +- Alexander Shadchin +- wgehalo +- tristanlatr <19967168+tristanlatr@users.noreply.github.com> +- rr- +- raylu +- mathieui +- markmcclain +- ioanatia +- grayjk +- Zbigniew Jędrzejewski-Szmek +- Zac Hatfield-Dodds +- Vilnis Termanis +- Valentin Valls +- Uilian Ries +- Tomas Novak +- Thirumal Venkat +- SupImDos <62866982+SupImDos@users.noreply.github.com> +- Stanislav Levin +- Simon Hewitt +- Serhiy Storchaka +- Roy Wright +- Robin Jarry +- René Fritze <47802+renefritze@users.noreply.github.com> +- Redoubts +- Philipp Hörist +- Peter de Blanc +- Peter Talley +- Ovidiu Sabou +- Nicolas Noirbent +- Neil Girdhar +- Michał Masłowski +- Michael K +- Mateusz Bysiek +- Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> +- Leandro T. C. Melo +- Konrad Weihmann +- Kian Meng, Ang +- Kai Mueller <15907922+kasium@users.noreply.github.com> +- Jörg Thalheim +- Jonathan Striebel +- John Belmonte +- Jeff Widman +- Jeff Quast +- Jarrad Hope +- Jared Garst +- Jakub Wilk +- Iva Miholic +- Ionel Maries Cristian +- HoverHell +- HQupgradeHQ <18361586+HQupgradeHQ@users.noreply.github.com> +- Grygorii Iermolenko +- Gregory P. Smith +- Giuseppe Scrivano +- Frédéric Chapoton +- Francis Charette Migneault +- Felix Mölder +- Federico Bond +- DudeNr33 <3929834+DudeNr33@users.noreply.github.com> +- Dmitry Shachnev +- Denis Laxalde +- David Poirier +- Dave Hirschfeld +- Dave Baum +- Daniel Martin +- Daniel Colascione +- Damien Baty +- Craig Franklin +- Colin Kennedy +- Cole Robinson +- Christoph Reiter +- Chris Philip +- BioGeek +- Bianca Power <30207144+biancapower@users.noreply.github.com> +- Benjamin Elven <25181435+S3ntinelX@users.noreply.github.com> +- Becker Awqatty +- BasPH +- Azeem Bande-Ali +- Aru Sahni +- Artsiom Kaval +- Anubhav <35621759+anubh-v@users.noreply.github.com> +- Antoine Boellinger +- Alphadelta14 +- Alexander Presnyakov +- Ahmed Azzaoui + +Co-Author +--------- +The following persons were credited manually but did not commit themselves +under this name, or we did not manage to find their commits in the history. + +- François Mockers +- platings +- carl +- alain lefroy +- Mark Gius +- jarradhope diff --git a/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/LICENSE new file mode 100644 index 0000000..182e0fb --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/LICENSE @@ -0,0 +1,508 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/METADATA b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/METADATA new file mode 100644 index 0000000..4096b32 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/METADATA @@ -0,0 +1,129 @@ +Metadata-Version: 2.1 +Name: astroid +Version: 2.11.7 +Summary: An abstract syntax tree for Python with inference support. +Home-page: https://github.com/PyCQA/astroid +Author: Python Code Quality Authority +Author-email: code-quality@python.org +License: LGPL-2.1-or-later +Project-URL: Bug tracker, https://github.com/PyCQA/astroid/issues +Project-URL: Discord server, https://discord.gg/Egy6P8AMB5 +Keywords: static code analysis,python,abstract syntax tree +Classifier: Development Status :: 6 - Mature +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 (LGPLv2) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Topic :: Software Development :: Testing +Requires-Python: >=3.6.2 +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: CONTRIBUTORS.txt +Requires-Dist: lazy-object-proxy (>=1.4.0) +Requires-Dist: wrapt (<2,>=1.11) +Requires-Dist: setuptools (>=20.0) +Requires-Dist: typed-ast (<2.0,>=1.4.0) ; implementation_name == "cpython" and python_version < "3.8" +Requires-Dist: typing-extensions (>=3.10) ; python_version < "3.10" + +Astroid +======= + +.. image:: https://coveralls.io/repos/github/PyCQA/astroid/badge.svg?branch=main + :target: https://coveralls.io/github/PyCQA/astroid?branch=main + :alt: Coverage badge from coveralls.io + +.. image:: https://readthedocs.org/projects/astroid/badge/?version=latest + :target: http://astroid.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + +.. image:: https://results.pre-commit.ci/badge/github/PyCQA/astroid/main.svg + :target: https://results.pre-commit.ci/latest/github/PyCQA/astroid/main + :alt: pre-commit.ci status + +.. |tidelift_logo| image:: https://raw.githubusercontent.com/PyCQA/astroid/main/doc/media/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White.png + :width: 75 + :height: 60 + :alt: Tidelift + +.. list-table:: + :widths: 10 100 + + * - |tidelift_logo| + - Professional support for astroid is available as part of the + `Tidelift Subscription`_. 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. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-astroid?utm_source=pypi-astroid&utm_medium=referral&utm_campaign=readme + + + +What's this? +------------ + +The aim of this module is to provide a common base representation of +python source code. It is currently the library powering pylint's capabilities. + +It provides a compatible representation which comes from the `_ast` +module. It rebuilds the tree generated by the builtin _ast module by +recursively walking down the AST and building an extended ast. The new +node classes have additional methods and attributes for different +usages. They include some support for static inference and local name +scopes. Furthermore, astroid can also build partial trees by inspecting living +objects. + + +Installation +------------ + +Extract the tarball, jump into the created directory and run:: + + pip install . + + +If you want to do an editable installation, you can run:: + + pip install -e . + + +If you have any questions, please mail the code-quality@python.org +mailing list for support. See +http://mail.python.org/mailman/listinfo/code-quality for subscription +information and archives. + +Documentation +------------- +http://astroid.readthedocs.io/en/latest/ + + +Python Versions +--------------- + +astroid 2.0 is currently available for Python 3 only. If you want Python 2 +support, use an older version of astroid (though note that these versions +are no longer supported). + +Test +---- + +Tests are in the 'test' subdirectory. To launch the whole tests suite, you can use +either `tox` or `pytest`:: + + tox + pytest astroid diff --git a/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/RECORD b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/RECORD new file mode 100644 index 0000000..8ded6ee --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/RECORD @@ -0,0 +1,101 @@ +astroid/__init__.py,sha256=PZRnmbvNyyztzoep3TNq10RnlnWgtWC3d-ntvmXettQ,5202 +astroid/__pkginfo__.py,sha256=B7AH_irTjoDqJDLb8H2GFcWt80is9hliU-R1XmszI3A,274 +astroid/_ast.py,sha256=GHCb1UhQYAdYq4FIWj4grPMEkCkGzgPtq9I-3546C1g,3713 +astroid/arguments.py,sha256=ioNM-KU0UQQw0Ji3cplijDRKMo3wKRYofr8JG071IlM,12772 +astroid/astroid_manager.py,sha256=0kHpLsw88YEdjEf11pHZV0Ru7u1sM3TkjKE64VJ6MAU,568 +astroid/bases.py,sha256=bL5597ATkiEYWvNlSLCATArt7Egd8234_ffq7YLNimc,20003 +astroid/builder.py,sha256=tRGbSQbB8B6hLNg347ylD5__1Awqf2DHgMj1tSt-y5Y,17317 +astroid/const.py,sha256=fLUo3VgP8jFaL9gw1HqHpsp1YdMfSksQXuJzvRqyghQ,868 +astroid/context.py,sha256=YPPvoNA8pHirJEyX3DHbKLDMALsNKPnNAuDlcnf4gSc,5688 +astroid/decorators.py,sha256=1opjj_aJdpKZfsVqT3_Ix6uCtVci4Lv9jvMHfP3xcfM,9503 +astroid/exceptions.py,sha256=9M4aj1kwg4kGzK4Q51eLOaYMQESsql1I4928s1oUC-c,8538 +astroid/filter_statements.py,sha256=1_xfnZHCrNyCKtwDwiVXhHXM977jXmRJ5VeXk44q7R0,9644 +astroid/helpers.py,sha256=hcAXP11C3a7J0jwOYudwCHTgajq7RcRAPTHmKpcqzSw,10276 +astroid/inference.py,sha256=jaiatB037N2KlCjcY62psVdY_LuLz1OlM9esZs9yawA,36351 +astroid/inference_tip.py,sha256=6fChETD0XKh7khW6DDXEgnnsShlHIAhRjYIWbxl8juY,2969 +astroid/manager.py,sha256=ekgbq49QWWPk4p-2lladUnHhjwv-xcnamx0hspHzWME,13558 +astroid/mixins.py,sha256=uLpgScOzCa1pIHk3D3aDQqT2gFEWvJA63ZJemClmI7s,5510 +astroid/modutils.py,sha256=psXAsy-YDA2k_8imNaN_wylQuc8mglgdgIYMEyhpu08,20773 +astroid/node_classes.py,sha256=OnYVG9E21mFM7R-xXO_Bn8Bn1UFYwM4GSwLDg8JwwLM,1802 +astroid/objects.py,sha256=G-MjRjqi8w-fmC1WmHvpC8tiBdhG7FpPrSV2fBaSFgc,11769 +astroid/protocols.py,sha256=ezS37nv-11NHq4Kn1nvRoWIu-GJbbwctvrxL0AJp6fE,30095 +astroid/raw_building.py,sha256=0PXzpGytJaQPqNA3T0V3K-FrOniCRHkGuxFImFf4TLc,18027 +astroid/rebuilder.py,sha256=MPgqHUf8p-B5aWr0P8L407_zBdXPJg0F8j2s3Q55mj4,79052 +astroid/scoped_nodes.py,sha256=rELeS8rKUxNcJZxHlKERD3im6HGKae4wbcx51VCiZmI,933 +astroid/test_utils.py,sha256=tRsndWUiEwr29S7Bf6Ej5x-Ooph2byfCTEf-pheLhjM,2397 +astroid/transforms.py,sha256=Gnm2oXDE7SrSNsh6Ks6e3ycqSWWNlNljhXTxkZvW4wg,3264 +astroid/typing.py,sha256=hEiny9JQuETF5eAyXrYE7wG8c_DO_4mc39027WRXrqM,737 +astroid/util.py,sha256=F5bbf33-dgaEaeSbkdNYnRBJSGJ39eWJFrZOT7q2EPk,4256 +astroid/brain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +astroid/brain/brain_argparse.py,sha256=WdKRrkd4--tdZtJzNI1nJAmA_-gdkz8KNguPUTe6jis,1441 +astroid/brain/brain_attrs.py,sha256=dwMHH4ou5jNq33hlXVW3e9QYB-BC_os41RgG2QNyMR4,2853 +astroid/brain/brain_boto3.py,sha256=-Ntjxs3fneXCwYWBMxjeKS6gKRYf609nNAdf_Fv5LQs,997 +astroid/brain/brain_builtin_inference.py,sha256=DLYc0S72TN7nEft1tunET5psSk_W5kThtop2QGnYWro,30630 +astroid/brain/brain_collections.py,sha256=3xGVDVZIG5RTydq-lda7GWViXqN506L1wDb6eKvIUIE,4307 +astroid/brain/brain_crypt.py,sha256=q-4C5kA8qEwk822Fi4KkbyVz5zq8UG2DUAKGFyXkpVI,1044 +astroid/brain/brain_ctypes.py,sha256=Zl6XWUMx852uwIGi8EeLywmhDOqzpRnWaPjD5hVshjA,2655 +astroid/brain/brain_curses.py,sha256=XXyCeLASFFksO2zSbrZgB_AImGBlIGZ7Pgjdm04x-jg,3477 +astroid/brain/brain_dataclasses.py,sha256=8PI0XKyeJO0sE9RMQUAHxSKgM_Ss4cm1A29AH8b_NaE,14992 +astroid/brain/brain_dateutil.py,sha256=ajM8Xkn6WrrPGQBleEM_XIb0SnAozIfaHpDbG8e5vyo,766 +astroid/brain/brain_fstrings.py,sha256=fxeEYe37aEHg5zTuAR3J1QP5fUNJLY-0ATB7jAxVof4,2175 +astroid/brain/brain_functools.py,sha256=I6SDzNjBGFqB33nAA9icvnL0hCa4CJhcI46CWESBQKw,5842 +astroid/brain/brain_gi.py,sha256=q_gfHJKL9IHGk0TnC7kvDISSVNMkCl-mn7ed1t-U1H8,7540 +astroid/brain/brain_hashlib.py,sha256=0wd-TK0BsMiAwVhrfZAm6_ACxRJYxix0WHw4ItZgnfo,2189 +astroid/brain/brain_http.py,sha256=OgqOSkOqctysaPycz9SOmF3NxpJ4OPg5nZ-PqYwUgow,10602 +astroid/brain/brain_hypothesis.py,sha256=ZypkmriFkll04Hkx_4wZH6xe1myMqjtmcOcr70kldvw,1725 +astroid/brain/brain_io.py,sha256=Rh84qonOdMIS_Z3zEFGvmyObPs4vjO3WzYV5V7LYTEM,1517 +astroid/brain/brain_mechanize.py,sha256=EyBHLek513PHyCE7NDW-dlkJ8gdJbjxwLMtKMbE0YGA,2530 +astroid/brain/brain_multiprocessing.py,sha256=5LlHw5efq01VUV-vUWpH8u7vHhk3SPp1tf4N-BZSmzU,3181 +astroid/brain/brain_namedtuple_enum.py,sha256=hzj09nO4N61wy-5TrYtzeL08aGZRSzdYwVOOnigNGYM,20516 +astroid/brain/brain_nose.py,sha256=DCUwKzR14Se5tF-s54AMwFoRvhsHH_nf6agrh966VpQ,2320 +astroid/brain/brain_numpy_core_fromnumeric.py,sha256=3UFRtK5U51AVQNxawf9ElhFv2tizhj5RfyCSnPT3u54,732 +astroid/brain/brain_numpy_core_function_base.py,sha256=_k-WRQ_x0QEHhvr9IwuTLnpGoCYOVO0GAH7e3DyoHNQ,1298 +astroid/brain/brain_numpy_core_multiarray.py,sha256=YPY78fKkr0pFimDu9hW1o9kytivAeylNsgbVvXs7xV8,4210 +astroid/brain/brain_numpy_core_numeric.py,sha256=VAc51Ud8QDujsh29e-RQK5SBcKW_jzjZIFmntCslCKU,1629 +astroid/brain/brain_numpy_core_numerictypes.py,sha256=HVJ_paQwjh2V8qz0Juei6b2ZRm_dmDJodiDKfAcE-mE,8546 +astroid/brain/brain_numpy_core_umath.py,sha256=2EhXmtiw8wQcdUtbnlLLTjHAOHpQ1c9BXHdc6kHJGbA,4893 +astroid/brain/brain_numpy_ma.py,sha256=Wb4CZAo6WzprymYTxWrF_IlhbKPzcJ_cmw5npSeq1mo,805 +astroid/brain/brain_numpy_ndarray.py,sha256=dAH8wFR7sjQF3pcUINlp6WkBQy4tSBTU_m6Emb0E9mE,8882 +astroid/brain/brain_numpy_random_mtrand.py,sha256=Wrpm9SX8kH0Xsk9b3qpR0rhs-MEb0I5aN4E-66wkLkM,3436 +astroid/brain/brain_numpy_utils.py,sha256=BOH-BYMYUrTLAsBf8VFumKDwcH_82AsCjtOqZbnqMWU,2543 +astroid/brain/brain_pkg_resources.py,sha256=W3Q4G6mYTYtJY9iWQv3vEO8_lpmLFAin9aQLtBRLxAc,2200 +astroid/brain/brain_pytest.py,sha256=suTDBHCJ_p4F7TGXjwVJAFtiAP-VlkFE2gncXjLRQKM,2223 +astroid/brain/brain_qt.py,sha256=dE30a8e7aeQlMss5Nn1OobZpdhn-nzn3ylOllbSlMxI,2505 +astroid/brain/brain_random.py,sha256=CqjCq2IIVspVcMGk43cn_RB7y5iHLaMjCP4mCWf-3tE,2692 +astroid/brain/brain_re.py,sha256=NzMzyUvRTMI3LqMFqMFEWAdzIxGcKSVjZnP55s5cDXk,2669 +astroid/brain/brain_responses.py,sha256=qI7BWS_fWS5c_PcMnLgqABJRlwn8j9IRlq-XOdKnAWs,1869 +astroid/brain/brain_scipy_signal.py,sha256=Mi93D6-j94tqhqDHCbabVs3_eDAhti88CL1_rOvnG_I,2276 +astroid/brain/brain_signal.py,sha256=MJCkmWmUTVEqVKwQfE8FzVh-x0XLzJpBdVjjeJynQbg,3859 +astroid/brain/brain_six.py,sha256=JNtmuokvVod0-mwSb4yU0Zhm_Qts4daSp__yvU3RnFM,7569 +astroid/brain/brain_sqlalchemy.py,sha256=onKAxgKY-GYLe2v6PVK3APBn_z8txokEZfDcXt33GuE,1009 +astroid/brain/brain_ssl.py,sha256=gUTdzoUVlA8ehtwCjyJ3o6omG1PqoBPs2cXDDDmGI3M,3578 +astroid/brain/brain_subprocess.py,sha256=mBC5ulUUt5JcPiZu1ZAeGDn_Y3vAgqMOrsz9HGwVAWo,3768 +astroid/brain/brain_threading.py,sha256=N7F9UUe9lsDYtySrC1pKn_etxYmJ13tWzfom5q7l54s,855 +astroid/brain/brain_type.py,sha256=4mQWbJBqwviXx2Rdul_3Gu4FVTXxMGD4vHxKHm43CjQ,2472 +astroid/brain/brain_typing.py,sha256=87RT9F5EJYxyj2-__L6IgxEUBsGszrKBWNsi3Mhaxyo,14380 +astroid/brain/brain_unittest.py,sha256=O8acdDUPDb21ytB8EJ-3UCU6cIZ1pegs-EiPvKzEutw,1136 +astroid/brain/brain_uuid.py,sha256=fztFKPbRbrZzbvrzp5LCvYU4cE_WLmfVo0ws_Uc9FSw,649 +astroid/brain/helpers.py,sha256=OQLzWcxOg1K8eOxXHKOKUxF1HkpNyZQCjWyEvqnSHdk,718 +astroid/interpreter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +astroid/interpreter/dunder_lookup.py,sha256=cDcopHXRrJRxPZ19698HwO5p5gIIdc4posLG3VHF6Bo,2139 +astroid/interpreter/objectmodel.py,sha256=TP7RewfIrYGyFrIHuJC_ig9KgS6teMa5di5gDsIZjqc,27766 +astroid/interpreter/_import/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +astroid/interpreter/_import/spec.py,sha256=WGAlH5e5xNaRgx22usKO13z3eD5wRD2kDMwgGWOBfvo,13329 +astroid/interpreter/_import/util.py,sha256=Rl7gWekrSdm3Nk3F2oVFmutA4HlSepHA5PAqEg44eOw,529 +astroid/nodes/__init__.py,sha256=8fyupLEs0pKqbWu_3iMQcOlC7QQYHmiLv7P52eT2fqE,4836 +astroid/nodes/as_string.py,sha256=_JYz5qTcbGqZUZ40sc_rllJzp7S4n_6kqN9XZYuspC8,23797 +astroid/nodes/const.py,sha256=iyQn_v-wEzK6uXc-dEMoliPVSRy0NZ8T3XmvvPXLuP4,797 +astroid/nodes/node_classes.py,sha256=N2gWXwBO8m8KWYINaoBsGKEr5mnbzoMUOvGdxMouePo,164847 +astroid/nodes/node_ng.py,sha256=CcKOGv6eu_hHMbM71ZU1Hm1yeIEiIMeTEqDZOtQL-YI,28103 +astroid/nodes/utils.py,sha256=Uy6xoownLyWwDtuZ5qUpjbq19P2pUIcj0J04khbH5HY,423 +astroid/nodes/scoped_nodes/__init__.py,sha256=S8pX4zg73KzuCIawKmdgj-BuvXAh29atqUm23z0zI6U,1218 +astroid/nodes/scoped_nodes/mixin.py,sha256=9_dyepx-vfwvhyxLd5S6nSnbdRvTPfYhWdwztdhHYfM,5819 +astroid/nodes/scoped_nodes/scoped_nodes.py,sha256=Oh9dJoTuweiSrp4umO048gedlLs1axaFc8kdlpNu_2Y,105931 +astroid/nodes/scoped_nodes/utils.py,sha256=k7XSCSLC-S5L-puGQM4mv0e4N5-qMfo7UhDO3dswhcQ,1112 +astroid-2.11.7.dist-info/CONTRIBUTORS.txt,sha256=2I_w7LagIB19_12quxx9uYsoY0OoPPtZ9fYzVxSK_io,6858 +astroid-2.11.7.dist-info/LICENSE,sha256=_qFr2p5zTeoNnI2fW5CYeO9BcWJjVDKWCf_889tCyyQ,26516 +astroid-2.11.7.dist-info/METADATA,sha256=MBjTQH1_yiEYoFgYWhTQb9_3Vu75UMQqnrPirG_rO-Q,4681 +astroid-2.11.7.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +astroid-2.11.7.dist-info/top_level.txt,sha256=HsdW4O2x7ZXRj6k-agi3RaQybGLobI3VSE-jt4vQUXM,8 +astroid-2.11.7.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +astroid-2.11.7.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/top_level.txt new file mode 100644 index 0000000..450d4fe --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid-2.11.7.dist-info/top_level.txt @@ -0,0 +1 @@ +astroid diff --git a/myenv/lib/python3.9/site-packages/astroid/__init__.py b/myenv/lib/python3.9/site-packages/astroid/__init__.py new file mode 100644 index 0000000..14a61c2 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/__init__.py @@ -0,0 +1,200 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Python Abstract Syntax Tree New Generation + +The aim of this module is to provide a common base representation of +python source code for projects such as pychecker, pyreverse, +pylint... Well, actually the development of this library is essentially +governed by pylint's needs. + +It mimics the class defined in the python's _ast module with some +additional methods and attributes. New nodes instances are not fully +compatible with python's _ast. + +Instance attributes are added by a +builder object, which can either generate extended ast (let's call +them astroid ;) by visiting an existent ast tree or by inspecting living +object. Methods are added by monkey patching ast classes. + +Main modules are: + +* nodes and scoped_nodes for more information about methods and + attributes added to different node classes + +* the manager contains a high level object to get astroid trees from + source files and living objects. It maintains a cache of previously + constructed tree for quick access + +* builder contains the class responsible to build astroid trees +""" + +import functools +import tokenize +from importlib import import_module +from pathlib import Path + +# isort: off +# We have an isort: off on '__version__' because the packaging need to access +# the version before the dependencies are installed (in particular 'wrapt' +# that is imported in astroid.inference) +from astroid.__pkginfo__ import __version__, version +from astroid.nodes import node_classes, scoped_nodes + +# isort: on + +from astroid import inference, raw_building +from astroid.astroid_manager import MANAGER +from astroid.bases import BaseInstance, BoundMethod, Instance, UnboundMethod +from astroid.brain.helpers import register_module_extender +from astroid.builder import extract_node, parse +from astroid.const import PY310_PLUS, Context, Del, Load, Store +from astroid.exceptions import ( + AstroidBuildingError, + AstroidBuildingException, + AstroidError, + AstroidImportError, + AstroidIndexError, + AstroidSyntaxError, + AstroidTypeError, + AstroidValueError, + AttributeInferenceError, + BinaryOperationError, + DuplicateBasesError, + InconsistentMroError, + InferenceError, + InferenceOverwriteError, + MroError, + NameInferenceError, + NoDefault, + NotFoundError, + OperationError, + ParentMissingError, + ResolveError, + StatementMissing, + SuperArgumentTypeError, + SuperError, + TooManyLevelsError, + UnaryOperationError, + UnresolvableName, + UseInferenceDefault, +) +from astroid.inference_tip import _inference_tip_cached, inference_tip +from astroid.objects import ExceptionInstance + +# isort: off +# It's impossible to import from astroid.nodes with a wildcard, because +# there is a cyclic import that prevent creating an __all__ in astroid/nodes +# and we need astroid/scoped_nodes and astroid/node_classes to work. So +# importing with a wildcard would clash with astroid/nodes/scoped_nodes +# and astroid/nodes/node_classes. +from astroid.nodes import ( # pylint: disable=redefined-builtin (Ellipsis) + CONST_CLS, + AnnAssign, + Arguments, + Assert, + Assign, + AssignAttr, + AssignName, + AsyncFor, + AsyncFunctionDef, + AsyncWith, + Attribute, + AugAssign, + Await, + BinOp, + BoolOp, + Break, + Call, + ClassDef, + Compare, + Comprehension, + ComprehensionScope, + Const, + Continue, + Decorators, + DelAttr, + Delete, + DelName, + Dict, + DictComp, + DictUnpack, + Ellipsis, + EmptyNode, + EvaluatedObject, + ExceptHandler, + Expr, + ExtSlice, + For, + FormattedValue, + FunctionDef, + GeneratorExp, + Global, + If, + IfExp, + Import, + ImportFrom, + Index, + JoinedStr, + Keyword, + Lambda, + List, + ListComp, + Match, + MatchAs, + MatchCase, + MatchClass, + MatchMapping, + MatchOr, + MatchSequence, + MatchSingleton, + MatchStar, + MatchValue, + Module, + Name, + NamedExpr, + NodeNG, + Nonlocal, + Pass, + Raise, + Return, + Set, + SetComp, + Slice, + Starred, + Subscript, + TryExcept, + TryFinally, + Tuple, + UnaryOp, + Unknown, + While, + With, + Yield, + YieldFrom, + are_exclusive, + builtin_lookup, + unpack_infer, + function_to_method, +) + +# isort: on + +from astroid.util import Uninferable + +# Performance hack for tokenize. See https://bugs.python.org/issue43014 +# Adapted from https://github.com/PyCQA/pycodestyle/pull/993 +if ( + not PY310_PLUS + and callable(getattr(tokenize, "_compile", None)) + and getattr(tokenize._compile, "__wrapped__", None) is None # type: ignore[attr-defined] +): + tokenize._compile = functools.lru_cache()(tokenize._compile) # type: ignore[attr-defined] + +# load brain plugins +ASTROID_INSTALL_DIRECTORY = Path(__file__).parent +BRAIN_MODULES_DIRECTORY = ASTROID_INSTALL_DIRECTORY / "brain" +for module in BRAIN_MODULES_DIRECTORY.iterdir(): + if module.suffix == ".py": + import_module(f"astroid.brain.{module.stem}") diff --git a/myenv/lib/python3.9/site-packages/astroid/__pkginfo__.py b/myenv/lib/python3.9/site-packages/astroid/__pkginfo__.py new file mode 100644 index 0000000..459314b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/__pkginfo__.py @@ -0,0 +1,6 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +__version__ = "2.11.7" +version = __version__ diff --git a/myenv/lib/python3.9/site-packages/astroid/_ast.py b/myenv/lib/python3.9/site-packages/astroid/_ast.py new file mode 100644 index 0000000..1c4da43 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/_ast.py @@ -0,0 +1,130 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import ast +import sys +import types +from collections import namedtuple +from functools import partial +from typing import Dict, Optional + +from astroid.const import PY38_PLUS, Context + +if sys.version_info >= (3, 8): + # On Python 3.8, typed_ast was merged back into `ast` + _ast_py3: Optional[types.ModuleType] = ast +else: + try: + import typed_ast.ast3 as _ast_py3 + except ImportError: + _ast_py3 = None + +FunctionType = namedtuple("FunctionType", ["argtypes", "returns"]) + + +class ParserModule( + namedtuple( + "ParserModule", + [ + "module", + "unary_op_classes", + "cmp_op_classes", + "bool_op_classes", + "bin_op_classes", + "context_classes", + ], + ) +): + def parse(self, string: str, type_comments=True): + if self.module is _ast_py3: + if PY38_PLUS: + parse_func = partial(self.module.parse, type_comments=type_comments) + else: + parse_func = partial( + self.module.parse, feature_version=sys.version_info.minor + ) + else: + parse_func = self.module.parse + return parse_func(string) + + +def parse_function_type_comment(type_comment: str) -> Optional[FunctionType]: + """Given a correct type comment, obtain a FunctionType object""" + if _ast_py3 is None: + return None + + func_type = _ast_py3.parse(type_comment, "", "func_type") # type: ignore[attr-defined] + return FunctionType(argtypes=func_type.argtypes, returns=func_type.returns) + + +def get_parser_module(type_comments=True) -> ParserModule: + parser_module = ast + if type_comments and _ast_py3: + parser_module = _ast_py3 + + unary_op_classes = _unary_operators_from_module(parser_module) + cmp_op_classes = _compare_operators_from_module(parser_module) + bool_op_classes = _bool_operators_from_module(parser_module) + bin_op_classes = _binary_operators_from_module(parser_module) + context_classes = _contexts_from_module(parser_module) + + return ParserModule( + parser_module, + unary_op_classes, + cmp_op_classes, + bool_op_classes, + bin_op_classes, + context_classes, + ) + + +def _unary_operators_from_module(module): + return {module.UAdd: "+", module.USub: "-", module.Not: "not", module.Invert: "~"} + + +def _binary_operators_from_module(module): + binary_operators = { + module.Add: "+", + module.BitAnd: "&", + module.BitOr: "|", + module.BitXor: "^", + module.Div: "/", + module.FloorDiv: "//", + module.MatMult: "@", + module.Mod: "%", + module.Mult: "*", + module.Pow: "**", + module.Sub: "-", + module.LShift: "<<", + module.RShift: ">>", + } + return binary_operators + + +def _bool_operators_from_module(module): + return {module.And: "and", module.Or: "or"} + + +def _compare_operators_from_module(module): + return { + module.Eq: "==", + module.Gt: ">", + module.GtE: ">=", + module.In: "in", + module.Is: "is", + module.IsNot: "is not", + module.Lt: "<", + module.LtE: "<=", + module.NotEq: "!=", + module.NotIn: "not in", + } + + +def _contexts_from_module(module) -> Dict[ast.expr_context, Context]: + return { + module.Load: Context.Load, + module.Store: Context.Store, + module.Del: Context.Del, + module.Param: Context.Store, + } diff --git a/myenv/lib/python3.9/site-packages/astroid/arguments.py b/myenv/lib/python3.9/site-packages/astroid/arguments.py new file mode 100644 index 0000000..40061d0 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/arguments.py @@ -0,0 +1,306 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from typing import Optional, Set + +from astroid import nodes +from astroid.bases import Instance +from astroid.context import CallContext, InferenceContext +from astroid.exceptions import InferenceError, NoDefault +from astroid.util import Uninferable + + +class CallSite: + """Class for understanding arguments passed into a call site + + It needs a call context, which contains the arguments and the + keyword arguments that were passed into a given call site. + In order to infer what an argument represents, call :meth:`infer_argument` + with the corresponding function node and the argument name. + + :param callcontext: + An instance of :class:`astroid.context.CallContext`, that holds + the arguments for the call site. + :param argument_context_map: + Additional contexts per node, passed in from :attr:`astroid.context.Context.extra_context` + :param context: + An instance of :class:`astroid.context.Context`. + """ + + def __init__( + self, callcontext: CallContext, argument_context_map=None, context=None + ): + if argument_context_map is None: + argument_context_map = {} + self.argument_context_map = argument_context_map + args = callcontext.args + keywords = callcontext.keywords + self.duplicated_keywords: Set[str] = set() + self._unpacked_args = self._unpack_args(args, context=context) + self._unpacked_kwargs = self._unpack_keywords(keywords, context=context) + + self.positional_arguments = [ + arg for arg in self._unpacked_args if arg is not Uninferable + ] + self.keyword_arguments = { + key: value + for key, value in self._unpacked_kwargs.items() + if value is not Uninferable + } + + @classmethod + def from_call(cls, call_node, context: Optional[InferenceContext] = None): + """Get a CallSite object from the given Call node. + + context will be used to force a single inference path. + """ + + # Determine the callcontext from the given `context` object if any. + context = context or InferenceContext() + callcontext = CallContext(call_node.args, call_node.keywords) + return cls(callcontext, context=context) + + def has_invalid_arguments(self): + """Check if in the current CallSite were passed *invalid* arguments + + This can mean multiple things. For instance, if an unpacking + of an invalid object was passed, then this method will return True. + Other cases can be when the arguments can't be inferred by astroid, + for example, by passing objects which aren't known statically. + """ + return len(self.positional_arguments) != len(self._unpacked_args) + + def has_invalid_keywords(self): + """Check if in the current CallSite were passed *invalid* keyword arguments + + For instance, unpacking a dictionary with integer keys is invalid + (**{1:2}), because the keys must be strings, which will make this + method to return True. Other cases where this might return True if + objects which can't be inferred were passed. + """ + return len(self.keyword_arguments) != len(self._unpacked_kwargs) + + def _unpack_keywords(self, keywords, context=None): + values = {} + context = context or InferenceContext() + context.extra_context = self.argument_context_map + for name, value in keywords: + if name is None: + # Then it's an unpacking operation (**) + try: + inferred = next(value.infer(context=context)) + except InferenceError: + values[name] = Uninferable + continue + except StopIteration: + continue + + if not isinstance(inferred, nodes.Dict): + # Not something we can work with. + values[name] = Uninferable + continue + + for dict_key, dict_value in inferred.items: + try: + dict_key = next(dict_key.infer(context=context)) + except InferenceError: + values[name] = Uninferable + continue + except StopIteration: + continue + if not isinstance(dict_key, nodes.Const): + values[name] = Uninferable + continue + if not isinstance(dict_key.value, str): + values[name] = Uninferable + continue + if dict_key.value in values: + # The name is already in the dictionary + values[dict_key.value] = Uninferable + self.duplicated_keywords.add(dict_key.value) + continue + values[dict_key.value] = dict_value + else: + values[name] = value + return values + + def _unpack_args(self, args, context=None): + values = [] + context = context or InferenceContext() + context.extra_context = self.argument_context_map + for arg in args: + if isinstance(arg, nodes.Starred): + try: + inferred = next(arg.value.infer(context=context)) + except InferenceError: + values.append(Uninferable) + continue + except StopIteration: + continue + + if inferred is Uninferable: + values.append(Uninferable) + continue + if not hasattr(inferred, "elts"): + values.append(Uninferable) + continue + values.extend(inferred.elts) + else: + values.append(arg) + return values + + def infer_argument(self, funcnode, name, context): + """infer a function argument value according to the call context + + Arguments: + funcnode: The function being called. + name: The name of the argument whose value is being inferred. + context: Inference context object + """ + if name in self.duplicated_keywords: + raise InferenceError( + "The arguments passed to {func!r} " " have duplicate keywords.", + call_site=self, + func=funcnode, + arg=name, + context=context, + ) + + # Look into the keywords first, maybe it's already there. + try: + return self.keyword_arguments[name].infer(context) + except KeyError: + pass + + # Too many arguments given and no variable arguments. + if len(self.positional_arguments) > len(funcnode.args.args): + if not funcnode.args.vararg and not funcnode.args.posonlyargs: + raise InferenceError( + "Too many positional arguments " + "passed to {func!r} that does " + "not have *args.", + call_site=self, + func=funcnode, + arg=name, + context=context, + ) + + positional = self.positional_arguments[: len(funcnode.args.args)] + vararg = self.positional_arguments[len(funcnode.args.args) :] + argindex = funcnode.args.find_argname(name)[0] + kwonlyargs = {arg.name for arg in funcnode.args.kwonlyargs} + kwargs = { + key: value + for key, value in self.keyword_arguments.items() + if key not in kwonlyargs + } + # If there are too few positionals compared to + # what the function expects to receive, check to see + # if the missing positional arguments were passed + # as keyword arguments and if so, place them into the + # positional args list. + if len(positional) < len(funcnode.args.args): + for func_arg in funcnode.args.args: + if func_arg.name in kwargs: + arg = kwargs.pop(func_arg.name) + positional.append(arg) + + if argindex is not None: + boundnode = getattr(context, "boundnode", None) + # 2. first argument of instance/class method + if argindex == 0 and funcnode.type in {"method", "classmethod"}: + # context.boundnode is None when an instance method is called with + # the class, e.g. MyClass.method(obj, ...). In this case, self + # is the first argument. + if boundnode is None and funcnode.type == "method" and positional: + return positional[0].infer(context=context) + if boundnode is None: + # XXX can do better ? + boundnode = funcnode.parent.frame(future=True) + + if isinstance(boundnode, nodes.ClassDef): + # Verify that we're accessing a method + # of the metaclass through a class, as in + # `cls.metaclass_method`. In this case, the + # first argument is always the class. + method_scope = funcnode.parent.scope() + if method_scope is boundnode.metaclass(): + return iter((boundnode,)) + + if funcnode.type == "method": + if not isinstance(boundnode, Instance): + boundnode = boundnode.instantiate_class() + return iter((boundnode,)) + if funcnode.type == "classmethod": + return iter((boundnode,)) + # if we have a method, extract one position + # from the index, so we'll take in account + # the extra parameter represented by `self` or `cls` + if funcnode.type in {"method", "classmethod"} and boundnode: + argindex -= 1 + # 2. search arg index + try: + return self.positional_arguments[argindex].infer(context) + except IndexError: + pass + + if funcnode.args.kwarg == name: + # It wants all the keywords that were passed into + # the call site. + if self.has_invalid_keywords(): + raise InferenceError( + "Inference failed to find values for all keyword arguments " + "to {func!r}: {unpacked_kwargs!r} doesn't correspond to " + "{keyword_arguments!r}.", + keyword_arguments=self.keyword_arguments, + unpacked_kwargs=self._unpacked_kwargs, + call_site=self, + func=funcnode, + arg=name, + context=context, + ) + kwarg = nodes.Dict( + lineno=funcnode.args.lineno, + col_offset=funcnode.args.col_offset, + parent=funcnode.args, + ) + kwarg.postinit( + [(nodes.const_factory(key), value) for key, value in kwargs.items()] + ) + return iter((kwarg,)) + if funcnode.args.vararg == name: + # It wants all the args that were passed into + # the call site. + if self.has_invalid_arguments(): + raise InferenceError( + "Inference failed to find values for all positional " + "arguments to {func!r}: {unpacked_args!r} doesn't " + "correspond to {positional_arguments!r}.", + positional_arguments=self.positional_arguments, + unpacked_args=self._unpacked_args, + call_site=self, + func=funcnode, + arg=name, + context=context, + ) + args = nodes.Tuple( + lineno=funcnode.args.lineno, + col_offset=funcnode.args.col_offset, + parent=funcnode.args, + ) + args.postinit(vararg) + return iter((args,)) + + # Check if it's a default parameter. + try: + return funcnode.args.default_value(name).infer(context) + except NoDefault: + pass + raise InferenceError( + "No value found for argument {arg} to {func!r}", + call_site=self, + func=funcnode, + arg=name, + context=context, + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/astroid_manager.py b/myenv/lib/python3.9/site-packages/astroid/astroid_manager.py new file mode 100644 index 0000000..da51de7 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/astroid_manager.py @@ -0,0 +1,15 @@ +""" +This file contain the global astroid MANAGER, to prevent circular import that happened +when the only possibility to import it was from astroid.__init__.py. + +This AstroidManager is a singleton/borg so it's possible to instantiate an +AstroidManager() directly. +""" + +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.manager import AstroidManager + +MANAGER = AstroidManager() diff --git a/myenv/lib/python3.9/site-packages/astroid/bases.py b/myenv/lib/python3.9/site-packages/astroid/bases.py new file mode 100644 index 0000000..5adaf51 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/bases.py @@ -0,0 +1,577 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""This module contains base classes and functions for the nodes and some +inference utils. +""" + +import collections + +from astroid import decorators +from astroid.const import PY310_PLUS +from astroid.context import ( + CallContext, + InferenceContext, + bind_context_to_node, + copy_context, +) +from astroid.exceptions import ( + AstroidTypeError, + AttributeInferenceError, + InferenceError, + NameInferenceError, +) +from astroid.util import Uninferable, lazy_descriptor, lazy_import + +objectmodel = lazy_import("interpreter.objectmodel") +helpers = lazy_import("helpers") +manager = lazy_import("manager") + + +# TODO: check if needs special treatment +BOOL_SPECIAL_METHOD = "__bool__" +BUILTINS = "builtins" # TODO Remove in 2.8 + +PROPERTIES = {"builtins.property", "abc.abstractproperty"} +if PY310_PLUS: + PROPERTIES.add("enum.property") + +# List of possible property names. We use this list in order +# to see if a method is a property or not. This should be +# pretty reliable and fast, the alternative being to check each +# decorator to see if its a real property-like descriptor, which +# can be too complicated. +# Also, these aren't qualified, because each project can +# define them, we shouldn't expect to know every possible +# property-like decorator! +POSSIBLE_PROPERTIES = { + "cached_property", + "cachedproperty", + "lazyproperty", + "lazy_property", + "reify", + "lazyattribute", + "lazy_attribute", + "LazyProperty", + "lazy", + "cache_readonly", + "DynamicClassAttribute", +} + + +def _is_property(meth, context=None): + decoratornames = meth.decoratornames(context=context) + if PROPERTIES.intersection(decoratornames): + return True + stripped = { + name.split(".")[-1] for name in decoratornames if name is not Uninferable + } + if any(name in stripped for name in POSSIBLE_PROPERTIES): + return True + + # Lookup for subclasses of *property* + if not meth.decorators: + return False + for decorator in meth.decorators.nodes or (): + inferred = helpers.safe_infer(decorator, context=context) + if inferred is None or inferred is Uninferable: + continue + if inferred.__class__.__name__ == "ClassDef": + for base_class in inferred.bases: + if base_class.__class__.__name__ != "Name": + continue + module, _ = base_class.lookup(base_class.name) + if module.name == "builtins" and base_class.name == "property": + return True + + return False + + +class Proxy: + """a simple proxy object + + Note: + + Subclasses of this object will need a custom __getattr__ + if new instance attributes are created. See the Const class + """ + + _proxied = None # proxied object may be set by class or by instance + + def __init__(self, proxied=None): + if proxied is not None: + self._proxied = proxied + + def __getattr__(self, name): + if name == "_proxied": + return self.__class__._proxied + if name in self.__dict__: + return self.__dict__[name] + return getattr(self._proxied, name) + + def infer(self, context=None): + yield self + + +def _infer_stmts(stmts, context, frame=None): + """Return an iterator on statements inferred by each statement in *stmts*.""" + inferred = False + if context is not None: + name = context.lookupname + context = context.clone() + else: + name = None + context = InferenceContext() + + for stmt in stmts: + if stmt is Uninferable: + yield stmt + inferred = True + continue + context.lookupname = stmt._infer_name(frame, name) + try: + for inf in stmt.infer(context=context): + yield inf + inferred = True + except NameInferenceError: + continue + except InferenceError: + yield Uninferable + inferred = True + if not inferred: + raise InferenceError( + "Inference failed for all members of {stmts!r}.", + stmts=stmts, + frame=frame, + context=context, + ) + + +def _infer_method_result_truth(instance, method_name, context): + # Get the method from the instance and try to infer + # its return's truth value. + meth = next(instance.igetattr(method_name, context=context), None) + if meth and hasattr(meth, "infer_call_result"): + if not meth.callable(): + return Uninferable + try: + context.callcontext = CallContext(args=[], callee=meth) + for value in meth.infer_call_result(instance, context=context): + if value is Uninferable: + return value + try: + inferred = next(value.infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context) from e + return inferred.bool_value() + except InferenceError: + pass + return Uninferable + + +class BaseInstance(Proxy): + """An instance base class, which provides lookup methods for potential instances.""" + + special_attributes = None + + def display_type(self): + return "Instance of" + + def getattr(self, name, context=None, lookupclass=True): + try: + values = self._proxied.instance_attr(name, context) + except AttributeInferenceError as exc: + if self.special_attributes and name in self.special_attributes: + return [self.special_attributes.lookup(name)] + + if lookupclass: + # Class attributes not available through the instance + # unless they are explicitly defined. + return self._proxied.getattr(name, context, class_context=False) + + raise AttributeInferenceError( + target=self, attribute=name, context=context + ) from exc + # since we've no context information, return matching class members as + # well + if lookupclass: + try: + return values + self._proxied.getattr( + name, context, class_context=False + ) + except AttributeInferenceError: + pass + return values + + def igetattr(self, name, context=None): + """inferred getattr""" + if not context: + context = InferenceContext() + try: + context.lookupname = name + # avoid recursively inferring the same attr on the same class + if context.push(self._proxied): + raise InferenceError( + message="Cannot infer the same attribute again", + node=self, + context=context, + ) + + # XXX frame should be self._proxied, or not ? + get_attr = self.getattr(name, context, lookupclass=False) + yield from _infer_stmts( + self._wrap_attr(get_attr, context), context, frame=self + ) + except AttributeInferenceError: + try: + # fallback to class.igetattr since it has some logic to handle + # descriptors + # But only if the _proxied is the Class. + if self._proxied.__class__.__name__ != "ClassDef": + raise + attrs = self._proxied.igetattr(name, context, class_context=False) + yield from self._wrap_attr(attrs, context) + except AttributeInferenceError as error: + raise InferenceError(**vars(error)) from error + + def _wrap_attr(self, attrs, context=None): + """wrap bound methods of attrs in a InstanceMethod proxies""" + for attr in attrs: + if isinstance(attr, UnboundMethod): + if _is_property(attr): + yield from attr.infer_call_result(self, context) + else: + yield BoundMethod(attr, self) + elif hasattr(attr, "name") and attr.name == "": + if attr.args.arguments and attr.args.arguments[0].name == "self": + yield BoundMethod(attr, self) + continue + yield attr + else: + yield attr + + def infer_call_result(self, caller, context=None): + """infer what a class instance is returning when called""" + context = bind_context_to_node(context, self) + inferred = False + for node in self._proxied.igetattr("__call__", context): + if node is Uninferable or not node.callable(): + continue + for res in node.infer_call_result(caller, context): + inferred = True + yield res + if not inferred: + raise InferenceError(node=self, caller=caller, context=context) + + +class Instance(BaseInstance): + """A special node representing a class instance.""" + + # pylint: disable=unnecessary-lambda + special_attributes = lazy_descriptor(lambda: objectmodel.InstanceModel()) + + def __repr__(self): + return "".format( + self._proxied.root().name, self._proxied.name, id(self) + ) + + def __str__(self): + return f"Instance of {self._proxied.root().name}.{self._proxied.name}" + + def callable(self): + try: + self._proxied.getattr("__call__", class_context=False) + return True + except AttributeInferenceError: + return False + + def pytype(self): + return self._proxied.qname() + + def display_type(self): + return "Instance of" + + def bool_value(self, context=None): + """Infer the truth value for an Instance + + The truth value of an instance is determined by these conditions: + + * if it implements __bool__ on Python 3 or __nonzero__ + on Python 2, then its bool value will be determined by + calling this special method and checking its result. + * when this method is not defined, __len__() is called, if it + is defined, and the object is considered true if its result is + nonzero. If a class defines neither __len__() nor __bool__(), + all its instances are considered true. + """ + context = context or InferenceContext() + context.boundnode = self + + try: + result = _infer_method_result_truth(self, BOOL_SPECIAL_METHOD, context) + except (InferenceError, AttributeInferenceError): + # Fallback to __len__. + try: + result = _infer_method_result_truth(self, "__len__", context) + except (AttributeInferenceError, InferenceError): + return True + return result + + def getitem(self, index, context=None): + # TODO: Rewrap index to Const for this case + new_context = bind_context_to_node(context, self) + if not context: + context = new_context + method = next(self.igetattr("__getitem__", context=context), None) + # Create a new CallContext for providing index as an argument. + new_context.callcontext = CallContext(args=[index], callee=method) + if not isinstance(method, BoundMethod): + raise InferenceError( + "Could not find __getitem__ for {node!r}.", node=self, context=context + ) + if len(method.args.arguments) != 2: # (self, index) + raise AstroidTypeError( + "__getitem__ for {node!r} does not have correct signature", + node=self, + context=context, + ) + return next(method.infer_call_result(self, new_context), None) + + +class UnboundMethod(Proxy): + """a special node representing a method not bound to an instance""" + + # pylint: disable=unnecessary-lambda + special_attributes = lazy_descriptor(lambda: objectmodel.UnboundMethodModel()) + + def __repr__(self): + frame = self._proxied.parent.frame(future=True) + return "<{} {} of {} at 0x{}".format( + self.__class__.__name__, self._proxied.name, frame.qname(), id(self) + ) + + def implicit_parameters(self): + return 0 + + def is_bound(self): + return False + + def getattr(self, name, context=None): + if name in self.special_attributes: + return [self.special_attributes.lookup(name)] + return self._proxied.getattr(name, context) + + def igetattr(self, name, context=None): + if name in self.special_attributes: + return iter((self.special_attributes.lookup(name),)) + return self._proxied.igetattr(name, context) + + def infer_call_result(self, caller, context): + """ + The boundnode of the regular context with a function called + on ``object.__new__`` will be of type ``object``, + which is incorrect for the argument in general. + If no context is given the ``object.__new__`` call argument will + correctly inferred except when inside a call that requires + the additional context (such as a classmethod) of the boundnode + to determine which class the method was called from + """ + + # If we're unbound method __new__ of builtin object, the result is an + # instance of the class given as first argument. + if ( + self._proxied.name == "__new__" + and self._proxied.parent.frame(future=True).qname() == "builtins.object" + ): + if caller.args: + node_context = context.extra_context.get(caller.args[0]) + infer = caller.args[0].infer(context=node_context) + else: + infer = [] + return (Instance(x) if x is not Uninferable else x for x in infer) + return self._proxied.infer_call_result(caller, context) + + def bool_value(self, context=None): + return True + + +class BoundMethod(UnboundMethod): + """a special node representing a method bound to an instance""" + + # pylint: disable=unnecessary-lambda + special_attributes = lazy_descriptor(lambda: objectmodel.BoundMethodModel()) + + def __init__(self, proxy, bound): + super().__init__(proxy) + self.bound = bound + + def implicit_parameters(self): + if self.name == "__new__": + # __new__ acts as a classmethod but the class argument is not implicit. + return 0 + return 1 + + def is_bound(self): + return True + + def _infer_type_new_call(self, caller, context): + """Try to infer what type.__new__(mcs, name, bases, attrs) returns. + + In order for such call to be valid, the metaclass needs to be + a subtype of ``type``, the name needs to be a string, the bases + needs to be a tuple of classes + """ + # pylint: disable=import-outside-toplevel; circular import + from astroid.nodes import Pass + + # Verify the metaclass + try: + mcs = next(caller.args[0].infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context) from e + if mcs.__class__.__name__ != "ClassDef": + # Not a valid first argument. + return None + if not mcs.is_subtype_of("builtins.type"): + # Not a valid metaclass. + return None + + # Verify the name + try: + name = next(caller.args[1].infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context) from e + if name.__class__.__name__ != "Const": + # Not a valid name, needs to be a const. + return None + if not isinstance(name.value, str): + # Needs to be a string. + return None + + # Verify the bases + try: + bases = next(caller.args[2].infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context) from e + if bases.__class__.__name__ != "Tuple": + # Needs to be a tuple. + return None + try: + inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts] + except StopIteration as e: + raise InferenceError(context=context) from e + if any(base.__class__.__name__ != "ClassDef" for base in inferred_bases): + # All the bases needs to be Classes + return None + + # Verify the attributes. + try: + attrs = next(caller.args[3].infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context) from e + if attrs.__class__.__name__ != "Dict": + # Needs to be a dictionary. + return None + cls_locals = collections.defaultdict(list) + for key, value in attrs.items: + try: + key = next(key.infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context) from e + try: + value = next(value.infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context) from e + # Ignore non string keys + if key.__class__.__name__ == "Const" and isinstance(key.value, str): + cls_locals[key.value].append(value) + + # Build the class from now. + cls = mcs.__class__( + name=name.value, + lineno=caller.lineno, + col_offset=caller.col_offset, + parent=caller, + ) + empty = Pass() + cls.postinit( + bases=bases.elts, + body=[empty], + decorators=[], + newstyle=True, + metaclass=mcs, + keywords=[], + ) + cls.locals = cls_locals + return cls + + def infer_call_result(self, caller, context=None): + context = bind_context_to_node(context, self.bound) + if ( + self.bound.__class__.__name__ == "ClassDef" + and self.bound.name == "type" + and self.name == "__new__" + and len(caller.args) == 4 + ): + # Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call. + new_cls = self._infer_type_new_call(caller, context) + if new_cls: + return iter((new_cls,)) + + return super().infer_call_result(caller, context) + + def bool_value(self, context=None): + return True + + +class Generator(BaseInstance): + """a special node representing a generator. + + Proxied class is set once for all in raw_building. + """ + + special_attributes = lazy_descriptor(objectmodel.GeneratorModel) + + def __init__(self, parent=None, generator_initial_context=None): + super().__init__() + self.parent = parent + self._call_context = copy_context(generator_initial_context) + + @decorators.cached + def infer_yield_types(self): + yield from self.parent.infer_yield_result(self._call_context) + + def callable(self): + return False + + def pytype(self): + return "builtins.generator" + + def display_type(self): + return "Generator" + + def bool_value(self, context=None): + return True + + def __repr__(self): + return f"" + + def __str__(self): + return f"Generator({self._proxied.name})" + + +class AsyncGenerator(Generator): + """Special node representing an async generator""" + + def pytype(self): + return "builtins.async_generator" + + def display_type(self): + return "AsyncGenerator" + + def __repr__(self): + return f"" + + def __str__(self): + return f"AsyncGenerator({self._proxied.name})" diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/__init__.py b/myenv/lib/python3.9/site-packages/astroid/brain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_argparse.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_argparse.py new file mode 100644 index 0000000..ea97179 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_argparse.py @@ -0,0 +1,41 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid import arguments, inference_tip, nodes +from astroid.exceptions import UseInferenceDefault +from astroid.manager import AstroidManager + + +def infer_namespace(node, context=None): + callsite = arguments.CallSite.from_call(node, context=context) + if not callsite.keyword_arguments: + # Cannot make sense of it. + raise UseInferenceDefault() + + class_node = nodes.ClassDef("Namespace") + # Set parent manually until ClassDef constructor fixed: + # https://github.com/PyCQA/astroid/issues/1490 + class_node.parent = node.parent + for attr in set(callsite.keyword_arguments): + fake_node = nodes.EmptyNode() + fake_node.parent = class_node + fake_node.attrname = attr + class_node.instance_attrs[attr] = [fake_node] + return iter((class_node.instantiate_class(),)) + + +def _looks_like_namespace(node): + func = node.func + if isinstance(func, nodes.Attribute): + return ( + func.attrname == "Namespace" + and isinstance(func.expr, nodes.Name) + and func.expr.name == "argparse" + ) + return False + + +AstroidManager().register_transform( + nodes.Call, inference_tip(infer_namespace), _looks_like_namespace +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_attrs.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_attrs.py new file mode 100644 index 0000000..32b8ce0 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_attrs.py @@ -0,0 +1,84 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Astroid hook for the attrs library + +Without this hook pylint reports unsupported-assignment-operation +for attrs classes +""" +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import AnnAssign, Assign, AssignName, Call, Unknown +from astroid.nodes.scoped_nodes import ClassDef + +ATTRIB_NAMES = frozenset( + ("attr.ib", "attrib", "attr.attrib", "attr.field", "attrs.field", "field") +) +ATTRS_NAMES = frozenset( + ( + "attr.s", + "attrs", + "attr.attrs", + "attr.attributes", + "attr.define", + "attr.mutable", + "attr.frozen", + "attrs.define", + "attrs.mutable", + "attrs.frozen", + ) +) + + +def is_decorated_with_attrs(node, decorator_names=ATTRS_NAMES): + """Return True if a decorated node has + an attr decorator applied.""" + if not node.decorators: + return False + for decorator_attribute in node.decorators.nodes: + if isinstance(decorator_attribute, Call): # decorator with arguments + decorator_attribute = decorator_attribute.func + if decorator_attribute.as_string() in decorator_names: + return True + return False + + +def attr_attributes_transform(node: ClassDef) -> None: + """Given that the ClassNode has an attr decorator, + rewrite class attributes as instance attributes + """ + # Astroid can't infer this attribute properly + # Prevents https://github.com/PyCQA/pylint/issues/1884 + node.locals["__attrs_attrs__"] = [Unknown(parent=node)] + + for cdef_body_node in node.body: + if not isinstance(cdef_body_node, (Assign, AnnAssign)): + continue + if isinstance(cdef_body_node.value, Call): + if cdef_body_node.value.func.as_string() not in ATTRIB_NAMES: + continue + else: + continue + targets = ( + cdef_body_node.targets + if hasattr(cdef_body_node, "targets") + else [cdef_body_node.target] + ) + for target in targets: + rhs_node = Unknown( + lineno=cdef_body_node.lineno, + col_offset=cdef_body_node.col_offset, + parent=cdef_body_node, + ) + if isinstance(target, AssignName): + # Could be a subscript if the code analysed is + # i = Optional[str] = "" + # See https://github.com/PyCQA/pylint/issues/4439 + node.locals[target.name] = [rhs_node] + node.instance_attrs[target.name] = [rhs_node] + + +AstroidManager().register_transform( + ClassDef, attr_attributes_transform, is_decorated_with_attrs +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_boto3.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_boto3.py new file mode 100644 index 0000000..54faa64 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_boto3.py @@ -0,0 +1,30 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for understanding boto3.ServiceRequest()""" +from astroid import extract_node +from astroid.manager import AstroidManager +from astroid.nodes.scoped_nodes import ClassDef + +BOTO_SERVICE_FACTORY_QUALIFIED_NAME = "boto3.resources.base.ServiceResource" + + +def service_request_transform(node): + """Transform ServiceResource to look like dynamic classes""" + code = """ + def __getattr__(self, attr): + return 0 + """ + func_getattr = extract_node(code) + node.locals["__getattr__"] = [func_getattr] + return node + + +def _looks_like_boto3_service_request(node): + return node.qname() == BOTO_SERVICE_FACTORY_QUALIFIED_NAME + + +AstroidManager().register_transform( + ClassDef, service_request_transform, _looks_like_boto3_service_request +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_builtin_inference.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_builtin_inference.py new file mode 100644 index 0000000..5d7040a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_builtin_inference.py @@ -0,0 +1,922 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for various builtins.""" + +from functools import partial +from typing import Optional + +from astroid import arguments, helpers, inference_tip, nodes, objects, util +from astroid.builder import AstroidBuilder +from astroid.context import InferenceContext +from astroid.exceptions import ( + AstroidTypeError, + AttributeInferenceError, + InferenceError, + MroError, + UseInferenceDefault, +) +from astroid.manager import AstroidManager +from astroid.nodes import scoped_nodes + +OBJECT_DUNDER_NEW = "object.__new__" + +STR_CLASS = """ +class whatever(object): + def join(self, iterable): + return {rvalue} + def replace(self, old, new, count=None): + return {rvalue} + def format(self, *args, **kwargs): + return {rvalue} + def encode(self, encoding='ascii', errors=None): + return b'' + def decode(self, encoding='ascii', errors=None): + return u'' + def capitalize(self): + return {rvalue} + def title(self): + return {rvalue} + def lower(self): + return {rvalue} + def upper(self): + return {rvalue} + def swapcase(self): + return {rvalue} + def index(self, sub, start=None, end=None): + return 0 + def find(self, sub, start=None, end=None): + return 0 + def count(self, sub, start=None, end=None): + return 0 + def strip(self, chars=None): + return {rvalue} + def lstrip(self, chars=None): + return {rvalue} + def rstrip(self, chars=None): + return {rvalue} + def rjust(self, width, fillchar=None): + return {rvalue} + def center(self, width, fillchar=None): + return {rvalue} + def ljust(self, width, fillchar=None): + return {rvalue} +""" + + +BYTES_CLASS = """ +class whatever(object): + def join(self, iterable): + return {rvalue} + def replace(self, old, new, count=None): + return {rvalue} + def decode(self, encoding='ascii', errors=None): + return u'' + def capitalize(self): + return {rvalue} + def title(self): + return {rvalue} + def lower(self): + return {rvalue} + def upper(self): + return {rvalue} + def swapcase(self): + return {rvalue} + def index(self, sub, start=None, end=None): + return 0 + def find(self, sub, start=None, end=None): + return 0 + def count(self, sub, start=None, end=None): + return 0 + def strip(self, chars=None): + return {rvalue} + def lstrip(self, chars=None): + return {rvalue} + def rstrip(self, chars=None): + return {rvalue} + def rjust(self, width, fillchar=None): + return {rvalue} + def center(self, width, fillchar=None): + return {rvalue} + def ljust(self, width, fillchar=None): + return {rvalue} +""" + + +def _extend_string_class(class_node, code, rvalue): + """function to extend builtin str/unicode class""" + code = code.format(rvalue=rvalue) + fake = AstroidBuilder(AstroidManager()).string_build(code)["whatever"] + for method in fake.mymethods(): + method.parent = class_node + method.lineno = None + method.col_offset = None + if "__class__" in method.locals: + method.locals["__class__"] = [class_node] + class_node.locals[method.name] = [method] + method.parent = class_node + + +def _extend_builtins(class_transforms): + builtin_ast = AstroidManager().builtins_module + for class_name, transform in class_transforms.items(): + transform(builtin_ast[class_name]) + + +_extend_builtins( + { + "bytes": partial(_extend_string_class, code=BYTES_CLASS, rvalue="b''"), + "str": partial(_extend_string_class, code=STR_CLASS, rvalue="''"), + } +) + + +def _builtin_filter_predicate(node, builtin_name): + if ( + builtin_name == "type" + and node.root().name == "re" + and isinstance(node.func, nodes.Name) + and node.func.name == "type" + and isinstance(node.parent, nodes.Assign) + and len(node.parent.targets) == 1 + and isinstance(node.parent.targets[0], nodes.AssignName) + and node.parent.targets[0].name in {"Pattern", "Match"} + ): + # Handle re.Pattern and re.Match in brain_re + # Match these patterns from stdlib/re.py + # ```py + # Pattern = type(...) + # Match = type(...) + # ``` + return False + if isinstance(node.func, nodes.Name) and node.func.name == builtin_name: + return True + if isinstance(node.func, nodes.Attribute): + return ( + node.func.attrname == "fromkeys" + and isinstance(node.func.expr, nodes.Name) + and node.func.expr.name == "dict" + ) + return False + + +def register_builtin_transform(transform, builtin_name): + """Register a new transform function for the given *builtin_name*. + + The transform function must accept two parameters, a node and + an optional context. + """ + + def _transform_wrapper(node, context=None): + result = transform(node, context=context) + if result: + if not result.parent: + # Let the transformation function determine + # the parent for its result. Otherwise, + # we set it to be the node we transformed from. + result.parent = node + + if result.lineno is None: + result.lineno = node.lineno + # Can be a 'Module' see https://github.com/PyCQA/pylint/issues/4671 + # We don't have a regression test on this one: tread carefully + if hasattr(result, "col_offset") and result.col_offset is None: + result.col_offset = node.col_offset + return iter([result]) + + AstroidManager().register_transform( + nodes.Call, + inference_tip(_transform_wrapper), + partial(_builtin_filter_predicate, builtin_name=builtin_name), + ) + + +def _container_generic_inference(node, context, node_type, transform): + args = node.args + if not args: + return node_type() + if len(node.args) > 1: + raise UseInferenceDefault() + + (arg,) = args + transformed = transform(arg) + if not transformed: + try: + inferred = next(arg.infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + if inferred is util.Uninferable: + raise UseInferenceDefault + transformed = transform(inferred) + if not transformed or transformed is util.Uninferable: + raise UseInferenceDefault + return transformed + + +def _container_generic_transform( # pylint: disable=inconsistent-return-statements + arg, context, klass, iterables, build_elts +): + if isinstance(arg, klass): + return arg + if isinstance(arg, iterables): + if all(isinstance(elt, nodes.Const) for elt in arg.elts): + elts = [elt.value for elt in arg.elts] + else: + # TODO: Does not handle deduplication for sets. + elts = [] + for element in arg.elts: + if not element: + continue + inferred = helpers.safe_infer(element, context=context) + if inferred: + evaluated_object = nodes.EvaluatedObject( + original=element, value=inferred + ) + elts.append(evaluated_object) + elif isinstance(arg, nodes.Dict): + # Dicts need to have consts as strings already. + if not all(isinstance(elt[0], nodes.Const) for elt in arg.items): + raise UseInferenceDefault() + elts = [item[0].value for item in arg.items] + elif isinstance(arg, nodes.Const) and isinstance(arg.value, (str, bytes)): + elts = arg.value + else: + return + return klass.from_elements(elts=build_elts(elts)) + + +def _infer_builtin_container( + node, context, klass=None, iterables=None, build_elts=None +): + transform_func = partial( + _container_generic_transform, + context=context, + klass=klass, + iterables=iterables, + build_elts=build_elts, + ) + + return _container_generic_inference(node, context, klass, transform_func) + + +# pylint: disable=invalid-name +infer_tuple = partial( + _infer_builtin_container, + klass=nodes.Tuple, + iterables=( + nodes.List, + nodes.Set, + objects.FrozenSet, + objects.DictItems, + objects.DictKeys, + objects.DictValues, + ), + build_elts=tuple, +) + +infer_list = partial( + _infer_builtin_container, + klass=nodes.List, + iterables=( + nodes.Tuple, + nodes.Set, + objects.FrozenSet, + objects.DictItems, + objects.DictKeys, + objects.DictValues, + ), + build_elts=list, +) + +infer_set = partial( + _infer_builtin_container, + klass=nodes.Set, + iterables=(nodes.List, nodes.Tuple, objects.FrozenSet, objects.DictKeys), + build_elts=set, +) + +infer_frozenset = partial( + _infer_builtin_container, + klass=objects.FrozenSet, + iterables=(nodes.List, nodes.Tuple, nodes.Set, objects.FrozenSet, objects.DictKeys), + build_elts=frozenset, +) + + +def _get_elts(arg, context): + def is_iterable(n): + return isinstance(n, (nodes.List, nodes.Tuple, nodes.Set)) + + try: + inferred = next(arg.infer(context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + if isinstance(inferred, nodes.Dict): + items = inferred.items + elif is_iterable(inferred): + items = [] + for elt in inferred.elts: + # If an item is not a pair of two items, + # then fallback to the default inference. + # Also, take in consideration only hashable items, + # tuples and consts. We are choosing Names as well. + if not is_iterable(elt): + raise UseInferenceDefault() + if len(elt.elts) != 2: + raise UseInferenceDefault() + if not isinstance(elt.elts[0], (nodes.Tuple, nodes.Const, nodes.Name)): + raise UseInferenceDefault() + items.append(tuple(elt.elts)) + else: + raise UseInferenceDefault() + return items + + +def infer_dict(node, context=None): + """Try to infer a dict call to a Dict node. + + The function treats the following cases: + + * dict() + * dict(mapping) + * dict(iterable) + * dict(iterable, **kwargs) + * dict(mapping, **kwargs) + * dict(**kwargs) + + If a case can't be inferred, we'll fallback to default inference. + """ + call = arguments.CallSite.from_call(node, context=context) + if call.has_invalid_arguments() or call.has_invalid_keywords(): + raise UseInferenceDefault + + args = call.positional_arguments + kwargs = list(call.keyword_arguments.items()) + + if not args and not kwargs: + # dict() + return nodes.Dict() + if kwargs and not args: + # dict(a=1, b=2, c=4) + items = [(nodes.Const(key), value) for key, value in kwargs] + elif len(args) == 1 and kwargs: + # dict(some_iterable, b=2, c=4) + elts = _get_elts(args[0], context) + keys = [(nodes.Const(key), value) for key, value in kwargs] + items = elts + keys + elif len(args) == 1: + items = _get_elts(args[0], context) + else: + raise UseInferenceDefault() + value = nodes.Dict( + col_offset=node.col_offset, lineno=node.lineno, parent=node.parent + ) + value.postinit(items) + return value + + +def infer_super(node, context=None): + """Understand super calls. + + There are some restrictions for what can be understood: + + * unbounded super (one argument form) is not understood. + + * if the super call is not inside a function (classmethod or method), + then the default inference will be used. + + * if the super arguments can't be inferred, the default inference + will be used. + """ + if len(node.args) == 1: + # Ignore unbounded super. + raise UseInferenceDefault + + scope = node.scope() + if not isinstance(scope, nodes.FunctionDef): + # Ignore non-method uses of super. + raise UseInferenceDefault + if scope.type not in ("classmethod", "method"): + # Not interested in staticmethods. + raise UseInferenceDefault + + cls = scoped_nodes.get_wrapping_class(scope) + if not node.args: + mro_pointer = cls + # In we are in a classmethod, the interpreter will fill + # automatically the class as the second argument, not an instance. + if scope.type == "classmethod": + mro_type = cls + else: + mro_type = cls.instantiate_class() + else: + try: + mro_pointer = next(node.args[0].infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + try: + mro_type = next(node.args[1].infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + + if mro_pointer is util.Uninferable or mro_type is util.Uninferable: + # No way we could understand this. + raise UseInferenceDefault + + super_obj = objects.Super( + mro_pointer=mro_pointer, mro_type=mro_type, self_class=cls, scope=scope + ) + super_obj.parent = node + return super_obj + + +def _infer_getattr_args(node, context): + if len(node.args) not in (2, 3): + # Not a valid getattr call. + raise UseInferenceDefault + + try: + obj = next(node.args[0].infer(context=context)) + attr = next(node.args[1].infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + + if obj is util.Uninferable or attr is util.Uninferable: + # If one of the arguments is something we can't infer, + # then also make the result of the getattr call something + # which is unknown. + return util.Uninferable, util.Uninferable + + is_string = isinstance(attr, nodes.Const) and isinstance(attr.value, str) + if not is_string: + raise UseInferenceDefault + + return obj, attr.value + + +def infer_getattr(node, context=None): + """Understand getattr calls + + If one of the arguments is an Uninferable object, then the + result will be an Uninferable object. Otherwise, the normal attribute + lookup will be done. + """ + obj, attr = _infer_getattr_args(node, context) + if ( + obj is util.Uninferable + or attr is util.Uninferable + or not hasattr(obj, "igetattr") + ): + return util.Uninferable + + try: + return next(obj.igetattr(attr, context=context)) + except (StopIteration, InferenceError, AttributeInferenceError): + if len(node.args) == 3: + # Try to infer the default and return it instead. + try: + return next(node.args[2].infer(context=context)) + except (StopIteration, InferenceError) as exc: + raise UseInferenceDefault from exc + + raise UseInferenceDefault + + +def infer_hasattr(node, context=None): + """Understand hasattr calls + + This always guarantees three possible outcomes for calling + hasattr: Const(False) when we are sure that the object + doesn't have the intended attribute, Const(True) when + we know that the object has the attribute and Uninferable + when we are unsure of the outcome of the function call. + """ + try: + obj, attr = _infer_getattr_args(node, context) + if ( + obj is util.Uninferable + or attr is util.Uninferable + or not hasattr(obj, "getattr") + ): + return util.Uninferable + obj.getattr(attr, context=context) + except UseInferenceDefault: + # Can't infer something from this function call. + return util.Uninferable + except AttributeInferenceError: + # Doesn't have it. + return nodes.Const(False) + return nodes.Const(True) + + +def infer_callable(node, context=None): + """Understand callable calls + + This follows Python's semantics, where an object + is callable if it provides an attribute __call__, + even though that attribute is something which can't be + called. + """ + if len(node.args) != 1: + # Invalid callable call. + raise UseInferenceDefault + + argument = node.args[0] + try: + inferred = next(argument.infer(context=context)) + except (InferenceError, StopIteration): + return util.Uninferable + if inferred is util.Uninferable: + return util.Uninferable + return nodes.Const(inferred.callable()) + + +def infer_property( + node: nodes.Call, context: Optional[InferenceContext] = None +) -> objects.Property: + """Understand `property` class + + This only infers the output of `property` + call, not the arguments themselves. + """ + if len(node.args) < 1: + # Invalid property call. + raise UseInferenceDefault + + getter = node.args[0] + try: + inferred = next(getter.infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + + if not isinstance(inferred, (nodes.FunctionDef, nodes.Lambda)): + raise UseInferenceDefault + + prop_func = objects.Property( + function=inferred, + name=inferred.name, + lineno=node.lineno, + parent=node, + col_offset=node.col_offset, + ) + prop_func.postinit( + body=[], + args=inferred.args, + doc_node=getattr(inferred, "doc_node", None), + ) + return prop_func + + +def infer_bool(node, context=None): + """Understand bool calls.""" + if len(node.args) > 1: + # Invalid bool call. + raise UseInferenceDefault + + if not node.args: + return nodes.Const(False) + + argument = node.args[0] + try: + inferred = next(argument.infer(context=context)) + except (InferenceError, StopIteration): + return util.Uninferable + if inferred is util.Uninferable: + return util.Uninferable + + bool_value = inferred.bool_value(context=context) + if bool_value is util.Uninferable: + return util.Uninferable + return nodes.Const(bool_value) + + +def infer_type(node, context=None): + """Understand the one-argument form of *type*.""" + if len(node.args) != 1: + raise UseInferenceDefault + + return helpers.object_type(node.args[0], context) + + +def infer_slice(node, context=None): + """Understand `slice` calls.""" + args = node.args + if not 0 < len(args) <= 3: + raise UseInferenceDefault + + infer_func = partial(helpers.safe_infer, context=context) + args = [infer_func(arg) for arg in args] + for arg in args: + if not arg or arg is util.Uninferable: + raise UseInferenceDefault + if not isinstance(arg, nodes.Const): + raise UseInferenceDefault + if not isinstance(arg.value, (type(None), int)): + raise UseInferenceDefault + + if len(args) < 3: + # Make sure we have 3 arguments. + args.extend([None] * (3 - len(args))) + + slice_node = nodes.Slice( + lineno=node.lineno, col_offset=node.col_offset, parent=node.parent + ) + slice_node.postinit(*args) + return slice_node + + +def _infer_object__new__decorator(node, context=None): + # Instantiate class immediately + # since that's what @object.__new__ does + return iter((node.instantiate_class(),)) + + +def _infer_object__new__decorator_check(node): + """Predicate before inference_tip + + Check if the given ClassDef has an @object.__new__ decorator + """ + if not node.decorators: + return False + + for decorator in node.decorators.nodes: + if isinstance(decorator, nodes.Attribute): + if decorator.as_string() == OBJECT_DUNDER_NEW: + return True + return False + + +def infer_issubclass(callnode, context=None): + """Infer issubclass() calls + + :param nodes.Call callnode: an `issubclass` call + :param InferenceContext context: the context for the inference + :rtype nodes.Const: Boolean Const value of the `issubclass` call + :raises UseInferenceDefault: If the node cannot be inferred + """ + call = arguments.CallSite.from_call(callnode, context=context) + if call.keyword_arguments: + # issubclass doesn't support keyword arguments + raise UseInferenceDefault("TypeError: issubclass() takes no keyword arguments") + if len(call.positional_arguments) != 2: + raise UseInferenceDefault( + f"Expected two arguments, got {len(call.positional_arguments)}" + ) + # The left hand argument is the obj to be checked + obj_node, class_or_tuple_node = call.positional_arguments + + try: + obj_type = next(obj_node.infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + if not isinstance(obj_type, nodes.ClassDef): + raise UseInferenceDefault("TypeError: arg 1 must be class") + + # The right hand argument is the class(es) that the given + # object is to be checked against. + try: + class_container = _class_or_tuple_to_container( + class_or_tuple_node, context=context + ) + except InferenceError as exc: + raise UseInferenceDefault from exc + try: + issubclass_bool = helpers.object_issubclass(obj_type, class_container, context) + except AstroidTypeError as exc: + raise UseInferenceDefault("TypeError: " + str(exc)) from exc + except MroError as exc: + raise UseInferenceDefault from exc + return nodes.Const(issubclass_bool) + + +def infer_isinstance(callnode, context=None): + """Infer isinstance calls + + :param nodes.Call callnode: an isinstance call + :param InferenceContext context: context for call + (currently unused but is a common interface for inference) + :rtype nodes.Const: Boolean Const value of isinstance call + + :raises UseInferenceDefault: If the node cannot be inferred + """ + call = arguments.CallSite.from_call(callnode, context=context) + if call.keyword_arguments: + # isinstance doesn't support keyword arguments + raise UseInferenceDefault("TypeError: isinstance() takes no keyword arguments") + if len(call.positional_arguments) != 2: + raise UseInferenceDefault( + f"Expected two arguments, got {len(call.positional_arguments)}" + ) + # The left hand argument is the obj to be checked + obj_node, class_or_tuple_node = call.positional_arguments + # The right hand argument is the class(es) that the given + # obj is to be check is an instance of + try: + class_container = _class_or_tuple_to_container( + class_or_tuple_node, context=context + ) + except InferenceError as exc: + raise UseInferenceDefault from exc + try: + isinstance_bool = helpers.object_isinstance(obj_node, class_container, context) + except AstroidTypeError as exc: + raise UseInferenceDefault("TypeError: " + str(exc)) from exc + except MroError as exc: + raise UseInferenceDefault from exc + if isinstance_bool is util.Uninferable: + raise UseInferenceDefault + return nodes.Const(isinstance_bool) + + +def _class_or_tuple_to_container(node, context=None): + # Move inferences results into container + # to simplify later logic + # raises InferenceError if any of the inferences fall through + try: + node_infer = next(node.infer(context=context)) + except StopIteration as e: + raise InferenceError(node=node, context=context) from e + # arg2 MUST be a type or a TUPLE of types + # for isinstance + if isinstance(node_infer, nodes.Tuple): + try: + class_container = [ + next(node.infer(context=context)) for node in node_infer.elts + ] + except StopIteration as e: + raise InferenceError(node=node, context=context) from e + class_container = [ + klass_node for klass_node in class_container if klass_node is not None + ] + else: + class_container = [node_infer] + return class_container + + +def infer_len(node, context=None): + """Infer length calls + + :param nodes.Call node: len call to infer + :param context.InferenceContext: node context + :rtype nodes.Const: a Const node with the inferred length, if possible + """ + call = arguments.CallSite.from_call(node, context=context) + if call.keyword_arguments: + raise UseInferenceDefault("TypeError: len() must take no keyword arguments") + if len(call.positional_arguments) != 1: + raise UseInferenceDefault( + "TypeError: len() must take exactly one argument " + "({len}) given".format(len=len(call.positional_arguments)) + ) + [argument_node] = call.positional_arguments + + try: + return nodes.Const(helpers.object_len(argument_node, context=context)) + except (AstroidTypeError, InferenceError) as exc: + raise UseInferenceDefault(str(exc)) from exc + + +def infer_str(node, context=None): + """Infer str() calls + + :param nodes.Call node: str() call to infer + :param context.InferenceContext: node context + :rtype nodes.Const: a Const containing an empty string + """ + call = arguments.CallSite.from_call(node, context=context) + if call.keyword_arguments: + raise UseInferenceDefault("TypeError: str() must take no keyword arguments") + try: + return nodes.Const("") + except (AstroidTypeError, InferenceError) as exc: + raise UseInferenceDefault(str(exc)) from exc + + +def infer_int(node, context=None): + """Infer int() calls + + :param nodes.Call node: int() call to infer + :param context.InferenceContext: node context + :rtype nodes.Const: a Const containing the integer value of the int() call + """ + call = arguments.CallSite.from_call(node, context=context) + if call.keyword_arguments: + raise UseInferenceDefault("TypeError: int() must take no keyword arguments") + + if call.positional_arguments: + try: + first_value = next(call.positional_arguments[0].infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault(str(exc)) from exc + + if first_value is util.Uninferable: + raise UseInferenceDefault + + if isinstance(first_value, nodes.Const) and isinstance( + first_value.value, (int, str) + ): + try: + actual_value = int(first_value.value) + except ValueError: + return nodes.Const(0) + return nodes.Const(actual_value) + + return nodes.Const(0) + + +def infer_dict_fromkeys(node, context=None): + """Infer dict.fromkeys + + :param nodes.Call node: dict.fromkeys() call to infer + :param context.InferenceContext context: node context + :rtype nodes.Dict: + a Dictionary containing the values that astroid was able to infer. + In case the inference failed for any reason, an empty dictionary + will be inferred instead. + """ + + def _build_dict_with_elements(elements): + new_node = nodes.Dict( + col_offset=node.col_offset, lineno=node.lineno, parent=node.parent + ) + new_node.postinit(elements) + return new_node + + call = arguments.CallSite.from_call(node, context=context) + if call.keyword_arguments: + raise UseInferenceDefault("TypeError: int() must take no keyword arguments") + if len(call.positional_arguments) not in {1, 2}: + raise UseInferenceDefault( + "TypeError: Needs between 1 and 2 positional arguments" + ) + + default = nodes.Const(None) + values = call.positional_arguments[0] + try: + inferred_values = next(values.infer(context=context)) + except (InferenceError, StopIteration): + return _build_dict_with_elements([]) + if inferred_values is util.Uninferable: + return _build_dict_with_elements([]) + + # Limit to a couple of potential values, as this can become pretty complicated + accepted_iterable_elements = (nodes.Const,) + if isinstance(inferred_values, (nodes.List, nodes.Set, nodes.Tuple)): + elements = inferred_values.elts + for element in elements: + if not isinstance(element, accepted_iterable_elements): + # Fallback to an empty dict + return _build_dict_with_elements([]) + + elements_with_value = [(element, default) for element in elements] + return _build_dict_with_elements(elements_with_value) + if isinstance(inferred_values, nodes.Const) and isinstance( + inferred_values.value, (str, bytes) + ): + elements = [ + (nodes.Const(element), default) for element in inferred_values.value + ] + return _build_dict_with_elements(elements) + if isinstance(inferred_values, nodes.Dict): + keys = inferred_values.itered() + for key in keys: + if not isinstance(key, accepted_iterable_elements): + # Fallback to an empty dict + return _build_dict_with_elements([]) + + elements_with_value = [(element, default) for element in keys] + return _build_dict_with_elements(elements_with_value) + + # Fallback to an empty dictionary + return _build_dict_with_elements([]) + + +# Builtins inference +register_builtin_transform(infer_bool, "bool") +register_builtin_transform(infer_super, "super") +register_builtin_transform(infer_callable, "callable") +register_builtin_transform(infer_property, "property") +register_builtin_transform(infer_getattr, "getattr") +register_builtin_transform(infer_hasattr, "hasattr") +register_builtin_transform(infer_tuple, "tuple") +register_builtin_transform(infer_set, "set") +register_builtin_transform(infer_list, "list") +register_builtin_transform(infer_dict, "dict") +register_builtin_transform(infer_frozenset, "frozenset") +register_builtin_transform(infer_type, "type") +register_builtin_transform(infer_slice, "slice") +register_builtin_transform(infer_isinstance, "isinstance") +register_builtin_transform(infer_issubclass, "issubclass") +register_builtin_transform(infer_len, "len") +register_builtin_transform(infer_str, "str") +register_builtin_transform(infer_int, "int") +register_builtin_transform(infer_dict_fromkeys, "dict.fromkeys") + + +# Infer object.__new__ calls +AstroidManager().register_transform( + nodes.ClassDef, + inference_tip(_infer_object__new__decorator), + _infer_object__new__decorator_check, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_collections.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_collections.py new file mode 100644 index 0000000..43304ec --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_collections.py @@ -0,0 +1,123 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.brain.helpers import register_module_extender +from astroid.builder import extract_node, parse +from astroid.const import PY39_PLUS +from astroid.exceptions import AttributeInferenceError +from astroid.manager import AstroidManager +from astroid.nodes.scoped_nodes import ClassDef + + +def _collections_transform(): + return parse( + """ + class defaultdict(dict): + default_factory = None + def __missing__(self, key): pass + def __getitem__(self, key): return default_factory + + """ + + _deque_mock() + + _ordered_dict_mock() + ) + + +def _deque_mock(): + base_deque_class = """ + class deque(object): + maxlen = 0 + def __init__(self, iterable=None, maxlen=None): + self.iterable = iterable or [] + def append(self, x): pass + def appendleft(self, x): pass + def clear(self): pass + def count(self, x): return 0 + def extend(self, iterable): pass + def extendleft(self, iterable): pass + def pop(self): return self.iterable[0] + def popleft(self): return self.iterable[0] + def remove(self, value): pass + def reverse(self): return reversed(self.iterable) + def rotate(self, n=1): return self + def __iter__(self): return self + def __reversed__(self): return self.iterable[::-1] + def __getitem__(self, index): return self.iterable[index] + def __setitem__(self, index, value): pass + def __delitem__(self, index): pass + def __bool__(self): return bool(self.iterable) + def __nonzero__(self): return bool(self.iterable) + def __contains__(self, o): return o in self.iterable + def __len__(self): return len(self.iterable) + def __copy__(self): return deque(self.iterable) + def copy(self): return deque(self.iterable) + def index(self, x, start=0, end=0): return 0 + def insert(self, i, x): pass + def __add__(self, other): pass + def __iadd__(self, other): pass + def __mul__(self, other): pass + def __imul__(self, other): pass + def __rmul__(self, other): pass""" + if PY39_PLUS: + base_deque_class += """ + @classmethod + def __class_getitem__(self, item): return cls""" + return base_deque_class + + +def _ordered_dict_mock(): + base_ordered_dict_class = """ + class OrderedDict(dict): + def __reversed__(self): return self[::-1] + def move_to_end(self, key, last=False): pass""" + if PY39_PLUS: + base_ordered_dict_class += """ + @classmethod + def __class_getitem__(cls, item): return cls""" + return base_ordered_dict_class + + +register_module_extender(AstroidManager(), "collections", _collections_transform) + + +def _looks_like_subscriptable(node: ClassDef) -> bool: + """ + Returns True if the node corresponds to a ClassDef of the Collections.abc module that + supports subscripting + + :param node: ClassDef node + """ + if node.qname().startswith("_collections") or node.qname().startswith( + "collections" + ): + try: + node.getattr("__class_getitem__") + return True + except AttributeInferenceError: + pass + return False + + +CLASS_GET_ITEM_TEMPLATE = """ +@classmethod +def __class_getitem__(cls, item): + return cls +""" + + +def easy_class_getitem_inference(node, context=None): + # Here __class_getitem__ exists but is quite a mess to infer thus + # put an easy inference tip + func_to_add = extract_node(CLASS_GET_ITEM_TEMPLATE) + node.locals["__class_getitem__"] = [func_to_add] + + +if PY39_PLUS: + # Starting with Python39 some objects of the collection module are subscriptable + # thanks to the __class_getitem__ method but the way it is implemented in + # _collection_abc makes it difficult to infer. (We would have to handle AssignName inference in the + # getitem method of the ClassDef class) Instead we put here a mock of the __class_getitem__ method + AstroidManager().register_transform( + ClassDef, easy_class_getitem_inference, _looks_like_subscriptable + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_crypt.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_crypt.py new file mode 100644 index 0000000..45c3055 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_crypt.py @@ -0,0 +1,28 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.const import PY37_PLUS +from astroid.manager import AstroidManager + +if PY37_PLUS: + # Since Python 3.7 Hashing Methods are added + # dynamically to globals() + + def _re_transform(): + return parse( + """ + from collections import namedtuple + _Method = namedtuple('_Method', 'name ident salt_chars total_size') + + METHOD_SHA512 = _Method('SHA512', '6', 16, 106) + METHOD_SHA256 = _Method('SHA256', '5', 16, 63) + METHOD_BLOWFISH = _Method('BLOWFISH', 2, 'b', 22) + METHOD_MD5 = _Method('MD5', '1', 8, 34) + METHOD_CRYPT = _Method('CRYPT', None, 2, 13) + """ + ) + + register_module_extender(AstroidManager(), "crypt", _re_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_ctypes.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_ctypes.py new file mode 100644 index 0000000..323b19c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_ctypes.py @@ -0,0 +1,82 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Astroid hooks for ctypes module. + +Inside the ctypes module, the value class is defined inside +the C coded module _ctypes. +Thus astroid doesn't know that the value member is a builtin type +among float, int, bytes or str. +""" +import sys + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def enrich_ctypes_redefined_types(): + """ + For each ctypes redefined types, overload 'value' and '_type_' members definition. + Overloading 'value' is mandatory otherwise astroid cannot infer the correct type for it. + Overloading '_type_' is necessary because the class definition made here replaces the original + one, in which '_type_' member is defined. Luckily those original class definitions are very short + and contain only the '_type_' member definition. + """ + c_class_to_type = ( + ("c_byte", "int", "b"), + ("c_char", "bytes", "c"), + ("c_double", "float", "d"), + ("c_float", "float", "f"), + ("c_int", "int", "i"), + ("c_int16", "int", "h"), + ("c_int32", "int", "i"), + ("c_int64", "int", "l"), + ("c_int8", "int", "b"), + ("c_long", "int", "l"), + ("c_longdouble", "float", "g"), + ("c_longlong", "int", "l"), + ("c_short", "int", "h"), + ("c_size_t", "int", "L"), + ("c_ssize_t", "int", "l"), + ("c_ubyte", "int", "B"), + ("c_uint", "int", "I"), + ("c_uint16", "int", "H"), + ("c_uint32", "int", "I"), + ("c_uint64", "int", "L"), + ("c_uint8", "int", "B"), + ("c_ulong", "int", "L"), + ("c_ulonglong", "int", "L"), + ("c_ushort", "int", "H"), + ("c_wchar", "str", "u"), + ) + + src = [ + """ +from _ctypes import _SimpleCData + +class c_bool(_SimpleCData): + def __init__(self, value): + self.value = True + self._type_ = '?' + """ + ] + + for c_type, builtin_type, type_code in c_class_to_type: + src.append( + f""" +class {c_type}(_SimpleCData): + def __init__(self, value): + self.value = {builtin_type}(value) + self._type_ = '{type_code}' + """ + ) + + return parse("\n".join(src)) + + +if not hasattr(sys, "pypy_version_info"): + # No need of this module in pypy where everything is written in python + register_module_extender(AstroidManager(), "ctypes", enrich_ctypes_redefined_types) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_curses.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_curses.py new file mode 100644 index 0000000..66cd5b2 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_curses.py @@ -0,0 +1,183 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def _curses_transform(): + return parse( + """ + A_ALTCHARSET = 1 + A_BLINK = 1 + A_BOLD = 1 + A_DIM = 1 + A_INVIS = 1 + A_ITALIC = 1 + A_NORMAL = 1 + A_PROTECT = 1 + A_REVERSE = 1 + A_STANDOUT = 1 + A_UNDERLINE = 1 + A_HORIZONTAL = 1 + A_LEFT = 1 + A_LOW = 1 + A_RIGHT = 1 + A_TOP = 1 + A_VERTICAL = 1 + A_CHARTEXT = 1 + A_ATTRIBUTES = 1 + A_CHARTEXT = 1 + A_COLOR = 1 + KEY_MIN = 1 + KEY_BREAK = 1 + KEY_DOWN = 1 + KEY_UP = 1 + KEY_LEFT = 1 + KEY_RIGHT = 1 + KEY_HOME = 1 + KEY_BACKSPACE = 1 + KEY_F0 = 1 + KEY_Fn = 1 + KEY_DL = 1 + KEY_IL = 1 + KEY_DC = 1 + KEY_IC = 1 + KEY_EIC = 1 + KEY_CLEAR = 1 + KEY_EOS = 1 + KEY_EOL = 1 + KEY_SF = 1 + KEY_SR = 1 + KEY_NPAGE = 1 + KEY_PPAGE = 1 + KEY_STAB = 1 + KEY_CTAB = 1 + KEY_CATAB = 1 + KEY_ENTER = 1 + KEY_SRESET = 1 + KEY_RESET = 1 + KEY_PRINT = 1 + KEY_LL = 1 + KEY_A1 = 1 + KEY_A3 = 1 + KEY_B2 = 1 + KEY_C1 = 1 + KEY_C3 = 1 + KEY_BTAB = 1 + KEY_BEG = 1 + KEY_CANCEL = 1 + KEY_CLOSE = 1 + KEY_COMMAND = 1 + KEY_COPY = 1 + KEY_CREATE = 1 + KEY_END = 1 + KEY_EXIT = 1 + KEY_FIND = 1 + KEY_HELP = 1 + KEY_MARK = 1 + KEY_MESSAGE = 1 + KEY_MOVE = 1 + KEY_NEXT = 1 + KEY_OPEN = 1 + KEY_OPTIONS = 1 + KEY_PREVIOUS = 1 + KEY_REDO = 1 + KEY_REFERENCE = 1 + KEY_REFRESH = 1 + KEY_REPLACE = 1 + KEY_RESTART = 1 + KEY_RESUME = 1 + KEY_SAVE = 1 + KEY_SBEG = 1 + KEY_SCANCEL = 1 + KEY_SCOMMAND = 1 + KEY_SCOPY = 1 + KEY_SCREATE = 1 + KEY_SDC = 1 + KEY_SDL = 1 + KEY_SELECT = 1 + KEY_SEND = 1 + KEY_SEOL = 1 + KEY_SEXIT = 1 + KEY_SFIND = 1 + KEY_SHELP = 1 + KEY_SHOME = 1 + KEY_SIC = 1 + KEY_SLEFT = 1 + KEY_SMESSAGE = 1 + KEY_SMOVE = 1 + KEY_SNEXT = 1 + KEY_SOPTIONS = 1 + KEY_SPREVIOUS = 1 + KEY_SPRINT = 1 + KEY_SREDO = 1 + KEY_SREPLACE = 1 + KEY_SRIGHT = 1 + KEY_SRSUME = 1 + KEY_SSAVE = 1 + KEY_SSUSPEND = 1 + KEY_SUNDO = 1 + KEY_SUSPEND = 1 + KEY_UNDO = 1 + KEY_MOUSE = 1 + KEY_RESIZE = 1 + KEY_MAX = 1 + ACS_BBSS = 1 + ACS_BLOCK = 1 + ACS_BOARD = 1 + ACS_BSBS = 1 + ACS_BSSB = 1 + ACS_BSSS = 1 + ACS_BTEE = 1 + ACS_BULLET = 1 + ACS_CKBOARD = 1 + ACS_DARROW = 1 + ACS_DEGREE = 1 + ACS_DIAMOND = 1 + ACS_GEQUAL = 1 + ACS_HLINE = 1 + ACS_LANTERN = 1 + ACS_LARROW = 1 + ACS_LEQUAL = 1 + ACS_LLCORNER = 1 + ACS_LRCORNER = 1 + ACS_LTEE = 1 + ACS_NEQUAL = 1 + ACS_PI = 1 + ACS_PLMINUS = 1 + ACS_PLUS = 1 + ACS_RARROW = 1 + ACS_RTEE = 1 + ACS_S1 = 1 + ACS_S3 = 1 + ACS_S7 = 1 + ACS_S9 = 1 + ACS_SBBS = 1 + ACS_SBSB = 1 + ACS_SBSS = 1 + ACS_SSBB = 1 + ACS_SSBS = 1 + ACS_SSSB = 1 + ACS_SSSS = 1 + ACS_STERLING = 1 + ACS_TTEE = 1 + ACS_UARROW = 1 + ACS_ULCORNER = 1 + ACS_URCORNER = 1 + ACS_VLINE = 1 + COLOR_BLACK = 1 + COLOR_BLUE = 1 + COLOR_CYAN = 1 + COLOR_GREEN = 1 + COLOR_MAGENTA = 1 + COLOR_RED = 1 + COLOR_WHITE = 1 + COLOR_YELLOW = 1 + """ + ) + + +register_module_extender(AstroidManager(), "curses", _curses_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_dataclasses.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_dataclasses.py new file mode 100644 index 0000000..769d9ee --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_dataclasses.py @@ -0,0 +1,467 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Astroid hook for the dataclasses library + +Support built-in dataclasses, pydantic.dataclasses, and marshmallow_dataclass-annotated +dataclasses. References: +- https://docs.python.org/3/library/dataclasses.html +- https://pydantic-docs.helpmanual.io/usage/dataclasses/ +- https://lovasoa.github.io/marshmallow_dataclass/ + +""" +import sys +from typing import FrozenSet, Generator, List, Optional, Tuple, Union + +from astroid import context, inference_tip +from astroid.builder import parse +from astroid.const import PY37_PLUS, PY39_PLUS +from astroid.exceptions import ( + AstroidSyntaxError, + InferenceError, + MroError, + UseInferenceDefault, +) +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import ( + AnnAssign, + Assign, + AssignName, + Attribute, + Call, + Name, + NodeNG, + Subscript, + Unknown, +) +from astroid.nodes.scoped_nodes import ClassDef, FunctionDef +from astroid.util import Uninferable + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +_FieldDefaultReturn = Union[ + None, Tuple[Literal["default"], NodeNG], Tuple[Literal["default_factory"], Call] +] + +DATACLASSES_DECORATORS = frozenset(("dataclass",)) +FIELD_NAME = "field" +DATACLASS_MODULES = frozenset( + ("dataclasses", "marshmallow_dataclass", "pydantic.dataclasses") +) +DEFAULT_FACTORY = "_HAS_DEFAULT_FACTORY" # based on typing.py + + +def is_decorated_with_dataclass(node, decorator_names=DATACLASSES_DECORATORS): + """Return True if a decorated node has a `dataclass` decorator applied.""" + if not isinstance(node, ClassDef) or not node.decorators: + return False + + return any( + _looks_like_dataclass_decorator(decorator_attribute, decorator_names) + for decorator_attribute in node.decorators.nodes + ) + + +def dataclass_transform(node: ClassDef) -> None: + """Rewrite a dataclass to be easily understood by pylint""" + node.is_dataclass = True + + for assign_node in _get_dataclass_attributes(node): + name = assign_node.target.name + + rhs_node = Unknown( + lineno=assign_node.lineno, + col_offset=assign_node.col_offset, + parent=assign_node, + ) + rhs_node = AstroidManager().visit_transforms(rhs_node) + node.instance_attrs[name] = [rhs_node] + + if not _check_generate_dataclass_init(node): + return + + try: + reversed_mro = list(reversed(node.mro())) + except MroError: + reversed_mro = [node] + + field_assigns = {} + field_order = [] + for klass in (k for k in reversed_mro if is_decorated_with_dataclass(k)): + for assign_node in _get_dataclass_attributes(klass, init=True): + name = assign_node.target.name + if name not in field_assigns: + field_order.append(name) + field_assigns[name] = assign_node + + init_str = _generate_dataclass_init([field_assigns[name] for name in field_order]) + try: + init_node = parse(init_str)["__init__"] + except AstroidSyntaxError: + pass + else: + init_node.parent = node + init_node.lineno, init_node.col_offset = None, None + node.locals["__init__"] = [init_node] + + root = node.root() + if DEFAULT_FACTORY not in root.locals: + new_assign = parse(f"{DEFAULT_FACTORY} = object()").body[0] + new_assign.parent = root + root.locals[DEFAULT_FACTORY] = [new_assign.targets[0]] + + +def _get_dataclass_attributes(node: ClassDef, init: bool = False) -> Generator: + """Yield the AnnAssign nodes of dataclass attributes for the node. + + If init is True, also include InitVars, but exclude attributes from calls to + field where init=False. + """ + for assign_node in node.body: + if not isinstance(assign_node, AnnAssign) or not isinstance( + assign_node.target, AssignName + ): + continue + + if _is_class_var(assign_node.annotation): # type: ignore[arg-type] # annotation is never None + continue + + if init: + value = assign_node.value + if ( + isinstance(value, Call) + and _looks_like_dataclass_field_call(value, check_scope=False) + and any( + keyword.arg == "init" + and not keyword.value.bool_value() # type: ignore[union-attr] # value is never None + for keyword in value.keywords + ) + ): + continue + elif _is_init_var(assign_node.annotation): # type: ignore[arg-type] # annotation is never None + continue + + yield assign_node + + +def _check_generate_dataclass_init(node: ClassDef) -> bool: + """Return True if we should generate an __init__ method for node. + + This is True when: + - node doesn't define its own __init__ method + - the dataclass decorator was called *without* the keyword argument init=False + """ + if "__init__" in node.locals: + return False + + found = None + + for decorator_attribute in node.decorators.nodes: + if not isinstance(decorator_attribute, Call): + continue + + if _looks_like_dataclass_decorator(decorator_attribute): + found = decorator_attribute + + if found is None: + return True + + # Check for keyword arguments of the form init=False + return all( + keyword.arg != "init" + and keyword.value.bool_value() # type: ignore[union-attr] # value is never None + for keyword in found.keywords + ) + + +def _generate_dataclass_init(assigns: List[AnnAssign]) -> str: + """Return an init method for a dataclass given the targets.""" + target_names = [] + params = [] + assignments = [] + + for assign in assigns: + name, annotation, value = assign.target.name, assign.annotation, assign.value + target_names.append(name) + + if _is_init_var(annotation): # type: ignore[arg-type] # annotation is never None + init_var = True + if isinstance(annotation, Subscript): + annotation = annotation.slice + else: + # Cannot determine type annotation for parameter from InitVar + annotation = None + assignment_str = "" + else: + init_var = False + assignment_str = f"self.{name} = {name}" + + if annotation: + param_str = f"{name}: {annotation.as_string()}" + else: + param_str = name + + if value: + if isinstance(value, Call) and _looks_like_dataclass_field_call( + value, check_scope=False + ): + result = _get_field_default(value) + if result: + default_type, default_node = result + if default_type == "default": + param_str += f" = {default_node.as_string()}" + elif default_type == "default_factory": + param_str += f" = {DEFAULT_FACTORY}" + assignment_str = ( + f"self.{name} = {default_node.as_string()} " + f"if {name} is {DEFAULT_FACTORY} else {name}" + ) + else: + param_str += f" = {value.as_string()}" + + params.append(param_str) + if not init_var: + assignments.append(assignment_str) + + params_string = ", ".join(["self"] + params) + assignments_string = "\n ".join(assignments) if assignments else "pass" + return f"def __init__({params_string}) -> None:\n {assignments_string}" + + +def infer_dataclass_attribute( + node: Unknown, ctx: Optional[context.InferenceContext] = None +) -> Generator: + """Inference tip for an Unknown node that was dynamically generated to + represent a dataclass attribute. + + In the case that a default value is provided, that is inferred first. + Then, an Instance of the annotated class is yielded. + """ + assign = node.parent + if not isinstance(assign, AnnAssign): + yield Uninferable + return + + annotation, value = assign.annotation, assign.value + if value is not None: + yield from value.infer(context=ctx) + if annotation is not None: + yield from _infer_instance_from_annotation(annotation, ctx=ctx) + else: + yield Uninferable + + +def infer_dataclass_field_call( + node: Call, ctx: Optional[context.InferenceContext] = None +) -> Generator: + """Inference tip for dataclass field calls.""" + if not isinstance(node.parent, (AnnAssign, Assign)): + raise UseInferenceDefault + result = _get_field_default(node) + if not result: + yield Uninferable + else: + default_type, default = result + if default_type == "default": + yield from default.infer(context=ctx) + else: + new_call = parse(default.as_string()).body[0].value + new_call.parent = node.parent + yield from new_call.infer(context=ctx) + + +def _looks_like_dataclass_decorator( + node: NodeNG, decorator_names: FrozenSet[str] = DATACLASSES_DECORATORS +) -> bool: + """Return True if node looks like a dataclass decorator. + + Uses inference to lookup the value of the node, and if that fails, + matches against specific names. + """ + if isinstance(node, Call): # decorator with arguments + node = node.func + try: + inferred = next(node.infer()) + except (InferenceError, StopIteration): + inferred = Uninferable + + if inferred is Uninferable: + if isinstance(node, Name): + return node.name in decorator_names + if isinstance(node, Attribute): + return node.attrname in decorator_names + + return False + + return ( + isinstance(inferred, FunctionDef) + and inferred.name in decorator_names + and inferred.root().name in DATACLASS_MODULES + ) + + +def _looks_like_dataclass_attribute(node: Unknown) -> bool: + """Return True if node was dynamically generated as the child of an AnnAssign + statement. + """ + parent = node.parent + if not parent: + return False + + scope = parent.scope() + return ( + isinstance(parent, AnnAssign) + and isinstance(scope, ClassDef) + and is_decorated_with_dataclass(scope) + ) + + +def _looks_like_dataclass_field_call(node: Call, check_scope: bool = True) -> bool: + """Return True if node is calling dataclasses field or Field + from an AnnAssign statement directly in the body of a ClassDef. + + If check_scope is False, skips checking the statement and body. + """ + if check_scope: + stmt = node.statement(future=True) + scope = stmt.scope() + if not ( + isinstance(stmt, AnnAssign) + and stmt.value is not None + and isinstance(scope, ClassDef) + and is_decorated_with_dataclass(scope) + ): + return False + + try: + inferred = next(node.func.infer()) + except (InferenceError, StopIteration): + return False + + if not isinstance(inferred, FunctionDef): + return False + + return inferred.name == FIELD_NAME and inferred.root().name in DATACLASS_MODULES + + +def _get_field_default(field_call: Call) -> _FieldDefaultReturn: + """Return a the default value of a field call, and the corresponding keyword argument name. + + field(default=...) results in the ... node + field(default_factory=...) results in a Call node with func ... and no arguments + + If neither or both arguments are present, return ("", None) instead, + indicating that there is not a valid default value. + """ + default, default_factory = None, None + for keyword in field_call.keywords: + if keyword.arg == "default": + default = keyword.value + elif keyword.arg == "default_factory": + default_factory = keyword.value + + if default is not None and default_factory is None: + return "default", default + + if default is None and default_factory is not None: + new_call = Call( + lineno=field_call.lineno, + col_offset=field_call.col_offset, + parent=field_call.parent, + ) + new_call.postinit(func=default_factory) + return "default_factory", new_call + + return None + + +def _is_class_var(node: NodeNG) -> bool: + """Return True if node is a ClassVar, with or without subscripting.""" + if PY39_PLUS: + try: + inferred = next(node.infer()) + except (InferenceError, StopIteration): + return False + + return getattr(inferred, "name", "") == "ClassVar" + + # Before Python 3.9, inference returns typing._SpecialForm instead of ClassVar. + # Our backup is to inspect the node's structure. + return isinstance(node, Subscript) and ( + isinstance(node.value, Name) + and node.value.name == "ClassVar" + or isinstance(node.value, Attribute) + and node.value.attrname == "ClassVar" + ) + + +def _is_init_var(node: NodeNG) -> bool: + """Return True if node is an InitVar, with or without subscripting.""" + try: + inferred = next(node.infer()) + except (InferenceError, StopIteration): + return False + + return getattr(inferred, "name", "") == "InitVar" + + +# Allowed typing classes for which we support inferring instances +_INFERABLE_TYPING_TYPES = frozenset( + ( + "Dict", + "FrozenSet", + "List", + "Set", + "Tuple", + ) +) + + +def _infer_instance_from_annotation( + node: NodeNG, ctx: Optional[context.InferenceContext] = None +) -> Generator: + """Infer an instance corresponding to the type annotation represented by node. + + Currently has limited support for the typing module. + """ + klass = None + try: + klass = next(node.infer(context=ctx)) + except (InferenceError, StopIteration): + yield Uninferable + if not isinstance(klass, ClassDef): + yield Uninferable + elif klass.root().name in { + "typing", + "_collections_abc", + "", + }: # "" because of synthetic nodes in brain_typing.py + if klass.name in _INFERABLE_TYPING_TYPES: + yield klass.instantiate_class() + else: + yield Uninferable + else: + yield klass.instantiate_class() + + +if PY37_PLUS: + AstroidManager().register_transform( + ClassDef, dataclass_transform, is_decorated_with_dataclass + ) + + AstroidManager().register_transform( + Call, + inference_tip(infer_dataclass_field_call, raise_on_overwrite=True), + _looks_like_dataclass_field_call, + ) + + AstroidManager().register_transform( + Unknown, + inference_tip(infer_dataclass_attribute, raise_on_overwrite=True), + _looks_like_dataclass_attribute, + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_dateutil.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_dateutil.py new file mode 100644 index 0000000..0d27135 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_dateutil.py @@ -0,0 +1,26 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for dateutil""" + +import textwrap + +from astroid.brain.helpers import register_module_extender +from astroid.builder import AstroidBuilder +from astroid.manager import AstroidManager + + +def dateutil_transform(): + return AstroidBuilder(AstroidManager()).string_build( + textwrap.dedent( + """ + import datetime + def parse(timestr, parserinfo=None, **kwargs): + return datetime.datetime() + """ + ) + ) + + +register_module_extender(AstroidManager(), "dateutil.parser", dateutil_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_fstrings.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_fstrings.py new file mode 100644 index 0000000..db7dd95 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_fstrings.py @@ -0,0 +1,48 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import collections.abc + +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import FormattedValue + + +def _clone_node_with_lineno(node, parent, lineno): + cls = node.__class__ + other_fields = node._other_fields + _astroid_fields = node._astroid_fields + init_params = {"lineno": lineno, "col_offset": node.col_offset, "parent": parent} + postinit_params = {param: getattr(node, param) for param in _astroid_fields} + if other_fields: + init_params.update({param: getattr(node, param) for param in other_fields}) + new_node = cls(**init_params) + if hasattr(node, "postinit") and _astroid_fields: + for param, child in postinit_params.items(): + if child and not isinstance(child, collections.abc.Sequence): + cloned_child = _clone_node_with_lineno( + node=child, lineno=new_node.lineno, parent=new_node + ) + postinit_params[param] = cloned_child + new_node.postinit(**postinit_params) + return new_node + + +def _transform_formatted_value(node): # pylint: disable=inconsistent-return-statements + if node.value and node.value.lineno == 1: + if node.lineno != node.value.lineno: + new_node = FormattedValue( + lineno=node.lineno, col_offset=node.col_offset, parent=node.parent + ) + new_value = _clone_node_with_lineno( + node=node.value, lineno=node.lineno, parent=new_node + ) + new_node.postinit(value=new_value, format_spec=node.format_spec) + return new_node + + +# TODO: this fix tries to *patch* http://bugs.python.org/issue29051 +# The problem is that FormattedValue.value, which is a Name node, +# has wrong line numbers, usually 1. This creates problems for pylint, +# which expects correct line numbers for things such as message control. +AstroidManager().register_transform(FormattedValue, _transform_formatted_value) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_functools.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_functools.py new file mode 100644 index 0000000..63333dc --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_functools.py @@ -0,0 +1,159 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for understanding functools library module.""" +from functools import partial +from itertools import chain +from typing import Iterator, Optional + +from astroid import BoundMethod, arguments, extract_node, helpers, nodes, objects +from astroid.context import InferenceContext +from astroid.exceptions import InferenceError, UseInferenceDefault +from astroid.inference_tip import inference_tip +from astroid.interpreter import objectmodel +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import AssignName, Attribute, Call, Name +from astroid.nodes.scoped_nodes import FunctionDef +from astroid.util import Uninferable + +LRU_CACHE = "functools.lru_cache" + + +class LruWrappedModel(objectmodel.FunctionModel): + """Special attribute model for functions decorated with functools.lru_cache. + + The said decorators patches at decoration time some functions onto + the decorated function. + """ + + @property + def attr___wrapped__(self): + return self._instance + + @property + def attr_cache_info(self): + cache_info = extract_node( + """ + from functools import _CacheInfo + _CacheInfo(0, 0, 0, 0) + """ + ) + + class CacheInfoBoundMethod(BoundMethod): + def infer_call_result(self, caller, context=None): + yield helpers.safe_infer(cache_info) + + return CacheInfoBoundMethod(proxy=self._instance, bound=self._instance) + + @property + def attr_cache_clear(self): + node = extract_node("""def cache_clear(self): pass""") + return BoundMethod(proxy=node, bound=self._instance.parent.scope()) + + +def _transform_lru_cache(node, context=None) -> None: + # TODO: this is not ideal, since the node should be immutable, + # but due to https://github.com/PyCQA/astroid/issues/354, + # there's not much we can do now. + # Replacing the node would work partially, because, + # in pylint, the old node would still be available, leading + # to spurious false positives. + node.special_attributes = LruWrappedModel()(node) + + +def _functools_partial_inference( + node: nodes.Call, context: Optional[InferenceContext] = None +) -> Iterator[objects.PartialFunction]: + call = arguments.CallSite.from_call(node, context=context) + number_of_positional = len(call.positional_arguments) + if number_of_positional < 1: + raise UseInferenceDefault("functools.partial takes at least one argument") + if number_of_positional == 1 and not call.keyword_arguments: + raise UseInferenceDefault( + "functools.partial needs at least to have some filled arguments" + ) + + partial_function = call.positional_arguments[0] + try: + inferred_wrapped_function = next(partial_function.infer(context=context)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + if inferred_wrapped_function is Uninferable: + raise UseInferenceDefault("Cannot infer the wrapped function") + if not isinstance(inferred_wrapped_function, FunctionDef): + raise UseInferenceDefault("The wrapped function is not a function") + + # Determine if the passed keywords into the callsite are supported + # by the wrapped function. + if not inferred_wrapped_function.args: + function_parameters = [] + else: + function_parameters = chain( + inferred_wrapped_function.args.args or (), + inferred_wrapped_function.args.posonlyargs or (), + inferred_wrapped_function.args.kwonlyargs or (), + ) + parameter_names = { + param.name for param in function_parameters if isinstance(param, AssignName) + } + if set(call.keyword_arguments) - parameter_names: + raise UseInferenceDefault("wrapped function received unknown parameters") + + partial_function = objects.PartialFunction( + call, + name=inferred_wrapped_function.name, + lineno=inferred_wrapped_function.lineno, + col_offset=inferred_wrapped_function.col_offset, + parent=node.parent, + ) + partial_function.postinit( + args=inferred_wrapped_function.args, + body=inferred_wrapped_function.body, + decorators=inferred_wrapped_function.decorators, + returns=inferred_wrapped_function.returns, + type_comment_returns=inferred_wrapped_function.type_comment_returns, + type_comment_args=inferred_wrapped_function.type_comment_args, + doc_node=inferred_wrapped_function.doc_node, + ) + return iter((partial_function,)) + + +def _looks_like_lru_cache(node): + """Check if the given function node is decorated with lru_cache.""" + if not node.decorators: + return False + for decorator in node.decorators.nodes: + if not isinstance(decorator, Call): + continue + if _looks_like_functools_member(decorator, "lru_cache"): + return True + return False + + +def _looks_like_functools_member(node, member) -> bool: + """Check if the given Call node is a functools.partial call""" + if isinstance(node.func, Name): + return node.func.name == member + if isinstance(node.func, Attribute): + return ( + node.func.attrname == member + and isinstance(node.func.expr, Name) + and node.func.expr.name == "functools" + ) + return False + + +_looks_like_partial = partial(_looks_like_functools_member, member="partial") + + +AstroidManager().register_transform( + FunctionDef, _transform_lru_cache, _looks_like_lru_cache +) + + +AstroidManager().register_transform( + Call, + inference_tip(_functools_partial_inference), + _looks_like_partial, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_gi.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_gi.py new file mode 100644 index 0000000..5728e2d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_gi.py @@ -0,0 +1,250 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for the Python 2 GObject introspection bindings. + +Helps with understanding everything imported from 'gi.repository' +""" + +# pylint:disable=import-error,import-outside-toplevel + +import inspect +import itertools +import re +import sys +import warnings + +from astroid import nodes +from astroid.builder import AstroidBuilder +from astroid.exceptions import AstroidBuildingError +from astroid.manager import AstroidManager + +_inspected_modules = {} + +_identifier_re = r"^[A-Za-z_]\w*$" + +_special_methods = frozenset( + { + "__lt__", + "__le__", + "__eq__", + "__ne__", + "__ge__", + "__gt__", + "__iter__", + "__getitem__", + "__setitem__", + "__delitem__", + "__len__", + "__bool__", + "__nonzero__", + "__next__", + "__str__", + "__len__", + "__contains__", + "__enter__", + "__exit__", + "__repr__", + "__getattr__", + "__setattr__", + "__delattr__", + "__del__", + "__hash__", + } +) + + +def _gi_build_stub(parent): + """ + Inspect the passed module recursively and build stubs for functions, + classes, etc. + """ + classes = {} + functions = {} + constants = {} + methods = {} + for name in dir(parent): + if name.startswith("__") and name not in _special_methods: + continue + + # Check if this is a valid name in python + if not re.match(_identifier_re, name): + continue + + try: + obj = getattr(parent, name) + except Exception: # pylint: disable=broad-except + # gi.module.IntrospectionModule.__getattr__() can raise all kinds of things + # like ValueError, TypeError, NotImplementedError, RepositoryError, etc + continue + + if inspect.isclass(obj): + classes[name] = obj + elif inspect.isfunction(obj) or inspect.isbuiltin(obj): + functions[name] = obj + elif inspect.ismethod(obj) or inspect.ismethoddescriptor(obj): + methods[name] = obj + elif ( + str(obj).startswith(", ) + # Only accept function calls with two constant arguments + if len(node.args) != 2: + return False + + if not all(isinstance(arg, nodes.Const) for arg in node.args): + return False + + func = node.func + if isinstance(func, nodes.Attribute): + if func.attrname != "require_version": + return False + if isinstance(func.expr, nodes.Name) and func.expr.name == "gi": + return True + + return False + + if isinstance(func, nodes.Name): + return func.name == "require_version" + + return False + + +def _register_require_version(node): + # Load the gi.require_version locally + try: + import gi + + gi.require_version(node.args[0].value, node.args[1].value) + except Exception: # pylint:disable=broad-except + pass + + return node + + +AstroidManager().register_failed_import_hook(_import_gi_module) +AstroidManager().register_transform( + nodes.Call, _register_require_version, _looks_like_require_version +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_hashlib.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_hashlib.py new file mode 100644 index 0000000..b628361 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_hashlib.py @@ -0,0 +1,58 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.const import PY39_PLUS +from astroid.manager import AstroidManager + + +def _hashlib_transform(): + maybe_usedforsecurity = ", usedforsecurity=True" if PY39_PLUS else "" + signature = f"value=''{maybe_usedforsecurity}" + template = """ + class %(name)s(object): + def __init__(self, %(signature)s): pass + def digest(self): + return %(digest)s + def copy(self): + return self + def update(self, value): pass + def hexdigest(self): + return '' + @property + def name(self): + return %(name)r + @property + def block_size(self): + return 1 + @property + def digest_size(self): + return 1 + """ + algorithms_with_signature = dict.fromkeys( + ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"], signature + ) + blake2b_signature = f"data=b'', *, digest_size=64, key=b'', salt=b'', \ + person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, \ + node_depth=0, inner_size=0, last_node=False{maybe_usedforsecurity}" + blake2s_signature = f"data=b'', *, digest_size=32, key=b'', salt=b'', \ + person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, \ + node_depth=0, inner_size=0, last_node=False{maybe_usedforsecurity}" + new_algorithms = dict.fromkeys( + ["sha3_224", "sha3_256", "sha3_384", "sha3_512", "shake_128", "shake_256"], + signature, + ) + algorithms_with_signature.update(new_algorithms) + algorithms_with_signature.update( + {"blake2b": blake2b_signature, "blake2s": blake2s_signature} + ) + classes = "".join( + template % {"name": hashfunc, "digest": 'b""', "signature": signature} + for hashfunc, signature in algorithms_with_signature.items() + ) + return parse(classes) + + +register_module_extender(AstroidManager(), "hashlib", _hashlib_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_http.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_http.py new file mode 100644 index 0000000..acf07bd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_http.py @@ -0,0 +1,211 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid brain hints for some of the `http` module.""" +import textwrap + +from astroid.brain.helpers import register_module_extender +from astroid.builder import AstroidBuilder +from astroid.manager import AstroidManager + + +def _http_transform(): + code = textwrap.dedent( + """ + from collections import namedtuple + _HTTPStatus = namedtuple('_HTTPStatus', 'value phrase description') + + class HTTPStatus: + + @property + def phrase(self): + return "" + @property + def value(self): + return 0 + @property + def description(self): + return "" + + # informational + CONTINUE = _HTTPStatus(100, 'Continue', 'Request received, please continue') + SWITCHING_PROTOCOLS = _HTTPStatus(101, 'Switching Protocols', + 'Switching to new protocol; obey Upgrade header') + PROCESSING = _HTTPStatus(102, 'Processing', '') + OK = _HTTPStatus(200, 'OK', 'Request fulfilled, document follows') + CREATED = _HTTPStatus(201, 'Created', 'Document created, URL follows') + ACCEPTED = _HTTPStatus(202, 'Accepted', + 'Request accepted, processing continues off-line') + NON_AUTHORITATIVE_INFORMATION = _HTTPStatus(203, + 'Non-Authoritative Information', 'Request fulfilled from cache') + NO_CONTENT = _HTTPStatus(204, 'No Content', 'Request fulfilled, nothing follows') + RESET_CONTENT =_HTTPStatus(205, 'Reset Content', 'Clear input form for further input') + PARTIAL_CONTENT = _HTTPStatus(206, 'Partial Content', 'Partial content follows') + MULTI_STATUS = _HTTPStatus(207, 'Multi-Status', '') + ALREADY_REPORTED = _HTTPStatus(208, 'Already Reported', '') + IM_USED = _HTTPStatus(226, 'IM Used', '') + MULTIPLE_CHOICES = _HTTPStatus(300, 'Multiple Choices', + 'Object has several resources -- see URI list') + MOVED_PERMANENTLY = _HTTPStatus(301, 'Moved Permanently', + 'Object moved permanently -- see URI list') + FOUND = _HTTPStatus(302, 'Found', 'Object moved temporarily -- see URI list') + SEE_OTHER = _HTTPStatus(303, 'See Other', 'Object moved -- see Method and URL list') + NOT_MODIFIED = _HTTPStatus(304, 'Not Modified', + 'Document has not changed since given time') + USE_PROXY = _HTTPStatus(305, 'Use Proxy', + 'You must use proxy specified in Location to access this resource') + TEMPORARY_REDIRECT = _HTTPStatus(307, 'Temporary Redirect', + 'Object moved temporarily -- see URI list') + PERMANENT_REDIRECT = _HTTPStatus(308, 'Permanent Redirect', + 'Object moved permanently -- see URI list') + BAD_REQUEST = _HTTPStatus(400, 'Bad Request', + 'Bad request syntax or unsupported method') + UNAUTHORIZED = _HTTPStatus(401, 'Unauthorized', + 'No permission -- see authorization schemes') + PAYMENT_REQUIRED = _HTTPStatus(402, 'Payment Required', + 'No payment -- see charging schemes') + FORBIDDEN = _HTTPStatus(403, 'Forbidden', + 'Request forbidden -- authorization will not help') + NOT_FOUND = _HTTPStatus(404, 'Not Found', + 'Nothing matches the given URI') + METHOD_NOT_ALLOWED = _HTTPStatus(405, 'Method Not Allowed', + 'Specified method is invalid for this resource') + NOT_ACCEPTABLE = _HTTPStatus(406, 'Not Acceptable', + 'URI not available in preferred format') + PROXY_AUTHENTICATION_REQUIRED = _HTTPStatus(407, + 'Proxy Authentication Required', + 'You must authenticate with this proxy before proceeding') + REQUEST_TIMEOUT = _HTTPStatus(408, 'Request Timeout', + 'Request timed out; try again later') + CONFLICT = _HTTPStatus(409, 'Conflict', 'Request conflict') + GONE = _HTTPStatus(410, 'Gone', + 'URI no longer exists and has been permanently removed') + LENGTH_REQUIRED = _HTTPStatus(411, 'Length Required', + 'Client must specify Content-Length') + PRECONDITION_FAILED = _HTTPStatus(412, 'Precondition Failed', + 'Precondition in headers is false') + REQUEST_ENTITY_TOO_LARGE = _HTTPStatus(413, 'Request Entity Too Large', + 'Entity is too large') + REQUEST_URI_TOO_LONG = _HTTPStatus(414, 'Request-URI Too Long', + 'URI is too long') + UNSUPPORTED_MEDIA_TYPE = _HTTPStatus(415, 'Unsupported Media Type', + 'Entity body in unsupported format') + REQUESTED_RANGE_NOT_SATISFIABLE = _HTTPStatus(416, + 'Requested Range Not Satisfiable', + 'Cannot satisfy request range') + EXPECTATION_FAILED = _HTTPStatus(417, 'Expectation Failed', + 'Expect condition could not be satisfied') + MISDIRECTED_REQUEST = _HTTPStatus(421, 'Misdirected Request', + 'Server is not able to produce a response') + UNPROCESSABLE_ENTITY = _HTTPStatus(422, 'Unprocessable Entity') + LOCKED = _HTTPStatus(423, 'Locked') + FAILED_DEPENDENCY = _HTTPStatus(424, 'Failed Dependency') + UPGRADE_REQUIRED = _HTTPStatus(426, 'Upgrade Required') + PRECONDITION_REQUIRED = _HTTPStatus(428, 'Precondition Required', + 'The origin server requires the request to be conditional') + TOO_MANY_REQUESTS = _HTTPStatus(429, 'Too Many Requests', + 'The user has sent too many requests in ' + 'a given amount of time ("rate limiting")') + REQUEST_HEADER_FIELDS_TOO_LARGE = _HTTPStatus(431, + 'Request Header Fields Too Large', + 'The server is unwilling to process the request because its header ' + 'fields are too large') + UNAVAILABLE_FOR_LEGAL_REASONS = _HTTPStatus(451, + 'Unavailable For Legal Reasons', + 'The server is denying access to the ' + 'resource as a consequence of a legal demand') + INTERNAL_SERVER_ERROR = _HTTPStatus(500, 'Internal Server Error', + 'Server got itself in trouble') + NOT_IMPLEMENTED = _HTTPStatus(501, 'Not Implemented', + 'Server does not support this operation') + BAD_GATEWAY = _HTTPStatus(502, 'Bad Gateway', + 'Invalid responses from another server/proxy') + SERVICE_UNAVAILABLE = _HTTPStatus(503, 'Service Unavailable', + 'The server cannot process the request due to a high load') + GATEWAY_TIMEOUT = _HTTPStatus(504, 'Gateway Timeout', + 'The gateway server did not receive a timely response') + HTTP_VERSION_NOT_SUPPORTED = _HTTPStatus(505, 'HTTP Version Not Supported', + 'Cannot fulfill request') + VARIANT_ALSO_NEGOTIATES = _HTTPStatus(506, 'Variant Also Negotiates') + INSUFFICIENT_STORAGE = _HTTPStatus(507, 'Insufficient Storage') + LOOP_DETECTED = _HTTPStatus(508, 'Loop Detected') + NOT_EXTENDED = _HTTPStatus(510, 'Not Extended') + NETWORK_AUTHENTICATION_REQUIRED = _HTTPStatus(511, + 'Network Authentication Required', + 'The client needs to authenticate to gain network access') + """ + ) + return AstroidBuilder(AstroidManager()).string_build(code) + + +def _http_client_transform(): + return AstroidBuilder(AstroidManager()).string_build( + textwrap.dedent( + """ + from http import HTTPStatus + + CONTINUE = HTTPStatus.CONTINUE + SWITCHING_PROTOCOLS = HTTPStatus.SWITCHING_PROTOCOLS + PROCESSING = HTTPStatus.PROCESSING + OK = HTTPStatus.OK + CREATED = HTTPStatus.CREATED + ACCEPTED = HTTPStatus.ACCEPTED + NON_AUTHORITATIVE_INFORMATION = HTTPStatus.NON_AUTHORITATIVE_INFORMATION + NO_CONTENT = HTTPStatus.NO_CONTENT + RESET_CONTENT = HTTPStatus.RESET_CONTENT + PARTIAL_CONTENT = HTTPStatus.PARTIAL_CONTENT + MULTI_STATUS = HTTPStatus.MULTI_STATUS + ALREADY_REPORTED = HTTPStatus.ALREADY_REPORTED + IM_USED = HTTPStatus.IM_USED + MULTIPLE_CHOICES = HTTPStatus.MULTIPLE_CHOICES + MOVED_PERMANENTLY = HTTPStatus.MOVED_PERMANENTLY + FOUND = HTTPStatus.FOUND + SEE_OTHER = HTTPStatus.SEE_OTHER + NOT_MODIFIED = HTTPStatus.NOT_MODIFIED + USE_PROXY = HTTPStatus.USE_PROXY + TEMPORARY_REDIRECT = HTTPStatus.TEMPORARY_REDIRECT + PERMANENT_REDIRECT = HTTPStatus.PERMANENT_REDIRECT + BAD_REQUEST = HTTPStatus.BAD_REQUEST + UNAUTHORIZED = HTTPStatus.UNAUTHORIZED + PAYMENT_REQUIRED = HTTPStatus.PAYMENT_REQUIRED + FORBIDDEN = HTTPStatus.FORBIDDEN + NOT_FOUND = HTTPStatus.NOT_FOUND + METHOD_NOT_ALLOWED = HTTPStatus.METHOD_NOT_ALLOWED + NOT_ACCEPTABLE = HTTPStatus.NOT_ACCEPTABLE + PROXY_AUTHENTICATION_REQUIRED = HTTPStatus.PROXY_AUTHENTICATION_REQUIRED + REQUEST_TIMEOUT = HTTPStatus.REQUEST_TIMEOUT + CONFLICT = HTTPStatus.CONFLICT + GONE = HTTPStatus.GONE + LENGTH_REQUIRED = HTTPStatus.LENGTH_REQUIRED + PRECONDITION_FAILED = HTTPStatus.PRECONDITION_FAILED + REQUEST_ENTITY_TOO_LARGE = HTTPStatus.REQUEST_ENTITY_TOO_LARGE + REQUEST_URI_TOO_LONG = HTTPStatus.REQUEST_URI_TOO_LONG + UNSUPPORTED_MEDIA_TYPE = HTTPStatus.UNSUPPORTED_MEDIA_TYPE + REQUESTED_RANGE_NOT_SATISFIABLE = HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE + EXPECTATION_FAILED = HTTPStatus.EXPECTATION_FAILED + UNPROCESSABLE_ENTITY = HTTPStatus.UNPROCESSABLE_ENTITY + LOCKED = HTTPStatus.LOCKED + FAILED_DEPENDENCY = HTTPStatus.FAILED_DEPENDENCY + UPGRADE_REQUIRED = HTTPStatus.UPGRADE_REQUIRED + PRECONDITION_REQUIRED = HTTPStatus.PRECONDITION_REQUIRED + TOO_MANY_REQUESTS = HTTPStatus.TOO_MANY_REQUESTS + REQUEST_HEADER_FIELDS_TOO_LARGE = HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE + INTERNAL_SERVER_ERROR = HTTPStatus.INTERNAL_SERVER_ERROR + NOT_IMPLEMENTED = HTTPStatus.NOT_IMPLEMENTED + BAD_GATEWAY = HTTPStatus.BAD_GATEWAY + SERVICE_UNAVAILABLE = HTTPStatus.SERVICE_UNAVAILABLE + GATEWAY_TIMEOUT = HTTPStatus.GATEWAY_TIMEOUT + HTTP_VERSION_NOT_SUPPORTED = HTTPStatus.HTTP_VERSION_NOT_SUPPORTED + VARIANT_ALSO_NEGOTIATES = HTTPStatus.VARIANT_ALSO_NEGOTIATES + INSUFFICIENT_STORAGE = HTTPStatus.INSUFFICIENT_STORAGE + LOOP_DETECTED = HTTPStatus.LOOP_DETECTED + NOT_EXTENDED = HTTPStatus.NOT_EXTENDED + NETWORK_AUTHENTICATION_REQUIRED = HTTPStatus.NETWORK_AUTHENTICATION_REQUIRED + """ + ) + ) + + +register_module_extender(AstroidManager(), "http", _http_transform) +register_module_extender(AstroidManager(), "http.client", _http_client_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_hypothesis.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_hypothesis.py new file mode 100644 index 0000000..dae8361 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_hypothesis.py @@ -0,0 +1,55 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Astroid hook for the Hypothesis library. + +Without this hook pylint reports no-value-for-parameter for use of strategies +defined using the `@hypothesis.strategies.composite` decorator. For example: + + from hypothesis import strategies as st + + @st.composite + def a_strategy(draw): + return draw(st.integers()) + + a_strategy() + +""" +from astroid.manager import AstroidManager +from astroid.nodes.scoped_nodes import FunctionDef + +COMPOSITE_NAMES = ( + "composite", + "st.composite", + "strategies.composite", + "hypothesis.strategies.composite", +) + + +def is_decorated_with_st_composite(node): + """Return True if a decorated node has @st.composite applied.""" + if node.decorators and node.args.args and node.args.args[0].name == "draw": + for decorator_attribute in node.decorators.nodes: + if decorator_attribute.as_string() in COMPOSITE_NAMES: + return True + return False + + +def remove_draw_parameter_from_composite_strategy(node): + """Given that the FunctionDef is decorated with @st.composite, remove the + first argument (`draw`) - it's always supplied by Hypothesis so we don't + need to emit the no-value-for-parameter lint. + """ + del node.args.args[0] + del node.args.annotations[0] + del node.args.type_comment_args[0] + return node + + +AstroidManager().register_transform( + node_class=FunctionDef, + transform=remove_draw_parameter_from_composite_strategy, + predicate=is_decorated_with_st_composite, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_io.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_io.py new file mode 100644 index 0000000..9957ce9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_io.py @@ -0,0 +1,41 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid brain hints for some of the _io C objects.""" +from astroid.manager import AstroidManager +from astroid.nodes import ClassDef + +BUFFERED = {"BufferedWriter", "BufferedReader"} +TextIOWrapper = "TextIOWrapper" +FileIO = "FileIO" +BufferedWriter = "BufferedWriter" + + +def _generic_io_transform(node, name, cls): + """Transform the given name, by adding the given *class* as a member of the node.""" + + io_module = AstroidManager().ast_from_module_name("_io") + attribute_object = io_module[cls] + instance = attribute_object.instantiate_class() + node.locals[name] = [instance] + + +def _transform_text_io_wrapper(node): + # This is not always correct, since it can vary with the type of the descriptor, + # being stdout, stderr or stdin. But we cannot get access to the name of the + # stream, which is why we are using the BufferedWriter class as a default + # value + return _generic_io_transform(node, name="buffer", cls=BufferedWriter) + + +def _transform_buffered(node): + return _generic_io_transform(node, name="raw", cls=FileIO) + + +AstroidManager().register_transform( + ClassDef, _transform_buffered, lambda node: node.name in BUFFERED +) +AstroidManager().register_transform( + ClassDef, _transform_text_io_wrapper, lambda node: node.name == TextIOWrapper +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_mechanize.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_mechanize.py new file mode 100644 index 0000000..4c86fd9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_mechanize.py @@ -0,0 +1,83 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.brain.helpers import register_module_extender +from astroid.builder import AstroidBuilder +from astroid.manager import AstroidManager + + +def mechanize_transform(): + return AstroidBuilder(AstroidManager()).string_build( + """ + +class Browser(object): + def __getattr__(self, name): + return None + def __getitem__(self, name): + return None + def __setitem__(self, name, val): + return None + def back(self, n=1): + return None + def clear_history(self): + return None + def click(self, *args, **kwds): + return None + def click_link(self, link=None, **kwds): + return None + def close(self): + return None + def encoding(self): + return None + def find_link(self, text=None, text_regex=None, name=None, name_regex=None, url=None, url_regex=None, tag=None, predicate=None, nr=0): + return None + def follow_link(self, link=None, **kwds): + return None + def forms(self): + return None + def geturl(self): + return None + def global_form(self): + return None + def links(self, **kwds): + return None + def open_local_file(self, filename): + return None + def open(self, url, data=None, timeout=None): + return None + def open_novisit(self, url, data=None, timeout=None): + return None + def open_local_file(self, filename): + return None + def reload(self): + return None + def response(self): + return None + def select_form(self, name=None, predicate=None, nr=None, **attrs): + return None + def set_cookie(self, cookie_string): + return None + def set_handle_referer(self, handle): + return None + def set_header(self, header, value=None): + return None + def set_html(self, html, url="http://example.com/"): + return None + def set_response(self, response): + return None + def set_simple_cookie(self, name, value, domain, path='/'): + return None + def submit(self, *args, **kwds): + return None + def title(self): + return None + def viewing_html(self): + return None + def visit_response(self, response, request=None): + return None +""" + ) + + +register_module_extender(AstroidManager(), "mechanize", mechanize_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_multiprocessing.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_multiprocessing.py new file mode 100644 index 0000000..fc98a06 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_multiprocessing.py @@ -0,0 +1,106 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.bases import BoundMethod +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.exceptions import InferenceError +from astroid.manager import AstroidManager +from astroid.nodes.scoped_nodes import FunctionDef + + +def _multiprocessing_transform(): + module = parse( + """ + from multiprocessing.managers import SyncManager + def Manager(): + return SyncManager() + """ + ) + # Multiprocessing uses a getattr lookup inside contexts, + # in order to get the attributes they need. Since it's extremely + # dynamic, we use this approach to fake it. + node = parse( + """ + from multiprocessing.context import DefaultContext, BaseContext + default = DefaultContext() + base = BaseContext() + """ + ) + try: + context = next(node["default"].infer()) + base = next(node["base"].infer()) + except (InferenceError, StopIteration): + return module + + for node in (context, base): + for key, value in node.locals.items(): + if key.startswith("_"): + continue + + value = value[0] + if isinstance(value, FunctionDef): + # We need to rebound this, since otherwise + # it will have an extra argument (self). + value = BoundMethod(value, node) + module[key] = value + return module + + +def _multiprocessing_managers_transform(): + return parse( + """ + import array + import threading + import multiprocessing.pool as pool + import queue + + class Namespace(object): + pass + + class Value(object): + def __init__(self, typecode, value, lock=True): + self._typecode = typecode + self._value = value + def get(self): + return self._value + def set(self, value): + self._value = value + def __repr__(self): + return '%s(%r, %r)'%(type(self).__name__, self._typecode, self._value) + value = property(get, set) + + def Array(typecode, sequence, lock=True): + return array.array(typecode, sequence) + + class SyncManager(object): + Queue = JoinableQueue = queue.Queue + Event = threading.Event + RLock = threading.RLock + BoundedSemaphore = threading.BoundedSemaphore + Condition = threading.Condition + Barrier = threading.Barrier + Pool = pool.Pool + list = list + dict = dict + Value = Value + Array = Array + Namespace = Namespace + __enter__ = lambda self: self + __exit__ = lambda *args: args + + def start(self, initializer=None, initargs=None): + pass + def shutdown(self): + pass + """ + ) + + +register_module_extender( + AstroidManager(), "multiprocessing.managers", _multiprocessing_managers_transform +) +register_module_extender( + AstroidManager(), "multiprocessing", _multiprocessing_transform +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_namedtuple_enum.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_namedtuple_enum.py new file mode 100644 index 0000000..dbd9667 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_namedtuple_enum.py @@ -0,0 +1,574 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for the Python standard library.""" + +import functools +import keyword +from textwrap import dedent +from typing import Iterator, List, Optional, Tuple + +import astroid +from astroid import arguments, inference_tip, nodes, util +from astroid.builder import AstroidBuilder, extract_node +from astroid.context import InferenceContext +from astroid.exceptions import ( + AstroidTypeError, + AstroidValueError, + InferenceError, + MroError, + UseInferenceDefault, +) +from astroid.manager import AstroidManager + +TYPING_NAMEDTUPLE_BASENAMES = {"NamedTuple", "typing.NamedTuple"} +ENUM_BASE_NAMES = { + "Enum", + "IntEnum", + "enum.Enum", + "enum.IntEnum", + "IntFlag", + "enum.IntFlag", +} + + +def _infer_first(node, context): + if node is util.Uninferable: + raise UseInferenceDefault + try: + value = next(node.infer(context=context)) + except StopIteration as exc: + raise InferenceError from exc + if value is util.Uninferable: + raise UseInferenceDefault() + return value + + +def _find_func_form_arguments(node, context): + def _extract_namedtuple_arg_or_keyword( # pylint: disable=inconsistent-return-statements + position, key_name=None + ): + if len(args) > position: + return _infer_first(args[position], context) + if key_name and key_name in found_keywords: + return _infer_first(found_keywords[key_name], context) + + args = node.args + keywords = node.keywords + found_keywords = ( + {keyword.arg: keyword.value for keyword in keywords} if keywords else {} + ) + + name = _extract_namedtuple_arg_or_keyword(position=0, key_name="typename") + names = _extract_namedtuple_arg_or_keyword(position=1, key_name="field_names") + if name and names: + return name.value, names + + raise UseInferenceDefault() + + +def infer_func_form( + node: nodes.Call, + base_type: nodes.NodeNG, + context: Optional[InferenceContext] = None, + enum: bool = False, +) -> Tuple[nodes.ClassDef, str, List[str]]: + """Specific inference function for namedtuple or Python 3 enum.""" + # node is a Call node, class name as first argument and generated class + # attributes as second argument + + # namedtuple or enums list of attributes can be a list of strings or a + # whitespace-separate string + try: + name, names = _find_func_form_arguments(node, context) + try: + attributes = names.value.replace(",", " ").split() + except AttributeError as exc: + # Handle attributes of NamedTuples + if not enum: + attributes = [ + _infer_first(const, context).value for const in names.elts + ] + + # Handle attributes of Enums + else: + # Enums supports either iterator of (name, value) pairs + # or mappings. + if hasattr(names, "items") and isinstance(names.items, list): + attributes = [ + _infer_first(const[0], context).value + for const in names.items + if isinstance(const[0], nodes.Const) + ] + elif hasattr(names, "elts"): + # Enums can support either ["a", "b", "c"] + # or [("a", 1), ("b", 2), ...], but they can't + # be mixed. + if all(isinstance(const, nodes.Tuple) for const in names.elts): + attributes = [ + _infer_first(const.elts[0], context).value + for const in names.elts + if isinstance(const, nodes.Tuple) + ] + else: + attributes = [ + _infer_first(const, context).value for const in names.elts + ] + else: + raise AttributeError from exc + if not attributes: + raise AttributeError from exc + except (AttributeError, InferenceError) as exc: + raise UseInferenceDefault from exc + + if not enum: + # namedtuple maps sys.intern(str()) over over field_names + attributes = [str(attr) for attr in attributes] + # XXX this should succeed *unless* __str__/__repr__ is incorrect or throws + # in which case we should not have inferred these values and raised earlier + attributes = [attr for attr in attributes if " " not in attr] + + # If we can't infer the name of the class, don't crash, up to this point + # we know it is a namedtuple anyway. + name = name or "Uninferable" + # we want to return a Class node instance with proper attributes set + class_node = nodes.ClassDef(name) + # A typical ClassDef automatically adds its name to the parent scope, + # but doing so causes problems, so defer setting parent until after init + # see: https://github.com/PyCQA/pylint/issues/5982 + class_node.parent = node.parent + class_node.postinit( + # set base class=tuple + bases=[base_type], + body=[], + decorators=None, + ) + # XXX add __init__(*attributes) method + for attr in attributes: + fake_node = nodes.EmptyNode() + fake_node.parent = class_node + fake_node.attrname = attr + class_node.instance_attrs[attr] = [fake_node] + return class_node, name, attributes + + +def _has_namedtuple_base(node): + """Predicate for class inference tip + + :type node: ClassDef + :rtype: bool + """ + return set(node.basenames) & TYPING_NAMEDTUPLE_BASENAMES + + +def _looks_like(node, name): + func = node.func + if isinstance(func, nodes.Attribute): + return func.attrname == name + if isinstance(func, nodes.Name): + return func.name == name + return False + + +_looks_like_namedtuple = functools.partial(_looks_like, name="namedtuple") +_looks_like_enum = functools.partial(_looks_like, name="Enum") +_looks_like_typing_namedtuple = functools.partial(_looks_like, name="NamedTuple") + + +def infer_named_tuple( + node: nodes.Call, context: Optional[InferenceContext] = None +) -> Iterator[nodes.ClassDef]: + """Specific inference function for namedtuple Call node""" + tuple_base_name = nodes.Name(name="tuple", parent=node.root()) + class_node, name, attributes = infer_func_form( + node, tuple_base_name, context=context + ) + call_site = arguments.CallSite.from_call(node, context=context) + node = extract_node("import collections; collections.namedtuple") + try: + + func = next(node.infer()) + except StopIteration as e: + raise InferenceError(node=node) from e + try: + rename = next(call_site.infer_argument(func, "rename", context)).bool_value() + except (InferenceError, StopIteration): + rename = False + + try: + attributes = _check_namedtuple_attributes(name, attributes, rename) + except AstroidTypeError as exc: + raise UseInferenceDefault("TypeError: " + str(exc)) from exc + except AstroidValueError as exc: + raise UseInferenceDefault("ValueError: " + str(exc)) from exc + + replace_args = ", ".join(f"{arg}=None" for arg in attributes) + field_def = ( + " {name} = property(lambda self: self[{index:d}], " + "doc='Alias for field number {index:d}')" + ) + field_defs = "\n".join( + field_def.format(name=name, index=index) + for index, name in enumerate(attributes) + ) + fake = AstroidBuilder(AstroidManager()).string_build( + f""" +class {name}(tuple): + __slots__ = () + _fields = {attributes!r} + def _asdict(self): + return self.__dict__ + @classmethod + def _make(cls, iterable, new=tuple.__new__, len=len): + return new(cls, iterable) + def _replace(self, {replace_args}): + return self + def __getnewargs__(self): + return tuple(self) +{field_defs} + """ + ) + class_node.locals["_asdict"] = fake.body[0].locals["_asdict"] + class_node.locals["_make"] = fake.body[0].locals["_make"] + class_node.locals["_replace"] = fake.body[0].locals["_replace"] + class_node.locals["_fields"] = fake.body[0].locals["_fields"] + for attr in attributes: + class_node.locals[attr] = fake.body[0].locals[attr] + # we use UseInferenceDefault, we can't be a generator so return an iterator + return iter([class_node]) + + +def _get_renamed_namedtuple_attributes(field_names): + names = list(field_names) + seen = set() + for i, name in enumerate(field_names): + if ( + not all(c.isalnum() or c == "_" for c in name) + or keyword.iskeyword(name) + or not name + or name[0].isdigit() + or name.startswith("_") + or name in seen + ): + names[i] = "_%d" % i + seen.add(name) + return tuple(names) + + +def _check_namedtuple_attributes(typename, attributes, rename=False): + attributes = tuple(attributes) + if rename: + attributes = _get_renamed_namedtuple_attributes(attributes) + + # The following snippet is derived from the CPython Lib/collections/__init__.py sources + # + for name in (typename,) + attributes: + if not isinstance(name, str): + raise AstroidTypeError("Type names and field names must be strings") + if not name.isidentifier(): + raise AstroidValueError( + "Type names and field names must be valid" + f"identifiers: {name!r}" + ) + if keyword.iskeyword(name): + raise AstroidValueError( + f"Type names and field names cannot be a keyword: {name!r}" + ) + + seen = set() + for name in attributes: + if name.startswith("_") and not rename: + raise AstroidValueError( + f"Field names cannot start with an underscore: {name!r}" + ) + if name in seen: + raise AstroidValueError(f"Encountered duplicate field name: {name!r}") + seen.add(name) + # + + return attributes + + +def infer_enum(node, context=None): + """Specific inference function for enum Call node.""" + enum_meta = extract_node( + """ + class EnumMeta(object): + 'docstring' + def __call__(self, node): + class EnumAttribute(object): + name = '' + value = 0 + return EnumAttribute() + def __iter__(self): + class EnumAttribute(object): + name = '' + value = 0 + return [EnumAttribute()] + def __reversed__(self): + class EnumAttribute(object): + name = '' + value = 0 + return (EnumAttribute, ) + def __next__(self): + return next(iter(self)) + def __getitem__(self, attr): + class Value(object): + @property + def name(self): + return '' + @property + def value(self): + return attr + + return Value() + __members__ = [''] + """ + ) + class_node = infer_func_form(node, enum_meta, context=context, enum=True)[0] + return iter([class_node.instantiate_class()]) + + +INT_FLAG_ADDITION_METHODS = """ + def __or__(self, other): + return {name}(self.value | other.value) + def __and__(self, other): + return {name}(self.value & other.value) + def __xor__(self, other): + return {name}(self.value ^ other.value) + def __add__(self, other): + return {name}(self.value + other.value) + def __div__(self, other): + return {name}(self.value / other.value) + def __invert__(self): + return {name}(~self.value) + def __mul__(self, other): + return {name}(self.value * other.value) +""" + + +def infer_enum_class(node): + """Specific inference for enums.""" + for basename in (b for cls in node.mro() for b in cls.basenames): + if basename not in ENUM_BASE_NAMES: + continue + if node.root().name == "enum": + # Skip if the class is directly from enum module. + break + dunder_members = {} + target_names = set() + for local, values in node.locals.items(): + if any(not isinstance(value, nodes.AssignName) for value in values): + continue + + stmt = values[0].statement(future=True) + if isinstance(stmt, nodes.Assign): + if isinstance(stmt.targets[0], nodes.Tuple): + targets = stmt.targets[0].itered() + else: + targets = stmt.targets + elif isinstance(stmt, nodes.AnnAssign): + targets = [stmt.target] + else: + continue + + inferred_return_value = None + if isinstance(stmt, nodes.Assign): + if isinstance(stmt.value, nodes.Const): + if isinstance(stmt.value.value, str): + inferred_return_value = repr(stmt.value.value) + else: + inferred_return_value = stmt.value.value + else: + inferred_return_value = stmt.value.as_string() + + new_targets = [] + for target in targets: + if isinstance(target, nodes.Starred): + continue + target_names.add(target.name) + # Replace all the assignments with our mocked class. + classdef = dedent( + """ + class {name}({types}): + @property + def value(self): + return {return_value} + @property + def name(self): + return "{name}" + """.format( + name=target.name, + types=", ".join(node.basenames), + return_value=inferred_return_value, + ) + ) + if "IntFlag" in basename: + # Alright, we need to add some additional methods. + # Unfortunately we still can't infer the resulting objects as + # Enum members, but once we'll be able to do that, the following + # should result in some nice symbolic execution + classdef += INT_FLAG_ADDITION_METHODS.format(name=target.name) + + fake = AstroidBuilder( + AstroidManager(), apply_transforms=False + ).string_build(classdef)[target.name] + fake.parent = target.parent + for method in node.mymethods(): + fake.locals[method.name] = [method] + new_targets.append(fake.instantiate_class()) + dunder_members[local] = fake + node.locals[local] = new_targets + members = nodes.Dict(parent=node) + members.postinit( + [ + (nodes.Const(k, parent=members), nodes.Name(v.name, parent=members)) + for k, v in dunder_members.items() + ] + ) + node.locals["__members__"] = [members] + # The enum.Enum class itself defines two @DynamicClassAttribute data-descriptors + # "name" and "value" (which we override in the mocked class for each enum member + # above). When dealing with inference of an arbitrary instance of the enum + # class, e.g. in a method defined in the class body like: + # class SomeEnum(enum.Enum): + # def method(self): + # self.name # <- here + # In the absence of an enum member called "name" or "value", these attributes + # should resolve to the descriptor on that particular instance, i.e. enum member. + # For "value", we have no idea what that should be, but for "name", we at least + # know that it should be a string, so infer that as a guess. + if "name" not in target_names: + code = dedent( + """ + @property + def name(self): + return '' + """ + ) + name_dynamicclassattr = AstroidBuilder(AstroidManager()).string_build(code)[ + "name" + ] + node.locals["name"] = [name_dynamicclassattr] + break + return node + + +def infer_typing_namedtuple_class(class_node, context=None): + """Infer a subclass of typing.NamedTuple""" + # Check if it has the corresponding bases + annassigns_fields = [ + annassign.target.name + for annassign in class_node.body + if isinstance(annassign, nodes.AnnAssign) + ] + code = dedent( + """ + from collections import namedtuple + namedtuple({typename!r}, {fields!r}) + """ + ).format(typename=class_node.name, fields=",".join(annassigns_fields)) + node = extract_node(code) + try: + generated_class_node = next(infer_named_tuple(node, context)) + except StopIteration as e: + raise InferenceError(node=node, context=context) from e + for method in class_node.mymethods(): + generated_class_node.locals[method.name] = [method] + + for body_node in class_node.body: + if isinstance(body_node, nodes.Assign): + for target in body_node.targets: + attr = target.name + generated_class_node.locals[attr] = class_node.locals[attr] + elif isinstance(body_node, nodes.ClassDef): + generated_class_node.locals[body_node.name] = [body_node] + + return iter((generated_class_node,)) + + +def infer_typing_namedtuple_function(node, context=None): + """ + Starting with python3.9, NamedTuple is a function of the typing module. + The class NamedTuple is build dynamically through a call to `type` during + initialization of the `_NamedTuple` variable. + """ + klass = extract_node( + """ + from typing import _NamedTuple + _NamedTuple + """ + ) + return klass.infer(context) + + +def infer_typing_namedtuple( + node: nodes.Call, context: Optional[InferenceContext] = None +) -> Iterator[nodes.ClassDef]: + """Infer a typing.NamedTuple(...) call.""" + # This is essentially a namedtuple with different arguments + # so we extract the args and infer a named tuple. + try: + func = next(node.func.infer()) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + + if func.qname() != "typing.NamedTuple": + raise UseInferenceDefault + + if len(node.args) != 2: + raise UseInferenceDefault + + if not isinstance(node.args[1], (nodes.List, nodes.Tuple)): + raise UseInferenceDefault + + names = [] + for elt in node.args[1].elts: + if not isinstance(elt, (nodes.List, nodes.Tuple)): + raise UseInferenceDefault + if len(elt.elts) != 2: + raise UseInferenceDefault + names.append(elt.elts[0].as_string()) + + typename = node.args[0].as_string() + if names: + field_names = f"({','.join(names)},)" + else: + field_names = "''" + node = extract_node(f"namedtuple({typename}, {field_names})") + return infer_named_tuple(node, context) + + +def _is_enum_subclass(cls: astroid.ClassDef) -> bool: + """Return whether cls is a subclass of an Enum.""" + try: + return any( + klass.name in ENUM_BASE_NAMES + and getattr(klass.root(), "name", None) == "enum" + for klass in cls.mro() + ) + except MroError: + return False + + +AstroidManager().register_transform( + nodes.Call, inference_tip(infer_named_tuple), _looks_like_namedtuple +) +AstroidManager().register_transform( + nodes.Call, inference_tip(infer_enum), _looks_like_enum +) +AstroidManager().register_transform( + nodes.ClassDef, infer_enum_class, predicate=_is_enum_subclass +) +AstroidManager().register_transform( + nodes.ClassDef, inference_tip(infer_typing_namedtuple_class), _has_namedtuple_base +) +AstroidManager().register_transform( + nodes.FunctionDef, + inference_tip(infer_typing_namedtuple_function), + lambda node: node.name == "NamedTuple" + and getattr(node.root(), "name", None) == "typing", +) +AstroidManager().register_transform( + nodes.Call, inference_tip(infer_typing_namedtuple), _looks_like_typing_namedtuple +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_nose.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_nose.py new file mode 100644 index 0000000..38e2229 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_nose.py @@ -0,0 +1,79 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Hooks for nose library.""" + +import re +import textwrap + +import astroid.builder +from astroid.brain.helpers import register_module_extender +from astroid.exceptions import InferenceError +from astroid.manager import AstroidManager + +_BUILDER = astroid.builder.AstroidBuilder(AstroidManager()) + + +CAPITALS = re.compile("([A-Z])") + + +def _pep8(name, caps=CAPITALS): + return caps.sub(lambda m: "_" + m.groups()[0].lower(), name) + + +def _nose_tools_functions(): + """Get an iterator of names and bound methods.""" + module = _BUILDER.string_build( + textwrap.dedent( + """ + import unittest + + class Test(unittest.TestCase): + pass + a = Test() + """ + ) + ) + try: + case = next(module["a"].infer()) + except (InferenceError, StopIteration): + return + for method in case.methods(): + if method.name.startswith("assert") and "_" not in method.name: + pep8_name = _pep8(method.name) + yield pep8_name, astroid.BoundMethod(method, case) + if method.name == "assertEqual": + # nose also exports assert_equals. + yield "assert_equals", astroid.BoundMethod(method, case) + + +def _nose_tools_transform(node): + for method_name, method in _nose_tools_functions(): + node.locals[method_name] = [method] + + +def _nose_tools_trivial_transform(): + """Custom transform for the nose.tools module.""" + stub = _BUILDER.string_build("""__all__ = []""") + all_entries = ["ok_", "eq_"] + + for pep8_name, method in _nose_tools_functions(): + all_entries.append(pep8_name) + stub[pep8_name] = method + + # Update the __all__ variable, since nose.tools + # does this manually with .append. + all_assign = stub["__all__"].parent + all_object = astroid.List(all_entries) + all_object.parent = all_assign + all_assign.value = all_object + return stub + + +register_module_extender( + AstroidManager(), "nose.tools.trivial", _nose_tools_trivial_transform +) +AstroidManager().register_transform( + astroid.Module, _nose_tools_transform, lambda n: n.name == "nose.tools" +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_fromnumeric.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_fromnumeric.py new file mode 100644 index 0000000..19d4822 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_fromnumeric.py @@ -0,0 +1,22 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for numpy.core.fromnumeric module.""" +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def numpy_core_fromnumeric_transform(): + return parse( + """ + def sum(a, axis=None, dtype=None, out=None, keepdims=None, initial=None): + return numpy.ndarray([0, 0]) + """ + ) + + +register_module_extender( + AstroidManager(), "numpy.core.fromnumeric", numpy_core_fromnumeric_transform +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_function_base.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_function_base.py new file mode 100644 index 0000000..31d53cb --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_function_base.py @@ -0,0 +1,29 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for numpy.core.function_base module.""" + +import functools + +from astroid.brain.brain_numpy_utils import infer_numpy_member, looks_like_numpy_member +from astroid.inference_tip import inference_tip +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import Attribute + +METHODS_TO_BE_INFERRED = { + "linspace": """def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): + return numpy.ndarray([0, 0])""", + "logspace": """def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0): + return numpy.ndarray([0, 0])""", + "geomspace": """def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0): + return numpy.ndarray([0, 0])""", +} + +for func_name, func_src in METHODS_TO_BE_INFERRED.items(): + inference_function = functools.partial(infer_numpy_member, func_src) + AstroidManager().register_transform( + Attribute, + inference_tip(inference_function), + functools.partial(looks_like_numpy_member, func_name), + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_multiarray.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_multiarray.py new file mode 100644 index 0000000..487ec47 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_multiarray.py @@ -0,0 +1,95 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for numpy.core.multiarray module.""" + +import functools + +from astroid.brain.brain_numpy_utils import infer_numpy_member, looks_like_numpy_member +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.inference_tip import inference_tip +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import Attribute, Name + + +def numpy_core_multiarray_transform(): + return parse( + """ + # different functions defined in multiarray.py + def inner(a, b): + return numpy.ndarray([0, 0]) + + def vdot(a, b): + return numpy.ndarray([0, 0]) + """ + ) + + +register_module_extender( + AstroidManager(), "numpy.core.multiarray", numpy_core_multiarray_transform +) + + +METHODS_TO_BE_INFERRED = { + "array": """def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): + return numpy.ndarray([0, 0])""", + "dot": """def dot(a, b, out=None): + return numpy.ndarray([0, 0])""", + "empty_like": """def empty_like(a, dtype=None, order='K', subok=True): + return numpy.ndarray((0, 0))""", + "concatenate": """def concatenate(arrays, axis=None, out=None): + return numpy.ndarray((0, 0))""", + "where": """def where(condition, x=None, y=None): + return numpy.ndarray([0, 0])""", + "empty": """def empty(shape, dtype=float, order='C'): + return numpy.ndarray([0, 0])""", + "bincount": """def bincount(x, weights=None, minlength=0): + return numpy.ndarray([0, 0])""", + "busday_count": """def busday_count(begindates, enddates, weekmask='1111100', holidays=[], busdaycal=None, out=None): + return numpy.ndarray([0, 0])""", + "busday_offset": """def busday_offset(dates, offsets, roll='raise', weekmask='1111100', holidays=None, busdaycal=None, out=None): + return numpy.ndarray([0, 0])""", + "can_cast": """def can_cast(from_, to, casting='safe'): + return True""", + "copyto": """def copyto(dst, src, casting='same_kind', where=True): + return None""", + "datetime_as_string": """def datetime_as_string(arr, unit=None, timezone='naive', casting='same_kind'): + return numpy.ndarray([0, 0])""", + "is_busday": """def is_busday(dates, weekmask='1111100', holidays=None, busdaycal=None, out=None): + return numpy.ndarray([0, 0])""", + "lexsort": """def lexsort(keys, axis=-1): + return numpy.ndarray([0, 0])""", + "may_share_memory": """def may_share_memory(a, b, max_work=None): + return True""", + # Not yet available because dtype is not yet present in those brains + # "min_scalar_type": """def min_scalar_type(a): + # return numpy.dtype('int16')""", + "packbits": """def packbits(a, axis=None, bitorder='big'): + return numpy.ndarray([0, 0])""", + # Not yet available because dtype is not yet present in those brains + # "result_type": """def result_type(*arrays_and_dtypes): + # return numpy.dtype('int16')""", + "shares_memory": """def shares_memory(a, b, max_work=None): + return True""", + "unpackbits": """def unpackbits(a, axis=None, count=None, bitorder='big'): + return numpy.ndarray([0, 0])""", + "unravel_index": """def unravel_index(indices, shape, order='C'): + return (numpy.ndarray([0, 0]),)""", + "zeros": """def zeros(shape, dtype=float, order='C'): + return numpy.ndarray([0, 0])""", +} + +for method_name, function_src in METHODS_TO_BE_INFERRED.items(): + inference_function = functools.partial(infer_numpy_member, function_src) + AstroidManager().register_transform( + Attribute, + inference_tip(inference_function), + functools.partial(looks_like_numpy_member, method_name), + ) + AstroidManager().register_transform( + Name, + inference_tip(inference_function), + functools.partial(looks_like_numpy_member, method_name), + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numeric.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numeric.py new file mode 100644 index 0000000..140d81a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numeric.py @@ -0,0 +1,46 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for numpy.core.numeric module.""" + +import functools + +from astroid.brain.brain_numpy_utils import infer_numpy_member, looks_like_numpy_member +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.inference_tip import inference_tip +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import Attribute + + +def numpy_core_numeric_transform(): + return parse( + """ + # different functions defined in numeric.py + import numpy + def zeros_like(a, dtype=None, order='K', subok=True, shape=None): return numpy.ndarray((0, 0)) + def ones_like(a, dtype=None, order='K', subok=True, shape=None): return numpy.ndarray((0, 0)) + def full_like(a, fill_value, dtype=None, order='K', subok=True, shape=None): return numpy.ndarray((0, 0)) + """ + ) + + +register_module_extender( + AstroidManager(), "numpy.core.numeric", numpy_core_numeric_transform +) + + +METHODS_TO_BE_INFERRED = { + "ones": """def ones(shape, dtype=None, order='C'): + return numpy.ndarray([0, 0])""" +} + + +for method_name, function_src in METHODS_TO_BE_INFERRED.items(): + inference_function = functools.partial(infer_numpy_member, function_src) + AstroidManager().register_transform( + Attribute, + inference_tip(inference_function), + functools.partial(looks_like_numpy_member, method_name), + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numerictypes.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numerictypes.py new file mode 100644 index 0000000..245296e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_numerictypes.py @@ -0,0 +1,263 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +# TODO(hippo91) : correct the methods signature. + +"""Astroid hooks for numpy.core.numerictypes module.""" +from astroid.brain.brain_numpy_utils import numpy_supports_type_hints +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def numpy_core_numerictypes_transform(): + # TODO: Uniformize the generic API with the ndarray one. + # According to numpy doc the generic object should expose + # the same API than ndarray. This has been done here partially + # through the astype method. + generic_src = """ + class generic(object): + def __init__(self, value): + self.T = np.ndarray([0, 0]) + self.base = None + self.data = None + self.dtype = None + self.flags = None + # Should be a numpy.flatiter instance but not available for now + # Putting an array instead so that iteration and indexing are authorized + self.flat = np.ndarray([0, 0]) + self.imag = None + self.itemsize = None + self.nbytes = None + self.ndim = None + self.real = None + self.size = None + self.strides = None + + def all(self): return uninferable + def any(self): return uninferable + def argmax(self): return uninferable + def argmin(self): return uninferable + def argsort(self): return uninferable + def astype(self, dtype, order='K', casting='unsafe', subok=True, copy=True): return np.ndarray([0, 0]) + def base(self): return uninferable + def byteswap(self): return uninferable + def choose(self): return uninferable + def clip(self): return uninferable + def compress(self): return uninferable + def conj(self): return uninferable + def conjugate(self): return uninferable + def copy(self): return uninferable + def cumprod(self): return uninferable + def cumsum(self): return uninferable + def data(self): return uninferable + def diagonal(self): return uninferable + def dtype(self): return uninferable + def dump(self): return uninferable + def dumps(self): return uninferable + def fill(self): return uninferable + def flags(self): return uninferable + def flat(self): return uninferable + def flatten(self): return uninferable + def getfield(self): return uninferable + def imag(self): return uninferable + def item(self): return uninferable + def itemset(self): return uninferable + def itemsize(self): return uninferable + def max(self): return uninferable + def mean(self): return uninferable + def min(self): return uninferable + def nbytes(self): return uninferable + def ndim(self): return uninferable + def newbyteorder(self): return uninferable + def nonzero(self): return uninferable + def prod(self): return uninferable + def ptp(self): return uninferable + def put(self): return uninferable + def ravel(self): return uninferable + def real(self): return uninferable + def repeat(self): return uninferable + def reshape(self): return uninferable + def resize(self): return uninferable + def round(self): return uninferable + def searchsorted(self): return uninferable + def setfield(self): return uninferable + def setflags(self): return uninferable + def shape(self): return uninferable + def size(self): return uninferable + def sort(self): return uninferable + def squeeze(self): return uninferable + def std(self): return uninferable + def strides(self): return uninferable + def sum(self): return uninferable + def swapaxes(self): return uninferable + def take(self): return uninferable + def tobytes(self): return uninferable + def tofile(self): return uninferable + def tolist(self): return uninferable + def tostring(self): return uninferable + def trace(self): return uninferable + def transpose(self): return uninferable + def var(self): return uninferable + def view(self): return uninferable + """ + if numpy_supports_type_hints(): + generic_src += """ + @classmethod + def __class_getitem__(cls, value): + return cls + """ + return parse( + generic_src + + """ + class dtype(object): + def __init__(self, obj, align=False, copy=False): + self.alignment = None + self.base = None + self.byteorder = None + self.char = None + self.descr = None + self.fields = None + self.flags = None + self.hasobject = None + self.isalignedstruct = None + self.isbuiltin = None + self.isnative = None + self.itemsize = None + self.kind = None + self.metadata = None + self.name = None + self.names = None + self.num = None + self.shape = None + self.str = None + self.subdtype = None + self.type = None + + def newbyteorder(self, new_order='S'): return uninferable + def __neg__(self): return uninferable + + class busdaycalendar(object): + def __init__(self, weekmask='1111100', holidays=None): + self.holidays = None + self.weekmask = None + + class flexible(generic): pass + class bool_(generic): pass + class number(generic): + def __neg__(self): return uninferable + class datetime64(generic): + def __init__(self, nb, unit=None): pass + + + class void(flexible): + def __init__(self, *args, **kwargs): + self.base = None + self.dtype = None + self.flags = None + def getfield(self): return uninferable + def setfield(self): return uninferable + + + class character(flexible): pass + + + class integer(number): + def __init__(self, value): + self.denominator = None + self.numerator = None + + + class inexact(number): pass + + + class str_(str, character): + def maketrans(self, x, y=None, z=None): return uninferable + + + class bytes_(bytes, character): + def fromhex(self, string): return uninferable + def maketrans(self, frm, to): return uninferable + + + class signedinteger(integer): pass + + + class unsignedinteger(integer): pass + + + class complexfloating(inexact): pass + + + class floating(inexact): pass + + + class float64(floating, float): + def fromhex(self, string): return uninferable + + + class uint64(unsignedinteger): pass + class complex64(complexfloating): pass + class int16(signedinteger): pass + class float96(floating): pass + class int8(signedinteger): pass + class uint32(unsignedinteger): pass + class uint8(unsignedinteger): pass + class _typedict(dict): pass + class complex192(complexfloating): pass + class timedelta64(signedinteger): + def __init__(self, nb, unit=None): pass + class int32(signedinteger): pass + class uint16(unsignedinteger): pass + class float32(floating): pass + class complex128(complexfloating, complex): pass + class float16(floating): pass + class int64(signedinteger): pass + + buffer_type = memoryview + bool8 = bool_ + byte = int8 + bytes0 = bytes_ + cdouble = complex128 + cfloat = complex128 + clongdouble = complex192 + clongfloat = complex192 + complex_ = complex128 + csingle = complex64 + double = float64 + float_ = float64 + half = float16 + int0 = int32 + int_ = int32 + intc = int32 + intp = int32 + long = int32 + longcomplex = complex192 + longdouble = float96 + longfloat = float96 + longlong = int64 + object0 = object_ + object_ = object_ + short = int16 + single = float32 + singlecomplex = complex64 + str0 = str_ + string_ = bytes_ + ubyte = uint8 + uint = uint32 + uint0 = uint32 + uintc = uint32 + uintp = uint32 + ulonglong = uint64 + unicode = str_ + unicode_ = str_ + ushort = uint16 + void0 = void + """ + ) + + +register_module_extender( + AstroidManager(), "numpy.core.numerictypes", numpy_core_numerictypes_transform +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_umath.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_umath.py new file mode 100644 index 0000000..42dfdfa --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_core_umath.py @@ -0,0 +1,154 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +# Note: starting with version 1.18 numpy module has `__getattr__` method which prevent +# `pylint` to emit `no-member` message for all numpy's attributes. (see pylint's module +# typecheck in `_emit_no_member` function) + +"""Astroid hooks for numpy.core.umath module.""" +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def numpy_core_umath_transform(): + ufunc_optional_keyword_arguments = ( + """out=None, where=True, casting='same_kind', order='K', """ + """dtype=None, subok=True""" + ) + return parse( + """ + class FakeUfunc: + def __init__(self): + self.__doc__ = str() + self.__name__ = str() + self.nin = 0 + self.nout = 0 + self.nargs = 0 + self.ntypes = 0 + self.types = None + self.identity = None + self.signature = None + + @classmethod + def reduce(cls, a, axis=None, dtype=None, out=None): + return numpy.ndarray([0, 0]) + + @classmethod + def accumulate(cls, array, axis=None, dtype=None, out=None): + return numpy.ndarray([0, 0]) + + @classmethod + def reduceat(cls, a, indices, axis=None, dtype=None, out=None): + return numpy.ndarray([0, 0]) + + @classmethod + def outer(cls, A, B, **kwargs): + return numpy.ndarray([0, 0]) + + @classmethod + def at(cls, a, indices, b=None): + return numpy.ndarray([0, 0]) + + class FakeUfuncOneArg(FakeUfunc): + def __call__(self, x, {opt_args:s}): + return numpy.ndarray([0, 0]) + + class FakeUfuncOneArgBis(FakeUfunc): + def __call__(self, x, {opt_args:s}): + return numpy.ndarray([0, 0]), numpy.ndarray([0, 0]) + + class FakeUfuncTwoArgs(FakeUfunc): + def __call__(self, x1, x2, {opt_args:s}): + return numpy.ndarray([0, 0]) + + # Constants + e = 2.718281828459045 + euler_gamma = 0.5772156649015329 + + # One arg functions with optional kwargs + arccos = FakeUfuncOneArg() + arccosh = FakeUfuncOneArg() + arcsin = FakeUfuncOneArg() + arcsinh = FakeUfuncOneArg() + arctan = FakeUfuncOneArg() + arctanh = FakeUfuncOneArg() + cbrt = FakeUfuncOneArg() + conj = FakeUfuncOneArg() + conjugate = FakeUfuncOneArg() + cosh = FakeUfuncOneArg() + deg2rad = FakeUfuncOneArg() + degrees = FakeUfuncOneArg() + exp2 = FakeUfuncOneArg() + expm1 = FakeUfuncOneArg() + fabs = FakeUfuncOneArg() + frexp = FakeUfuncOneArgBis() + isfinite = FakeUfuncOneArg() + isinf = FakeUfuncOneArg() + log = FakeUfuncOneArg() + log1p = FakeUfuncOneArg() + log2 = FakeUfuncOneArg() + logical_not = FakeUfuncOneArg() + modf = FakeUfuncOneArgBis() + negative = FakeUfuncOneArg() + positive = FakeUfuncOneArg() + rad2deg = FakeUfuncOneArg() + radians = FakeUfuncOneArg() + reciprocal = FakeUfuncOneArg() + rint = FakeUfuncOneArg() + sign = FakeUfuncOneArg() + signbit = FakeUfuncOneArg() + sinh = FakeUfuncOneArg() + spacing = FakeUfuncOneArg() + square = FakeUfuncOneArg() + tan = FakeUfuncOneArg() + tanh = FakeUfuncOneArg() + trunc = FakeUfuncOneArg() + + # Two args functions with optional kwargs + add = FakeUfuncTwoArgs() + bitwise_and = FakeUfuncTwoArgs() + bitwise_or = FakeUfuncTwoArgs() + bitwise_xor = FakeUfuncTwoArgs() + copysign = FakeUfuncTwoArgs() + divide = FakeUfuncTwoArgs() + divmod = FakeUfuncTwoArgs() + equal = FakeUfuncTwoArgs() + float_power = FakeUfuncTwoArgs() + floor_divide = FakeUfuncTwoArgs() + fmax = FakeUfuncTwoArgs() + fmin = FakeUfuncTwoArgs() + fmod = FakeUfuncTwoArgs() + greater = FakeUfuncTwoArgs() + gcd = FakeUfuncTwoArgs() + hypot = FakeUfuncTwoArgs() + heaviside = FakeUfuncTwoArgs() + lcm = FakeUfuncTwoArgs() + ldexp = FakeUfuncTwoArgs() + left_shift = FakeUfuncTwoArgs() + less = FakeUfuncTwoArgs() + logaddexp = FakeUfuncTwoArgs() + logaddexp2 = FakeUfuncTwoArgs() + logical_and = FakeUfuncTwoArgs() + logical_or = FakeUfuncTwoArgs() + logical_xor = FakeUfuncTwoArgs() + maximum = FakeUfuncTwoArgs() + minimum = FakeUfuncTwoArgs() + multiply = FakeUfuncTwoArgs() + nextafter = FakeUfuncTwoArgs() + not_equal = FakeUfuncTwoArgs() + power = FakeUfuncTwoArgs() + remainder = FakeUfuncTwoArgs() + right_shift = FakeUfuncTwoArgs() + subtract = FakeUfuncTwoArgs() + true_divide = FakeUfuncTwoArgs() + """.format( + opt_args=ufunc_optional_keyword_arguments + ) + ) + + +register_module_extender( + AstroidManager(), "numpy.core.umath", numpy_core_umath_transform +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ma.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ma.py new file mode 100644 index 0000000..241665c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ma.py @@ -0,0 +1,28 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for numpy ma module""" + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def numpy_ma_transform(): + """ + Infer the call of the masked_where function + + :param node: node to infer + :param context: inference context + """ + return parse( + """ + import numpy.ma + def masked_where(condition, a, copy=True): + return numpy.ma.masked_array(a, mask=[]) + """ + ) + + +register_module_extender(AstroidManager(), "numpy.ma", numpy_ma_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ndarray.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ndarray.py new file mode 100644 index 0000000..f9b611e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_ndarray.py @@ -0,0 +1,159 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for numpy ndarray class.""" +from astroid.brain.brain_numpy_utils import numpy_supports_type_hints +from astroid.builder import extract_node +from astroid.inference_tip import inference_tip +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import Attribute + + +def infer_numpy_ndarray(node, context=None): + ndarray = """ + class ndarray(object): + def __init__(self, shape, dtype=float, buffer=None, offset=0, + strides=None, order=None): + self.T = numpy.ndarray([0, 0]) + self.base = None + self.ctypes = None + self.data = None + self.dtype = None + self.flags = None + # Should be a numpy.flatiter instance but not available for now + # Putting an array instead so that iteration and indexing are authorized + self.flat = np.ndarray([0, 0]) + self.imag = np.ndarray([0, 0]) + self.itemsize = None + self.nbytes = None + self.ndim = None + self.real = np.ndarray([0, 0]) + self.shape = numpy.ndarray([0, 0]) + self.size = None + self.strides = None + + def __abs__(self): return numpy.ndarray([0, 0]) + def __add__(self, value): return numpy.ndarray([0, 0]) + def __and__(self, value): return numpy.ndarray([0, 0]) + def __array__(self, dtype=None): return numpy.ndarray([0, 0]) + def __array_wrap__(self, obj): return numpy.ndarray([0, 0]) + def __contains__(self, key): return True + def __copy__(self): return numpy.ndarray([0, 0]) + def __deepcopy__(self, memo): return numpy.ndarray([0, 0]) + def __divmod__(self, value): return (numpy.ndarray([0, 0]), numpy.ndarray([0, 0])) + def __eq__(self, value): return numpy.ndarray([0, 0]) + def __float__(self): return 0. + def __floordiv__(self): return numpy.ndarray([0, 0]) + def __ge__(self, value): return numpy.ndarray([0, 0]) + def __getitem__(self, key): return uninferable + def __gt__(self, value): return numpy.ndarray([0, 0]) + def __iadd__(self, value): return numpy.ndarray([0, 0]) + def __iand__(self, value): return numpy.ndarray([0, 0]) + def __ifloordiv__(self, value): return numpy.ndarray([0, 0]) + def __ilshift__(self, value): return numpy.ndarray([0, 0]) + def __imod__(self, value): return numpy.ndarray([0, 0]) + def __imul__(self, value): return numpy.ndarray([0, 0]) + def __int__(self): return 0 + def __invert__(self): return numpy.ndarray([0, 0]) + def __ior__(self, value): return numpy.ndarray([0, 0]) + def __ipow__(self, value): return numpy.ndarray([0, 0]) + def __irshift__(self, value): return numpy.ndarray([0, 0]) + def __isub__(self, value): return numpy.ndarray([0, 0]) + def __itruediv__(self, value): return numpy.ndarray([0, 0]) + def __ixor__(self, value): return numpy.ndarray([0, 0]) + def __le__(self, value): return numpy.ndarray([0, 0]) + def __len__(self): return 1 + def __lshift__(self, value): return numpy.ndarray([0, 0]) + def __lt__(self, value): return numpy.ndarray([0, 0]) + def __matmul__(self, value): return numpy.ndarray([0, 0]) + def __mod__(self, value): return numpy.ndarray([0, 0]) + def __mul__(self, value): return numpy.ndarray([0, 0]) + def __ne__(self, value): return numpy.ndarray([0, 0]) + def __neg__(self): return numpy.ndarray([0, 0]) + def __or__(self, value): return numpy.ndarray([0, 0]) + def __pos__(self): return numpy.ndarray([0, 0]) + def __pow__(self): return numpy.ndarray([0, 0]) + def __repr__(self): return str() + def __rshift__(self): return numpy.ndarray([0, 0]) + def __setitem__(self, key, value): return uninferable + def __str__(self): return str() + def __sub__(self, value): return numpy.ndarray([0, 0]) + def __truediv__(self, value): return numpy.ndarray([0, 0]) + def __xor__(self, value): return numpy.ndarray([0, 0]) + def all(self, axis=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def any(self, axis=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def argmax(self, axis=None, out=None): return np.ndarray([0, 0]) + def argmin(self, axis=None, out=None): return np.ndarray([0, 0]) + def argpartition(self, kth, axis=-1, kind='introselect', order=None): return np.ndarray([0, 0]) + def argsort(self, axis=-1, kind='quicksort', order=None): return np.ndarray([0, 0]) + def astype(self, dtype, order='K', casting='unsafe', subok=True, copy=True): return np.ndarray([0, 0]) + def byteswap(self, inplace=False): return np.ndarray([0, 0]) + def choose(self, choices, out=None, mode='raise'): return np.ndarray([0, 0]) + def clip(self, min=None, max=None, out=None): return np.ndarray([0, 0]) + def compress(self, condition, axis=None, out=None): return np.ndarray([0, 0]) + def conj(self): return np.ndarray([0, 0]) + def conjugate(self): return np.ndarray([0, 0]) + def copy(self, order='C'): return np.ndarray([0, 0]) + def cumprod(self, axis=None, dtype=None, out=None): return np.ndarray([0, 0]) + def cumsum(self, axis=None, dtype=None, out=None): return np.ndarray([0, 0]) + def diagonal(self, offset=0, axis1=0, axis2=1): return np.ndarray([0, 0]) + def dot(self, b, out=None): return np.ndarray([0, 0]) + def dump(self, file): return None + def dumps(self): return str() + def fill(self, value): return None + def flatten(self, order='C'): return np.ndarray([0, 0]) + def getfield(self, dtype, offset=0): return np.ndarray([0, 0]) + def item(self, *args): return uninferable + def itemset(self, *args): return None + def max(self, axis=None, out=None): return np.ndarray([0, 0]) + def mean(self, axis=None, dtype=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def min(self, axis=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def newbyteorder(self, new_order='S'): return np.ndarray([0, 0]) + def nonzero(self): return (1,) + def partition(self, kth, axis=-1, kind='introselect', order=None): return None + def prod(self, axis=None, dtype=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def ptp(self, axis=None, out=None): return np.ndarray([0, 0]) + def put(self, indices, values, mode='raise'): return None + def ravel(self, order='C'): return np.ndarray([0, 0]) + def repeat(self, repeats, axis=None): return np.ndarray([0, 0]) + def reshape(self, shape, order='C'): return np.ndarray([0, 0]) + def resize(self, new_shape, refcheck=True): return None + def round(self, decimals=0, out=None): return np.ndarray([0, 0]) + def searchsorted(self, v, side='left', sorter=None): return np.ndarray([0, 0]) + def setfield(self, val, dtype, offset=0): return None + def setflags(self, write=None, align=None, uic=None): return None + def sort(self, axis=-1, kind='quicksort', order=None): return None + def squeeze(self, axis=None): return np.ndarray([0, 0]) + def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False): return np.ndarray([0, 0]) + def sum(self, axis=None, dtype=None, out=None, keepdims=False): return np.ndarray([0, 0]) + def swapaxes(self, axis1, axis2): return np.ndarray([0, 0]) + def take(self, indices, axis=None, out=None, mode='raise'): return np.ndarray([0, 0]) + def tobytes(self, order='C'): return b'' + def tofile(self, fid, sep="", format="%s"): return None + def tolist(self, ): return [] + def tostring(self, order='C'): return b'' + def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None): return np.ndarray([0, 0]) + def transpose(self, *axes): return np.ndarray([0, 0]) + def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False): return np.ndarray([0, 0]) + def view(self, dtype=None, type=None): return np.ndarray([0, 0]) + """ + if numpy_supports_type_hints(): + ndarray += """ + @classmethod + def __class_getitem__(cls, value): + return cls + """ + node = extract_node(ndarray) + return node.infer(context=context) + + +def _looks_like_numpy_ndarray(node): + return isinstance(node, Attribute) and node.attrname == "ndarray" + + +AstroidManager().register_transform( + Attribute, + inference_tip(infer_numpy_ndarray), + _looks_like_numpy_ndarray, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_random_mtrand.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_random_mtrand.py new file mode 100644 index 0000000..b1f0d45 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_random_mtrand.py @@ -0,0 +1,71 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +# TODO(hippo91) : correct the functions return types +"""Astroid hooks for numpy.random.mtrand module.""" +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def numpy_random_mtrand_transform(): + return parse( + """ + def beta(a, b, size=None): return uninferable + def binomial(n, p, size=None): return uninferable + def bytes(length): return uninferable + def chisquare(df, size=None): return uninferable + def choice(a, size=None, replace=True, p=None): return uninferable + def dirichlet(alpha, size=None): return uninferable + def exponential(scale=1.0, size=None): return uninferable + def f(dfnum, dfden, size=None): return uninferable + def gamma(shape, scale=1.0, size=None): return uninferable + def geometric(p, size=None): return uninferable + def get_state(): return uninferable + def gumbel(loc=0.0, scale=1.0, size=None): return uninferable + def hypergeometric(ngood, nbad, nsample, size=None): return uninferable + def laplace(loc=0.0, scale=1.0, size=None): return uninferable + def logistic(loc=0.0, scale=1.0, size=None): return uninferable + def lognormal(mean=0.0, sigma=1.0, size=None): return uninferable + def logseries(p, size=None): return uninferable + def multinomial(n, pvals, size=None): return uninferable + def multivariate_normal(mean, cov, size=None): return uninferable + def negative_binomial(n, p, size=None): return uninferable + def noncentral_chisquare(df, nonc, size=None): return uninferable + def noncentral_f(dfnum, dfden, nonc, size=None): return uninferable + def normal(loc=0.0, scale=1.0, size=None): return uninferable + def pareto(a, size=None): return uninferable + def permutation(x): return uninferable + def poisson(lam=1.0, size=None): return uninferable + def power(a, size=None): return uninferable + def rand(*args): return uninferable + def randint(low, high=None, size=None, dtype='l'): + import numpy + return numpy.ndarray((1,1)) + def randn(*args): return uninferable + def random(size=None): return uninferable + def random_integers(low, high=None, size=None): return uninferable + def random_sample(size=None): return uninferable + def rayleigh(scale=1.0, size=None): return uninferable + def seed(seed=None): return uninferable + def set_state(state): return uninferable + def shuffle(x): return uninferable + def standard_cauchy(size=None): return uninferable + def standard_exponential(size=None): return uninferable + def standard_gamma(shape, size=None): return uninferable + def standard_normal(size=None): return uninferable + def standard_t(df, size=None): return uninferable + def triangular(left, mode, right, size=None): return uninferable + def uniform(low=0.0, high=1.0, size=None): return uninferable + def vonmises(mu, kappa, size=None): return uninferable + def wald(mean, scale, size=None): return uninferable + def weibull(a, size=None): return uninferable + def zipf(a, size=None): return uninferable + """ + ) + + +register_module_extender( + AstroidManager(), "numpy.random.mtrand", numpy_random_mtrand_transform +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_utils.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_utils.py new file mode 100644 index 0000000..c32d6d6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_numpy_utils.py @@ -0,0 +1,85 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Different utilities for the numpy brains""" +from typing import Tuple + +from astroid.builder import extract_node +from astroid.nodes.node_classes import Attribute, Import, Name, NodeNG + +# Class subscript is available in numpy starting with version 1.20.0 +NUMPY_VERSION_TYPE_HINTS_SUPPORT = ("1", "20", "0") + + +def numpy_supports_type_hints() -> bool: + """ + Returns True if numpy supports type hints + """ + np_ver = _get_numpy_version() + return np_ver and np_ver > NUMPY_VERSION_TYPE_HINTS_SUPPORT + + +def _get_numpy_version() -> Tuple[str, str, str]: + """ + Return the numpy version number if numpy can be imported. Otherwise returns + ('0', '0', '0') + """ + try: + import numpy # pylint: disable=import-outside-toplevel + + return tuple(numpy.version.version.split(".")) + except ImportError: + return ("0", "0", "0") + + +def infer_numpy_member(src, node, context=None): + node = extract_node(src) + return node.infer(context=context) + + +def _is_a_numpy_module(node: Name) -> bool: + """ + Returns True if the node is a representation of a numpy module. + + For example in : + import numpy as np + x = np.linspace(1, 2) + The node is a representation of the numpy module. + + :param node: node to test + :return: True if the node is a representation of the numpy module. + """ + module_nickname = node.name + potential_import_target = [ + x for x in node.lookup(module_nickname)[1] if isinstance(x, Import) + ] + return any( + ("numpy", module_nickname) in target.names or ("numpy", None) in target.names + for target in potential_import_target + ) + + +def looks_like_numpy_member(member_name: str, node: NodeNG) -> bool: + """ + Returns True if the node is a member of numpy whose + name is member_name. + + :param member_name: name of the member + :param node: node to test + :return: True if the node is a member of numpy + """ + if ( + isinstance(node, Attribute) + and node.attrname == member_name + and isinstance(node.expr, Name) + and _is_a_numpy_module(node.expr) + ): + return True + if ( + isinstance(node, Name) + and node.name == member_name + and node.root().name.startswith("numpy") + ): + return True + return False diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_pkg_resources.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_pkg_resources.py new file mode 100644 index 0000000..689dd74 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_pkg_resources.py @@ -0,0 +1,70 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid import parse +from astroid.brain.helpers import register_module_extender +from astroid.manager import AstroidManager + + +def pkg_resources_transform(): + return parse( + """ +def require(*requirements): + return pkg_resources.working_set.require(*requirements) + +def run_script(requires, script_name): + return pkg_resources.working_set.run_script(requires, script_name) + +def iter_entry_points(group, name=None): + return pkg_resources.working_set.iter_entry_points(group, name) + +def resource_exists(package_or_requirement, resource_name): + return get_provider(package_or_requirement).has_resource(resource_name) + +def resource_isdir(package_or_requirement, resource_name): + return get_provider(package_or_requirement).resource_isdir( + resource_name) + +def resource_filename(package_or_requirement, resource_name): + return get_provider(package_or_requirement).get_resource_filename( + self, resource_name) + +def resource_stream(package_or_requirement, resource_name): + return get_provider(package_or_requirement).get_resource_stream( + self, resource_name) + +def resource_string(package_or_requirement, resource_name): + return get_provider(package_or_requirement).get_resource_string( + self, resource_name) + +def resource_listdir(package_or_requirement, resource_name): + return get_provider(package_or_requirement).resource_listdir( + resource_name) + +def extraction_error(): + pass + +def get_cache_path(archive_name, names=()): + extract_path = self.extraction_path or get_default_cache() + target_path = os.path.join(extract_path, archive_name+'-tmp', *names) + return target_path + +def postprocess(tempname, filename): + pass + +def set_extraction_path(path): + pass + +def cleanup_resources(force=False): + pass + +def get_distribution(dist): + return Distribution(dist) + +_namespace_packages = {} +""" + ) + + +register_module_extender(AstroidManager(), "pkg_resources", pkg_resources_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_pytest.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_pytest.py new file mode 100644 index 0000000..78c9779 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_pytest.py @@ -0,0 +1,83 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for pytest.""" +from astroid.brain.helpers import register_module_extender +from astroid.builder import AstroidBuilder +from astroid.manager import AstroidManager + + +def pytest_transform(): + return AstroidBuilder(AstroidManager()).string_build( + """ + +try: + import _pytest.mark + import _pytest.recwarn + import _pytest.runner + import _pytest.python + import _pytest.skipping + import _pytest.assertion +except ImportError: + pass +else: + deprecated_call = _pytest.recwarn.deprecated_call + warns = _pytest.recwarn.warns + + exit = _pytest.runner.exit + fail = _pytest.runner.fail + skip = _pytest.runner.skip + importorskip = _pytest.runner.importorskip + + xfail = _pytest.skipping.xfail + mark = _pytest.mark.MarkGenerator() + raises = _pytest.python.raises + + # New in pytest 3.0 + try: + approx = _pytest.python.approx + register_assert_rewrite = _pytest.assertion.register_assert_rewrite + except AttributeError: + pass + + +# Moved in pytest 3.0 + +try: + import _pytest.freeze_support + freeze_includes = _pytest.freeze_support.freeze_includes +except ImportError: + try: + import _pytest.genscript + freeze_includes = _pytest.genscript.freeze_includes + except ImportError: + pass + +try: + import _pytest.debugging + set_trace = _pytest.debugging.pytestPDB().set_trace +except ImportError: + try: + import _pytest.pdb + set_trace = _pytest.pdb.pytestPDB().set_trace + except ImportError: + pass + +try: + import _pytest.fixtures + fixture = _pytest.fixtures.fixture + yield_fixture = _pytest.fixtures.yield_fixture +except ImportError: + try: + import _pytest.python + fixture = _pytest.python.fixture + yield_fixture = _pytest.python.yield_fixture + except ImportError: + pass +""" + ) + + +register_module_extender(AstroidManager(), "pytest", pytest_transform) +register_module_extender(AstroidManager(), "py.test", pytest_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_qt.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_qt.py new file mode 100644 index 0000000..6b97bf6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_qt.py @@ -0,0 +1,82 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for the PyQT library.""" + +from astroid import nodes, parse +from astroid.brain.helpers import register_module_extender +from astroid.builder import AstroidBuilder +from astroid.manager import AstroidManager + + +def _looks_like_signal(node, signal_name="pyqtSignal"): + if "__class__" in node.instance_attrs: + try: + cls = node.instance_attrs["__class__"][0] + return cls.name == signal_name + except AttributeError: + # return False if the cls does not have a name attribute + pass + return False + + +def transform_pyqt_signal(node: nodes.FunctionDef) -> None: + module = parse( + """ + _UNSET = object() + + class pyqtSignal(object): + def connect(self, slot, type=None, no_receiver_check=False): + pass + def disconnect(self, slot=_UNSET): + pass + def emit(self, *args): + pass + """ + ) + signal_cls: nodes.ClassDef = module["pyqtSignal"] + node.instance_attrs["emit"] = [signal_cls["emit"]] + node.instance_attrs["disconnect"] = [signal_cls["disconnect"]] + node.instance_attrs["connect"] = [signal_cls["connect"]] + + +def transform_pyside_signal(node: nodes.FunctionDef) -> None: + module = parse( + """ + class NotPySideSignal(object): + def connect(self, receiver, type=None): + pass + def disconnect(self, receiver): + pass + def emit(self, *args): + pass + """ + ) + signal_cls: nodes.ClassDef = module["NotPySideSignal"] + node.instance_attrs["connect"] = [signal_cls["connect"]] + node.instance_attrs["disconnect"] = [signal_cls["disconnect"]] + node.instance_attrs["emit"] = [signal_cls["emit"]] + + +def pyqt4_qtcore_transform(): + return AstroidBuilder(AstroidManager()).string_build( + """ + +def SIGNAL(signal_name): pass + +class QObject(object): + def emit(self, signal): pass +""" + ) + + +register_module_extender(AstroidManager(), "PyQt4.QtCore", pyqt4_qtcore_transform) +AstroidManager().register_transform( + nodes.FunctionDef, transform_pyqt_signal, _looks_like_signal +) +AstroidManager().register_transform( + nodes.ClassDef, + transform_pyside_signal, + lambda node: node.qname() in {"PySide.QtCore.Signal", "PySide2.QtCore.Signal"}, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_random.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_random.py new file mode 100644 index 0000000..e66aa81 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_random.py @@ -0,0 +1,87 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import random + +from astroid import helpers +from astroid.exceptions import UseInferenceDefault +from astroid.inference_tip import inference_tip +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import ( + Attribute, + Call, + Const, + EvaluatedObject, + List, + Name, + Set, + Tuple, +) + +ACCEPTED_ITERABLES_FOR_SAMPLE = (List, Set, Tuple) + + +def _clone_node_with_lineno(node, parent, lineno): + if isinstance(node, EvaluatedObject): + node = node.original + cls = node.__class__ + other_fields = node._other_fields + _astroid_fields = node._astroid_fields + init_params = {"lineno": lineno, "col_offset": node.col_offset, "parent": parent} + postinit_params = {param: getattr(node, param) for param in _astroid_fields} + if other_fields: + init_params.update({param: getattr(node, param) for param in other_fields}) + new_node = cls(**init_params) + if hasattr(node, "postinit") and _astroid_fields: + new_node.postinit(**postinit_params) + return new_node + + +def infer_random_sample(node, context=None): + if len(node.args) != 2: + raise UseInferenceDefault + + length = node.args[1] + if not isinstance(length, Const): + raise UseInferenceDefault + if not isinstance(length.value, int): + raise UseInferenceDefault + + inferred_sequence = helpers.safe_infer(node.args[0], context=context) + if not inferred_sequence: + raise UseInferenceDefault + + if not isinstance(inferred_sequence, ACCEPTED_ITERABLES_FOR_SAMPLE): + raise UseInferenceDefault + + if length.value > len(inferred_sequence.elts): + # In this case, this will raise a ValueError + raise UseInferenceDefault + + try: + elts = random.sample(inferred_sequence.elts, length.value) + except ValueError as exc: + raise UseInferenceDefault from exc + + new_node = List(lineno=node.lineno, col_offset=node.col_offset, parent=node.scope()) + new_elts = [ + _clone_node_with_lineno(elt, parent=new_node, lineno=new_node.lineno) + for elt in elts + ] + new_node.postinit(new_elts) + return iter((new_node,)) + + +def _looks_like_random_sample(node): + func = node.func + if isinstance(func, Attribute): + return func.attrname == "sample" + if isinstance(func, Name): + return func.name == "sample" + return False + + +AstroidManager().register_transform( + Call, inference_tip(infer_random_sample), _looks_like_random_sample +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_re.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_re.py new file mode 100644 index 0000000..0dd346a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_re.py @@ -0,0 +1,90 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from typing import Optional + +from astroid import context, inference_tip, nodes +from astroid.brain.helpers import register_module_extender +from astroid.builder import _extract_single_node, parse +from astroid.const import PY37_PLUS, PY39_PLUS +from astroid.manager import AstroidManager + + +def _re_transform(): + # Since Python 3.6 there is the RegexFlag enum + # where every entry will be exposed via updating globals() + return parse( + """ + import sre_compile + ASCII = sre_compile.SRE_FLAG_ASCII + IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE + LOCALE = sre_compile.SRE_FLAG_LOCALE + UNICODE = sre_compile.SRE_FLAG_UNICODE + MULTILINE = sre_compile.SRE_FLAG_MULTILINE + DOTALL = sre_compile.SRE_FLAG_DOTALL + VERBOSE = sre_compile.SRE_FLAG_VERBOSE + A = ASCII + I = IGNORECASE + L = LOCALE + U = UNICODE + M = MULTILINE + S = DOTALL + X = VERBOSE + TEMPLATE = sre_compile.SRE_FLAG_TEMPLATE + T = TEMPLATE + DEBUG = sre_compile.SRE_FLAG_DEBUG + """ + ) + + +register_module_extender(AstroidManager(), "re", _re_transform) + + +CLASS_GETITEM_TEMPLATE = """ +@classmethod +def __class_getitem__(cls, item): + return cls +""" + + +def _looks_like_pattern_or_match(node: nodes.Call) -> bool: + """Check for re.Pattern or re.Match call in stdlib. + + Match these patterns from stdlib/re.py + ```py + Pattern = type(...) + Match = type(...) + ``` + """ + return ( + node.root().name == "re" + and isinstance(node.func, nodes.Name) + and node.func.name == "type" + and isinstance(node.parent, nodes.Assign) + and len(node.parent.targets) == 1 + and isinstance(node.parent.targets[0], nodes.AssignName) + and node.parent.targets[0].name in {"Pattern", "Match"} + ) + + +def infer_pattern_match( + node: nodes.Call, ctx: Optional[context.InferenceContext] = None +): + """Infer re.Pattern and re.Match as classes. For PY39+ add `__class_getitem__`.""" + class_def = nodes.ClassDef( + name=node.parent.targets[0].name, + lineno=node.lineno, + col_offset=node.col_offset, + parent=node.parent, + ) + if PY39_PLUS: + func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE) + class_def.locals["__class_getitem__"] = [func_to_add] + return iter([class_def]) + + +if PY37_PLUS: + AstroidManager().register_transform( + nodes.Call, inference_tip(infer_pattern_match), _looks_like_pattern_or_match + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_responses.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_responses.py new file mode 100644 index 0000000..0fb0e42 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_responses.py @@ -0,0 +1,79 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Astroid hooks for responses. + +It might need to be manually updated from the public methods of +:class:`responses.RequestsMock`. + +See: https://github.com/getsentry/responses/blob/master/responses.py + +""" +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def responses_funcs(): + return parse( + """ + DELETE = "DELETE" + GET = "GET" + HEAD = "HEAD" + OPTIONS = "OPTIONS" + PATCH = "PATCH" + POST = "POST" + PUT = "PUT" + response_callback = None + + def reset(): + return + + def add( + method=None, # method or ``Response`` + url=None, + body="", + adding_headers=None, + *args, + **kwargs + ): + return + + def add_passthru(prefix): + return + + def remove(method_or_response=None, url=None): + return + + def replace(method_or_response=None, url=None, body="", *args, **kwargs): + return + + def add_callback( + method, url, callback, match_querystring=False, content_type="text/plain" + ): + return + + calls = [] + + def __enter__(): + return + + def __exit__(type, value, traceback): + success = type is None + return success + + def activate(func): + return func + + def start(): + return + + def stop(allow_assert=True): + return + """ + ) + + +register_module_extender(AstroidManager(), "responses", responses_funcs) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_scipy_signal.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_scipy_signal.py new file mode 100644 index 0000000..578022f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_scipy_signal.py @@ -0,0 +1,88 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for scipy.signal module.""" +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def scipy_signal(): + return parse( + """ + # different functions defined in scipy.signals + + def barthann(M, sym=True): + return numpy.ndarray([0]) + + def bartlett(M, sym=True): + return numpy.ndarray([0]) + + def blackman(M, sym=True): + return numpy.ndarray([0]) + + def blackmanharris(M, sym=True): + return numpy.ndarray([0]) + + def bohman(M, sym=True): + return numpy.ndarray([0]) + + def boxcar(M, sym=True): + return numpy.ndarray([0]) + + def chebwin(M, at, sym=True): + return numpy.ndarray([0]) + + def cosine(M, sym=True): + return numpy.ndarray([0]) + + def exponential(M, center=None, tau=1.0, sym=True): + return numpy.ndarray([0]) + + def flattop(M, sym=True): + return numpy.ndarray([0]) + + def gaussian(M, std, sym=True): + return numpy.ndarray([0]) + + def general_gaussian(M, p, sig, sym=True): + return numpy.ndarray([0]) + + def hamming(M, sym=True): + return numpy.ndarray([0]) + + def hann(M, sym=True): + return numpy.ndarray([0]) + + def hanning(M, sym=True): + return numpy.ndarray([0]) + + def impulse2(system, X0=None, T=None, N=None, **kwargs): + return numpy.ndarray([0]), numpy.ndarray([0]) + + def kaiser(M, beta, sym=True): + return numpy.ndarray([0]) + + def nuttall(M, sym=True): + return numpy.ndarray([0]) + + def parzen(M, sym=True): + return numpy.ndarray([0]) + + def slepian(M, width, sym=True): + return numpy.ndarray([0]) + + def step2(system, X0=None, T=None, N=None, **kwargs): + return numpy.ndarray([0]), numpy.ndarray([0]) + + def triang(M, sym=True): + return numpy.ndarray([0]) + + def tukey(M, alpha=0.5, sym=True): + return numpy.ndarray([0]) + """ + ) + + +register_module_extender(AstroidManager(), "scipy.signal", scipy_signal) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_signal.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_signal.py new file mode 100644 index 0000000..5eee7f6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_signal.py @@ -0,0 +1,119 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for the signal library. + +The signal module generates the 'Signals', 'Handlers' and 'Sigmasks' IntEnums +dynamically using the IntEnum._convert() classmethod, which modifies the module +globals. Astroid is unable to handle this type of code. + +Without these hooks, the following are erroneously triggered by Pylint: + * E1101: Module 'signal' has no 'Signals' member (no-member) + * E1101: Module 'signal' has no 'Handlers' member (no-member) + * E1101: Module 'signal' has no 'Sigmasks' member (no-member) + +These enums are defined slightly differently depending on the user's operating +system and platform. These platform differences should follow the current +Python typeshed stdlib `signal.pyi` stub file, available at: + +* https://github.com/python/typeshed/blob/master/stdlib/signal.pyi + +Note that the enum.auto() values defined here for the Signals, Handlers and +Sigmasks IntEnums are just dummy integer values, and do not correspond to the +actual standard signal numbers - which may vary depending on the system. +""" + + +import sys + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def _signals_enums_transform(): + """Generates the AST for 'Signals', 'Handlers' and 'Sigmasks' IntEnums.""" + return parse(_signals_enum() + _handlers_enum() + _sigmasks_enum()) + + +def _signals_enum(): + """Generates the source code for the Signals int enum.""" + signals_enum = """ + import enum + class Signals(enum.IntEnum): + SIGABRT = enum.auto() + SIGEMT = enum.auto() + SIGFPE = enum.auto() + SIGILL = enum.auto() + SIGINFO = enum.auto() + SIGINT = enum.auto() + SIGSEGV = enum.auto() + SIGTERM = enum.auto() + """ + if sys.platform != "win32": + signals_enum += """ + SIGALRM = enum.auto() + SIGBUS = enum.auto() + SIGCHLD = enum.auto() + SIGCONT = enum.auto() + SIGHUP = enum.auto() + SIGIO = enum.auto() + SIGIOT = enum.auto() + SIGKILL = enum.auto() + SIGPIPE = enum.auto() + SIGPROF = enum.auto() + SIGQUIT = enum.auto() + SIGSTOP = enum.auto() + SIGSYS = enum.auto() + SIGTRAP = enum.auto() + SIGTSTP = enum.auto() + SIGTTIN = enum.auto() + SIGTTOU = enum.auto() + SIGURG = enum.auto() + SIGUSR1 = enum.auto() + SIGUSR2 = enum.auto() + SIGVTALRM = enum.auto() + SIGWINCH = enum.auto() + SIGXCPU = enum.auto() + SIGXFSZ = enum.auto() + """ + if sys.platform == "win32": + signals_enum += """ + SIGBREAK = enum.auto() + """ + if sys.platform not in ("darwin", "win32"): + signals_enum += """ + SIGCLD = enum.auto() + SIGPOLL = enum.auto() + SIGPWR = enum.auto() + SIGRTMAX = enum.auto() + SIGRTMIN = enum.auto() + """ + return signals_enum + + +def _handlers_enum(): + """Generates the source code for the Handlers int enum.""" + return """ + import enum + class Handlers(enum.IntEnum): + SIG_DFL = enum.auto() + SIG_IGN = eunm.auto() + """ + + +def _sigmasks_enum(): + """Generates the source code for the Sigmasks int enum.""" + if sys.platform != "win32": + return """ + import enum + class Sigmasks(enum.IntEnum): + SIG_BLOCK = enum.auto() + SIG_UNBLOCK = enum.auto() + SIG_SETMASK = enum.auto() + """ + return "" + + +register_module_extender(AstroidManager(), "signal", _signals_enums_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_six.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_six.py new file mode 100644 index 0000000..022fcf2 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_six.py @@ -0,0 +1,239 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for six module.""" + +from textwrap import dedent + +from astroid import nodes +from astroid.brain.helpers import register_module_extender +from astroid.builder import AstroidBuilder +from astroid.exceptions import ( + AstroidBuildingError, + AttributeInferenceError, + InferenceError, +) +from astroid.manager import AstroidManager + +SIX_ADD_METACLASS = "six.add_metaclass" +SIX_WITH_METACLASS = "six.with_metaclass" + + +def default_predicate(line): + return line.strip() + + +def _indent(text, prefix, predicate=default_predicate): + """Adds 'prefix' to the beginning of selected lines in 'text'. + + If 'predicate' is provided, 'prefix' will only be added to the lines + where 'predicate(line)' is True. If 'predicate' is not provided, + it will default to adding 'prefix' to all non-empty lines that do not + consist solely of whitespace characters. + """ + + def prefixed_lines(): + for line in text.splitlines(True): + yield prefix + line if predicate(line) else line + + return "".join(prefixed_lines()) + + +_IMPORTS = """ +import _io +cStringIO = _io.StringIO +filter = filter +from itertools import filterfalse +input = input +from sys import intern +map = map +range = range +from importlib import reload +reload_module = lambda module: reload(module) +from functools import reduce +from shlex import quote as shlex_quote +from io import StringIO +from collections import UserDict, UserList, UserString +xrange = range +zip = zip +from itertools import zip_longest +import builtins +import configparser +import copyreg +import _dummy_thread +import http.cookiejar as http_cookiejar +import http.cookies as http_cookies +import html.entities as html_entities +import html.parser as html_parser +import http.client as http_client +import http.server as http_server +BaseHTTPServer = CGIHTTPServer = SimpleHTTPServer = http.server +import pickle as cPickle +import queue +import reprlib +import socketserver +import _thread +import winreg +import xmlrpc.server as xmlrpc_server +import xmlrpc.client as xmlrpc_client +import urllib.robotparser as urllib_robotparser +import email.mime.multipart as email_mime_multipart +import email.mime.nonmultipart as email_mime_nonmultipart +import email.mime.text as email_mime_text +import email.mime.base as email_mime_base +import urllib.parse as urllib_parse +import urllib.error as urllib_error +import tkinter +import tkinter.dialog as tkinter_dialog +import tkinter.filedialog as tkinter_filedialog +import tkinter.scrolledtext as tkinter_scrolledtext +import tkinter.simpledialog as tkinder_simpledialog +import tkinter.tix as tkinter_tix +import tkinter.ttk as tkinter_ttk +import tkinter.constants as tkinter_constants +import tkinter.dnd as tkinter_dnd +import tkinter.colorchooser as tkinter_colorchooser +import tkinter.commondialog as tkinter_commondialog +import tkinter.filedialog as tkinter_tkfiledialog +import tkinter.font as tkinter_font +import tkinter.messagebox as tkinter_messagebox +import urllib +import urllib.request as urllib_request +import urllib.robotparser as urllib_robotparser +import urllib.parse as urllib_parse +import urllib.error as urllib_error +""" + + +def six_moves_transform(): + code = dedent( + """ + class Moves(object): + {} + moves = Moves() + """ + ).format(_indent(_IMPORTS, " ")) + module = AstroidBuilder(AstroidManager()).string_build(code) + module.name = "six.moves" + return module + + +def _six_fail_hook(modname): + """Fix six.moves imports due to the dynamic nature of this + class. + + Construct a pseudo-module which contains all the necessary imports + for six + + :param modname: Name of failed module + :type modname: str + + :return: An astroid module + :rtype: nodes.Module + """ + + attribute_of = modname != "six.moves" and modname.startswith("six.moves") + if modname != "six.moves" and not attribute_of: + raise AstroidBuildingError(modname=modname) + module = AstroidBuilder(AstroidManager()).string_build(_IMPORTS) + module.name = "six.moves" + if attribute_of: + # Facilitate import of submodules in Moves + start_index = len(module.name) + attribute = modname[start_index:].lstrip(".").replace(".", "_") + try: + import_attr = module.getattr(attribute)[0] + except AttributeInferenceError as exc: + raise AstroidBuildingError(modname=modname) from exc + if isinstance(import_attr, nodes.Import): + submodule = AstroidManager().ast_from_module_name(import_attr.names[0][0]) + return submodule + # Let dummy submodule imports pass through + # This will cause an Uninferable result, which is okay + return module + + +def _looks_like_decorated_with_six_add_metaclass(node): + if not node.decorators: + return False + + for decorator in node.decorators.nodes: + if not isinstance(decorator, nodes.Call): + continue + if decorator.func.as_string() == SIX_ADD_METACLASS: + return True + return False + + +def transform_six_add_metaclass(node): # pylint: disable=inconsistent-return-statements + """Check if the given class node is decorated with *six.add_metaclass* + + If so, inject its argument as the metaclass of the underlying class. + """ + if not node.decorators: + return + + for decorator in node.decorators.nodes: + if not isinstance(decorator, nodes.Call): + continue + + try: + func = next(decorator.func.infer()) + except (InferenceError, StopIteration): + continue + if func.qname() == SIX_ADD_METACLASS and decorator.args: + metaclass = decorator.args[0] + node._metaclass = metaclass + return node + return + + +def _looks_like_nested_from_six_with_metaclass(node): + if len(node.bases) != 1: + return False + base = node.bases[0] + if not isinstance(base, nodes.Call): + return False + try: + if hasattr(base.func, "expr"): + # format when explicit 'six.with_metaclass' is used + mod = base.func.expr.name + func = base.func.attrname + func = f"{mod}.{func}" + else: + # format when 'with_metaclass' is used directly (local import from six) + # check reference module to avoid 'with_metaclass' name clashes + mod = base.parent.parent + import_from = mod.locals["with_metaclass"][0] + func = f"{import_from.modname}.{base.func.name}" + except (AttributeError, KeyError, IndexError): + return False + return func == SIX_WITH_METACLASS + + +def transform_six_with_metaclass(node): + """Check if the given class node is defined with *six.with_metaclass* + + If so, inject its argument as the metaclass of the underlying class. + """ + call = node.bases[0] + node._metaclass = call.args[0] + return node + + +register_module_extender(AstroidManager(), "six", six_moves_transform) +register_module_extender( + AstroidManager(), "requests.packages.urllib3.packages.six", six_moves_transform +) +AstroidManager().register_failed_import_hook(_six_fail_hook) +AstroidManager().register_transform( + nodes.ClassDef, + transform_six_add_metaclass, + _looks_like_decorated_with_six_add_metaclass, +) +AstroidManager().register_transform( + nodes.ClassDef, + transform_six_with_metaclass, + _looks_like_nested_from_six_with_metaclass, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_sqlalchemy.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_sqlalchemy.py new file mode 100644 index 0000000..f3695de --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_sqlalchemy.py @@ -0,0 +1,39 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def _session_transform(): + return parse( + """ + from sqlalchemy.orm.session import Session + + class sessionmaker: + def __init__( + self, + bind=None, + class_=Session, + autoflush=True, + autocommit=False, + expire_on_commit=True, + info=None, + **kw + ): + return + + def __call__(self, **local_kw): + return Session() + + def configure(self, **new_kw): + return + + return Session() + """ + ) + + +register_module_extender(AstroidManager(), "sqlalchemy.orm.session", _session_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_ssl.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_ssl.py new file mode 100644 index 0000000..6ca0d5a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_ssl.py @@ -0,0 +1,71 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for the ssl library.""" + +from astroid import parse +from astroid.brain.helpers import register_module_extender +from astroid.manager import AstroidManager + + +def ssl_transform(): + return parse( + """ + from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION + from _ssl import _SSLContext, MemoryBIO + from _ssl import ( + SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError, + SSLSyscallError, SSLEOFError, + ) + from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED + from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj + from _ssl import RAND_status, RAND_add, RAND_bytes, RAND_pseudo_bytes + try: + from _ssl import RAND_egd + except ImportError: + # LibreSSL does not provide RAND_egd + pass + from _ssl import (OP_ALL, OP_CIPHER_SERVER_PREFERENCE, + OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3, + OP_NO_TLSv1, OP_NO_TLSv1_1, OP_NO_TLSv1_2, + OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE) + + from _ssl import (ALERT_DESCRIPTION_ACCESS_DENIED, ALERT_DESCRIPTION_BAD_CERTIFICATE, + ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE, + ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE, + ALERT_DESCRIPTION_BAD_RECORD_MAC, + ALERT_DESCRIPTION_CERTIFICATE_EXPIRED, + ALERT_DESCRIPTION_CERTIFICATE_REVOKED, + ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN, + ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE, + ALERT_DESCRIPTION_CLOSE_NOTIFY, ALERT_DESCRIPTION_DECODE_ERROR, + ALERT_DESCRIPTION_DECOMPRESSION_FAILURE, + ALERT_DESCRIPTION_DECRYPT_ERROR, + ALERT_DESCRIPTION_HANDSHAKE_FAILURE, + ALERT_DESCRIPTION_ILLEGAL_PARAMETER, + ALERT_DESCRIPTION_INSUFFICIENT_SECURITY, + ALERT_DESCRIPTION_INTERNAL_ERROR, + ALERT_DESCRIPTION_NO_RENEGOTIATION, + ALERT_DESCRIPTION_PROTOCOL_VERSION, + ALERT_DESCRIPTION_RECORD_OVERFLOW, + ALERT_DESCRIPTION_UNEXPECTED_MESSAGE, + ALERT_DESCRIPTION_UNKNOWN_CA, + ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY, + ALERT_DESCRIPTION_UNRECOGNIZED_NAME, + ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE, + ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION, + ALERT_DESCRIPTION_USER_CANCELLED) + from _ssl import (SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, SSL_ERROR_SSL, + SSL_ERROR_SYSCALL, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_READ, + SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_X509_LOOKUP, SSL_ERROR_ZERO_RETURN) + from _ssl import VERIFY_CRL_CHECK_CHAIN, VERIFY_CRL_CHECK_LEAF, VERIFY_DEFAULT, VERIFY_X509_STRICT + from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN + from _ssl import _OPENSSL_API_VERSION + from _ssl import PROTOCOL_SSLv23, PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2 + from _ssl import PROTOCOL_TLS, PROTOCOL_TLS_CLIENT, PROTOCOL_TLS_SERVER + """ + ) + + +register_module_extender(AstroidManager(), "ssl", ssl_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_subprocess.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_subprocess.py new file mode 100644 index 0000000..f296ab4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_subprocess.py @@ -0,0 +1,131 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import textwrap + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.const import PY37_PLUS, PY39_PLUS, PY310_PLUS, PY311_PLUS +from astroid.manager import AstroidManager + + +def _subprocess_transform(): + communicate = (bytes("string", "ascii"), bytes("string", "ascii")) + communicate_signature = "def communicate(self, input=None, timeout=None)" + args = """\ + self, args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, + universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True, + start_new_session=False, pass_fds=(), *, encoding=None, errors=None, text=None""" + + if PY39_PLUS: + args += ", user=None, group=None, extra_groups=None, umask=-1" + if PY310_PLUS: + args += ", pipesize=-1" + if PY311_PLUS: + args += ", process_group=None" + + init = f""" + def __init__({args}): + pass""" + wait_signature = "def wait(self, timeout=None)" + ctx_manager = """ + def __enter__(self): return self + def __exit__(self, *args): pass + """ + py3_args = "args = []" + + if PY37_PLUS: + check_output_signature = """ + check_output( + args, *, + stdin=None, + stderr=None, + shell=False, + cwd=None, + encoding=None, + errors=None, + universal_newlines=False, + timeout=None, + env=None, + text=None, + restore_signals=True, + preexec_fn=None, + pass_fds=(), + input=None, + bufsize=0, + executable=None, + close_fds=False, + startupinfo=None, + creationflags=0, + start_new_session=False + ): + """.strip() + else: + check_output_signature = """ + check_output( + args, *, + stdin=None, + stderr=None, + shell=False, + cwd=None, + encoding=None, + errors=None, + universal_newlines=False, + timeout=None, + env=None, + restore_signals=True, + preexec_fn=None, + pass_fds=(), + input=None, + bufsize=0, + executable=None, + close_fds=False, + startupinfo=None, + creationflags=0, + start_new_session=False + ): + """.strip() + + code = textwrap.dedent( + f""" + def {check_output_signature} + if universal_newlines: + return "" + return b"" + + class Popen(object): + returncode = pid = 0 + stdin = stdout = stderr = file() + {py3_args} + + {communicate_signature}: + return {communicate!r} + {wait_signature}: + return self.returncode + def poll(self): + return self.returncode + def send_signal(self, signal): + pass + def terminate(self): + pass + def kill(self): + pass + {ctx_manager} + """ + ) + if PY39_PLUS: + code += """ + @classmethod + def __class_getitem__(cls, item): + pass + """ + + init_lines = textwrap.dedent(init).splitlines() + indented_init = "\n".join(" " * 4 + line for line in init_lines) + code += indented_init + return parse(code) + + +register_module_extender(AstroidManager(), "subprocess", _subprocess_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_threading.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_threading.py new file mode 100644 index 0000000..a85055d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_threading.py @@ -0,0 +1,31 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.manager import AstroidManager + + +def _thread_transform(): + return parse( + """ + class lock(object): + def acquire(self, blocking=True, timeout=-1): + return False + def release(self): + pass + def __enter__(self): + return True + def __exit__(self, *args): + pass + def locked(self): + return False + + def Lock(): + return lock() + """ + ) + + +register_module_extender(AstroidManager(), "threading", _thread_transform) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_type.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_type.py new file mode 100644 index 0000000..f9c3ff4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_type.py @@ -0,0 +1,69 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Astroid hooks for type support. + +Starting from python3.9, type object behaves as it had __class_getitem__ method. +However it was not possible to simply add this method inside type's body, otherwise +all types would also have this method. In this case it would have been possible +to write str[int]. +Guido Van Rossum proposed a hack to handle this in the interpreter: +https://github.com/python/cpython/blob/67e394562d67cbcd0ac8114e5439494e7645b8f5/Objects/abstract.c#L181-L184 + +This brain follows the same logic. It is no wise to add permanently the __class_getitem__ method +to the type object. Instead we choose to add it only in the case of a subscript node +which inside name node is type. +Doing this type[int] is allowed whereas str[int] is not. + +Thanks to Lukasz Langa for fruitful discussion. +""" + +from astroid import extract_node, inference_tip, nodes +from astroid.const import PY39_PLUS +from astroid.exceptions import UseInferenceDefault +from astroid.manager import AstroidManager + + +def _looks_like_type_subscript(node): + """ + Try to figure out if a Name node is used inside a type related subscript + + :param node: node to check + :type node: astroid.nodes.node_classes.NodeNG + :return: true if the node is a Name node inside a type related subscript + :rtype: bool + """ + if isinstance(node, nodes.Name) and isinstance(node.parent, nodes.Subscript): + return node.name == "type" + return False + + +def infer_type_sub(node, context=None): + """ + Infer a type[...] subscript + + :param node: node to infer + :type node: astroid.nodes.node_classes.NodeNG + :param context: inference context + :type context: astroid.context.InferenceContext + :return: the inferred node + :rtype: nodes.NodeNG + """ + node_scope, _ = node.scope().lookup("type") + if not isinstance(node_scope, nodes.Module) or node_scope.qname() != "builtins": + raise UseInferenceDefault() + class_src = """ + class type: + def __class_getitem__(cls, key): + return cls + """ + node = extract_node(class_src) + return node.infer(context=context) + + +if PY39_PLUS: + AstroidManager().register_transform( + nodes.Name, inference_tip(infer_type_sub), _looks_like_type_subscript + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_typing.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_typing.py new file mode 100644 index 0000000..6077773 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_typing.py @@ -0,0 +1,433 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for typing.py support.""" +import typing +from functools import partial + +from astroid import context, extract_node, inference_tip +from astroid.builder import _extract_single_node +from astroid.const import PY37_PLUS, PY38_PLUS, PY39_PLUS +from astroid.exceptions import ( + AttributeInferenceError, + InferenceError, + UseInferenceDefault, +) +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import ( + Assign, + AssignName, + Attribute, + Call, + Const, + JoinedStr, + Name, + NodeNG, + Subscript, + Tuple, +) +from astroid.nodes.scoped_nodes import ClassDef, FunctionDef +from astroid.util import Uninferable + +TYPING_NAMEDTUPLE_BASENAMES = {"NamedTuple", "typing.NamedTuple"} +TYPING_TYPEVARS = {"TypeVar", "NewType"} +TYPING_TYPEVARS_QUALIFIED = {"typing.TypeVar", "typing.NewType"} +TYPING_TYPE_TEMPLATE = """ +class Meta(type): + def __getitem__(self, item): + return self + + @property + def __args__(self): + return () + +class {0}(metaclass=Meta): + pass +""" +TYPING_MEMBERS = set(getattr(typing, "__all__", [])) + +TYPING_ALIAS = frozenset( + ( + "typing.Hashable", + "typing.Awaitable", + "typing.Coroutine", + "typing.AsyncIterable", + "typing.AsyncIterator", + "typing.Iterable", + "typing.Iterator", + "typing.Reversible", + "typing.Sized", + "typing.Container", + "typing.Collection", + "typing.Callable", + "typing.AbstractSet", + "typing.MutableSet", + "typing.Mapping", + "typing.MutableMapping", + "typing.Sequence", + "typing.MutableSequence", + "typing.ByteString", + "typing.Tuple", + "typing.List", + "typing.Deque", + "typing.Set", + "typing.FrozenSet", + "typing.MappingView", + "typing.KeysView", + "typing.ItemsView", + "typing.ValuesView", + "typing.ContextManager", + "typing.AsyncContextManager", + "typing.Dict", + "typing.DefaultDict", + "typing.OrderedDict", + "typing.Counter", + "typing.ChainMap", + "typing.Generator", + "typing.AsyncGenerator", + "typing.Type", + "typing.Pattern", + "typing.Match", + ) +) + +CLASS_GETITEM_TEMPLATE = """ +@classmethod +def __class_getitem__(cls, item): + return cls +""" + + +def looks_like_typing_typevar_or_newtype(node): + func = node.func + if isinstance(func, Attribute): + return func.attrname in TYPING_TYPEVARS + if isinstance(func, Name): + return func.name in TYPING_TYPEVARS + return False + + +def infer_typing_typevar_or_newtype(node, context_itton=None): + """Infer a typing.TypeVar(...) or typing.NewType(...) call""" + try: + func = next(node.func.infer(context=context_itton)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + + if func.qname() not in TYPING_TYPEVARS_QUALIFIED: + raise UseInferenceDefault + if not node.args: + raise UseInferenceDefault + # Cannot infer from a dynamic class name (f-string) + if isinstance(node.args[0], JoinedStr): + raise UseInferenceDefault + + typename = node.args[0].as_string().strip("'") + node = extract_node(TYPING_TYPE_TEMPLATE.format(typename)) + return node.infer(context=context_itton) + + +def _looks_like_typing_subscript(node): + """Try to figure out if a Subscript node *might* be a typing-related subscript""" + if isinstance(node, Name): + return node.name in TYPING_MEMBERS + if isinstance(node, Attribute): + return node.attrname in TYPING_MEMBERS + if isinstance(node, Subscript): + return _looks_like_typing_subscript(node.value) + return False + + +def infer_typing_attr( + node: Subscript, ctx: typing.Optional[context.InferenceContext] = None +) -> typing.Iterator[ClassDef]: + """Infer a typing.X[...] subscript""" + try: + value = next(node.value.infer()) # type: ignore[union-attr] # value shouldn't be None for Subscript. + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + + if ( + not value.qname().startswith("typing.") + or PY37_PLUS + and value.qname() in TYPING_ALIAS + ): + # If typing subscript belongs to an alias + # (PY37+) handle it separately. + raise UseInferenceDefault + + if ( + PY37_PLUS + and isinstance(value, ClassDef) + and value.qname() + in {"typing.Generic", "typing.Annotated", "typing_extensions.Annotated"} + ): + # With PY37+ typing.Generic and typing.Annotated (PY39) are subscriptable + # through __class_getitem__. Since astroid can't easily + # infer the native methods, replace them for an easy inference tip + func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE) + value.locals["__class_getitem__"] = [func_to_add] + if ( + isinstance(node.parent, ClassDef) + and node in node.parent.bases + and getattr(node.parent, "__cache", None) + ): + # node.parent.slots is evaluated and cached before the inference tip + # is first applied. Remove the last result to allow a recalculation of slots + cache = node.parent.__cache # type: ignore[attr-defined] # Unrecognized getattr + if cache.get(node.parent.slots) is not None: + del cache[node.parent.slots] + return iter([value]) + + node = extract_node(TYPING_TYPE_TEMPLATE.format(value.qname().split(".")[-1])) + return node.infer(context=ctx) + + +def _looks_like_typedDict( # pylint: disable=invalid-name + node: typing.Union[FunctionDef, ClassDef], +) -> bool: + """Check if node is TypedDict FunctionDef.""" + return node.qname() in {"typing.TypedDict", "typing_extensions.TypedDict"} + + +def infer_old_typedDict( # pylint: disable=invalid-name + node: ClassDef, ctx: typing.Optional[context.InferenceContext] = None +) -> typing.Iterator[ClassDef]: + func_to_add = _extract_single_node("dict") + node.locals["__call__"] = [func_to_add] + return iter([node]) + + +def infer_typedDict( # pylint: disable=invalid-name + node: FunctionDef, ctx: typing.Optional[context.InferenceContext] = None +) -> typing.Iterator[ClassDef]: + """Replace TypedDict FunctionDef with ClassDef.""" + class_def = ClassDef( + name="TypedDict", + lineno=node.lineno, + col_offset=node.col_offset, + parent=node.parent, + ) + class_def.postinit(bases=[extract_node("dict")], body=[], decorators=None) + func_to_add = _extract_single_node("dict") + class_def.locals["__call__"] = [func_to_add] + return iter([class_def]) + + +def _looks_like_typing_alias(node: Call) -> bool: + """ + Returns True if the node corresponds to a call to _alias function. + For example : + + MutableSet = _alias(collections.abc.MutableSet, T) + + :param node: call node + """ + return ( + isinstance(node.func, Name) + and node.func.name == "_alias" + and ( + # _alias function works also for builtins object such as list and dict + isinstance(node.args[0], (Attribute, Name)) + ) + ) + + +def _forbid_class_getitem_access(node: ClassDef) -> None: + """ + Disable the access to __class_getitem__ method for the node in parameters + """ + + def full_raiser(origin_func, attr, *args, **kwargs): + """ + Raises an AttributeInferenceError in case of access to __class_getitem__ method. + Otherwise just call origin_func. + """ + if attr == "__class_getitem__": + raise AttributeInferenceError("__class_getitem__ access is not allowed") + return origin_func(attr, *args, **kwargs) + + try: + node.getattr("__class_getitem__") + # If we are here, then we are sure to modify object that do have __class_getitem__ method (which origin is one the + # protocol defined in collections module) whereas the typing module consider it should not + # We do not want __class_getitem__ to be found in the classdef + partial_raiser = partial(full_raiser, node.getattr) + node.getattr = partial_raiser + except AttributeInferenceError: + pass + + +def infer_typing_alias( + node: Call, ctx: typing.Optional[context.InferenceContext] = None +) -> typing.Iterator[ClassDef]: + """ + Infers the call to _alias function + Insert ClassDef, with same name as aliased class, + in mro to simulate _GenericAlias. + + :param node: call node + :param context: inference context + """ + if ( + not isinstance(node.parent, Assign) + or not len(node.parent.targets) == 1 + or not isinstance(node.parent.targets[0], AssignName) + ): + raise UseInferenceDefault + try: + res = next(node.args[0].infer(context=ctx)) + except StopIteration as e: + raise InferenceError(node=node.args[0], context=context) from e + + assign_name = node.parent.targets[0] + + class_def = ClassDef( + name=assign_name.name, + lineno=assign_name.lineno, + col_offset=assign_name.col_offset, + parent=node.parent, + ) + if res != Uninferable and isinstance(res, ClassDef): + # Only add `res` as base if it's a `ClassDef` + # This isn't the case for `typing.Pattern` and `typing.Match` + class_def.postinit(bases=[res], body=[], decorators=None) + + maybe_type_var = node.args[1] + if ( + not PY39_PLUS + and not (isinstance(maybe_type_var, Tuple) and not maybe_type_var.elts) + or PY39_PLUS + and isinstance(maybe_type_var, Const) + and maybe_type_var.value > 0 + ): + # If typing alias is subscriptable, add `__class_getitem__` to ClassDef + func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE) + class_def.locals["__class_getitem__"] = [func_to_add] + else: + # If not, make sure that `__class_getitem__` access is forbidden. + # This is an issue in cases where the aliased class implements it, + # but the typing alias isn't subscriptable. E.g., `typing.ByteString` for PY39+ + _forbid_class_getitem_access(class_def) + return iter([class_def]) + + +def _looks_like_special_alias(node: Call) -> bool: + """Return True if call is for Tuple or Callable alias. + + In PY37 and PY38 the call is to '_VariadicGenericAlias' with 'tuple' as + first argument. In PY39+ it is replaced by a call to '_TupleType'. + + PY37: Tuple = _VariadicGenericAlias(tuple, (), inst=False, special=True) + PY39: Tuple = _TupleType(tuple, -1, inst=False, name='Tuple') + + + PY37: Callable = _VariadicGenericAlias(collections.abc.Callable, (), special=True) + PY39: Callable = _CallableType(collections.abc.Callable, 2) + """ + return isinstance(node.func, Name) and ( + not PY39_PLUS + and node.func.name == "_VariadicGenericAlias" + and ( + isinstance(node.args[0], Name) + and node.args[0].name == "tuple" + or isinstance(node.args[0], Attribute) + and node.args[0].as_string() == "collections.abc.Callable" + ) + or PY39_PLUS + and ( + node.func.name == "_TupleType" + and isinstance(node.args[0], Name) + and node.args[0].name == "tuple" + or node.func.name == "_CallableType" + and isinstance(node.args[0], Attribute) + and node.args[0].as_string() == "collections.abc.Callable" + ) + ) + + +def infer_special_alias( + node: Call, ctx: typing.Optional[context.InferenceContext] = None +) -> typing.Iterator[ClassDef]: + """Infer call to tuple alias as new subscriptable class typing.Tuple.""" + if not ( + isinstance(node.parent, Assign) + and len(node.parent.targets) == 1 + and isinstance(node.parent.targets[0], AssignName) + ): + raise UseInferenceDefault + try: + res = next(node.args[0].infer(context=ctx)) + except StopIteration as e: + raise InferenceError(node=node.args[0], context=context) from e + + assign_name = node.parent.targets[0] + class_def = ClassDef( + name=assign_name.name, + parent=node.parent, + ) + class_def.postinit(bases=[res], body=[], decorators=None) + func_to_add = _extract_single_node(CLASS_GETITEM_TEMPLATE) + class_def.locals["__class_getitem__"] = [func_to_add] + return iter([class_def]) + + +def _looks_like_typing_cast(node: Call) -> bool: + return isinstance(node, Call) and ( + isinstance(node.func, Name) + and node.func.name == "cast" + or isinstance(node.func, Attribute) + and node.func.attrname == "cast" + ) + + +def infer_typing_cast( + node: Call, ctx: typing.Optional[context.InferenceContext] = None +) -> typing.Iterator[NodeNG]: + """Infer call to cast() returning same type as casted-from var""" + if not isinstance(node.func, (Name, Attribute)): + raise UseInferenceDefault + + try: + func = next(node.func.infer(context=ctx)) + except (InferenceError, StopIteration) as exc: + raise UseInferenceDefault from exc + if ( + not isinstance(func, FunctionDef) + or func.qname() != "typing.cast" + or len(node.args) != 2 + ): + raise UseInferenceDefault + + return node.args[1].infer(context=ctx) + + +AstroidManager().register_transform( + Call, + inference_tip(infer_typing_typevar_or_newtype), + looks_like_typing_typevar_or_newtype, +) +AstroidManager().register_transform( + Subscript, inference_tip(infer_typing_attr), _looks_like_typing_subscript +) +AstroidManager().register_transform( + Call, inference_tip(infer_typing_cast), _looks_like_typing_cast +) + +if PY39_PLUS: + AstroidManager().register_transform( + FunctionDef, inference_tip(infer_typedDict), _looks_like_typedDict + ) +elif PY38_PLUS: + AstroidManager().register_transform( + ClassDef, inference_tip(infer_old_typedDict), _looks_like_typedDict + ) + +if PY37_PLUS: + AstroidManager().register_transform( + Call, inference_tip(infer_typing_alias), _looks_like_typing_alias + ) + AstroidManager().register_transform( + Call, inference_tip(infer_special_alias), _looks_like_special_alias + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_unittest.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_unittest.py new file mode 100644 index 0000000..b34e1cf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_unittest.py @@ -0,0 +1,31 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for unittest module""" +from astroid.brain.helpers import register_module_extender +from astroid.builder import parse +from astroid.const import PY38_PLUS +from astroid.manager import AstroidManager + + +def IsolatedAsyncioTestCaseImport(): + """ + In the unittest package, the IsolatedAsyncioTestCase class is imported lazily, i.e only + when the __getattr__ method of the unittest module is called with 'IsolatedAsyncioTestCase' as + argument. Thus the IsolatedAsyncioTestCase is not imported statically (during import time). + This function mocks a classical static import of the IsolatedAsyncioTestCase. + + (see https://github.com/PyCQA/pylint/issues/4060) + """ + return parse( + """ + from .async_case import IsolatedAsyncioTestCase + """ + ) + + +if PY38_PLUS: + register_module_extender( + AstroidManager(), "unittest", IsolatedAsyncioTestCaseImport + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/brain_uuid.py b/myenv/lib/python3.9/site-packages/astroid/brain/brain_uuid.py new file mode 100644 index 0000000..f6ba888 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/brain_uuid.py @@ -0,0 +1,18 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Astroid hooks for the UUID module.""" +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import Const +from astroid.nodes.scoped_nodes import ClassDef + + +def _patch_uuid_class(node): + # The .int member is patched using __dict__ + node.locals["int"] = [Const(0, parent=node)] + + +AstroidManager().register_transform( + ClassDef, _patch_uuid_class, lambda node: node.qname() == "uuid.UUID" +) diff --git a/myenv/lib/python3.9/site-packages/astroid/brain/helpers.py b/myenv/lib/python3.9/site-packages/astroid/brain/helpers.py new file mode 100644 index 0000000..d74f595 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/brain/helpers.py @@ -0,0 +1,17 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from astroid.nodes.scoped_nodes import Module + + +def register_module_extender(manager, module_name, get_extension_mod): + def transform(node): + extension_module = get_extension_mod() + for name, objs in extension_module.locals.items(): + node.locals[name] = objs + for obj in objs: + if obj.parent is extension_module: + obj.parent = node + + manager.register_transform(Module, transform, lambda n: n.name == module_name) diff --git a/myenv/lib/python3.9/site-packages/astroid/builder.py b/myenv/lib/python3.9/site-packages/astroid/builder.py new file mode 100644 index 0000000..1cdb963 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/builder.py @@ -0,0 +1,464 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""The AstroidBuilder makes astroid from living object and / or from _ast + +The builder is not thread safe and can't be used to parse different sources +at the same time. +""" +import os +import textwrap +import types +from tokenize import detect_encoding +from typing import List, Optional, Tuple, Union + +from astroid import bases, modutils, nodes, raw_building, rebuilder, util +from astroid._ast import get_parser_module +from astroid.exceptions import AstroidBuildingError, AstroidSyntaxError, InferenceError +from astroid.manager import AstroidManager +from astroid.nodes.node_classes import NodeNG + +objects = util.lazy_import("objects") + +# The name of the transient function that is used to +# wrap expressions to be extracted when calling +# extract_node. +_TRANSIENT_FUNCTION = "__" + +# The comment used to select a statement to be extracted +# when calling extract_node. +_STATEMENT_SELECTOR = "#@" +MISPLACED_TYPE_ANNOTATION_ERROR = "misplaced type annotation" + + +def open_source_file(filename): + # pylint: disable=consider-using-with + with open(filename, "rb") as byte_stream: + encoding = detect_encoding(byte_stream.readline)[0] + stream = open(filename, newline=None, encoding=encoding) + data = stream.read() + return stream, encoding, data + + +def _can_assign_attr(node, attrname): + try: + slots = node.slots() + except NotImplementedError: + pass + else: + if slots and attrname not in {slot.value for slot in slots}: + return False + return node.qname() != "builtins.object" + + +class AstroidBuilder(raw_building.InspectBuilder): + """Class for building an astroid tree from source code or from a live module. + + The param *manager* specifies the manager class which should be used. + If no manager is given, then the default one will be used. The + param *apply_transforms* determines if the transforms should be + applied after the tree was built from source or from a live object, + by default being True. + """ + + # pylint: disable=redefined-outer-name + def __init__(self, manager=None, apply_transforms=True): + super().__init__(manager) + self._apply_transforms = apply_transforms + + def module_build( + self, module: types.ModuleType, modname: Optional[str] = None + ) -> nodes.Module: + """Build an astroid from a living module instance.""" + node = None + path = getattr(module, "__file__", None) + loader = getattr(module, "__loader__", None) + # Prefer the loader to get the source rather than assuming we have a + # filesystem to read the source file from ourselves. + if loader: + modname = modname or module.__name__ + source = loader.get_source(modname) + if source: + node = self.string_build(source, modname, path=path) + if node is None and path is not None: + path_, ext = os.path.splitext(modutils._path_from_filename(path)) + if ext in {".py", ".pyc", ".pyo"} and os.path.exists(path_ + ".py"): + node = self.file_build(path_ + ".py", modname) + if node is None: + # this is a built-in module + # get a partial representation by introspection + node = self.inspect_build(module, modname=modname, path=path) + if self._apply_transforms: + # We have to handle transformation by ourselves since the + # rebuilder isn't called for builtin nodes + node = self._manager.visit_transforms(node) + return node + + def file_build(self, path, modname=None): + """Build astroid from a source code file (i.e. from an ast) + + *path* is expected to be a python source file + """ + try: + stream, encoding, data = open_source_file(path) + except OSError as exc: + raise AstroidBuildingError( + "Unable to load file {path}:\n{error}", + modname=modname, + path=path, + error=exc, + ) from exc + except (SyntaxError, LookupError) as exc: + raise AstroidSyntaxError( + "Python 3 encoding specification error or unknown encoding:\n" + "{error}", + modname=modname, + path=path, + error=exc, + ) from exc + except UnicodeError as exc: # wrong encoding + # detect_encoding returns utf-8 if no encoding specified + raise AstroidBuildingError( + "Wrong or no encoding specified for {filename}.", filename=path + ) from exc + with stream: + # get module name if necessary + if modname is None: + try: + modname = ".".join(modutils.modpath_from_file(path)) + except ImportError: + modname = os.path.splitext(os.path.basename(path))[0] + # build astroid representation + module, builder = self._data_build(data, modname, path) + return self._post_build(module, builder, encoding) + + def string_build(self, data, modname="", path=None): + """Build astroid from source code string.""" + module, builder = self._data_build(data, modname, path) + module.file_bytes = data.encode("utf-8") + return self._post_build(module, builder, "utf-8") + + def _post_build( + self, module: nodes.Module, builder: rebuilder.TreeRebuilder, encoding: str + ) -> nodes.Module: + """Handles encoding and delayed nodes after a module has been built""" + module.file_encoding = encoding + self._manager.cache_module(module) + # post tree building steps after we stored the module in the cache: + for from_node in builder._import_from_nodes: + if from_node.modname == "__future__": + for symbol, _ in from_node.names: + module.future_imports.add(symbol) + self.add_from_names_to_locals(from_node) + # handle delayed assattr nodes + for delayed in builder._delayed_assattr: + self.delayed_assattr(delayed) + + # Visit the transforms + if self._apply_transforms: + module = self._manager.visit_transforms(module) + return module + + def _data_build( + self, data: str, modname, path + ) -> Tuple[nodes.Module, rebuilder.TreeRebuilder]: + """Build tree node from data and add some informations""" + try: + node, parser_module = _parse_string(data, type_comments=True) + except (TypeError, ValueError, SyntaxError) as exc: + raise AstroidSyntaxError( + "Parsing Python code failed:\n{error}", + source=data, + modname=modname, + path=path, + error=exc, + ) from exc + + if path is not None: + node_file = os.path.abspath(path) + else: + node_file = "" + if modname.endswith(".__init__"): + modname = modname[:-9] + package = True + else: + package = ( + path is not None + and os.path.splitext(os.path.basename(path))[0] == "__init__" + ) + builder = rebuilder.TreeRebuilder(self._manager, parser_module, data) + module = builder.visit_module(node, modname, node_file, package) + return module, builder + + def add_from_names_to_locals(self, node): + """Store imported names to the locals + + Resort the locals if coming from a delayed node + """ + + def _key_func(node): + return node.fromlineno + + def sort_locals(my_list): + my_list.sort(key=_key_func) + + for (name, asname) in node.names: + if name == "*": + try: + imported = node.do_import_module() + except AstroidBuildingError: + continue + for name in imported.public_names(): + node.parent.set_local(name, node) + sort_locals(node.parent.scope().locals[name]) + else: + node.parent.set_local(asname or name, node) + sort_locals(node.parent.scope().locals[asname or name]) + + def delayed_assattr(self, node): + """Visit a AssAttr node + + This adds name to locals and handle members definition. + """ + try: + frame = node.frame(future=True) + for inferred in node.expr.infer(): + if inferred is util.Uninferable: + continue + try: + cls = inferred.__class__ + if cls is bases.Instance or cls is objects.ExceptionInstance: + inferred = inferred._proxied + iattrs = inferred.instance_attrs + if not _can_assign_attr(inferred, node.attrname): + continue + elif isinstance(inferred, bases.Instance): + # Const, Tuple or other containers that inherit from + # `Instance` + continue + elif inferred.is_function: + iattrs = inferred.instance_attrs + else: + iattrs = inferred.locals + except AttributeError: + # XXX log error + continue + values = iattrs.setdefault(node.attrname, []) + if node in values: + continue + # get assign in __init__ first XXX useful ? + if ( + frame.name == "__init__" + and values + and values[0].frame(future=True).name != "__init__" + ): + values.insert(0, node) + else: + values.append(node) + except InferenceError: + pass + + +def build_namespace_package_module(name: str, path: List[str]) -> nodes.Module: + return nodes.Module(name, path=path, package=True) + + +def parse(code, module_name="", path=None, apply_transforms=True): + """Parses a source string in order to obtain an astroid AST from it + + :param str code: The code for the module. + :param str module_name: The name for the module, if any + :param str path: The path for the module + :param bool apply_transforms: + Apply the transforms for the give code. Use it if you + don't want the default transforms to be applied. + """ + code = textwrap.dedent(code) + builder = AstroidBuilder( + manager=AstroidManager(), apply_transforms=apply_transforms + ) + return builder.string_build(code, modname=module_name, path=path) + + +def _extract_expressions(node): + """Find expressions in a call to _TRANSIENT_FUNCTION and extract them. + + The function walks the AST recursively to search for expressions that + are wrapped into a call to _TRANSIENT_FUNCTION. If it finds such an + expression, it completely removes the function call node from the tree, + replacing it by the wrapped expression inside the parent. + + :param node: An astroid node. + :type node: astroid.bases.NodeNG + :yields: The sequence of wrapped expressions on the modified tree + expression can be found. + """ + if ( + isinstance(node, nodes.Call) + and isinstance(node.func, nodes.Name) + and node.func.name == _TRANSIENT_FUNCTION + ): + real_expr = node.args[0] + real_expr.parent = node.parent + # Search for node in all _astng_fields (the fields checked when + # get_children is called) of its parent. Some of those fields may + # be lists or tuples, in which case the elements need to be checked. + # When we find it, replace it by real_expr, so that the AST looks + # like no call to _TRANSIENT_FUNCTION ever took place. + for name in node.parent._astroid_fields: + child = getattr(node.parent, name) + if isinstance(child, (list, tuple)): + for idx, compound_child in enumerate(child): + if compound_child is node: + child[idx] = real_expr + elif child is node: + setattr(node.parent, name, real_expr) + yield real_expr + else: + for child in node.get_children(): + yield from _extract_expressions(child) + + +def _find_statement_by_line(node, line): + """Extracts the statement on a specific line from an AST. + + If the line number of node matches line, it will be returned; + otherwise its children are iterated and the function is called + recursively. + + :param node: An astroid node. + :type node: astroid.bases.NodeNG + :param line: The line number of the statement to extract. + :type line: int + :returns: The statement on the line, or None if no statement for the line + can be found. + :rtype: astroid.bases.NodeNG or None + """ + if isinstance(node, (nodes.ClassDef, nodes.FunctionDef, nodes.MatchCase)): + # This is an inaccuracy in the AST: the nodes that can be + # decorated do not carry explicit information on which line + # the actual definition (class/def), but .fromline seems to + # be close enough. + node_line = node.fromlineno + else: + node_line = node.lineno + + if node_line == line: + return node + + for child in node.get_children(): + result = _find_statement_by_line(child, line) + if result: + return result + + return None + + +def extract_node(code: str, module_name: str = "") -> Union[NodeNG, List[NodeNG]]: + """Parses some Python code as a module and extracts a designated AST node. + + Statements: + To extract one or more statement nodes, append #@ to the end of the line + + Examples: + >>> def x(): + >>> def y(): + >>> return 1 #@ + + The return statement will be extracted. + + >>> class X(object): + >>> def meth(self): #@ + >>> pass + + The function object 'meth' will be extracted. + + Expressions: + To extract arbitrary expressions, surround them with the fake + function call __(...). After parsing, the surrounded expression + will be returned and the whole AST (accessible via the returned + node's parent attribute) will look like the function call was + never there in the first place. + + Examples: + >>> a = __(1) + + The const node will be extracted. + + >>> def x(d=__(foo.bar)): pass + + The node containing the default argument will be extracted. + + >>> def foo(a, b): + >>> return 0 < __(len(a)) < b + + The node containing the function call 'len' will be extracted. + + If no statements or expressions are selected, the last toplevel + statement will be returned. + + If the selected statement is a discard statement, (i.e. an expression + turned into a statement), the wrapped expression is returned instead. + + For convenience, singleton lists are unpacked. + + :param str code: A piece of Python code that is parsed as + a module. Will be passed through textwrap.dedent first. + :param str module_name: The name of the module. + :returns: The designated node from the parse tree, or a list of nodes. + """ + + def _extract(node): + if isinstance(node, nodes.Expr): + return node.value + + return node + + requested_lines = [] + for idx, line in enumerate(code.splitlines()): + if line.strip().endswith(_STATEMENT_SELECTOR): + requested_lines.append(idx + 1) + + tree = parse(code, module_name=module_name) + if not tree.body: + raise ValueError("Empty tree, cannot extract from it") + + extracted = [] + if requested_lines: + extracted = [_find_statement_by_line(tree, line) for line in requested_lines] + + # Modifies the tree. + extracted.extend(_extract_expressions(tree)) + + if not extracted: + extracted.append(tree.body[-1]) + + extracted = [_extract(node) for node in extracted] + if len(extracted) == 1: + return extracted[0] + return extracted + + +def _extract_single_node(code: str, module_name: str = "") -> NodeNG: + """Call extract_node while making sure that only one value is returned.""" + ret = extract_node(code, module_name) + if isinstance(ret, list): + return ret[0] + return ret + + +def _parse_string(data, type_comments=True): + parser_module = get_parser_module(type_comments=type_comments) + try: + parsed = parser_module.parse(data + "\n", type_comments=type_comments) + except SyntaxError as exc: + # If the type annotations are misplaced for some reason, we do not want + # to fail the entire parsing of the file, so we need to retry the parsing without + # type comment support. + if exc.args[0] != MISPLACED_TYPE_ANNOTATION_ERROR or not type_comments: + raise + + parser_module = get_parser_module(type_comments=False) + parsed = parser_module.parse(data + "\n", type_comments=False) + return parsed, parser_module diff --git a/myenv/lib/python3.9/site-packages/astroid/const.py b/myenv/lib/python3.9/site-packages/astroid/const.py new file mode 100644 index 0000000..0cb2d09 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/const.py @@ -0,0 +1,32 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import enum +import sys + +PY36 = sys.version_info[:2] == (3, 6) +PY38 = sys.version_info[:2] == (3, 8) +PY37_PLUS = sys.version_info >= (3, 7) +PY38_PLUS = sys.version_info >= (3, 8) +PY39_PLUS = sys.version_info >= (3, 9) +PY310_PLUS = sys.version_info >= (3, 10) +PY311_PLUS = sys.version_info >= (3, 11) +BUILTINS = "builtins" # TODO Remove in 2.8 + +WIN32 = sys.platform == "win32" + +IS_PYPY = sys.implementation.name == "pypy" +IS_JYTHON = sys.implementation.name == "jython" + + +class Context(enum.Enum): + Load = 1 + Store = 2 + Del = 3 + + +# TODO Remove in 3.0 in favor of Context +Load = Context.Load +Store = Context.Store +Del = Context.Del diff --git a/myenv/lib/python3.9/site-packages/astroid/context.py b/myenv/lib/python3.9/site-packages/astroid/context.py new file mode 100644 index 0000000..a04996e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/context.py @@ -0,0 +1,201 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Various context related utilities, including inference and call contexts.""" +import contextlib +import pprint +from typing import TYPE_CHECKING, List, MutableMapping, Optional, Sequence, Tuple + +if TYPE_CHECKING: + from astroid.nodes.node_classes import Keyword, NodeNG + + +_INFERENCE_CACHE = {} + + +def _invalidate_cache(): + _INFERENCE_CACHE.clear() + + +class InferenceContext: + """Provide context for inference + + Store already inferred nodes to save time + Account for already visited nodes to stop infinite recursion + """ + + __slots__ = ( + "path", + "lookupname", + "callcontext", + "boundnode", + "extra_context", + "_nodes_inferred", + ) + + max_inferred = 100 + + def __init__(self, path=None, nodes_inferred=None): + if nodes_inferred is None: + self._nodes_inferred = [0] + else: + self._nodes_inferred = nodes_inferred + self.path = path or set() + """ + :type: set(tuple(NodeNG, optional(str))) + + Path of visited nodes and their lookupname + + Currently this key is ``(node, context.lookupname)`` + """ + self.lookupname = None + """ + :type: optional[str] + + The original name of the node + + e.g. + foo = 1 + The inference of 'foo' is nodes.Const(1) but the lookup name is 'foo' + """ + self.callcontext = None + """ + :type: optional[CallContext] + + The call arguments and keywords for the given context + """ + self.boundnode = None + """ + :type: optional[NodeNG] + + The bound node of the given context + + e.g. the bound node of object.__new__(cls) is the object node + """ + self.extra_context = {} + """ + :type: dict(NodeNG, Context) + + Context that needs to be passed down through call stacks + for call arguments + """ + + @property + def nodes_inferred(self): + """ + Number of nodes inferred in this context and all its clones/descendents + + Wrap inner value in a mutable cell to allow for mutating a class + variable in the presence of __slots__ + """ + return self._nodes_inferred[0] + + @nodes_inferred.setter + def nodes_inferred(self, value): + self._nodes_inferred[0] = value + + @property + def inferred( + self, + ) -> MutableMapping[ + Tuple["NodeNG", Optional[str], Optional[str], Optional[str]], Sequence["NodeNG"] + ]: + """ + Inferred node contexts to their mapped results + + Currently the key is ``(node, lookupname, callcontext, boundnode)`` + and the value is tuple of the inferred results + """ + return _INFERENCE_CACHE + + def push(self, node): + """Push node into inference path + + :return: True if node is already in context path else False + :rtype: bool + + Allows one to see if the given node has already + been looked at for this inference context""" + name = self.lookupname + if (node, name) in self.path: + return True + + self.path.add((node, name)) + return False + + def clone(self): + """Clone inference path + + For example, each side of a binary operation (BinOp) + starts with the same context but diverge as each side is inferred + so the InferenceContext will need be cloned""" + # XXX copy lookupname/callcontext ? + clone = InferenceContext(self.path.copy(), nodes_inferred=self._nodes_inferred) + clone.callcontext = self.callcontext + clone.boundnode = self.boundnode + clone.extra_context = self.extra_context + return clone + + @contextlib.contextmanager + def restore_path(self): + path = set(self.path) + yield + self.path = path + + def __str__(self): + state = ( + f"{field}={pprint.pformat(getattr(self, field), width=80 - len(field))}" + for field in self.__slots__ + ) + return "{}({})".format(type(self).__name__, ",\n ".join(state)) + + +class CallContext: + """Holds information for a call site.""" + + __slots__ = ("args", "keywords", "callee") + + def __init__( + self, + args: List["NodeNG"], + keywords: Optional[List["Keyword"]] = None, + callee: Optional["NodeNG"] = None, + ): + self.args = args # Call positional arguments + if keywords: + keywords = [(arg.arg, arg.value) for arg in keywords] + else: + keywords = [] + self.keywords = keywords # Call keyword arguments + self.callee = callee # Function being called + + +def copy_context(context: Optional[InferenceContext]) -> InferenceContext: + """Clone a context if given, or return a fresh contexxt""" + if context is not None: + return context.clone() + + return InferenceContext() + + +def bind_context_to_node(context, node): + """Give a context a boundnode + to retrieve the correct function name or attribute value + with from further inference. + + Do not use an existing context since the boundnode could then + be incorrectly propagated higher up in the call stack. + + :param context: Context to use + :type context: Optional(context) + + :param node: Node to do name lookups from + :type node NodeNG: + + :returns: A new context + :rtype: InferenceContext + """ + context = copy_context(context) + context.boundnode = node + return context diff --git a/myenv/lib/python3.9/site-packages/astroid/decorators.py b/myenv/lib/python3.9/site-packages/astroid/decorators.py new file mode 100644 index 0000000..ec16fea --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/decorators.py @@ -0,0 +1,273 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" A few useful function/method decorators.""" + +import functools +import inspect +import sys +import warnings +from typing import Callable, TypeVar + +import wrapt + +from astroid import util +from astroid.context import InferenceContext +from astroid.exceptions import InferenceError + +if sys.version_info >= (3, 10): + from typing import ParamSpec +else: + from typing_extensions import ParamSpec + +R = TypeVar("R") +P = ParamSpec("P") + + +@wrapt.decorator +def cached(func, instance, args, kwargs): + """Simple decorator to cache result of method calls without args.""" + cache = getattr(instance, "__cache", None) + if cache is None: + instance.__cache = cache = {} + try: + return cache[func] + except KeyError: + cache[func] = result = func(*args, **kwargs) + return result + + +# TODO: Remove when support for 3.7 is dropped +# TODO: astroid 3.0 -> move class behind sys.version_info < (3, 8) guard +class cachedproperty: + """Provides a cached property equivalent to the stacking of + @cached and @property, but more efficient. + + After first usage, the becomes part of the object's + __dict__. Doing: + + del obj. empties the cache. + + Idea taken from the pyramid_ framework and the mercurial_ project. + + .. _pyramid: http://pypi.python.org/pypi/pyramid + .. _mercurial: http://pypi.python.org/pypi/Mercurial + """ + + __slots__ = ("wrapped",) + + def __init__(self, wrapped): + if sys.version_info >= (3, 8): + warnings.warn( + "cachedproperty has been deprecated and will be removed in astroid 3.0 for Python 3.8+. " + "Use functools.cached_property instead.", + DeprecationWarning, + ) + try: + wrapped.__name__ + except AttributeError as exc: + raise TypeError(f"{wrapped} must have a __name__ attribute") from exc + self.wrapped = wrapped + + @property + def __doc__(self): + doc = getattr(self.wrapped, "__doc__", None) + return "%s" % ( + "\n%s" % doc if doc else "" + ) + + def __get__(self, inst, objtype=None): + if inst is None: + return self + val = self.wrapped(inst) + setattr(inst, self.wrapped.__name__, val) + return val + + +def path_wrapper(func): + """return the given infer function wrapped to handle the path + + Used to stop inference if the node has already been looked + at for a given `InferenceContext` to prevent infinite recursion + """ + + @functools.wraps(func) + def wrapped(node, context=None, _func=func, **kwargs): + """wrapper function handling context""" + if context is None: + context = InferenceContext() + if context.push(node): + return + + yielded = set() + + for res in _func(node, context, **kwargs): + # unproxy only true instance, not const, tuple, dict... + if res.__class__.__name__ == "Instance": + ares = res._proxied + else: + ares = res + if ares not in yielded: + yield res + yielded.add(ares) + + return wrapped + + +@wrapt.decorator +def yes_if_nothing_inferred(func, instance, args, kwargs): + generator = func(*args, **kwargs) + + try: + yield next(generator) + except StopIteration: + # generator is empty + yield util.Uninferable + return + + yield from generator + + +@wrapt.decorator +def raise_if_nothing_inferred(func, instance, args, kwargs): + generator = func(*args, **kwargs) + try: + yield next(generator) + except StopIteration as error: + # generator is empty + if error.args: + # pylint: disable=not-a-mapping + raise InferenceError(**error.args[0]) from error + raise InferenceError( + "StopIteration raised without any error information." + ) from error + + yield from generator + + +# Expensive decorators only used to emit Deprecation warnings. +# If no other than the default DeprecationWarning are enabled, +# fall back to passthrough implementations. +if util.check_warnings_filter(): + + def deprecate_default_argument_values( + astroid_version: str = "3.0", **arguments: str + ) -> Callable[[Callable[P, R]], Callable[P, R]]: + """Decorator which emits a DeprecationWarning if any arguments specified + are None or not passed at all. + + Arguments should be a key-value mapping, with the key being the argument to check + and the value being a type annotation as string for the value of the argument. + + To improve performance, only used when DeprecationWarnings other than + the default one are enabled. + """ + # Helpful links + # Decorator for DeprecationWarning: https://stackoverflow.com/a/49802489 + # Typing of stacked decorators: https://stackoverflow.com/a/68290080 + + def deco(func: Callable[P, R]) -> Callable[P, R]: + """Decorator function.""" + + @functools.wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: + """Emit DeprecationWarnings if conditions are met.""" + + keys = list(inspect.signature(func).parameters.keys()) + for arg, type_annotation in arguments.items(): + try: + index = keys.index(arg) + except ValueError: + raise Exception( + f"Can't find argument '{arg}' for '{args[0].__class__.__qualname__}'" + ) from None + if ( + # Check kwargs + # - if found, check it's not None + (arg in kwargs and kwargs[arg] is None) + # Check args + # - make sure not in kwargs + # - len(args) needs to be long enough, if too short + # arg can't be in args either + # - args[index] should not be None + or arg not in kwargs + and ( + index == -1 + or len(args) <= index + or (len(args) > index and args[index] is None) + ) + ): + warnings.warn( + f"'{arg}' will be a required argument for " + f"'{args[0].__class__.__qualname__}.{func.__name__}' in astroid {astroid_version} " + f"('{arg}' should be of type: '{type_annotation}')", + DeprecationWarning, + ) + return func(*args, **kwargs) + + return wrapper + + return deco + + def deprecate_arguments( + astroid_version: str = "3.0", **arguments: str + ) -> Callable[[Callable[P, R]], Callable[P, R]]: + """Decorator which emits a DeprecationWarning if any arguments specified + are passed. + + Arguments should be a key-value mapping, with the key being the argument to check + and the value being a string that explains what to do instead of passing the argument. + + To improve performance, only used when DeprecationWarnings other than + the default one are enabled. + """ + + def deco(func: Callable[P, R]) -> Callable[P, R]: + @functools.wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: + + keys = list(inspect.signature(func).parameters.keys()) + for arg, note in arguments.items(): + try: + index = keys.index(arg) + except ValueError: + raise Exception( + f"Can't find argument '{arg}' for '{args[0].__class__.__qualname__}'" + ) from None + if arg in kwargs or len(args) > index: + warnings.warn( + f"The argument '{arg}' for " + f"'{args[0].__class__.__qualname__}.{func.__name__}' is deprecated " + f"and will be removed in astroid {astroid_version} ({note})", + DeprecationWarning, + ) + return func(*args, **kwargs) + + return wrapper + + return deco + +else: + + def deprecate_default_argument_values( + astroid_version: str = "3.0", **arguments: str + ) -> Callable[[Callable[P, R]], Callable[P, R]]: + """Passthrough decorator to improve performance if DeprecationWarnings are disabled.""" + + def deco(func: Callable[P, R]) -> Callable[P, R]: + """Decorator function.""" + return func + + return deco + + def deprecate_arguments( + astroid_version: str = "3.0", **arguments: str + ) -> Callable[[Callable[P, R]], Callable[P, R]]: + """Passthrough decorator to improve performance if DeprecationWarnings are disabled.""" + + def deco(func: Callable[P, R]) -> Callable[P, R]: + """Decorator function.""" + return func + + return deco diff --git a/myenv/lib/python3.9/site-packages/astroid/exceptions.py b/myenv/lib/python3.9/site-packages/astroid/exceptions.py new file mode 100644 index 0000000..c3909b2 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/exceptions.py @@ -0,0 +1,292 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""this module contains exceptions used in the astroid library +""" +from typing import TYPE_CHECKING + +from astroid import util + +if TYPE_CHECKING: + from astroid import nodes + +__all__ = ( + "AstroidBuildingError", + "AstroidBuildingException", + "AstroidError", + "AstroidImportError", + "AstroidIndexError", + "AstroidSyntaxError", + "AstroidTypeError", + "AstroidValueError", + "AttributeInferenceError", + "BinaryOperationError", + "DuplicateBasesError", + "InconsistentMroError", + "InferenceError", + "InferenceOverwriteError", + "MroError", + "NameInferenceError", + "NoDefault", + "NotFoundError", + "OperationError", + "ParentMissingError", + "ResolveError", + "StatementMissing", + "SuperArgumentTypeError", + "SuperError", + "TooManyLevelsError", + "UnaryOperationError", + "UnresolvableName", + "UseInferenceDefault", +) + + +class AstroidError(Exception): + """base exception class for all astroid related exceptions + + AstroidError and its subclasses are structured, intended to hold + objects representing state when the exception is thrown. Field + values are passed to the constructor as keyword-only arguments. + Each subclass has its own set of standard fields, but use your + best judgment to decide whether a specific exception instance + needs more or fewer fields for debugging. Field values may be + used to lazily generate the error message: self.message.format() + will be called with the field names and values supplied as keyword + arguments. + """ + + def __init__(self, message="", **kws): + super().__init__(message) + self.message = message + for key, value in kws.items(): + setattr(self, key, value) + + def __str__(self): + return self.message.format(**vars(self)) + + +class AstroidBuildingError(AstroidError): + """exception class when we are unable to build an astroid representation + + Standard attributes: + modname: Name of the module that AST construction failed for. + error: Exception raised during construction. + """ + + def __init__(self, message="Failed to import module {modname}.", **kws): + super().__init__(message, **kws) + + +class AstroidImportError(AstroidBuildingError): + """Exception class used when a module can't be imported by astroid.""" + + +class TooManyLevelsError(AstroidImportError): + """Exception class which is raised when a relative import was beyond the top-level. + + Standard attributes: + level: The level which was attempted. + name: the name of the module on which the relative import was attempted. + """ + + level = None + name = None + + def __init__( + self, + message="Relative import with too many levels " "({level}) for module {name!r}", + **kws, + ): + super().__init__(message, **kws) + + +class AstroidSyntaxError(AstroidBuildingError): + """Exception class used when a module can't be parsed.""" + + +class NoDefault(AstroidError): + """raised by function's `default_value` method when an argument has + no default value + + Standard attributes: + func: Function node. + name: Name of argument without a default. + """ + + func = None + name = None + + def __init__(self, message="{func!r} has no default for {name!r}.", **kws): + super().__init__(message, **kws) + + +class ResolveError(AstroidError): + """Base class of astroid resolution/inference error. + + ResolveError is not intended to be raised. + + Standard attributes: + context: InferenceContext object. + """ + + context = None + + +class MroError(ResolveError): + """Error raised when there is a problem with method resolution of a class. + + Standard attributes: + mros: A sequence of sequences containing ClassDef nodes. + cls: ClassDef node whose MRO resolution failed. + context: InferenceContext object. + """ + + mros = () + cls = None + + def __str__(self): + mro_names = ", ".join(f"({', '.join(b.name for b in m)})" for m in self.mros) + return self.message.format(mros=mro_names, cls=self.cls) + + +class DuplicateBasesError(MroError): + """Error raised when there are duplicate bases in the same class bases.""" + + +class InconsistentMroError(MroError): + """Error raised when a class's MRO is inconsistent.""" + + +class SuperError(ResolveError): + """Error raised when there is a problem with a *super* call. + + Standard attributes: + *super_*: The Super instance that raised the exception. + context: InferenceContext object. + """ + + super_ = None + + def __str__(self): + return self.message.format(**vars(self.super_)) + + +class InferenceError(ResolveError): + """raised when we are unable to infer a node + + Standard attributes: + node: The node inference was called on. + context: InferenceContext object. + """ + + node = None + context = None + + def __init__(self, message="Inference failed for {node!r}.", **kws): + super().__init__(message, **kws) + + +# Why does this inherit from InferenceError rather than ResolveError? +# Changing it causes some inference tests to fail. +class NameInferenceError(InferenceError): + """Raised when a name lookup fails, corresponds to NameError. + + Standard attributes: + name: The name for which lookup failed, as a string. + scope: The node representing the scope in which the lookup occurred. + context: InferenceContext object. + """ + + name = None + scope = None + + def __init__(self, message="{name!r} not found in {scope!r}.", **kws): + super().__init__(message, **kws) + + +class AttributeInferenceError(ResolveError): + """Raised when an attribute lookup fails, corresponds to AttributeError. + + Standard attributes: + target: The node for which lookup failed. + attribute: The attribute for which lookup failed, as a string. + context: InferenceContext object. + """ + + target = None + attribute = None + + def __init__(self, message="{attribute!r} not found on {target!r}.", **kws): + super().__init__(message, **kws) + + +class UseInferenceDefault(Exception): + """exception to be raised in custom inference function to indicate that it + should go back to the default behaviour + """ + + +class _NonDeducibleTypeHierarchy(Exception): + """Raised when is_subtype / is_supertype can't deduce the relation between two types.""" + + +class AstroidIndexError(AstroidError): + """Raised when an Indexable / Mapping does not have an index / key.""" + + +class AstroidTypeError(AstroidError): + """Raised when a TypeError would be expected in Python code.""" + + +class AstroidValueError(AstroidError): + """Raised when a ValueError would be expected in Python code.""" + + +class InferenceOverwriteError(AstroidError): + """Raised when an inference tip is overwritten + + Currently only used for debugging. + """ + + +class ParentMissingError(AstroidError): + """Raised when a node which is expected to have a parent attribute is missing one + + Standard attributes: + target: The node for which the parent lookup failed. + """ + + def __init__(self, target: "nodes.NodeNG") -> None: + self.target = target + super().__init__(message=f"Parent not found on {target!r}.") + + +class StatementMissing(ParentMissingError): + """Raised when a call to node.statement() does not return a node. This is because + a node in the chain does not have a parent attribute and therefore does not + return a node for statement(). + + Standard attributes: + target: The node for which the parent lookup failed. + """ + + def __init__(self, target: "nodes.NodeNG") -> None: + # pylint: disable-next=bad-super-call + # https://github.com/PyCQA/pylint/issues/2903 + # https://github.com/PyCQA/astroid/pull/1217#discussion_r744149027 + super(ParentMissingError, self).__init__( + message=f"Statement not found on {target!r}" + ) + + +# Backwards-compatibility aliases +OperationError = util.BadOperationMessage +UnaryOperationError = util.BadUnaryOperationMessage +BinaryOperationError = util.BadBinaryOperationMessage + +SuperArgumentTypeError = SuperError +UnresolvableName = NameInferenceError +NotFoundError = AttributeInferenceError +AstroidBuildingException = AstroidBuildingError diff --git a/myenv/lib/python3.9/site-packages/astroid/filter_statements.py b/myenv/lib/python3.9/site-packages/astroid/filter_statements.py new file mode 100644 index 0000000..86a63f3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/filter_statements.py @@ -0,0 +1,239 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""_filter_stmts and helper functions. This method gets used in LocalsDictnodes.NodeNG._scope_lookup. +It is not considered public. +""" + +from typing import List, Optional, Tuple + +from astroid import nodes + + +def _get_filtered_node_statements( + base_node: nodes.NodeNG, stmt_nodes: List[nodes.NodeNG] +) -> List[Tuple[nodes.NodeNG, nodes.Statement]]: + statements = [(node, node.statement(future=True)) for node in stmt_nodes] + # Next we check if we have ExceptHandlers that are parent + # of the underlying variable, in which case the last one survives + if len(statements) > 1 and all( + isinstance(stmt, nodes.ExceptHandler) for _, stmt in statements + ): + statements = [ + (node, stmt) for node, stmt in statements if stmt.parent_of(base_node) + ] + return statements + + +def _is_from_decorator(node): + """Return True if the given node is the child of a decorator""" + return any(isinstance(parent, nodes.Decorators) for parent in node.node_ancestors()) + + +def _get_if_statement_ancestor(node: nodes.NodeNG) -> Optional[nodes.If]: + """Return the first parent node that is an If node (or None)""" + for parent in node.node_ancestors(): + if isinstance(parent, nodes.If): + return parent + return None + + +def _filter_stmts(base_node: nodes.NodeNG, stmts, frame, offset): + """Filter the given list of statements to remove ignorable statements. + + If base_node is not a frame itself and the name is found in the inner + frame locals, statements will be filtered to remove ignorable + statements according to base_node's location. + + :param stmts: The statements to filter. + :type stmts: list(nodes.NodeNG) + + :param frame: The frame that all of the given statements belong to. + :type frame: nodes.NodeNG + + :param offset: The line offset to filter statements up to. + :type offset: int + + :returns: The filtered statements. + :rtype: list(nodes.NodeNG) + """ + # if offset == -1, my actual frame is not the inner frame but its parent + # + # class A(B): pass + # + # we need this to resolve B correctly + if offset == -1: + myframe = base_node.frame().parent.frame() + else: + myframe = base_node.frame() + # If the frame of this node is the same as the statement + # of this node, then the node is part of a class or + # a function definition and the frame of this node should be the + # the upper frame, not the frame of the definition. + # For more information why this is important, + # see Pylint issue #295. + # For example, for 'b', the statement is the same + # as the frame / scope: + # + # def test(b=1): + # ... + if ( + base_node.parent + and base_node.statement(future=True) is myframe + and myframe.parent + ): + myframe = myframe.parent.frame() + + mystmt: Optional[nodes.Statement] = None + if base_node.parent: + mystmt = base_node.statement(future=True) + + # line filtering if we are in the same frame + # + # take care node may be missing lineno information (this is the case for + # nodes inserted for living objects) + if myframe is frame and mystmt and mystmt.fromlineno is not None: + assert mystmt.fromlineno is not None, mystmt + mylineno = mystmt.fromlineno + offset + else: + # disabling lineno filtering + mylineno = 0 + + _stmts = [] + _stmt_parents = [] + statements = _get_filtered_node_statements(base_node, stmts) + for node, stmt in statements: + # line filtering is on and we have reached our location, break + if stmt.fromlineno and stmt.fromlineno > mylineno > 0: + break + # Ignore decorators with the same name as the + # decorated function + # Fixes issue #375 + if mystmt is stmt and _is_from_decorator(base_node): + continue + if node.has_base(base_node): + break + + if isinstance(node, nodes.EmptyNode): + # EmptyNode does not have assign_type(), so just add it and move on + _stmts.append(node) + continue + + assign_type = node.assign_type() + _stmts, done = assign_type._get_filtered_stmts(base_node, node, _stmts, mystmt) + if done: + break + + optional_assign = assign_type.optional_assign + if optional_assign and assign_type.parent_of(base_node): + # we are inside a loop, loop var assignment is hiding previous + # assignment + _stmts = [node] + _stmt_parents = [stmt.parent] + continue + + if isinstance(assign_type, nodes.NamedExpr): + # If the NamedExpr is in an if statement we do some basic control flow inference + if_parent = _get_if_statement_ancestor(assign_type) + if if_parent: + # If the if statement is within another if statement we append the node + # to possible statements + if _get_if_statement_ancestor(if_parent): + optional_assign = False + _stmts.append(node) + _stmt_parents.append(stmt.parent) + # If the if statement is first-level and not within an orelse block + # we know that it will be evaluated + elif not if_parent.is_orelse: + _stmts = [node] + _stmt_parents = [stmt.parent] + # Else we do not known enough about the control flow to be 100% certain + # and we append to possible statements + else: + _stmts.append(node) + _stmt_parents.append(stmt.parent) + else: + _stmts = [node] + _stmt_parents = [stmt.parent] + + # XXX comment various branches below!!! + try: + pindex = _stmt_parents.index(stmt.parent) + except ValueError: + pass + else: + # we got a parent index, this means the currently visited node + # is at the same block level as a previously visited node + if _stmts[pindex].assign_type().parent_of(assign_type): + # both statements are not at the same block level + continue + # if currently visited node is following previously considered + # assignment and both are not exclusive, we can drop the + # previous one. For instance in the following code :: + # + # if a: + # x = 1 + # else: + # x = 2 + # print x + # + # we can't remove neither x = 1 nor x = 2 when looking for 'x' + # of 'print x'; while in the following :: + # + # x = 1 + # x = 2 + # print x + # + # we can remove x = 1 when we see x = 2 + # + # moreover, on loop assignment types, assignment won't + # necessarily be done if the loop has no iteration, so we don't + # want to clear previous assignments if any (hence the test on + # optional_assign) + if not (optional_assign or nodes.are_exclusive(_stmts[pindex], node)): + del _stmt_parents[pindex] + del _stmts[pindex] + + # If base_node and node are exclusive, then we can ignore node + if nodes.are_exclusive(base_node, node): + continue + + # An AssignName node overrides previous assignments if: + # 1. node's statement always assigns + # 2. node and base_node are in the same block (i.e., has the same parent as base_node) + if isinstance(node, (nodes.NamedExpr, nodes.AssignName)): + if isinstance(stmt, nodes.ExceptHandler): + # If node's statement is an ExceptHandler, then it is the variable + # bound to the caught exception. If base_node is not contained within + # the exception handler block, node should override previous assignments; + # otherwise, node should be ignored, as an exception variable + # is local to the handler block. + if stmt.parent_of(base_node): + _stmts = [] + _stmt_parents = [] + else: + continue + elif not optional_assign and mystmt and stmt.parent is mystmt.parent: + _stmts = [] + _stmt_parents = [] + elif isinstance(node, nodes.DelName): + # Remove all previously stored assignments + _stmts = [] + _stmt_parents = [] + continue + # Add the new assignment + _stmts.append(node) + if isinstance(node, nodes.Arguments) or isinstance( + node.parent, nodes.Arguments + ): + # Special case for _stmt_parents when node is a function parameter; + # in this case, stmt is the enclosing FunctionDef, which is what we + # want to add to _stmt_parents, not stmt.parent. This case occurs when + # node is an Arguments node (representing varargs or kwargs parameter), + # and when node.parent is an Arguments node (other parameters). + # See issue #180. + _stmt_parents.append(stmt) + else: + _stmt_parents.append(stmt.parent) + return _stmts diff --git a/myenv/lib/python3.9/site-packages/astroid/helpers.py b/myenv/lib/python3.9/site-packages/astroid/helpers.py new file mode 100644 index 0000000..8462f87 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/helpers.py @@ -0,0 +1,304 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Various helper utilities. +""" + + +from astroid import bases, manager, nodes, raw_building, util +from astroid.context import CallContext, InferenceContext +from astroid.exceptions import ( + AstroidTypeError, + AttributeInferenceError, + InferenceError, + MroError, + _NonDeducibleTypeHierarchy, +) +from astroid.nodes import scoped_nodes + + +def _build_proxy_class(cls_name, builtins): + proxy = raw_building.build_class(cls_name) + proxy.parent = builtins + return proxy + + +def _function_type(function, builtins): + if isinstance(function, scoped_nodes.Lambda): + if function.root().name == "builtins": + cls_name = "builtin_function_or_method" + else: + cls_name = "function" + elif isinstance(function, bases.BoundMethod): + cls_name = "method" + elif isinstance(function, bases.UnboundMethod): + cls_name = "function" + return _build_proxy_class(cls_name, builtins) + + +def _object_type(node, context=None): + astroid_manager = manager.AstroidManager() + builtins = astroid_manager.builtins_module + context = context or InferenceContext() + + for inferred in node.infer(context=context): + if isinstance(inferred, scoped_nodes.ClassDef): + if inferred.newstyle: + metaclass = inferred.metaclass(context=context) + if metaclass: + yield metaclass + continue + yield builtins.getattr("type")[0] + elif isinstance(inferred, (scoped_nodes.Lambda, bases.UnboundMethod)): + yield _function_type(inferred, builtins) + elif isinstance(inferred, scoped_nodes.Module): + yield _build_proxy_class("module", builtins) + elif isinstance(inferred, nodes.Unknown): + raise InferenceError + else: + yield inferred._proxied + + +def object_type(node, context=None): + """Obtain the type of the given node + + This is used to implement the ``type`` builtin, which means that it's + used for inferring type calls, as well as used in a couple of other places + in the inference. + The node will be inferred first, so this function can support all + sorts of objects, as long as they support inference. + """ + + try: + types = set(_object_type(node, context)) + except InferenceError: + return util.Uninferable + if len(types) > 1 or not types: + return util.Uninferable + return list(types)[0] + + +def _object_type_is_subclass(obj_type, class_or_seq, context=None): + if not isinstance(class_or_seq, (tuple, list)): + class_seq = (class_or_seq,) + else: + class_seq = class_or_seq + + if obj_type is util.Uninferable: + return util.Uninferable + + # Instances are not types + class_seq = [ + item if not isinstance(item, bases.Instance) else util.Uninferable + for item in class_seq + ] + # strict compatibility with issubclass + # issubclass(type, (object, 1)) evaluates to true + # issubclass(object, (1, type)) raises TypeError + for klass in class_seq: + if klass is util.Uninferable: + raise AstroidTypeError("arg 2 must be a type or tuple of types") + + for obj_subclass in obj_type.mro(): + if obj_subclass == klass: + return True + return False + + +def object_isinstance(node, class_or_seq, context=None): + """Check if a node 'isinstance' any node in class_or_seq + + :param node: A given node + :param class_or_seq: Union[nodes.NodeNG, Sequence[nodes.NodeNG]] + :rtype: bool + + :raises AstroidTypeError: if the given ``classes_or_seq`` are not types + """ + obj_type = object_type(node, context) + if obj_type is util.Uninferable: + return util.Uninferable + return _object_type_is_subclass(obj_type, class_or_seq, context=context) + + +def object_issubclass(node, class_or_seq, context=None): + """Check if a type is a subclass of any node in class_or_seq + + :param node: A given node + :param class_or_seq: Union[Nodes.NodeNG, Sequence[nodes.NodeNG]] + :rtype: bool + + :raises AstroidTypeError: if the given ``classes_or_seq`` are not types + :raises AstroidError: if the type of the given node cannot be inferred + or its type's mro doesn't work + """ + if not isinstance(node, nodes.ClassDef): + raise TypeError(f"{node} needs to be a ClassDef node") + return _object_type_is_subclass(node, class_or_seq, context=context) + + +def safe_infer(node, context=None): + """Return the inferred value for the given node. + + Return None if inference failed or if there is some ambiguity (more than + one node has been inferred). + """ + try: + inferit = node.infer(context=context) + value = next(inferit) + except (InferenceError, StopIteration): + return None + try: + next(inferit) + return None # None if there is ambiguity on the inferred node + except InferenceError: + return None # there is some kind of ambiguity + except StopIteration: + return value + + +def has_known_bases(klass, context=None): + """Return true if all base classes of a class could be inferred.""" + try: + return klass._all_bases_known + except AttributeError: + pass + for base in klass.bases: + result = safe_infer(base, context=context) + # TODO: check for A->B->A->B pattern in class structure too? + if ( + not isinstance(result, scoped_nodes.ClassDef) + or result is klass + or not has_known_bases(result, context=context) + ): + klass._all_bases_known = False + return False + klass._all_bases_known = True + return True + + +def _type_check(type1, type2): + if not all(map(has_known_bases, (type1, type2))): + raise _NonDeducibleTypeHierarchy + + if not all([type1.newstyle, type2.newstyle]): + return False + try: + return type1 in type2.mro()[:-1] + except MroError as e: + # The MRO is invalid. + raise _NonDeducibleTypeHierarchy from e + + +def is_subtype(type1, type2): + """Check if *type1* is a subtype of *type2*.""" + return _type_check(type1=type2, type2=type1) + + +def is_supertype(type1, type2): + """Check if *type2* is a supertype of *type1*.""" + return _type_check(type1, type2) + + +def class_instance_as_index(node): + """Get the value as an index for the given instance. + + If an instance provides an __index__ method, then it can + be used in some scenarios where an integer is expected, + for instance when multiplying or subscripting a list. + """ + context = InferenceContext() + try: + for inferred in node.igetattr("__index__", context=context): + if not isinstance(inferred, bases.BoundMethod): + continue + + context.boundnode = node + context.callcontext = CallContext(args=[], callee=inferred) + for result in inferred.infer_call_result(node, context=context): + if isinstance(result, nodes.Const) and isinstance(result.value, int): + return result + except InferenceError: + pass + return None + + +def object_len(node, context=None): + """Infer length of given node object + + :param Union[nodes.ClassDef, nodes.Instance] node: + :param node: Node to infer length of + + :raises AstroidTypeError: If an invalid node is returned + from __len__ method or no __len__ method exists + :raises InferenceError: If the given node cannot be inferred + or if multiple nodes are inferred or if the code executed in python + would result in a infinite recursive check for length + :rtype int: Integer length of node + """ + # pylint: disable=import-outside-toplevel; circular import + from astroid.objects import FrozenSet + + inferred_node = safe_infer(node, context=context) + + # prevent self referential length calls from causing a recursion error + # see https://github.com/PyCQA/astroid/issues/777 + node_frame = node.frame(future=True) + if ( + isinstance(node_frame, scoped_nodes.FunctionDef) + and node_frame.name == "__len__" + and hasattr(inferred_node, "_proxied") + and inferred_node._proxied == node_frame.parent + ): + message = ( + "Self referential __len__ function will " + "cause a RecursionError on line {} of {}".format( + node.lineno, node.root().file + ) + ) + raise InferenceError(message) + + if inferred_node is None or inferred_node is util.Uninferable: + raise InferenceError(node=node) + if isinstance(inferred_node, nodes.Const) and isinstance( + inferred_node.value, (bytes, str) + ): + return len(inferred_node.value) + if isinstance(inferred_node, (nodes.List, nodes.Set, nodes.Tuple, FrozenSet)): + return len(inferred_node.elts) + if isinstance(inferred_node, nodes.Dict): + return len(inferred_node.items) + + node_type = object_type(inferred_node, context=context) + if not node_type: + raise InferenceError(node=node) + + try: + len_call = next(node_type.igetattr("__len__", context=context)) + except StopIteration as e: + raise AstroidTypeError(str(e)) from e + except AttributeInferenceError as e: + raise AstroidTypeError( + f"object of type '{node_type.pytype()}' has no len()" + ) from e + + inferred = len_call.infer_call_result(node, context) + if inferred is util.Uninferable: + raise InferenceError(node=node, context=context) + result_of_len = next(inferred, None) + if ( + isinstance(result_of_len, nodes.Const) + and result_of_len.pytype() == "builtins.int" + ): + return result_of_len.value + if ( + result_of_len is None + or isinstance(result_of_len, bases.Instance) + and result_of_len.is_subtype_of("builtins.int") + ): + # Fake a result as we don't know the arguments of the instance call. + return 0 + raise AstroidTypeError( + f"'{result_of_len}' object cannot be interpreted as an integer" + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/inference.py b/myenv/lib/python3.9/site-packages/astroid/inference.py new file mode 100644 index 0000000..d220300 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/inference.py @@ -0,0 +1,1081 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""this module contains a set of functions to handle inference on astroid trees +""" + +import ast +import functools +import itertools +import operator +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + Generator, + Iterable, + Iterator, + Optional, + Type, + TypeVar, + Union, +) + +import wrapt + +from astroid import bases, decorators, helpers, nodes, protocols, util +from astroid.context import ( + CallContext, + InferenceContext, + bind_context_to_node, + copy_context, +) +from astroid.exceptions import ( + AstroidBuildingError, + AstroidError, + AstroidIndexError, + AstroidTypeError, + AttributeInferenceError, + InferenceError, + NameInferenceError, + _NonDeducibleTypeHierarchy, +) +from astroid.interpreter import dunder_lookup +from astroid.manager import AstroidManager +from astroid.typing import InferenceErrorInfo + +if TYPE_CHECKING: + from astroid.objects import Property + +# Prevents circular imports +objects = util.lazy_import("objects") + + +_FunctionDefT = TypeVar("_FunctionDefT", bound=nodes.FunctionDef) + + +# .infer method ############################################################### + + +def infer_end(self, context=None): + """Inference's end for nodes that yield themselves on inference + + These are objects for which inference does not have any semantic, + such as Module or Consts. + """ + yield self + + +# We add ignores to all these assignments in this file +# See https://github.com/python/mypy/issues/2427 +nodes.Module._infer = infer_end # type: ignore[assignment] +nodes.ClassDef._infer = infer_end # type: ignore[assignment] +nodes.Lambda._infer = infer_end # type: ignore[assignment] +nodes.Const._infer = infer_end # type: ignore[assignment] +nodes.Slice._infer = infer_end # type: ignore[assignment] + + +def _infer_sequence_helper(node, context=None): + """Infer all values based on _BaseContainer.elts""" + values = [] + + for elt in node.elts: + if isinstance(elt, nodes.Starred): + starred = helpers.safe_infer(elt.value, context) + if not starred: + raise InferenceError(node=node, context=context) + if not hasattr(starred, "elts"): + raise InferenceError(node=node, context=context) + values.extend(_infer_sequence_helper(starred)) + elif isinstance(elt, nodes.NamedExpr): + value = helpers.safe_infer(elt.value, context) + if not value: + raise InferenceError(node=node, context=context) + values.append(value) + else: + values.append(elt) + return values + + +@decorators.raise_if_nothing_inferred +def infer_sequence(self, context=None): + has_starred_named_expr = any( + isinstance(e, (nodes.Starred, nodes.NamedExpr)) for e in self.elts + ) + if has_starred_named_expr: + values = _infer_sequence_helper(self, context) + new_seq = type(self)( + lineno=self.lineno, col_offset=self.col_offset, parent=self.parent + ) + new_seq.postinit(values) + + yield new_seq + else: + yield self + + +nodes.List._infer = infer_sequence # type: ignore[assignment] +nodes.Tuple._infer = infer_sequence # type: ignore[assignment] +nodes.Set._infer = infer_sequence # type: ignore[assignment] + + +def infer_map(self, context=None): + if not any(isinstance(k, nodes.DictUnpack) for k, _ in self.items): + yield self + else: + items = _infer_map(self, context) + new_seq = type(self)(self.lineno, self.col_offset, self.parent) + new_seq.postinit(list(items.items())) + yield new_seq + + +def _update_with_replacement(lhs_dict, rhs_dict): + """Delete nodes that equate to duplicate keys + + Since an astroid node doesn't 'equal' another node with the same value, + this function uses the as_string method to make sure duplicate keys + don't get through + + Note that both the key and the value are astroid nodes + + Fixes issue with DictUnpack causing duplicte keys + in inferred Dict items + + :param dict(nodes.NodeNG, nodes.NodeNG) lhs_dict: Dictionary to 'merge' nodes into + :param dict(nodes.NodeNG, nodes.NodeNG) rhs_dict: Dictionary with nodes to pull from + :return dict(nodes.NodeNG, nodes.NodeNG): merged dictionary of nodes + """ + combined_dict = itertools.chain(lhs_dict.items(), rhs_dict.items()) + # Overwrite keys which have the same string values + string_map = {key.as_string(): (key, value) for key, value in combined_dict} + # Return to dictionary + return dict(string_map.values()) + + +def _infer_map(node, context): + """Infer all values based on Dict.items""" + values = {} + for name, value in node.items: + if isinstance(name, nodes.DictUnpack): + double_starred = helpers.safe_infer(value, context) + if not double_starred: + raise InferenceError + if not isinstance(double_starred, nodes.Dict): + raise InferenceError(node=node, context=context) + unpack_items = _infer_map(double_starred, context) + values = _update_with_replacement(values, unpack_items) + else: + key = helpers.safe_infer(name, context=context) + value = helpers.safe_infer(value, context=context) + if any(not elem for elem in (key, value)): + raise InferenceError(node=node, context=context) + values = _update_with_replacement(values, {key: value}) + return values + + +nodes.Dict._infer = infer_map # type: ignore[assignment] + + +def _higher_function_scope(node): + """Search for the first function which encloses the given + scope. This can be used for looking up in that function's + scope, in case looking up in a lower scope for a particular + name fails. + + :param node: A scope node. + :returns: + ``None``, if no parent function scope was found, + otherwise an instance of :class:`astroid.nodes.scoped_nodes.Function`, + which encloses the given node. + """ + current = node + while current.parent and not isinstance(current.parent, nodes.FunctionDef): + current = current.parent + if current and current.parent: + return current.parent + return None + + +def infer_name(self, context=None): + """infer a Name: use name lookup rules""" + frame, stmts = self.lookup(self.name) + if not stmts: + # Try to see if the name is enclosed in a nested function + # and use the higher (first function) scope for searching. + parent_function = _higher_function_scope(self.scope()) + if parent_function: + _, stmts = parent_function.lookup(self.name) + + if not stmts: + raise NameInferenceError( + name=self.name, scope=self.scope(), context=context + ) + context = copy_context(context) + context.lookupname = self.name + return bases._infer_stmts(stmts, context, frame) + + +# pylint: disable=no-value-for-parameter +nodes.Name._infer = decorators.raise_if_nothing_inferred( + decorators.path_wrapper(infer_name) +) +nodes.AssignName.infer_lhs = infer_name # won't work with a path wrapper + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_call(self, context=None): + """infer a Call node by trying to guess what the function returns""" + callcontext = copy_context(context) + callcontext.boundnode = None + if context is not None: + callcontext.extra_context = _populate_context_lookup(self, context.clone()) + + for callee in self.func.infer(context): + if callee is util.Uninferable: + yield callee + continue + try: + if hasattr(callee, "infer_call_result"): + callcontext.callcontext = CallContext( + args=self.args, keywords=self.keywords, callee=callee + ) + yield from callee.infer_call_result(caller=self, context=callcontext) + except InferenceError: + continue + return dict(node=self, context=context) + + +nodes.Call._infer = infer_call # type: ignore[assignment] + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_import(self, context=None, asname=True): + """infer an Import node: return the imported module/object""" + name = context.lookupname + if name is None: + raise InferenceError(node=self, context=context) + + try: + if asname: + yield self.do_import_module(self.real_name(name)) + else: + yield self.do_import_module(name) + except AstroidBuildingError as exc: + raise InferenceError(node=self, context=context) from exc + + +nodes.Import._infer = infer_import + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_import_from(self, context=None, asname=True): + """infer a ImportFrom node: return the imported module/object""" + name = context.lookupname + if name is None: + raise InferenceError(node=self, context=context) + if asname: + try: + name = self.real_name(name) + except AttributeInferenceError as exc: + # See https://github.com/PyCQA/pylint/issues/4692 + raise InferenceError(node=self, context=context) from exc + try: + module = self.do_import_module() + except AstroidBuildingError as exc: + raise InferenceError(node=self, context=context) from exc + + try: + context = copy_context(context) + context.lookupname = name + stmts = module.getattr(name, ignore_locals=module is self.root()) + return bases._infer_stmts(stmts, context) + except AttributeInferenceError as error: + raise InferenceError( + str(error), target=self, attribute=name, context=context + ) from error + + +nodes.ImportFrom._infer = infer_import_from # type: ignore[assignment] + + +def infer_attribute(self, context=None): + """infer an Attribute node by using getattr on the associated object""" + for owner in self.expr.infer(context): + if owner is util.Uninferable: + yield owner + continue + + if not context: + context = InferenceContext() + else: + context = copy_context(context) + + old_boundnode = context.boundnode + try: + context.boundnode = owner + yield from owner.igetattr(self.attrname, context) + except ( + AttributeInferenceError, + InferenceError, + AttributeError, + ): + pass + finally: + context.boundnode = old_boundnode + return dict(node=self, context=context) + + +nodes.Attribute._infer = decorators.raise_if_nothing_inferred( + decorators.path_wrapper(infer_attribute) +) +# won't work with a path wrapper +nodes.AssignAttr.infer_lhs = decorators.raise_if_nothing_inferred(infer_attribute) + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_global(self, context=None): + if context.lookupname is None: + raise InferenceError(node=self, context=context) + try: + return bases._infer_stmts(self.root().getattr(context.lookupname), context) + except AttributeInferenceError as error: + raise InferenceError( + str(error), target=self, attribute=context.lookupname, context=context + ) from error + + +nodes.Global._infer = infer_global # type: ignore[assignment] + + +_SUBSCRIPT_SENTINEL = object() + + +def infer_subscript(self, context=None): + """Inference for subscripts + + We're understanding if the index is a Const + or a slice, passing the result of inference + to the value's `getitem` method, which should + handle each supported index type accordingly. + """ + + found_one = False + for value in self.value.infer(context): + if value is util.Uninferable: + yield util.Uninferable + return None + for index in self.slice.infer(context): + if index is util.Uninferable: + yield util.Uninferable + return None + + # Try to deduce the index value. + index_value = _SUBSCRIPT_SENTINEL + if value.__class__ == bases.Instance: + index_value = index + elif index.__class__ == bases.Instance: + instance_as_index = helpers.class_instance_as_index(index) + if instance_as_index: + index_value = instance_as_index + else: + index_value = index + + if index_value is _SUBSCRIPT_SENTINEL: + raise InferenceError(node=self, context=context) + + try: + assigned = value.getitem(index_value, context) + except ( + AstroidTypeError, + AstroidIndexError, + AttributeInferenceError, + AttributeError, + ) as exc: + raise InferenceError(node=self, context=context) from exc + + # Prevent inferring if the inferred subscript + # is the same as the original subscripted object. + if self is assigned or assigned is util.Uninferable: + yield util.Uninferable + return None + yield from assigned.infer(context) + found_one = True + + if found_one: + return dict(node=self, context=context) + return None + + +nodes.Subscript._infer = decorators.raise_if_nothing_inferred( # type: ignore[assignment] + decorators.path_wrapper(infer_subscript) +) +nodes.Subscript.infer_lhs = decorators.raise_if_nothing_inferred(infer_subscript) + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def _infer_boolop(self, context=None): + """Infer a boolean operation (and / or / not). + + The function will calculate the boolean operation + for all pairs generated through inference for each component + node. + """ + values = self.values + if self.op == "or": + predicate = operator.truth + else: + predicate = operator.not_ + + try: + values = [value.infer(context=context) for value in values] + except InferenceError: + yield util.Uninferable + return None + + for pair in itertools.product(*values): + if any(item is util.Uninferable for item in pair): + # Can't infer the final result, just yield Uninferable. + yield util.Uninferable + continue + + bool_values = [item.bool_value() for item in pair] + if any(item is util.Uninferable for item in bool_values): + # Can't infer the final result, just yield Uninferable. + yield util.Uninferable + continue + + # Since the boolean operations are short circuited operations, + # this code yields the first value for which the predicate is True + # and if no value respected the predicate, then the last value will + # be returned (or Uninferable if there was no last value). + # This is conforming to the semantics of `and` and `or`: + # 1 and 0 -> 1 + # 0 and 1 -> 0 + # 1 or 0 -> 1 + # 0 or 1 -> 1 + value = util.Uninferable + for value, bool_value in zip(pair, bool_values): + if predicate(bool_value): + yield value + break + else: + yield value + + return dict(node=self, context=context) + + +nodes.BoolOp._infer = _infer_boolop + + +# UnaryOp, BinOp and AugAssign inferences + + +def _filter_operation_errors(self, infer_callable, context, error): + for result in infer_callable(self, context): + if isinstance(result, error): + # For the sake of .infer(), we don't care about operation + # errors, which is the job of pylint. So return something + # which shows that we can't infer the result. + yield util.Uninferable + else: + yield result + + +def _infer_unaryop(self, context=None): + """Infer what an UnaryOp should return when evaluated.""" + for operand in self.operand.infer(context): + try: + yield operand.infer_unary_op(self.op) + except TypeError as exc: + # The operand doesn't support this operation. + yield util.BadUnaryOperationMessage(operand, self.op, exc) + except AttributeError as exc: + meth = protocols.UNARY_OP_METHOD[self.op] + if meth is None: + # `not node`. Determine node's boolean + # value and negate its result, unless it is + # Uninferable, which will be returned as is. + bool_value = operand.bool_value() + if bool_value is not util.Uninferable: + yield nodes.const_factory(not bool_value) + else: + yield util.Uninferable + else: + if not isinstance(operand, (bases.Instance, nodes.ClassDef)): + # The operation was used on something which + # doesn't support it. + yield util.BadUnaryOperationMessage(operand, self.op, exc) + continue + + try: + try: + methods = dunder_lookup.lookup(operand, meth) + except AttributeInferenceError: + yield util.BadUnaryOperationMessage(operand, self.op, exc) + continue + + meth = methods[0] + inferred = next(meth.infer(context=context), None) + if inferred is util.Uninferable or not inferred.callable(): + continue + + context = copy_context(context) + context.boundnode = operand + context.callcontext = CallContext(args=[], callee=inferred) + + call_results = inferred.infer_call_result(self, context=context) + result = next(call_results, None) + if result is None: + # Failed to infer, return the same type. + yield operand + else: + yield result + except AttributeInferenceError as exc: + # The unary operation special method was not found. + yield util.BadUnaryOperationMessage(operand, self.op, exc) + except InferenceError: + yield util.Uninferable + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_unaryop(self, context=None): + """Infer what an UnaryOp should return when evaluated.""" + yield from _filter_operation_errors( + self, _infer_unaryop, context, util.BadUnaryOperationMessage + ) + return dict(node=self, context=context) + + +nodes.UnaryOp._infer_unaryop = _infer_unaryop +nodes.UnaryOp._infer = infer_unaryop + + +def _is_not_implemented(const): + """Check if the given const node is NotImplemented.""" + return isinstance(const, nodes.Const) and const.value is NotImplemented + + +def _invoke_binop_inference(instance, opnode, op, other, context, method_name): + """Invoke binary operation inference on the given instance.""" + methods = dunder_lookup.lookup(instance, method_name) + context = bind_context_to_node(context, instance) + method = methods[0] + context.callcontext.callee = method + try: + inferred = next(method.infer(context=context)) + except StopIteration as e: + raise InferenceError(node=method, context=context) from e + if inferred is util.Uninferable: + raise InferenceError + return instance.infer_binary_op(opnode, op, other, context, inferred) + + +def _aug_op(instance, opnode, op, other, context, reverse=False): + """Get an inference callable for an augmented binary operation.""" + method_name = protocols.AUGMENTED_OP_METHOD[op] + return functools.partial( + _invoke_binop_inference, + instance=instance, + op=op, + opnode=opnode, + other=other, + context=context, + method_name=method_name, + ) + + +def _bin_op(instance, opnode, op, other, context, reverse=False): + """Get an inference callable for a normal binary operation. + + If *reverse* is True, then the reflected method will be used instead. + """ + if reverse: + method_name = protocols.REFLECTED_BIN_OP_METHOD[op] + else: + method_name = protocols.BIN_OP_METHOD[op] + return functools.partial( + _invoke_binop_inference, + instance=instance, + op=op, + opnode=opnode, + other=other, + context=context, + method_name=method_name, + ) + + +def _get_binop_contexts(context, left, right): + """Get contexts for binary operations. + + This will return two inference contexts, the first one + for x.__op__(y), the other one for y.__rop__(x), where + only the arguments are inversed. + """ + # The order is important, since the first one should be + # left.__op__(right). + for arg in (right, left): + new_context = context.clone() + new_context.callcontext = CallContext(args=[arg]) + new_context.boundnode = None + yield new_context + + +def _same_type(type1, type2): + """Check if type1 is the same as type2.""" + return type1.qname() == type2.qname() + + +def _get_binop_flow( + left, left_type, binary_opnode, right, right_type, context, reverse_context +): + """Get the flow for binary operations. + + The rules are a bit messy: + + * if left and right have the same type, then only one + method will be called, left.__op__(right) + * if left and right are unrelated typewise, then first + left.__op__(right) is tried and if this does not exist + or returns NotImplemented, then right.__rop__(left) is tried. + * if left is a subtype of right, then only left.__op__(right) + is tried. + * if left is a supertype of right, then right.__rop__(left) + is first tried and then left.__op__(right) + """ + op = binary_opnode.op + if _same_type(left_type, right_type): + methods = [_bin_op(left, binary_opnode, op, right, context)] + elif helpers.is_subtype(left_type, right_type): + methods = [_bin_op(left, binary_opnode, op, right, context)] + elif helpers.is_supertype(left_type, right_type): + methods = [ + _bin_op(right, binary_opnode, op, left, reverse_context, reverse=True), + _bin_op(left, binary_opnode, op, right, context), + ] + else: + methods = [ + _bin_op(left, binary_opnode, op, right, context), + _bin_op(right, binary_opnode, op, left, reverse_context, reverse=True), + ] + return methods + + +def _get_aug_flow( + left, left_type, aug_opnode, right, right_type, context, reverse_context +): + """Get the flow for augmented binary operations. + + The rules are a bit messy: + + * if left and right have the same type, then left.__augop__(right) + is first tried and then left.__op__(right). + * if left and right are unrelated typewise, then + left.__augop__(right) is tried, then left.__op__(right) + is tried and then right.__rop__(left) is tried. + * if left is a subtype of right, then left.__augop__(right) + is tried and then left.__op__(right). + * if left is a supertype of right, then left.__augop__(right) + is tried, then right.__rop__(left) and then + left.__op__(right) + """ + bin_op = aug_opnode.op.strip("=") + aug_op = aug_opnode.op + if _same_type(left_type, right_type): + methods = [ + _aug_op(left, aug_opnode, aug_op, right, context), + _bin_op(left, aug_opnode, bin_op, right, context), + ] + elif helpers.is_subtype(left_type, right_type): + methods = [ + _aug_op(left, aug_opnode, aug_op, right, context), + _bin_op(left, aug_opnode, bin_op, right, context), + ] + elif helpers.is_supertype(left_type, right_type): + methods = [ + _aug_op(left, aug_opnode, aug_op, right, context), + _bin_op(right, aug_opnode, bin_op, left, reverse_context, reverse=True), + _bin_op(left, aug_opnode, bin_op, right, context), + ] + else: + methods = [ + _aug_op(left, aug_opnode, aug_op, right, context), + _bin_op(left, aug_opnode, bin_op, right, context), + _bin_op(right, aug_opnode, bin_op, left, reverse_context, reverse=True), + ] + return methods + + +def _infer_binary_operation(left, right, binary_opnode, context, flow_factory): + """Infer a binary operation between a left operand and a right operand + + This is used by both normal binary operations and augmented binary + operations, the only difference is the flow factory used. + """ + + context, reverse_context = _get_binop_contexts(context, left, right) + left_type = helpers.object_type(left) + right_type = helpers.object_type(right) + methods = flow_factory( + left, left_type, binary_opnode, right, right_type, context, reverse_context + ) + for method in methods: + try: + results = list(method()) + except AttributeError: + continue + except AttributeInferenceError: + continue + except InferenceError: + yield util.Uninferable + return + else: + if any(result is util.Uninferable for result in results): + yield util.Uninferable + return + + if all(map(_is_not_implemented, results)): + continue + not_implemented = sum( + 1 for result in results if _is_not_implemented(result) + ) + if not_implemented and not_implemented != len(results): + # Can't infer yet what this is. + yield util.Uninferable + return + + yield from results + return + # The operation doesn't seem to be supported so let the caller know about it + yield util.BadBinaryOperationMessage(left_type, binary_opnode.op, right_type) + + +def _infer_binop(self, context): + """Binary operation inference logic.""" + left = self.left + right = self.right + + # we use two separate contexts for evaluating lhs and rhs because + # 1. evaluating lhs may leave some undesired entries in context.path + # which may not let us infer right value of rhs + context = context or InferenceContext() + lhs_context = copy_context(context) + rhs_context = copy_context(context) + lhs_iter = left.infer(context=lhs_context) + rhs_iter = right.infer(context=rhs_context) + for lhs, rhs in itertools.product(lhs_iter, rhs_iter): + if any(value is util.Uninferable for value in (rhs, lhs)): + # Don't know how to process this. + yield util.Uninferable + return + + try: + yield from _infer_binary_operation(lhs, rhs, self, context, _get_binop_flow) + except _NonDeducibleTypeHierarchy: + yield util.Uninferable + + +@decorators.yes_if_nothing_inferred +@decorators.path_wrapper +def infer_binop(self, context=None): + return _filter_operation_errors( + self, _infer_binop, context, util.BadBinaryOperationMessage + ) + + +nodes.BinOp._infer_binop = _infer_binop +nodes.BinOp._infer = infer_binop + +COMPARE_OPS: Dict[str, Callable[[Any, Any], bool]] = { + "==": operator.eq, + "!=": operator.ne, + "<": operator.lt, + "<=": operator.le, + ">": operator.gt, + ">=": operator.ge, + "in": lambda a, b: a in b, + "not in": lambda a, b: a not in b, +} +UNINFERABLE_OPS = { + "is", + "is not", +} + + +def _to_literal(node: nodes.NodeNG) -> Any: + # Can raise SyntaxError or ValueError from ast.literal_eval + # Can raise AttributeError from node.as_string() as not all nodes have a visitor + # Is this the stupidest idea or the simplest idea? + return ast.literal_eval(node.as_string()) + + +def _do_compare( + left_iter: Iterable[nodes.NodeNG], op: str, right_iter: Iterable[nodes.NodeNG] +) -> "bool | type[util.Uninferable]": + """ + If all possible combinations are either True or False, return that: + >>> _do_compare([1, 2], '<=', [3, 4]) + True + >>> _do_compare([1, 2], '==', [3, 4]) + False + + If any item is uninferable, or if some combinations are True and some + are False, return Uninferable: + >>> _do_compare([1, 3], '<=', [2, 4]) + util.Uninferable + """ + retval: Union[None, bool] = None + if op in UNINFERABLE_OPS: + return util.Uninferable + op_func = COMPARE_OPS[op] + + for left, right in itertools.product(left_iter, right_iter): + if left is util.Uninferable or right is util.Uninferable: + return util.Uninferable + + try: + left, right = _to_literal(left), _to_literal(right) + except (SyntaxError, ValueError, AttributeError): + return util.Uninferable + + try: + expr = op_func(left, right) + except TypeError as exc: + raise AstroidTypeError from exc + + if retval is None: + retval = expr + elif retval != expr: + return util.Uninferable + # (or both, but "True | False" is basically the same) + + assert retval is not None + return retval # it was all the same value + + +def _infer_compare( + self: nodes.Compare, context: Optional[InferenceContext] = None +) -> Iterator[Union[nodes.Const, Type[util.Uninferable]]]: + """Chained comparison inference logic.""" + retval: Union[bool, Type[util.Uninferable]] = True + + ops = self.ops + left_node = self.left + lhs = list(left_node.infer(context=context)) + # should we break early if first element is uninferable? + for op, right_node in ops: + # eagerly evaluate rhs so that values can be re-used as lhs + rhs = list(right_node.infer(context=context)) + try: + retval = _do_compare(lhs, op, rhs) + except AstroidTypeError: + retval = util.Uninferable + break + if retval is not True: + break # short-circuit + lhs = rhs # continue + if retval is util.Uninferable: + yield retval # type: ignore[misc] + else: + yield nodes.Const(retval) + + +nodes.Compare._infer = _infer_compare # type: ignore[assignment] + + +def _infer_augassign(self, context=None): + """Inference logic for augmented binary operations.""" + if context is None: + context = InferenceContext() + + rhs_context = context.clone() + + lhs_iter = self.target.infer_lhs(context=context) + rhs_iter = self.value.infer(context=rhs_context) + for lhs, rhs in itertools.product(lhs_iter, rhs_iter): + if any(value is util.Uninferable for value in (rhs, lhs)): + # Don't know how to process this. + yield util.Uninferable + return + + try: + yield from _infer_binary_operation( + left=lhs, + right=rhs, + binary_opnode=self, + context=context, + flow_factory=_get_aug_flow, + ) + except _NonDeducibleTypeHierarchy: + yield util.Uninferable + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_augassign(self, context=None): + return _filter_operation_errors( + self, _infer_augassign, context, util.BadBinaryOperationMessage + ) + + +nodes.AugAssign._infer_augassign = _infer_augassign +nodes.AugAssign._infer = infer_augassign + +# End of binary operation inference. + + +@decorators.raise_if_nothing_inferred +def infer_arguments(self, context=None): + name = context.lookupname + if name is None: + raise InferenceError(node=self, context=context) + return protocols._arguments_infer_argname(self, name, context) + + +nodes.Arguments._infer = infer_arguments # type: ignore[assignment] + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_assign(self, context=None): + """infer a AssignName/AssignAttr: need to inspect the RHS part of the + assign node + """ + if isinstance(self.parent, nodes.AugAssign): + return self.parent.infer(context) + + stmts = list(self.assigned_stmts(context=context)) + return bases._infer_stmts(stmts, context) + + +nodes.AssignName._infer = infer_assign +nodes.AssignAttr._infer = infer_assign + + +@decorators.raise_if_nothing_inferred +@decorators.path_wrapper +def infer_empty_node(self, context=None): + if not self.has_underlying_object(): + yield util.Uninferable + else: + try: + yield from AstroidManager().infer_ast_from_something( + self.object, context=context + ) + except AstroidError: + yield util.Uninferable + + +nodes.EmptyNode._infer = infer_empty_node # type: ignore[assignment] + + +@decorators.raise_if_nothing_inferred +def infer_index(self, context=None): + return self.value.infer(context) + + +nodes.Index._infer = infer_index # type: ignore[assignment] + + +def _populate_context_lookup(call, context): + # Allows context to be saved for later + # for inference inside a function + context_lookup = {} + if context is None: + return context_lookup + for arg in call.args: + if isinstance(arg, nodes.Starred): + context_lookup[arg.value] = context + else: + context_lookup[arg] = context + keywords = call.keywords if call.keywords is not None else [] + for keyword in keywords: + context_lookup[keyword.value] = context + return context_lookup + + +@decorators.raise_if_nothing_inferred +def infer_ifexp(self, context=None): + """Support IfExp inference + + If we can't infer the truthiness of the condition, we default + to inferring both branches. Otherwise, we infer either branch + depending on the condition. + """ + both_branches = False + # We use two separate contexts for evaluating lhs and rhs because + # evaluating lhs may leave some undesired entries in context.path + # which may not let us infer right value of rhs. + + context = context or InferenceContext() + lhs_context = copy_context(context) + rhs_context = copy_context(context) + try: + test = next(self.test.infer(context=context.clone())) + except (InferenceError, StopIteration): + both_branches = True + else: + if test is not util.Uninferable: + if test.bool_value(): + yield from self.body.infer(context=lhs_context) + else: + yield from self.orelse.infer(context=rhs_context) + else: + both_branches = True + if both_branches: + yield from self.body.infer(context=lhs_context) + yield from self.orelse.infer(context=rhs_context) + + +nodes.IfExp._infer = infer_ifexp # type: ignore[assignment] + + +# pylint: disable=dangerous-default-value +@wrapt.decorator +def _cached_generator( + func, instance: _FunctionDefT, args, kwargs, _cache={} # noqa: B006 +): + node = instance + try: + return iter(_cache[func, id(node)]) + except KeyError: + result = func(*args, **kwargs) + # Need to keep an iterator around + original, copy = itertools.tee(result) + _cache[func, id(node)] = list(copy) + return original + + +# When inferring a property, we instantiate a new `objects.Property` object, +# which in turn, because it inherits from `FunctionDef`, sets itself in the locals +# of the wrapping frame. This means that every time we infer a property, the locals +# are mutated with a new instance of the property. This is why we cache the result +# of the function's inference. +@_cached_generator +def infer_functiondef( + self: _FunctionDefT, context: Optional[InferenceContext] = None +) -> Generator[Union["Property", _FunctionDefT], None, InferenceErrorInfo]: + if not self.decorators or not bases._is_property(self): + yield self + return InferenceErrorInfo(node=self, context=context) + + prop_func = objects.Property( + function=self, + name=self.name, + lineno=self.lineno, + parent=self.parent, + col_offset=self.col_offset, + ) + prop_func.postinit(body=[], args=self.args, doc_node=self.doc_node) + yield prop_func + return InferenceErrorInfo(node=self, context=context) + + +nodes.FunctionDef._infer = infer_functiondef # type: ignore[assignment] diff --git a/myenv/lib/python3.9/site-packages/astroid/inference_tip.py b/myenv/lib/python3.9/site-packages/astroid/inference_tip.py new file mode 100644 index 0000000..f74ff23 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/inference_tip.py @@ -0,0 +1,89 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Transform utilities (filters and decorator)""" + +import typing + +import wrapt + +from astroid import bases, util +from astroid.exceptions import InferenceOverwriteError, UseInferenceDefault +from astroid.nodes import NodeNG +from astroid.typing import InferFn + +InferOptions = typing.Union[ + NodeNG, bases.Instance, bases.UnboundMethod, typing.Type[util.Uninferable] +] + +_cache: typing.Dict[ + typing.Tuple[InferFn, NodeNG], typing.Optional[typing.List[InferOptions]] +] = {} + + +def clear_inference_tip_cache(): + """Clear the inference tips cache.""" + _cache.clear() + + +@wrapt.decorator +def _inference_tip_cached( + func: InferFn, instance: None, args: typing.Any, kwargs: typing.Any +) -> typing.Iterator[InferOptions]: + """Cache decorator used for inference tips""" + node = args[0] + try: + result = _cache[func, node] + # If through recursion we end up trying to infer the same + # func + node we raise here. + if result is None: + raise UseInferenceDefault() + except KeyError: + _cache[func, node] = None + result = _cache[func, node] = list(func(*args, **kwargs)) + assert result + return iter(result) + + +def inference_tip(infer_function: InferFn, raise_on_overwrite: bool = False) -> InferFn: + """Given an instance specific inference function, return a function to be + given to AstroidManager().register_transform to set this inference function. + + :param bool raise_on_overwrite: Raise an `InferenceOverwriteError` + if the inference tip will overwrite another. Used for debugging + + Typical usage + + .. sourcecode:: python + + AstroidManager().register_transform(Call, inference_tip(infer_named_tuple), + predicate) + + .. Note:: + + Using an inference tip will override + any previously set inference tip for the given + node. Use a predicate in the transform to prevent + excess overwrites. + """ + + def transform(node: NodeNG, infer_function: InferFn = infer_function) -> NodeNG: + if ( + raise_on_overwrite + and node._explicit_inference is not None + and node._explicit_inference is not infer_function + ): + raise InferenceOverwriteError( + "Inference already set to {existing_inference}. " + "Trying to overwrite with {new_inference} for {node}".format( + existing_inference=infer_function, + new_inference=node._explicit_inference, + node=node, + ) + ) + # pylint: disable=no-value-for-parameter + node._explicit_inference = _inference_tip_cached(infer_function) + return node + + return transform diff --git a/myenv/lib/python3.9/site-packages/astroid/interpreter/__init__.py b/myenv/lib/python3.9/site-packages/astroid/interpreter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/__init__.py b/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/spec.py b/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/spec.py new file mode 100644 index 0000000..73192ef --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/spec.py @@ -0,0 +1,378 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import abc +import collections +import enum +import importlib.machinery +import importlib.util +import os +import sys +import zipimport +from functools import lru_cache +from pathlib import Path + +from astroid.modutils import EXT_LIB_DIRS + +from . import util + +ModuleType = enum.Enum( + "ModuleType", + "C_BUILTIN C_EXTENSION PKG_DIRECTORY " + "PY_CODERESOURCE PY_COMPILED PY_FROZEN PY_RESOURCE " + "PY_SOURCE PY_ZIPMODULE PY_NAMESPACE", +) + + +_ModuleSpec = collections.namedtuple( + "_ModuleSpec", "name type location " "origin submodule_search_locations" +) + + +class ModuleSpec(_ModuleSpec): + """Defines a class similar to PEP 420's ModuleSpec + + A module spec defines a name of a module, its type, location + and where submodules can be found, if the module is a package. + """ + + def __new__( + cls, + name, + module_type, + location=None, + origin=None, + submodule_search_locations=None, + ): + return _ModuleSpec.__new__( + cls, + name=name, + type=module_type, + location=location, + origin=origin, + submodule_search_locations=submodule_search_locations, + ) + + +class Finder: + """A finder is a class which knows how to find a particular module.""" + + def __init__(self, path=None): + self._path = path or sys.path + + @abc.abstractmethod + def find_module(self, modname, module_parts, processed, submodule_path): + """Find the given module + + Each finder is responsible for each protocol of finding, as long as + they all return a ModuleSpec. + + :param str modname: The module which needs to be searched. + :param list module_parts: It should be a list of strings, + where each part contributes to the module's + namespace. + :param list processed: What parts from the module parts were processed + so far. + :param list submodule_path: A list of paths where the module + can be looked into. + :returns: A ModuleSpec, describing how and where the module was found, + None, otherwise. + """ + + def contribute_to_path(self, spec, processed): + """Get a list of extra paths where this finder can search.""" + + +class ImportlibFinder(Finder): + """A finder based on the importlib module.""" + + _SUFFIXES = ( + [(s, ModuleType.C_EXTENSION) for s in importlib.machinery.EXTENSION_SUFFIXES] + + [(s, ModuleType.PY_SOURCE) for s in importlib.machinery.SOURCE_SUFFIXES] + + [(s, ModuleType.PY_COMPILED) for s in importlib.machinery.BYTECODE_SUFFIXES] + ) + + def find_module(self, modname, module_parts, processed, submodule_path): + if not isinstance(modname, str): + raise TypeError(f"'modname' must be a str, not {type(modname)}") + if submodule_path is not None: + submodule_path = list(submodule_path) + else: + try: + spec = importlib.util.find_spec(modname) + if spec: + if spec.loader is importlib.machinery.BuiltinImporter: + return ModuleSpec( + name=modname, + location=None, + module_type=ModuleType.C_BUILTIN, + ) + if spec.loader is importlib.machinery.FrozenImporter: + return ModuleSpec( + name=modname, + location=None, + module_type=ModuleType.PY_FROZEN, + ) + except ValueError: + pass + submodule_path = sys.path + + for entry in submodule_path: + package_directory = os.path.join(entry, modname) + for suffix in (".py", importlib.machinery.BYTECODE_SUFFIXES[0]): + package_file_name = "__init__" + suffix + file_path = os.path.join(package_directory, package_file_name) + if os.path.isfile(file_path): + return ModuleSpec( + name=modname, + location=package_directory, + module_type=ModuleType.PKG_DIRECTORY, + ) + for suffix, type_ in ImportlibFinder._SUFFIXES: + file_name = modname + suffix + file_path = os.path.join(entry, file_name) + if os.path.isfile(file_path): + return ModuleSpec( + name=modname, location=file_path, module_type=type_ + ) + return None + + def contribute_to_path(self, spec, processed): + if spec.location is None: + # Builtin. + return None + + if _is_setuptools_namespace(spec.location): + # extend_path is called, search sys.path for module/packages + # of this name see pkgutil.extend_path documentation + path = [ + os.path.join(p, *processed) + for p in sys.path + if os.path.isdir(os.path.join(p, *processed)) + ] + elif spec.name == "distutils" and not any( + spec.location.lower().startswith(ext_lib_dir.lower()) + for ext_lib_dir in EXT_LIB_DIRS + ): + # virtualenv below 20.0 patches distutils in an unexpected way + # so we just find the location of distutils that will be + # imported to avoid spurious import-error messages + # https://github.com/PyCQA/pylint/issues/5645 + # A regression test to create this scenario exists in release-tests.yml + # and can be triggered manually from GitHub Actions + distutils_spec = importlib.util.find_spec("distutils") + if distutils_spec and distutils_spec.origin: + origin_path = Path( + distutils_spec.origin + ) # e.g. .../distutils/__init__.py + path = [str(origin_path.parent)] # e.g. .../distutils + else: + path = [spec.location] + else: + path = [spec.location] + return path + + +class ExplicitNamespacePackageFinder(ImportlibFinder): + """A finder for the explicit namespace packages, generated through pkg_resources.""" + + def find_module(self, modname, module_parts, processed, submodule_path): + if processed: + modname = ".".join(processed + [modname]) + if util.is_namespace(modname) and modname in sys.modules: + submodule_path = sys.modules[modname].__path__ + return ModuleSpec( + name=modname, + location="", + origin="namespace", + module_type=ModuleType.PY_NAMESPACE, + submodule_search_locations=submodule_path, + ) + return None + + def contribute_to_path(self, spec, processed): + return spec.submodule_search_locations + + +class ZipFinder(Finder): + """Finder that knows how to find a module inside zip files.""" + + def __init__(self, path): + super().__init__(path) + self._zipimporters = _precache_zipimporters(path) + + def find_module(self, modname, module_parts, processed, submodule_path): + try: + file_type, filename, path = _search_zip(module_parts, self._zipimporters) + except ImportError: + return None + + return ModuleSpec( + name=modname, + location=filename, + origin="egg", + module_type=file_type, + submodule_search_locations=path, + ) + + +class PathSpecFinder(Finder): + """Finder based on importlib.machinery.PathFinder.""" + + def find_module(self, modname, module_parts, processed, submodule_path): + spec = importlib.machinery.PathFinder.find_spec(modname, path=submodule_path) + if spec: + # origin can be either a string on older Python versions + # or None in case it is a namespace package: + # https://github.com/python/cpython/pull/5481 + is_namespace_pkg = spec.origin in {"namespace", None} + location = spec.origin if not is_namespace_pkg else None + module_type = ModuleType.PY_NAMESPACE if is_namespace_pkg else None + spec = ModuleSpec( + name=spec.name, + location=location, + origin=spec.origin, + module_type=module_type, + submodule_search_locations=list(spec.submodule_search_locations or []), + ) + return spec + + def contribute_to_path(self, spec, processed): + if spec.type == ModuleType.PY_NAMESPACE: + return spec.submodule_search_locations + return None + + +_SPEC_FINDERS = ( + ImportlibFinder, + ZipFinder, + PathSpecFinder, + ExplicitNamespacePackageFinder, +) + + +def _is_setuptools_namespace(location): + try: + with open(os.path.join(location, "__init__.py"), "rb") as stream: + data = stream.read(4096) + except OSError: + return None + else: + extend_path = b"pkgutil" in data and b"extend_path" in data + declare_namespace = ( + b"pkg_resources" in data and b"declare_namespace(__name__)" in data + ) + return extend_path or declare_namespace + + +@lru_cache() +def _cached_set_diff(left, right): + result = set(left) + result.difference_update(right) + return result + + +def _precache_zipimporters(path=None): + """ + For each path that has not been already cached + in the sys.path_importer_cache, create a new zipimporter + instance and add it into the cache. + Return a dict associating all paths, stored in the cache, to corresponding + zipimporter instances. + + :param path: paths that has to be added into the cache + :return: association between paths stored in the cache and zipimporter instances + """ + pic = sys.path_importer_cache + + # When measured, despite having the same complexity (O(n)), + # converting to tuples and then caching the conversion to sets + # and the set difference is faster than converting to sets + # and then only caching the set difference. + + req_paths = tuple(path or sys.path) + cached_paths = tuple(pic) + new_paths = _cached_set_diff(req_paths, cached_paths) + # pylint: disable=no-member + for entry_path in new_paths: + try: + pic[entry_path] = zipimport.zipimporter(entry_path) + except zipimport.ZipImportError: + continue + return { + key: value + for key, value in pic.items() + if isinstance(value, zipimport.zipimporter) + } + + +def _search_zip(modpath, pic): + for filepath, importer in list(pic.items()): + if importer is not None: + found = importer.find_module(modpath[0]) + if found: + if not importer.find_module(os.path.sep.join(modpath)): + raise ImportError( + "No module named %s in %s/%s" + % (".".join(modpath[1:]), filepath, modpath) + ) + # import code; code.interact(local=locals()) + return ( + ModuleType.PY_ZIPMODULE, + os.path.abspath(filepath) + os.path.sep + os.path.sep.join(modpath), + filepath, + ) + raise ImportError(f"No module named {'.'.join(modpath)}") + + +def _find_spec_with_path(search_path, modname, module_parts, processed, submodule_path): + finders = [finder(search_path) for finder in _SPEC_FINDERS] + for finder in finders: + spec = finder.find_module(modname, module_parts, processed, submodule_path) + if spec is None: + continue + return finder, spec + + raise ImportError(f"No module named {'.'.join(module_parts)}") + + +def find_spec(modpath, path=None): + """Find a spec for the given module. + + :type modpath: list or tuple + :param modpath: + split module's name (i.e name of a module or package split + on '.'), with leading empty strings for explicit relative import + + :type path: list or None + :param path: + optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + :rtype: ModuleSpec + :return: A module spec, which describes how the module was + found and where. + """ + _path = path or sys.path + + # Need a copy for not mutating the argument. + modpath = modpath[:] + + submodule_path = None + module_parts = modpath[:] + processed = [] + + while modpath: + modname = modpath.pop(0) + finder, spec = _find_spec_with_path( + _path, modname, module_parts, processed, submodule_path or path + ) + processed.append(modname) + if modpath: + submodule_path = finder.contribute_to_path(spec, processed) + + if spec.type == ModuleType.PKG_DIRECTORY: + spec = spec._replace(submodule_search_locations=submodule_path) + + return spec diff --git a/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/util.py b/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/util.py new file mode 100644 index 0000000..ce3da7e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/interpreter/_import/util.py @@ -0,0 +1,16 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +try: + import pkg_resources +except ImportError: + pkg_resources = None # type: ignore[assignment] + + +def is_namespace(modname): + return ( + pkg_resources is not None + and hasattr(pkg_resources, "_namespace_packages") + and modname in pkg_resources._namespace_packages + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/interpreter/dunder_lookup.py b/myenv/lib/python3.9/site-packages/astroid/interpreter/dunder_lookup.py new file mode 100644 index 0000000..b0c7ae5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/interpreter/dunder_lookup.py @@ -0,0 +1,66 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Contains logic for retrieving special methods. + +This implementation does not rely on the dot attribute access +logic, found in ``.getattr()``. The difference between these two +is that the dunder methods are looked with the type slots +(you can find more about these here +http://lucumr.pocoo.org/2014/8/16/the-python-i-would-like-to-see/) +As such, the lookup for the special methods is actually simpler than +the dot attribute access. +""" +import itertools + +import astroid +from astroid.exceptions import AttributeInferenceError + + +def _lookup_in_mro(node, name): + attrs = node.locals.get(name, []) + + nodes = itertools.chain.from_iterable( + ancestor.locals.get(name, []) for ancestor in node.ancestors(recurs=True) + ) + values = list(itertools.chain(attrs, nodes)) + if not values: + raise AttributeInferenceError(attribute=name, target=node) + + return values + + +def lookup(node, name): + """Lookup the given special method name in the given *node* + + If the special method was found, then a list of attributes + will be returned. Otherwise, `astroid.AttributeInferenceError` + is going to be raised. + """ + if isinstance( + node, (astroid.List, astroid.Tuple, astroid.Const, astroid.Dict, astroid.Set) + ): + return _builtin_lookup(node, name) + if isinstance(node, astroid.Instance): + return _lookup_in_mro(node, name) + if isinstance(node, astroid.ClassDef): + return _class_lookup(node, name) + + raise AttributeInferenceError(attribute=name, target=node) + + +def _class_lookup(node, name): + metaclass = node.metaclass() + if metaclass is None: + raise AttributeInferenceError(attribute=name, target=node) + + return _lookup_in_mro(metaclass, name) + + +def _builtin_lookup(node, name): + values = node.locals.get(name, []) + if not values: + raise AttributeInferenceError(attribute=name, target=node) + + return values diff --git a/myenv/lib/python3.9/site-packages/astroid/interpreter/objectmodel.py b/myenv/lib/python3.9/site-packages/astroid/interpreter/objectmodel.py new file mode 100644 index 0000000..cf9227b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/interpreter/objectmodel.py @@ -0,0 +1,856 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Data object model, as per https://docs.python.org/3/reference/datamodel.html. + +This module describes, at least partially, a data object model for some +of astroid's nodes. The model contains special attributes that nodes such +as functions, classes, modules etc have, such as __doc__, __class__, +__module__ etc, being used when doing attribute lookups over nodes. + +For instance, inferring `obj.__class__` will first trigger an inference +of the `obj` variable. If it was successfully inferred, then an attribute +`__class__ will be looked for in the inferred object. This is the part +where the data model occurs. The model is attached to those nodes +and the lookup mechanism will try to see if attributes such as +`__class__` are defined by the model or not. If they are defined, +the model will be requested to return the corresponding value of that +attribute. Thus the model can be viewed as a special part of the lookup +mechanism. +""" + +import itertools +import os +import pprint +import types +from typing import TYPE_CHECKING, List, Optional + +import astroid +from astroid import util +from astroid.context import InferenceContext, copy_context +from astroid.exceptions import AttributeInferenceError, InferenceError, NoDefault +from astroid.manager import AstroidManager +from astroid.nodes import node_classes + +objects = util.lazy_import("objects") + +if TYPE_CHECKING: + from astroid.objects import Property + +IMPL_PREFIX = "attr_" +LEN_OF_IMPL_PREFIX = len(IMPL_PREFIX) + + +def _dunder_dict(instance, attributes): + obj = node_classes.Dict(parent=instance) + + # Convert the keys to node strings + keys = [ + node_classes.Const(value=value, parent=obj) for value in list(attributes.keys()) + ] + + # The original attribute has a list of elements for each key, + # but that is not useful for retrieving the special attribute's value. + # In this case, we're picking the last value from each list. + values = [elem[-1] for elem in attributes.values()] + + obj.postinit(list(zip(keys, values))) + return obj + + +class ObjectModel: + def __init__(self): + self._instance = None + + def __repr__(self): + result = [] + cname = type(self).__name__ + string = "%(cname)s(%(fields)s)" + alignment = len(cname) + 1 + for field in sorted(self.attributes()): + width = 80 - len(field) - alignment + lines = pprint.pformat(field, indent=2, width=width).splitlines(True) + + inner = [lines[0]] + for line in lines[1:]: + inner.append(" " * alignment + line) + result.append(field) + + return string % { + "cname": cname, + "fields": (",\n" + " " * alignment).join(result), + } + + def __call__(self, instance): + self._instance = instance + return self + + def __get__(self, instance, cls=None): + # ObjectModel needs to be a descriptor so that just doing + # `special_attributes = SomeObjectModel` should be enough in the body of a node. + # But at the same time, node.special_attributes should return an object + # which can be used for manipulating the special attributes. That's the reason + # we pass the instance through which it got accessed to ObjectModel.__call__, + # returning itself afterwards, so we can still have access to the + # underlying data model and to the instance for which it got accessed. + return self(instance) + + def __contains__(self, name): + return name in self.attributes() + + def attributes(self) -> List[str]: + """Get the attributes which are exported by this object model.""" + return [o[LEN_OF_IMPL_PREFIX:] for o in dir(self) if o.startswith(IMPL_PREFIX)] + + def lookup(self, name): + """Look up the given *name* in the current model + + It should return an AST or an interpreter object, + but if the name is not found, then an AttributeInferenceError will be raised. + """ + if name in self.attributes(): + return getattr(self, IMPL_PREFIX + name) + raise AttributeInferenceError(target=self._instance, attribute=name) + + +class ModuleModel(ObjectModel): + def _builtins(self): + builtins_ast_module = AstroidManager().builtins_module + return builtins_ast_module.special_attributes.lookup("__dict__") + + @property + def attr_builtins(self): + return self._builtins() + + @property + def attr___path__(self): + if not self._instance.package: + raise AttributeInferenceError(target=self._instance, attribute="__path__") + + path_objs = [ + node_classes.Const( + value=path + if not path.endswith("__init__.py") + else os.path.dirname(path), + parent=self._instance, + ) + for path in self._instance.path + ] + + container = node_classes.List(parent=self._instance) + container.postinit(path_objs) + + return container + + @property + def attr___name__(self): + return node_classes.Const(value=self._instance.name, parent=self._instance) + + @property + def attr___doc__(self): + return node_classes.Const( + value=getattr(self._instance.doc_node, "value", None), + parent=self._instance, + ) + + @property + def attr___file__(self): + return node_classes.Const(value=self._instance.file, parent=self._instance) + + @property + def attr___dict__(self): + return _dunder_dict(self._instance, self._instance.globals) + + @property + def attr___package__(self): + if not self._instance.package: + value = "" + else: + value = self._instance.name + + return node_classes.Const(value=value, parent=self._instance) + + # These are related to the Python 3 implementation of the + # import system, + # https://docs.python.org/3/reference/import.html#import-related-module-attributes + + @property + def attr___spec__(self): + # No handling for now. + return node_classes.Unknown() + + @property + def attr___loader__(self): + # No handling for now. + return node_classes.Unknown() + + @property + def attr___cached__(self): + # No handling for now. + return node_classes.Unknown() + + +class FunctionModel(ObjectModel): + @property + def attr___name__(self): + return node_classes.Const(value=self._instance.name, parent=self._instance) + + @property + def attr___doc__(self): + return node_classes.Const( + value=getattr(self._instance.doc_node, "value", None), + parent=self._instance, + ) + + @property + def attr___qualname__(self): + return node_classes.Const(value=self._instance.qname(), parent=self._instance) + + @property + def attr___defaults__(self): + func = self._instance + if not func.args.defaults: + return node_classes.Const(value=None, parent=func) + + defaults_obj = node_classes.Tuple(parent=func) + defaults_obj.postinit(func.args.defaults) + return defaults_obj + + @property + def attr___annotations__(self): + obj = node_classes.Dict(parent=self._instance) + + if not self._instance.returns: + returns = None + else: + returns = self._instance.returns + + args = self._instance.args + pair_annotations = itertools.chain( + zip(args.args or [], args.annotations), + zip(args.kwonlyargs, args.kwonlyargs_annotations), + zip(args.posonlyargs or [], args.posonlyargs_annotations), + ) + + annotations = { + arg.name: annotation for (arg, annotation) in pair_annotations if annotation + } + if args.varargannotation: + annotations[args.vararg] = args.varargannotation + if args.kwargannotation: + annotations[args.kwarg] = args.kwargannotation + if returns: + annotations["return"] = returns + + items = [ + (node_classes.Const(key, parent=obj), value) + for (key, value) in annotations.items() + ] + + obj.postinit(items) + return obj + + @property + def attr___dict__(self): + return node_classes.Dict(parent=self._instance) + + attr___globals__ = attr___dict__ + + @property + def attr___kwdefaults__(self): + def _default_args(args, parent): + for arg in args.kwonlyargs: + try: + default = args.default_value(arg.name) + except NoDefault: + continue + + name = node_classes.Const(arg.name, parent=parent) + yield name, default + + args = self._instance.args + obj = node_classes.Dict(parent=self._instance) + defaults = dict(_default_args(args, obj)) + + obj.postinit(list(defaults.items())) + return obj + + @property + def attr___module__(self): + return node_classes.Const(self._instance.root().qname()) + + @property + def attr___get__(self): + # pylint: disable=import-outside-toplevel; circular import + from astroid import bases + + func = self._instance + + class DescriptorBoundMethod(bases.BoundMethod): + """Bound method which knows how to understand calling descriptor binding.""" + + def implicit_parameters(self): + # Different than BoundMethod since the signature + # is different. + return 0 + + def infer_call_result(self, caller, context=None): + if len(caller.args) > 2 or len(caller.args) < 1: + raise InferenceError( + "Invalid arguments for descriptor binding", + target=self, + context=context, + ) + + context = copy_context(context) + try: + cls = next(caller.args[0].infer(context=context)) + except StopIteration as e: + raise InferenceError(context=context, node=caller.args[0]) from e + + if cls is astroid.Uninferable: + raise InferenceError( + "Invalid class inferred", target=self, context=context + ) + + # For some reason func is a Node that the below + # code is not expecting + if isinstance(func, bases.BoundMethod): + yield func + return + + # Rebuild the original value, but with the parent set as the + # class where it will be bound. + new_func = func.__class__( + name=func.name, + lineno=func.lineno, + col_offset=func.col_offset, + parent=func.parent, + ) + # pylint: disable=no-member + new_func.postinit( + func.args, + func.body, + func.decorators, + func.returns, + doc_node=func.doc_node, + ) + + # Build a proper bound method that points to our newly built function. + proxy = bases.UnboundMethod(new_func) + yield bases.BoundMethod(proxy=proxy, bound=cls) + + @property + def args(self): + """Overwrite the underlying args to match those of the underlying func + + Usually the underlying *func* is a function/method, as in: + + def test(self): + pass + + This has only the *self* parameter but when we access test.__get__ + we get a new object which has two parameters, *self* and *type*. + """ + nonlocal func + positional_or_keyword_params = func.args.args.copy() + positional_or_keyword_params.append(astroid.AssignName(name="type")) + + positional_only_params = func.args.posonlyargs.copy() + + arguments = astroid.Arguments(parent=func.args.parent) + arguments.postinit( + args=positional_or_keyword_params, + posonlyargs=positional_only_params, + defaults=[], + kwonlyargs=[], + kw_defaults=[], + annotations=[], + ) + return arguments + + return DescriptorBoundMethod(proxy=self._instance, bound=self._instance) + + # These are here just for completion. + @property + def attr___ne__(self): + return node_classes.Unknown() + + attr___subclasshook__ = attr___ne__ + attr___str__ = attr___ne__ + attr___sizeof__ = attr___ne__ + attr___setattr___ = attr___ne__ + attr___repr__ = attr___ne__ + attr___reduce__ = attr___ne__ + attr___reduce_ex__ = attr___ne__ + attr___new__ = attr___ne__ + attr___lt__ = attr___ne__ + attr___eq__ = attr___ne__ + attr___gt__ = attr___ne__ + attr___format__ = attr___ne__ + attr___delattr___ = attr___ne__ + attr___getattribute__ = attr___ne__ + attr___hash__ = attr___ne__ + attr___init__ = attr___ne__ + attr___dir__ = attr___ne__ + attr___call__ = attr___ne__ + attr___class__ = attr___ne__ + attr___closure__ = attr___ne__ + attr___code__ = attr___ne__ + + +class ClassModel(ObjectModel): + def __init__(self): + # Add a context so that inferences called from an instance don't recurse endlessly + self.context = InferenceContext() + + super().__init__() + + @property + def attr___module__(self): + return node_classes.Const(self._instance.root().qname()) + + @property + def attr___name__(self): + return node_classes.Const(self._instance.name) + + @property + def attr___qualname__(self): + return node_classes.Const(self._instance.qname()) + + @property + def attr___doc__(self): + return node_classes.Const(getattr(self._instance.doc_node, "value", None)) + + @property + def attr___mro__(self): + if not self._instance.newstyle: + raise AttributeInferenceError(target=self._instance, attribute="__mro__") + + mro = self._instance.mro() + obj = node_classes.Tuple(parent=self._instance) + obj.postinit(mro) + return obj + + @property + def attr_mro(self): + if not self._instance.newstyle: + raise AttributeInferenceError(target=self._instance, attribute="mro") + + # pylint: disable=import-outside-toplevel; circular import + from astroid import bases + + other_self = self + + # Cls.mro is a method and we need to return one in order to have a proper inference. + # The method we're returning is capable of inferring the underlying MRO though. + class MroBoundMethod(bases.BoundMethod): + def infer_call_result(self, caller, context=None): + yield other_self.attr___mro__ + + implicit_metaclass = self._instance.implicit_metaclass() + mro_method = implicit_metaclass.locals["mro"][0] + return MroBoundMethod(proxy=mro_method, bound=implicit_metaclass) + + @property + def attr___bases__(self): + obj = node_classes.Tuple() + context = InferenceContext() + elts = list(self._instance._inferred_bases(context)) + obj.postinit(elts=elts) + return obj + + @property + def attr___class__(self): + # pylint: disable=import-outside-toplevel; circular import + from astroid import helpers + + return helpers.object_type(self._instance) + + @property + def attr___subclasses__(self): + """Get the subclasses of the underlying class + + This looks only in the current module for retrieving the subclasses, + thus it might miss a couple of them. + """ + # pylint: disable=import-outside-toplevel; circular import + from astroid import bases + from astroid.nodes import scoped_nodes + + if not self._instance.newstyle: + raise AttributeInferenceError( + target=self._instance, attribute="__subclasses__" + ) + + qname = self._instance.qname() + root = self._instance.root() + classes = [ + cls + for cls in root.nodes_of_class(scoped_nodes.ClassDef) + if cls != self._instance and cls.is_subtype_of(qname, context=self.context) + ] + + obj = node_classes.List(parent=self._instance) + obj.postinit(classes) + + class SubclassesBoundMethod(bases.BoundMethod): + def infer_call_result(self, caller, context=None): + yield obj + + implicit_metaclass = self._instance.implicit_metaclass() + subclasses_method = implicit_metaclass.locals["__subclasses__"][0] + return SubclassesBoundMethod(proxy=subclasses_method, bound=implicit_metaclass) + + @property + def attr___dict__(self): + return node_classes.Dict(parent=self._instance) + + +class SuperModel(ObjectModel): + @property + def attr___thisclass__(self): + return self._instance.mro_pointer + + @property + def attr___self_class__(self): + return self._instance._self_class + + @property + def attr___self__(self): + return self._instance.type + + @property + def attr___class__(self): + return self._instance._proxied + + +class UnboundMethodModel(ObjectModel): + @property + def attr___class__(self): + # pylint: disable=import-outside-toplevel; circular import + from astroid import helpers + + return helpers.object_type(self._instance) + + @property + def attr___func__(self): + return self._instance._proxied + + @property + def attr___self__(self): + return node_classes.Const(value=None, parent=self._instance) + + attr_im_func = attr___func__ + attr_im_class = attr___class__ + attr_im_self = attr___self__ + + +class BoundMethodModel(FunctionModel): + @property + def attr___func__(self): + return self._instance._proxied._proxied + + @property + def attr___self__(self): + return self._instance.bound + + +class GeneratorModel(FunctionModel): + def __new__(cls, *args, **kwargs): + # Append the values from the GeneratorType unto this object. + ret = super().__new__(cls, *args, **kwargs) + generator = AstroidManager().builtins_module["generator"] + for name, values in generator.locals.items(): + method = values[0] + + def patched(cls, meth=method): + return meth + + setattr(type(ret), IMPL_PREFIX + name, property(patched)) + + return ret + + @property + def attr___name__(self): + return node_classes.Const( + value=self._instance.parent.name, parent=self._instance + ) + + @property + def attr___doc__(self): + return node_classes.Const( + value=getattr(self._instance.parent.doc_node, "value", None), + parent=self._instance, + ) + + +class AsyncGeneratorModel(GeneratorModel): + def __new__(cls, *args, **kwargs): + # Append the values from the AGeneratorType unto this object. + ret = super().__new__(cls, *args, **kwargs) + astroid_builtins = AstroidManager().builtins_module + generator = astroid_builtins.get("async_generator") + if generator is None: + # Make it backward compatible. + generator = astroid_builtins.get("generator") + + for name, values in generator.locals.items(): + method = values[0] + + def patched(cls, meth=method): + return meth + + setattr(type(ret), IMPL_PREFIX + name, property(patched)) + + return ret + + +class InstanceModel(ObjectModel): + @property + def attr___class__(self): + return self._instance._proxied + + @property + def attr___module__(self): + return node_classes.Const(self._instance.root().qname()) + + @property + def attr___doc__(self): + return node_classes.Const(getattr(self._instance.doc_node, "value", None)) + + @property + def attr___dict__(self): + return _dunder_dict(self._instance, self._instance.instance_attrs) + + +# Exception instances + + +class ExceptionInstanceModel(InstanceModel): + @property + def attr_args(self): + message = node_classes.Const("") + args = node_classes.Tuple(parent=self._instance) + args.postinit((message,)) + return args + + @property + def attr___traceback__(self): + builtins_ast_module = AstroidManager().builtins_module + traceback_type = builtins_ast_module[types.TracebackType.__name__] + return traceback_type.instantiate_class() + + +class SyntaxErrorInstanceModel(ExceptionInstanceModel): + @property + def attr_text(self): + return node_classes.Const("") + + +class OSErrorInstanceModel(ExceptionInstanceModel): + @property + def attr_filename(self): + return node_classes.Const("") + + @property + def attr_errno(self): + return node_classes.Const(0) + + @property + def attr_strerror(self): + return node_classes.Const("") + + attr_filename2 = attr_filename + + +class ImportErrorInstanceModel(ExceptionInstanceModel): + @property + def attr_name(self): + return node_classes.Const("") + + @property + def attr_path(self): + return node_classes.Const("") + + +class UnicodeDecodeErrorInstanceModel(ExceptionInstanceModel): + @property + def attr_object(self): + return node_classes.Const("") + + +BUILTIN_EXCEPTIONS = { + "builtins.SyntaxError": SyntaxErrorInstanceModel, + "builtins.ImportError": ImportErrorInstanceModel, + "builtins.UnicodeDecodeError": UnicodeDecodeErrorInstanceModel, + # These are all similar to OSError in terms of attributes + "builtins.OSError": OSErrorInstanceModel, + "builtins.BlockingIOError": OSErrorInstanceModel, + "builtins.BrokenPipeError": OSErrorInstanceModel, + "builtins.ChildProcessError": OSErrorInstanceModel, + "builtins.ConnectionAbortedError": OSErrorInstanceModel, + "builtins.ConnectionError": OSErrorInstanceModel, + "builtins.ConnectionRefusedError": OSErrorInstanceModel, + "builtins.ConnectionResetError": OSErrorInstanceModel, + "builtins.FileExistsError": OSErrorInstanceModel, + "builtins.FileNotFoundError": OSErrorInstanceModel, + "builtins.InterruptedError": OSErrorInstanceModel, + "builtins.IsADirectoryError": OSErrorInstanceModel, + "builtins.NotADirectoryError": OSErrorInstanceModel, + "builtins.PermissionError": OSErrorInstanceModel, + "builtins.ProcessLookupError": OSErrorInstanceModel, + "builtins.TimeoutError": OSErrorInstanceModel, +} + + +class DictModel(ObjectModel): + @property + def attr___class__(self): + return self._instance._proxied + + def _generic_dict_attribute(self, obj, name): + """Generate a bound method that can infer the given *obj*.""" + + class DictMethodBoundMethod(astroid.BoundMethod): + def infer_call_result(self, caller, context=None): + yield obj + + meth = next(self._instance._proxied.igetattr(name), None) + return DictMethodBoundMethod(proxy=meth, bound=self._instance) + + @property + def attr_items(self): + elems = [] + obj = node_classes.List(parent=self._instance) + for key, value in self._instance.items: + elem = node_classes.Tuple(parent=obj) + elem.postinit((key, value)) + elems.append(elem) + obj.postinit(elts=elems) + + obj = objects.DictItems(obj) + return self._generic_dict_attribute(obj, "items") + + @property + def attr_keys(self): + keys = [key for (key, _) in self._instance.items] + obj = node_classes.List(parent=self._instance) + obj.postinit(elts=keys) + + obj = objects.DictKeys(obj) + return self._generic_dict_attribute(obj, "keys") + + @property + def attr_values(self): + + values = [value for (_, value) in self._instance.items] + obj = node_classes.List(parent=self._instance) + obj.postinit(values) + + obj = objects.DictValues(obj) + return self._generic_dict_attribute(obj, "values") + + +class PropertyModel(ObjectModel): + """Model for a builtin property""" + + # pylint: disable=import-outside-toplevel + def _init_function(self, name): + from astroid.nodes.node_classes import Arguments + from astroid.nodes.scoped_nodes import FunctionDef + + args = Arguments() + args.postinit( + args=[], + defaults=[], + kwonlyargs=[], + kw_defaults=[], + annotations=[], + posonlyargs=[], + posonlyargs_annotations=[], + kwonlyargs_annotations=[], + ) + + function = FunctionDef(name=name, parent=self._instance) + + function.postinit(args=args, body=[]) + return function + + @property + def attr_fget(self): + from astroid.nodes.scoped_nodes import FunctionDef + + func = self._instance + + class PropertyFuncAccessor(FunctionDef): + def infer_call_result(self, caller=None, context=None): + nonlocal func + if caller and len(caller.args) != 1: + raise InferenceError( + "fget() needs a single argument", target=self, context=context + ) + + yield from func.function.infer_call_result( + caller=caller, context=context + ) + + property_accessor = PropertyFuncAccessor(name="fget", parent=self._instance) + property_accessor.postinit(args=func.args, body=func.body) + return property_accessor + + @property + def attr_fset(self): + from astroid.nodes.scoped_nodes import FunctionDef + + func = self._instance + + def find_setter(func: "Property") -> Optional[astroid.FunctionDef]: + """ + Given a property, find the corresponding setter function and returns it. + + :param func: property for which the setter has to be found + :return: the setter function or None + """ + for target in [ + t for t in func.parent.get_children() if t.name == func.function.name + ]: + for dec_name in target.decoratornames(): + if dec_name.endswith(func.function.name + ".setter"): + return target + return None + + func_setter = find_setter(func) + if not func_setter: + raise InferenceError( + f"Unable to find the setter of property {func.function.name}" + ) + + class PropertyFuncAccessor(FunctionDef): + def infer_call_result(self, caller=None, context=None): + nonlocal func_setter + if caller and len(caller.args) != 2: + raise InferenceError( + "fset() needs two arguments", target=self, context=context + ) + yield from func_setter.infer_call_result(caller=caller, context=context) + + property_accessor = PropertyFuncAccessor(name="fset", parent=self._instance) + property_accessor.postinit(args=func_setter.args, body=func_setter.body) + return property_accessor + + @property + def attr_setter(self): + return self._init_function("setter") + + @property + def attr_deleter(self): + return self._init_function("deleter") + + @property + def attr_getter(self): + return self._init_function("getter") + + # pylint: enable=import-outside-toplevel diff --git a/myenv/lib/python3.9/site-packages/astroid/manager.py b/myenv/lib/python3.9/site-packages/astroid/manager.py new file mode 100644 index 0000000..950842e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/manager.py @@ -0,0 +1,353 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""astroid manager: avoid multiple astroid build of a same module when +possible by providing a class responsible to get astroid representation +from various source and using a cache of built modules) +""" + +import os +import types +import zipimport +from typing import TYPE_CHECKING, ClassVar, List, Optional + +from astroid.exceptions import AstroidBuildingError, AstroidImportError +from astroid.interpreter._import import spec +from astroid.modutils import ( + NoSourceFile, + file_info_from_modpath, + get_source_file, + is_module_name_part_of_extension_package_whitelist, + is_python_source, + is_standard_module, + load_module_from_name, + modpath_from_file, +) +from astroid.transforms import TransformVisitor + +if TYPE_CHECKING: + from astroid import nodes + +ZIP_IMPORT_EXTS = (".zip", ".egg", ".whl", ".pyz", ".pyzw") + + +def safe_repr(obj): + try: + return repr(obj) + except Exception: # pylint: disable=broad-except + return "???" + + +class AstroidManager: + """Responsible to build astroid from files or modules. + + Use the Borg (singleton) pattern. + """ + + name = "astroid loader" + brain = {} + max_inferable_values: ClassVar[int] = 100 + + def __init__(self): + self.__dict__ = AstroidManager.brain + if not self.__dict__: + # NOTE: cache entries are added by the [re]builder + self.astroid_cache = {} + self._mod_file_cache = {} + self._failed_import_hooks = [] + self.always_load_extensions = False + self.optimize_ast = False + self.extension_package_whitelist = set() + self._transform = TransformVisitor() + + @property + def register_transform(self): + # This and unregister_transform below are exported for convenience + return self._transform.register_transform + + @property + def unregister_transform(self): + return self._transform.unregister_transform + + @property + def builtins_module(self): + return self.astroid_cache["builtins"] + + def visit_transforms(self, node): + """Visit the transforms and apply them to the given *node*.""" + return self._transform.visit(node) + + def ast_from_file(self, filepath, modname=None, fallback=True, source=False): + """given a module name, return the astroid object""" + try: + filepath = get_source_file(filepath, include_no_ext=True) + source = True + except NoSourceFile: + pass + if modname is None: + try: + modname = ".".join(modpath_from_file(filepath)) + except ImportError: + modname = filepath + if ( + modname in self.astroid_cache + and self.astroid_cache[modname].file == filepath + ): + return self.astroid_cache[modname] + if source: + # pylint: disable=import-outside-toplevel; circular import + from astroid.builder import AstroidBuilder + + return AstroidBuilder(self).file_build(filepath, modname) + if fallback and modname: + return self.ast_from_module_name(modname) + raise AstroidBuildingError("Unable to build an AST for {path}.", path=filepath) + + def ast_from_string(self, data, modname="", filepath=None): + """Given some source code as a string, return its corresponding astroid object""" + # pylint: disable=import-outside-toplevel; circular import + from astroid.builder import AstroidBuilder + + return AstroidBuilder(self).string_build(data, modname, filepath) + + def _build_stub_module(self, modname): + # pylint: disable=import-outside-toplevel; circular import + from astroid.builder import AstroidBuilder + + return AstroidBuilder(self).string_build("", modname) + + def _build_namespace_module(self, modname: str, path: List[str]) -> "nodes.Module": + # pylint: disable=import-outside-toplevel; circular import + from astroid.builder import build_namespace_package_module + + return build_namespace_package_module(modname, path) + + def _can_load_extension(self, modname: str) -> bool: + if self.always_load_extensions: + return True + if is_standard_module(modname): + return True + return is_module_name_part_of_extension_package_whitelist( + modname, self.extension_package_whitelist + ) + + def ast_from_module_name(self, modname, context_file=None): + """given a module name, return the astroid object""" + if modname in self.astroid_cache: + return self.astroid_cache[modname] + if modname == "__main__": + return self._build_stub_module(modname) + if context_file: + old_cwd = os.getcwd() + os.chdir(os.path.dirname(context_file)) + try: + found_spec = self.file_from_module_name(modname, context_file) + if found_spec.type == spec.ModuleType.PY_ZIPMODULE: + module = self.zip_import_data(found_spec.location) + if module is not None: + return module + + elif found_spec.type in ( + spec.ModuleType.C_BUILTIN, + spec.ModuleType.C_EXTENSION, + ): + if ( + found_spec.type == spec.ModuleType.C_EXTENSION + and not self._can_load_extension(modname) + ): + return self._build_stub_module(modname) + try: + module = load_module_from_name(modname) + except Exception as e: + raise AstroidImportError( + "Loading {modname} failed with:\n{error}", + modname=modname, + path=found_spec.location, + ) from e + return self.ast_from_module(module, modname) + + elif found_spec.type == spec.ModuleType.PY_COMPILED: + raise AstroidImportError( + "Unable to load compiled module {modname}.", + modname=modname, + path=found_spec.location, + ) + + elif found_spec.type == spec.ModuleType.PY_NAMESPACE: + return self._build_namespace_module( + modname, found_spec.submodule_search_locations + ) + elif found_spec.type == spec.ModuleType.PY_FROZEN: + return self._build_stub_module(modname) + + if found_spec.location is None: + raise AstroidImportError( + "Can't find a file for module {modname}.", modname=modname + ) + + return self.ast_from_file(found_spec.location, modname, fallback=False) + except AstroidBuildingError as e: + for hook in self._failed_import_hooks: + try: + return hook(modname) + except AstroidBuildingError: + pass + raise e + finally: + if context_file: + os.chdir(old_cwd) + + def zip_import_data(self, filepath): + if zipimport is None: + return None + + # pylint: disable=import-outside-toplevel; circular import + from astroid.builder import AstroidBuilder + + builder = AstroidBuilder(self) + for ext in ZIP_IMPORT_EXTS: + try: + eggpath, resource = filepath.rsplit(ext + os.path.sep, 1) + except ValueError: + continue + try: + # pylint: disable-next=no-member + importer = zipimport.zipimporter(eggpath + ext) + zmodname = resource.replace(os.path.sep, ".") + if importer.is_package(resource): + zmodname = zmodname + ".__init__" + module = builder.string_build( + importer.get_source(resource), zmodname, filepath + ) + return module + except Exception: # pylint: disable=broad-except + continue + return None + + def file_from_module_name(self, modname, contextfile): + try: + value = self._mod_file_cache[(modname, contextfile)] + except KeyError: + try: + value = file_info_from_modpath( + modname.split("."), context_file=contextfile + ) + except ImportError as e: + value = AstroidImportError( + "Failed to import module {modname} with error:\n{error}.", + modname=modname, + # we remove the traceback here to save on memory usage (since these exceptions are cached) + error=e.with_traceback(None), + ) + self._mod_file_cache[(modname, contextfile)] = value + if isinstance(value, AstroidBuildingError): + # we remove the traceback here to save on memory usage (since these exceptions are cached) + raise value.with_traceback(None) + return value + + def ast_from_module(self, module: types.ModuleType, modname: Optional[str] = None): + """given an imported module, return the astroid object""" + modname = modname or module.__name__ + if modname in self.astroid_cache: + return self.astroid_cache[modname] + try: + # some builtin modules don't have __file__ attribute + filepath = module.__file__ + if is_python_source(filepath): + return self.ast_from_file(filepath, modname) + except AttributeError: + pass + + # pylint: disable=import-outside-toplevel; circular import + from astroid.builder import AstroidBuilder + + return AstroidBuilder(self).module_build(module, modname) + + def ast_from_class(self, klass, modname=None): + """get astroid for the given class""" + if modname is None: + try: + modname = klass.__module__ + except AttributeError as exc: + raise AstroidBuildingError( + "Unable to get module for class {class_name}.", + cls=klass, + class_repr=safe_repr(klass), + modname=modname, + ) from exc + modastroid = self.ast_from_module_name(modname) + return modastroid.getattr(klass.__name__)[0] # XXX + + def infer_ast_from_something(self, obj, context=None): + """infer astroid for the given class""" + if hasattr(obj, "__class__") and not isinstance(obj, type): + klass = obj.__class__ + else: + klass = obj + try: + modname = klass.__module__ + except AttributeError as exc: + raise AstroidBuildingError( + "Unable to get module for {class_repr}.", + cls=klass, + class_repr=safe_repr(klass), + ) from exc + except Exception as exc: + raise AstroidImportError( + "Unexpected error while retrieving module for {class_repr}:\n" + "{error}", + cls=klass, + class_repr=safe_repr(klass), + ) from exc + try: + name = klass.__name__ + except AttributeError as exc: + raise AstroidBuildingError( + "Unable to get name for {class_repr}:\n", + cls=klass, + class_repr=safe_repr(klass), + ) from exc + except Exception as exc: + raise AstroidImportError( + "Unexpected error while retrieving name for {class_repr}:\n" "{error}", + cls=klass, + class_repr=safe_repr(klass), + ) from exc + # take care, on living object __module__ is regularly wrong :( + modastroid = self.ast_from_module_name(modname) + if klass is obj: + for inferred in modastroid.igetattr(name, context): + yield inferred + else: + for inferred in modastroid.igetattr(name, context): + yield inferred.instantiate_class() + + def register_failed_import_hook(self, hook): + """Registers a hook to resolve imports that cannot be found otherwise. + + `hook` must be a function that accepts a single argument `modname` which + contains the name of the module or package that could not be imported. + If `hook` can resolve the import, must return a node of type `astroid.Module`, + otherwise, it must raise `AstroidBuildingError`. + """ + self._failed_import_hooks.append(hook) + + def cache_module(self, module): + """Cache a module if no module with the same name is known yet.""" + self.astroid_cache.setdefault(module.name, module) + + def bootstrap(self): + """Bootstrap the required AST modules needed for the manager to work + + The bootstrap usually involves building the AST for the builtins + module, which is required by the rest of astroid to work correctly. + """ + from astroid import raw_building # pylint: disable=import-outside-toplevel + + raw_building._astroid_bootstrapping() + + def clear_cache(self): + """Clear the underlying cache. Also bootstraps the builtins module.""" + self.astroid_cache.clear() + self.bootstrap() diff --git a/myenv/lib/python3.9/site-packages/astroid/mixins.py b/myenv/lib/python3.9/site-packages/astroid/mixins.py new file mode 100644 index 0000000..ea68aff --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/mixins.py @@ -0,0 +1,163 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""This module contains some mixins for the different nodes. +""" +import itertools +import sys +from typing import TYPE_CHECKING, Optional + +from astroid import decorators +from astroid.exceptions import AttributeInferenceError + +if TYPE_CHECKING: + from astroid import nodes + +if sys.version_info >= (3, 8) or TYPE_CHECKING: + from functools import cached_property +else: + from astroid.decorators import cachedproperty as cached_property + + +class BlockRangeMixIn: + """override block range""" + + @cached_property + def blockstart_tolineno(self): + return self.lineno + + def _elsed_block_range(self, lineno, orelse, last=None): + """handle block line numbers range for try/finally, for, if and while + statements + """ + if lineno == self.fromlineno: + return lineno, lineno + if orelse: + if lineno >= orelse[0].fromlineno: + return lineno, orelse[-1].tolineno + return lineno, orelse[0].fromlineno - 1 + return lineno, last or self.tolineno + + +class FilterStmtsMixin: + """Mixin for statement filtering and assignment type""" + + def _get_filtered_stmts(self, _, node, _stmts, mystmt: Optional["nodes.Statement"]): + """method used in _filter_stmts to get statements and trigger break""" + if self.statement(future=True) is mystmt: + # original node's statement is the assignment, only keep + # current node (gen exp, list comp) + return [node], True + return _stmts, False + + def assign_type(self): + return self + + +class AssignTypeMixin: + def assign_type(self): + return self + + def _get_filtered_stmts( + self, lookup_node, node, _stmts, mystmt: Optional["nodes.Statement"] + ): + """method used in filter_stmts""" + if self is mystmt: + return _stmts, True + if self.statement(future=True) is mystmt: + # original node's statement is the assignment, only keep + # current node (gen exp, list comp) + return [node], True + return _stmts, False + + +class ParentAssignTypeMixin(AssignTypeMixin): + def assign_type(self): + return self.parent.assign_type() + + +class ImportFromMixin(FilterStmtsMixin): + """MixIn for From and Import Nodes""" + + def _infer_name(self, frame, name): + return name + + def do_import_module(self, modname=None): + """return the ast for a module whose name is imported by """ + # handle special case where we are on a package node importing a module + # using the same name as the package, which may end in an infinite loop + # on relative imports + # XXX: no more needed ? + mymodule = self.root() + level = getattr(self, "level", None) # Import as no level + if modname is None: + modname = self.modname + # XXX we should investigate deeper if we really want to check + # importing itself: modname and mymodule.name be relative or absolute + if mymodule.relative_to_absolute_name(modname, level) == mymodule.name: + # FIXME: we used to raise InferenceError here, but why ? + return mymodule + + return mymodule.import_module( + modname, level=level, relative_only=level and level >= 1 + ) + + def real_name(self, asname): + """get name from 'as' name""" + for name, _asname in self.names: + if name == "*": + return asname + if not _asname: + name = name.split(".", 1)[0] + _asname = name + if asname == _asname: + return name + raise AttributeInferenceError( + "Could not find original name for {attribute} in {target!r}", + target=self, + attribute=asname, + ) + + +class MultiLineBlockMixin: + """Mixin for nodes with multi-line blocks, e.g. For and FunctionDef. + Note that this does not apply to every node with a `body` field. + For instance, an If node has a multi-line body, but the body of an + IfExpr is not multi-line, and hence cannot contain Return nodes, + Assign nodes, etc. + """ + + @cached_property + def _multi_line_blocks(self): + return tuple(getattr(self, field) for field in self._multi_line_block_fields) + + def _get_return_nodes_skip_functions(self): + for block in self._multi_line_blocks: + for child_node in block: + if child_node.is_function: + continue + yield from child_node._get_return_nodes_skip_functions() + + def _get_yield_nodes_skip_lambdas(self): + for block in self._multi_line_blocks: + for child_node in block: + if child_node.is_lambda: + continue + yield from child_node._get_yield_nodes_skip_lambdas() + + @decorators.cached + def _get_assign_nodes(self): + children_assign_nodes = ( + child_node._get_assign_nodes() + for block in self._multi_line_blocks + for child_node in block + ) + return list(itertools.chain.from_iterable(children_assign_nodes)) + + +class NoChildrenMixin: + """Mixin for nodes with no children, e.g. Pass.""" + + def get_children(self): + yield from () diff --git a/myenv/lib/python3.9/site-packages/astroid/modutils.py b/myenv/lib/python3.9/site-packages/astroid/modutils.py new file mode 100644 index 0000000..01135ef --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/modutils.py @@ -0,0 +1,626 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Python modules manipulation utility functions. + +:type PY_SOURCE_EXTS: tuple(str) +:var PY_SOURCE_EXTS: list of possible python source file extension + +:type STD_LIB_DIRS: set of str +:var STD_LIB_DIRS: directories where standard modules are located + +:type BUILTIN_MODULES: dict +:var BUILTIN_MODULES: dictionary with builtin module names has key +""" + +import importlib +import importlib.machinery +import importlib.util +import itertools +import os +import sys +import sysconfig +import types +from pathlib import Path +from typing import Dict, Set + +from astroid.const import IS_JYTHON, IS_PYPY +from astroid.interpreter._import import spec, util + +if sys.platform.startswith("win"): + PY_SOURCE_EXTS = ("py", "pyw") + PY_COMPILED_EXTS = ("dll", "pyd") +else: + PY_SOURCE_EXTS = ("py",) + PY_COMPILED_EXTS = ("so",) + + +# TODO: Adding `platstdlib` is a fix for a workaround in virtualenv. At some point we should +# revisit whether this is still necessary. See https://github.com/PyCQA/astroid/pull/1323. +STD_LIB_DIRS = {sysconfig.get_path("stdlib"), sysconfig.get_path("platstdlib")} + +if os.name == "nt": + STD_LIB_DIRS.add(os.path.join(sys.prefix, "dlls")) + try: + # real_prefix is defined when running inside virtual environments, + # created with the **virtualenv** library. + # Deprecated in virtualenv==16.7.9 + # See: https://github.com/pypa/virtualenv/issues/1622 + STD_LIB_DIRS.add(os.path.join(sys.real_prefix, "dlls")) # type: ignore[attr-defined] + except AttributeError: + # sys.base_exec_prefix is always defined, but in a virtual environment + # created with the stdlib **venv** module, it points to the original + # installation, if the virtual env is activated. + try: + STD_LIB_DIRS.add(os.path.join(sys.base_exec_prefix, "dlls")) + except AttributeError: + pass + +if IS_PYPY and sys.version_info < (3, 8): + # PyPy stores the stdlib in two places: sys.prefix/lib_pypy and sys.prefix/lib-python/3 + # sysconfig.get_path on PyPy returns the first, but without an underscore so we patch this manually. + # Beginning with 3.8 the stdlib is only stored in: sys.prefix/pypy{py_version_short} + STD_LIB_DIRS.add(str(Path(sysconfig.get_path("stdlib")).parent / "lib_pypy")) + STD_LIB_DIRS.add(str(Path(sysconfig.get_path("stdlib")).parent / "lib-python/3")) + + # TODO: This is a fix for a workaround in virtualenv. At some point we should revisit + # whether this is still necessary. See https://github.com/PyCQA/astroid/pull/1324. + STD_LIB_DIRS.add(str(Path(sysconfig.get_path("platstdlib")).parent / "lib_pypy")) + STD_LIB_DIRS.add( + str(Path(sysconfig.get_path("platstdlib")).parent / "lib-python/3") + ) + +if os.name == "posix": + # Need the real prefix if we're in a virtualenv, otherwise + # the usual one will do. + # Deprecated in virtualenv==16.7.9 + # See: https://github.com/pypa/virtualenv/issues/1622 + try: + prefix = sys.real_prefix # type: ignore[attr-defined] + except AttributeError: + prefix = sys.prefix + + def _posix_path(path): + base_python = "python%d.%d" % sys.version_info[:2] + return os.path.join(prefix, path, base_python) + + STD_LIB_DIRS.add(_posix_path("lib")) + if sys.maxsize > 2**32: + # This tries to fix a problem with /usr/lib64 builds, + # where systems are running both 32-bit and 64-bit code + # on the same machine, which reflects into the places where + # standard library could be found. More details can be found + # here http://bugs.python.org/issue1294959. + # An easy reproducing case would be + # https://github.com/PyCQA/pylint/issues/712#issuecomment-163178753 + STD_LIB_DIRS.add(_posix_path("lib64")) + +EXT_LIB_DIRS = {sysconfig.get_path("purelib"), sysconfig.get_path("platlib")} +BUILTIN_MODULES = dict.fromkeys(sys.builtin_module_names, True) + + +class NoSourceFile(Exception): + """exception raised when we are not able to get a python + source file for a precompiled file + """ + + +def _normalize_path(path: str) -> str: + """Resolve symlinks in path and convert to absolute path. + + Note that environment variables and ~ in the path need to be expanded in + advance. + + This can be cached by using _cache_normalize_path. + """ + return os.path.normcase(os.path.realpath(path)) + + +def _path_from_filename(filename, is_jython=IS_JYTHON): + if not is_jython: + return filename + head, has_pyclass, _ = filename.partition("$py.class") + if has_pyclass: + return head + ".py" + return filename + + +def _handle_blacklist(blacklist, dirnames, filenames): + """remove files/directories in the black list + + dirnames/filenames are usually from os.walk + """ + for norecurs in blacklist: + if norecurs in dirnames: + dirnames.remove(norecurs) + elif norecurs in filenames: + filenames.remove(norecurs) + + +_NORM_PATH_CACHE: Dict[str, str] = {} + + +def _cache_normalize_path(path: str) -> str: + """Normalize path with caching.""" + # _module_file calls abspath on every path in sys.path every time it's + # called; on a larger codebase this easily adds up to half a second just + # assembling path components. This cache alleviates that. + try: + return _NORM_PATH_CACHE[path] + except KeyError: + if not path: # don't cache result for '' + return _normalize_path(path) + result = _NORM_PATH_CACHE[path] = _normalize_path(path) + return result + + +def load_module_from_name(dotted_name: str) -> types.ModuleType: + """Load a Python module from its name. + + :type dotted_name: str + :param dotted_name: python name of a module or package + + :raise ImportError: if the module or package is not found + + :rtype: module + :return: the loaded module + """ + try: + return sys.modules[dotted_name] + except KeyError: + pass + + return importlib.import_module(dotted_name) + + +def load_module_from_modpath(parts): + """Load a python module from its split name. + + :type parts: list(str) or tuple(str) + :param parts: + python name of a module or package split on '.' + + :raise ImportError: if the module or package is not found + + :rtype: module + :return: the loaded module + """ + return load_module_from_name(".".join(parts)) + + +def load_module_from_file(filepath: str): + """Load a Python module from it's path. + + :type filepath: str + :param filepath: path to the python module or package + + :raise ImportError: if the module or package is not found + + :rtype: module + :return: the loaded module + """ + modpath = modpath_from_file(filepath) + return load_module_from_modpath(modpath) + + +def check_modpath_has_init(path, mod_path): + """check there are some __init__.py all along the way""" + modpath = [] + for part in mod_path: + modpath.append(part) + path = os.path.join(path, part) + if not _has_init(path): + old_namespace = util.is_namespace(".".join(modpath)) + if not old_namespace: + return False + return True + + +def _get_relative_base_path(filename, path_to_check): + """Extracts the relative mod path of the file to import from + + Check if a file is within the passed in path and if so, returns the + relative mod path from the one passed in. + + If the filename is no in path_to_check, returns None + + Note this function will look for both abs and realpath of the file, + this allows to find the relative base path even if the file is a + symlink of a file in the passed in path + + Examples: + _get_relative_base_path("/a/b/c/d.py", "/a/b") -> ["c","d"] + _get_relative_base_path("/a/b/c/d.py", "/dev") -> None + """ + importable_path = None + path_to_check = os.path.normcase(path_to_check) + abs_filename = os.path.abspath(filename) + if os.path.normcase(abs_filename).startswith(path_to_check): + importable_path = abs_filename + + real_filename = os.path.realpath(filename) + if os.path.normcase(real_filename).startswith(path_to_check): + importable_path = real_filename + + # if "var" in path_to_check: + # breakpoint() + + if importable_path: + base_path = os.path.splitext(importable_path)[0] + relative_base_path = base_path[len(path_to_check) :] + return [pkg for pkg in relative_base_path.split(os.sep) if pkg] + + return None + + +def modpath_from_file_with_callback(filename, path=None, is_package_cb=None): + filename = os.path.expanduser(_path_from_filename(filename)) + paths_to_check = sys.path.copy() + if path: + paths_to_check += path + for pathname in itertools.chain( + paths_to_check, map(_cache_normalize_path, paths_to_check) + ): + if not pathname: + continue + modpath = _get_relative_base_path(filename, pathname) + if not modpath: + continue + if is_package_cb(pathname, modpath[:-1]): + return modpath + + raise ImportError( + "Unable to find module for {} in {}".format(filename, ", \n".join(sys.path)) + ) + + +def modpath_from_file(filename, path=None): + """Get the corresponding split module's name from a filename + + This function will return the name of a module or package split on `.`. + + :type filename: str + :param filename: file's path for which we want the module's name + + :type Optional[List[str]] path: + Optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + :raise ImportError: + if the corresponding module's name has not been found + + :rtype: list(str) + :return: the corresponding split module's name + """ + return modpath_from_file_with_callback(filename, path, check_modpath_has_init) + + +def file_from_modpath(modpath, path=None, context_file=None): + return file_info_from_modpath(modpath, path, context_file).location + + +def file_info_from_modpath(modpath, path=None, context_file=None): + """given a mod path (i.e. split module / package name), return the + corresponding file, giving priority to source file over precompiled + file if it exists + + :type modpath: list or tuple + :param modpath: + split module's name (i.e name of a module or package split + on '.') + (this means explicit relative imports that start with dots have + empty strings in this list!) + + :type path: list or None + :param path: + optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + :type context_file: str or None + :param context_file: + context file to consider, necessary if the identifier has been + introduced using a relative import unresolvable in the actual + context (i.e. modutils) + + :raise ImportError: if there is no such module in the directory + + :rtype: (str or None, import type) + :return: + the path to the module's file or None if it's an integrated + builtin module such as 'sys' + """ + if context_file is not None: + context = os.path.dirname(context_file) + else: + context = context_file + if modpath[0] == "xml": + # handle _xmlplus + try: + return _spec_from_modpath(["_xmlplus"] + modpath[1:], path, context) + except ImportError: + return _spec_from_modpath(modpath, path, context) + elif modpath == ["os", "path"]: + # FIXME: currently ignoring search_path... + return spec.ModuleSpec( + name="os.path", + location=os.path.__file__, + module_type=spec.ModuleType.PY_SOURCE, + ) + return _spec_from_modpath(modpath, path, context) + + +def get_module_part(dotted_name, context_file=None): + """given a dotted name return the module part of the name : + + >>> get_module_part('astroid.as_string.dump') + 'astroid.as_string' + + :type dotted_name: str + :param dotted_name: full name of the identifier we are interested in + + :type context_file: str or None + :param context_file: + context file to consider, necessary if the identifier has been + introduced using a relative import unresolvable in the actual + context (i.e. modutils) + + + :raise ImportError: if there is no such module in the directory + + :rtype: str or None + :return: + the module part of the name or None if we have not been able at + all to import the given name + + XXX: deprecated, since it doesn't handle package precedence over module + (see #10066) + """ + # os.path trick + if dotted_name.startswith("os.path"): + return "os.path" + parts = dotted_name.split(".") + if context_file is not None: + # first check for builtin module which won't be considered latter + # in that case (path != None) + if parts[0] in BUILTIN_MODULES: + if len(parts) > 2: + raise ImportError(dotted_name) + return parts[0] + # don't use += or insert, we want a new list to be created ! + path = None + starti = 0 + if parts[0] == "": + assert ( + context_file is not None + ), "explicit relative import, but no context_file?" + path = [] # prevent resolving the import non-relatively + starti = 1 + while parts[starti] == "": # for all further dots: change context + starti += 1 + context_file = os.path.dirname(context_file) + for i in range(starti, len(parts)): + try: + file_from_modpath( + parts[starti : i + 1], path=path, context_file=context_file + ) + except ImportError: + if i < max(1, len(parts) - 2): + raise + return ".".join(parts[:i]) + return dotted_name + + +def get_module_files(src_directory, blacklist, list_all=False): + """given a package directory return a list of all available python + module's files in the package and its subpackages + + :type src_directory: str + :param src_directory: + path of the directory corresponding to the package + + :type blacklist: list or tuple + :param blacklist: iterable + list of files or directories to ignore. + + :type list_all: bool + :param list_all: + get files from all paths, including ones without __init__.py + + :rtype: list + :return: + the list of all available python module's files in the package and + its subpackages + """ + files = [] + for directory, dirnames, filenames in os.walk(src_directory): + if directory in blacklist: + continue + _handle_blacklist(blacklist, dirnames, filenames) + # check for __init__.py + if not list_all and "__init__.py" not in filenames: + dirnames[:] = () + continue + for filename in filenames: + if _is_python_file(filename): + src = os.path.join(directory, filename) + files.append(src) + return files + + +def get_source_file(filename, include_no_ext=False): + """given a python module's file name return the matching source file + name (the filename will be returned identically if it's already an + absolute path to a python source file...) + + :type filename: str + :param filename: python module's file name + + + :raise NoSourceFile: if no source file exists on the file system + + :rtype: str + :return: the absolute path of the source file if it exists + """ + filename = os.path.abspath(_path_from_filename(filename)) + base, orig_ext = os.path.splitext(filename) + for ext in PY_SOURCE_EXTS: + source_path = f"{base}.{ext}" + if os.path.exists(source_path): + return source_path + if include_no_ext and not orig_ext and os.path.exists(base): + return base + raise NoSourceFile(filename) + + +def is_python_source(filename): + """ + rtype: bool + return: True if the filename is a python source file + """ + return os.path.splitext(filename)[1][1:] in PY_SOURCE_EXTS + + +def is_standard_module(modname, std_path=None): + """try to guess if a module is a standard python module (by default, + see `std_path` parameter's description) + + :type modname: str + :param modname: name of the module we are interested in + + :type std_path: list(str) or tuple(str) + :param std_path: list of path considered has standard + + + :rtype: bool + :return: + true if the module: + - is located on the path listed in one of the directory in `std_path` + - is a built-in module + """ + modname = modname.split(".")[0] + try: + filename = file_from_modpath([modname]) + except ImportError: + # import failed, i'm probably not so wrong by supposing it's + # not standard... + return False + # modules which are not living in a file are considered standard + # (sys and __builtin__ for instance) + if filename is None: + # we assume there are no namespaces in stdlib + return not util.is_namespace(modname) + filename = _normalize_path(filename) + for path in EXT_LIB_DIRS: + if filename.startswith(_cache_normalize_path(path)): + return False + if std_path is None: + std_path = STD_LIB_DIRS + + return any(filename.startswith(_cache_normalize_path(path)) for path in std_path) + + +def is_relative(modname, from_file): + """return true if the given module name is relative to the given + file name + + :type modname: str + :param modname: name of the module we are interested in + + :type from_file: str + :param from_file: + path of the module from which modname has been imported + + :rtype: bool + :return: + true if the module has been imported relatively to `from_file` + """ + if not os.path.isdir(from_file): + from_file = os.path.dirname(from_file) + if from_file in sys.path: + return False + return bool( + importlib.machinery.PathFinder.find_spec( + modname.split(".", maxsplit=1)[0], [from_file] + ) + ) + + +# internal only functions ##################################################### + + +def _spec_from_modpath(modpath, path=None, context=None): + """given a mod path (i.e. split module / package name), return the + corresponding spec + + this function is used internally, see `file_from_modpath`'s + documentation for more information + """ + assert modpath + location = None + if context is not None: + try: + found_spec = spec.find_spec(modpath, [context]) + location = found_spec.location + except ImportError: + found_spec = spec.find_spec(modpath, path) + location = found_spec.location + else: + found_spec = spec.find_spec(modpath, path) + if found_spec.type == spec.ModuleType.PY_COMPILED: + try: + location = get_source_file(found_spec.location) + return found_spec._replace( + location=location, type=spec.ModuleType.PY_SOURCE + ) + except NoSourceFile: + return found_spec._replace(location=location) + elif found_spec.type == spec.ModuleType.C_BUILTIN: + # integrated builtin module + return found_spec._replace(location=None) + elif found_spec.type == spec.ModuleType.PKG_DIRECTORY: + location = _has_init(found_spec.location) + return found_spec._replace(location=location, type=spec.ModuleType.PY_SOURCE) + return found_spec + + +def _is_python_file(filename): + """return true if the given filename should be considered as a python file + + .pyc and .pyo are ignored + """ + return filename.endswith((".py", ".so", ".pyd", ".pyw")) + + +def _has_init(directory): + """if the given directory has a valid __init__ file, return its path, + else return None + """ + mod_or_pack = os.path.join(directory, "__init__") + for ext in PY_SOURCE_EXTS + ("pyc", "pyo"): + if os.path.exists(mod_or_pack + "." + ext): + return mod_or_pack + "." + ext + return None + + +def is_namespace(specobj): + return specobj.type == spec.ModuleType.PY_NAMESPACE + + +def is_directory(specobj): + return specobj.type == spec.ModuleType.PKG_DIRECTORY + + +def is_module_name_part_of_extension_package_whitelist( + module_name: str, package_whitelist: Set[str] +) -> bool: + """ + Returns True if one part of the module name is in the package whitelist + + >>> is_module_name_part_of_extension_package_whitelist('numpy.core.umath', {'numpy'}) + True + """ + parts = module_name.split(".") + return any( + ".".join(parts[:x]) in package_whitelist for x in range(1, len(parts) + 1) + ) diff --git a/myenv/lib/python3.9/site-packages/astroid/node_classes.py b/myenv/lib/python3.9/site-packages/astroid/node_classes.py new file mode 100644 index 0000000..3711309 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/node_classes.py @@ -0,0 +1,97 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +# pylint: disable=unused-import + +import warnings + +from astroid.nodes.node_classes import ( # pylint: disable=redefined-builtin (Ellipsis) + CONST_CLS, + AnnAssign, + Arguments, + Assert, + Assign, + AssignAttr, + AssignName, + AsyncFor, + AsyncWith, + Attribute, + AugAssign, + Await, + BaseContainer, + BinOp, + BoolOp, + Break, + Call, + Compare, + Comprehension, + Const, + Continue, + Decorators, + DelAttr, + Delete, + DelName, + Dict, + DictUnpack, + Ellipsis, + EmptyNode, + EvaluatedObject, + ExceptHandler, + Expr, + ExtSlice, + For, + FormattedValue, + Global, + If, + IfExp, + Import, + ImportFrom, + Index, + JoinedStr, + Keyword, + List, + LookupMixIn, + Match, + MatchAs, + MatchCase, + MatchClass, + MatchMapping, + MatchOr, + MatchSequence, + MatchSingleton, + MatchStar, + MatchValue, + Name, + NamedExpr, + NodeNG, + Nonlocal, + Pass, + Pattern, + Raise, + Return, + Set, + Slice, + Starred, + Subscript, + TryExcept, + TryFinally, + Tuple, + UnaryOp, + Unknown, + While, + With, + Yield, + YieldFrom, + are_exclusive, + const_factory, + unpack_infer, +) + +# We cannot create a __all__ here because it would create a circular import +# Please remove astroid/scoped_nodes.py|astroid/node_classes.py in autoflake +# exclude when removing this file. +warnings.warn( + "The 'astroid.node_classes' module is deprecated and will be replaced by 'astroid.nodes' in astroid 3.0.0", + DeprecationWarning, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/__init__.py b/myenv/lib/python3.9/site-packages/astroid/nodes/__init__.py new file mode 100644 index 0000000..0a98ed1 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/__init__.py @@ -0,0 +1,299 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Every available node class. + +.. seealso:: + :doc:`ast documentation ` + +All nodes inherit from :class:`~astroid.nodes.node_classes.NodeNG`. +""" + +# Nodes not present in the builtin ast module: DictUnpack, Unknown, and EvaluatedObject. + +from astroid.nodes.node_classes import ( # pylint: disable=redefined-builtin (Ellipsis) + CONST_CLS, + AnnAssign, + Arguments, + Assert, + Assign, + AssignAttr, + AssignName, + AsyncFor, + AsyncWith, + Attribute, + AugAssign, + Await, + BaseContainer, + BinOp, + BoolOp, + Break, + Call, + Compare, + Comprehension, + Const, + Continue, + Decorators, + DelAttr, + Delete, + DelName, + Dict, + DictUnpack, + Ellipsis, + EmptyNode, + EvaluatedObject, + ExceptHandler, + Expr, + ExtSlice, + For, + FormattedValue, + Global, + If, + IfExp, + Import, + ImportFrom, + Index, + JoinedStr, + Keyword, + List, + Match, + MatchAs, + MatchCase, + MatchClass, + MatchMapping, + MatchOr, + MatchSequence, + MatchSingleton, + MatchStar, + MatchValue, + Name, + NamedExpr, + NodeNG, + Nonlocal, + Pass, + Pattern, + Raise, + Return, + Set, + Slice, + Starred, + Statement, + Subscript, + TryExcept, + TryFinally, + Tuple, + UnaryOp, + Unknown, + While, + With, + Yield, + YieldFrom, + are_exclusive, + const_factory, + unpack_infer, +) +from astroid.nodes.scoped_nodes import ( + AsyncFunctionDef, + ClassDef, + ComprehensionScope, + DictComp, + FunctionDef, + GeneratorExp, + Lambda, + ListComp, + LocalsDictNodeNG, + Module, + SetComp, + builtin_lookup, + function_to_method, + get_wrapping_class, +) +from astroid.nodes.utils import Position + +_BaseContainer = BaseContainer # TODO Remove for astroid 3.0 + +ALL_NODE_CLASSES = ( + _BaseContainer, + BaseContainer, + AnnAssign, + Arguments, + Assert, + Assign, + AssignAttr, + AssignName, + AsyncFor, + AsyncFunctionDef, + AsyncWith, + Attribute, + AugAssign, + Await, + BinOp, + BoolOp, + Break, + Call, + ClassDef, + Compare, + Comprehension, + ComprehensionScope, + Const, + const_factory, + Continue, + Decorators, + DelAttr, + Delete, + DelName, + Dict, + DictComp, + DictUnpack, + Ellipsis, + EmptyNode, + EvaluatedObject, + ExceptHandler, + Expr, + ExtSlice, + For, + FormattedValue, + FunctionDef, + GeneratorExp, + Global, + If, + IfExp, + Import, + ImportFrom, + Index, + JoinedStr, + Keyword, + Lambda, + List, + ListComp, + LocalsDictNodeNG, + Match, + MatchAs, + MatchCase, + MatchClass, + MatchMapping, + MatchOr, + MatchSequence, + MatchSingleton, + MatchStar, + MatchValue, + Module, + Name, + NamedExpr, + NodeNG, + Nonlocal, + Pass, + Pattern, + Raise, + Return, + Set, + SetComp, + Slice, + Starred, + Subscript, + TryExcept, + TryFinally, + Tuple, + UnaryOp, + Unknown, + While, + With, + Yield, + YieldFrom, +) + +__all__ = ( + "AnnAssign", + "are_exclusive", + "Arguments", + "Assert", + "Assign", + "AssignAttr", + "AssignName", + "AsyncFor", + "AsyncFunctionDef", + "AsyncWith", + "Attribute", + "AugAssign", + "Await", + "BinOp", + "BoolOp", + "Break", + "builtin_lookup", + "Call", + "ClassDef", + "CONST_CLS", + "Compare", + "Comprehension", + "ComprehensionScope", + "Const", + "const_factory", + "Continue", + "Decorators", + "DelAttr", + "Delete", + "DelName", + "Dict", + "DictComp", + "DictUnpack", + "Ellipsis", + "EmptyNode", + "EvaluatedObject", + "ExceptHandler", + "Expr", + "ExtSlice", + "For", + "FormattedValue", + "FunctionDef", + "function_to_method", + "GeneratorExp", + "get_wrapping_class", + "Global", + "If", + "IfExp", + "Import", + "ImportFrom", + "Index", + "JoinedStr", + "Keyword", + "Lambda", + "List", + "ListComp", + "LocalsDictNodeNG", + "Match", + "MatchAs", + "MatchCase", + "MatchClass", + "MatchMapping", + "MatchOr", + "MatchSequence", + "MatchSingleton", + "MatchStar", + "MatchValue", + "Module", + "Name", + "NamedExpr", + "NodeNG", + "Nonlocal", + "Pass", + "Position", + "Raise", + "Return", + "Set", + "SetComp", + "Slice", + "Starred", + "Statement", + "Subscript", + "TryExcept", + "TryFinally", + "Tuple", + "UnaryOp", + "Unknown", + "unpack_infer", + "While", + "With", + "Yield", + "YieldFrom", +) diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/as_string.py b/myenv/lib/python3.9/site-packages/astroid/nodes/as_string.py new file mode 100644 index 0000000..2e2bdcf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/as_string.py @@ -0,0 +1,650 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""This module renders Astroid nodes as string""" +from typing import TYPE_CHECKING, List, Optional + +if TYPE_CHECKING: + from astroid.nodes import Const + from astroid.nodes.node_classes import ( + Match, + MatchAs, + MatchCase, + MatchClass, + MatchMapping, + MatchOr, + MatchSequence, + MatchSingleton, + MatchStar, + MatchValue, + Unknown, + ) + +# pylint: disable=unused-argument + +DOC_NEWLINE = "\0" + + +# Visitor pattern require argument all the time and is not better with staticmethod +# noinspection PyUnusedLocal,PyMethodMayBeStatic +class AsStringVisitor: + """Visitor to render an Astroid node as a valid python code string""" + + def __init__(self, indent=" "): + self.indent = indent + + def __call__(self, node): + """Makes this visitor behave as a simple function""" + return node.accept(self).replace(DOC_NEWLINE, "\n") + + def _docs_dedent(self, doc_node: Optional["Const"]) -> str: + """Stop newlines in docs being indented by self._stmt_list""" + if not doc_node: + return "" + + return '\n{}"""{}"""'.format( + self.indent, doc_node.value.replace("\n", DOC_NEWLINE) + ) + + def _stmt_list(self, stmts, indent=True): + """return a list of nodes to string""" + stmts = "\n".join(nstr for nstr in [n.accept(self) for n in stmts] if nstr) + if indent: + return self.indent + stmts.replace("\n", "\n" + self.indent) + + return stmts + + def _precedence_parens(self, node, child, is_left=True): + """Wrap child in parens only if required to keep same semantics""" + if self._should_wrap(node, child, is_left): + return f"({child.accept(self)})" + + return child.accept(self) + + def _should_wrap(self, node, child, is_left): + """Wrap child if: + - it has lower precedence + - same precedence with position opposite to associativity direction + """ + node_precedence = node.op_precedence() + child_precedence = child.op_precedence() + + if node_precedence > child_precedence: + # 3 * (4 + 5) + return True + + if ( + node_precedence == child_precedence + and is_left != node.op_left_associative() + ): + # 3 - (4 - 5) + # (2**3)**4 + return True + + return False + + # visit_ methods ########################################### + + def visit_await(self, node): + return f"await {node.value.accept(self)}" + + def visit_asyncwith(self, node): + return f"async {self.visit_with(node)}" + + def visit_asyncfor(self, node): + return f"async {self.visit_for(node)}" + + def visit_arguments(self, node): + """return an astroid.Function node as string""" + return node.format_args() + + def visit_assignattr(self, node): + """return an astroid.AssAttr node as string""" + return self.visit_attribute(node) + + def visit_assert(self, node): + """return an astroid.Assert node as string""" + if node.fail: + return f"assert {node.test.accept(self)}, {node.fail.accept(self)}" + return f"assert {node.test.accept(self)}" + + def visit_assignname(self, node): + """return an astroid.AssName node as string""" + return node.name + + def visit_assign(self, node): + """return an astroid.Assign node as string""" + lhs = " = ".join(n.accept(self) for n in node.targets) + return f"{lhs} = {node.value.accept(self)}" + + def visit_augassign(self, node): + """return an astroid.AugAssign node as string""" + return f"{node.target.accept(self)} {node.op} {node.value.accept(self)}" + + def visit_annassign(self, node): + """Return an astroid.AugAssign node as string""" + + target = node.target.accept(self) + annotation = node.annotation.accept(self) + if node.value is None: + return f"{target}: {annotation}" + return f"{target}: {annotation} = {node.value.accept(self)}" + + def visit_binop(self, node): + """return an astroid.BinOp node as string""" + left = self._precedence_parens(node, node.left) + right = self._precedence_parens(node, node.right, is_left=False) + if node.op == "**": + return f"{left}{node.op}{right}" + + return f"{left} {node.op} {right}" + + def visit_boolop(self, node): + """return an astroid.BoolOp node as string""" + values = [f"{self._precedence_parens(node, n)}" for n in node.values] + return (f" {node.op} ").join(values) + + def visit_break(self, node): + """return an astroid.Break node as string""" + return "break" + + def visit_call(self, node): + """return an astroid.Call node as string""" + expr_str = self._precedence_parens(node, node.func) + args = [arg.accept(self) for arg in node.args] + if node.keywords: + keywords = [kwarg.accept(self) for kwarg in node.keywords] + else: + keywords = [] + + args.extend(keywords) + return f"{expr_str}({', '.join(args)})" + + def visit_classdef(self, node): + """return an astroid.ClassDef node as string""" + decorate = node.decorators.accept(self) if node.decorators else "" + args = [n.accept(self) for n in node.bases] + if node._metaclass and not node.has_metaclass_hack(): + args.append("metaclass=" + node._metaclass.accept(self)) + args += [n.accept(self) for n in node.keywords] + args = f"({', '.join(args)})" if args else "" + docs = self._docs_dedent(node.doc_node) + return "\n\n{}class {}{}:{}\n{}\n".format( + decorate, node.name, args, docs, self._stmt_list(node.body) + ) + + def visit_compare(self, node): + """return an astroid.Compare node as string""" + rhs_str = " ".join( + f"{op} {self._precedence_parens(node, expr, is_left=False)}" + for op, expr in node.ops + ) + return f"{self._precedence_parens(node, node.left)} {rhs_str}" + + def visit_comprehension(self, node): + """return an astroid.Comprehension node as string""" + ifs = "".join(f" if {n.accept(self)}" for n in node.ifs) + generated = f"for {node.target.accept(self)} in {node.iter.accept(self)}{ifs}" + return f"{'async ' if node.is_async else ''}{generated}" + + def visit_const(self, node): + """return an astroid.Const node as string""" + if node.value is Ellipsis: + return "..." + return repr(node.value) + + def visit_continue(self, node): + """return an astroid.Continue node as string""" + return "continue" + + def visit_delete(self, node): # XXX check if correct + """return an astroid.Delete node as string""" + return f"del {', '.join(child.accept(self) for child in node.targets)}" + + def visit_delattr(self, node): + """return an astroid.DelAttr node as string""" + return self.visit_attribute(node) + + def visit_delname(self, node): + """return an astroid.DelName node as string""" + return node.name + + def visit_decorators(self, node): + """return an astroid.Decorators node as string""" + return "@%s\n" % "\n@".join(item.accept(self) for item in node.nodes) + + def visit_dict(self, node): + """return an astroid.Dict node as string""" + return "{%s}" % ", ".join(self._visit_dict(node)) + + def _visit_dict(self, node): + for key, value in node.items: + key = key.accept(self) + value = value.accept(self) + if key == "**": + # It can only be a DictUnpack node. + yield key + value + else: + yield f"{key}: {value}" + + def visit_dictunpack(self, node): + return "**" + + def visit_dictcomp(self, node): + """return an astroid.DictComp node as string""" + return "{{{}: {} {}}}".format( + node.key.accept(self), + node.value.accept(self), + " ".join(n.accept(self) for n in node.generators), + ) + + def visit_expr(self, node): + """return an astroid.Discard node as string""" + return node.value.accept(self) + + def visit_emptynode(self, node): + """dummy method for visiting an Empty node""" + return "" + + def visit_excepthandler(self, node): + if node.type: + if node.name: + excs = f"except {node.type.accept(self)} as {node.name.accept(self)}" + else: + excs = f"except {node.type.accept(self)}" + else: + excs = "except" + return f"{excs}:\n{self._stmt_list(node.body)}" + + def visit_empty(self, node): + """return an Empty node as string""" + return "" + + def visit_for(self, node): + """return an astroid.For node as string""" + fors = "for {} in {}:\n{}".format( + node.target.accept(self), node.iter.accept(self), self._stmt_list(node.body) + ) + if node.orelse: + fors = f"{fors}\nelse:\n{self._stmt_list(node.orelse)}" + return fors + + def visit_importfrom(self, node): + """return an astroid.ImportFrom node as string""" + return "from {} import {}".format( + "." * (node.level or 0) + node.modname, _import_string(node.names) + ) + + def visit_joinedstr(self, node): + string = "".join( + # Use repr on the string literal parts + # to get proper escapes, e.g. \n, \\, \" + # But strip the quotes off the ends + # (they will always be one character: ' or ") + repr(value.value)[1:-1] + # Literal braces must be doubled to escape them + .replace("{", "{{").replace("}", "}}") + # Each value in values is either a string literal (Const) + # or a FormattedValue + if type(value).__name__ == "Const" else value.accept(self) + for value in node.values + ) + + # Try to find surrounding quotes that don't appear at all in the string. + # Because the formatted values inside {} can't contain backslash (\) + # using a triple quote is sometimes necessary + for quote in ("'", '"', '"""', "'''"): + if quote not in string: + break + + return "f" + quote + string + quote + + def visit_formattedvalue(self, node): + result = node.value.accept(self) + if node.conversion and node.conversion >= 0: + # e.g. if node.conversion == 114: result += "!r" + result += "!" + chr(node.conversion) + if node.format_spec: + # The format spec is itself a JoinedString, i.e. an f-string + # We strip the f and quotes of the ends + result += ":" + node.format_spec.accept(self)[2:-1] + return "{%s}" % result + + def handle_functiondef(self, node, keyword): + """return a (possibly async) function definition node as string""" + decorate = node.decorators.accept(self) if node.decorators else "" + docs = self._docs_dedent(node.doc_node) + trailer = ":" + if node.returns: + return_annotation = " -> " + node.returns.as_string() + trailer = return_annotation + ":" + def_format = "\n%s%s %s(%s)%s%s\n%s" + return def_format % ( + decorate, + keyword, + node.name, + node.args.accept(self), + trailer, + docs, + self._stmt_list(node.body), + ) + + def visit_functiondef(self, node): + """return an astroid.FunctionDef node as string""" + return self.handle_functiondef(node, "def") + + def visit_asyncfunctiondef(self, node): + """return an astroid.AsyncFunction node as string""" + return self.handle_functiondef(node, "async def") + + def visit_generatorexp(self, node): + """return an astroid.GeneratorExp node as string""" + return "({} {})".format( + node.elt.accept(self), " ".join(n.accept(self) for n in node.generators) + ) + + def visit_attribute(self, node): + """return an astroid.Getattr node as string""" + left = self._precedence_parens(node, node.expr) + if left.isdigit(): + left = f"({left})" + return f"{left}.{node.attrname}" + + def visit_global(self, node): + """return an astroid.Global node as string""" + return f"global {', '.join(node.names)}" + + def visit_if(self, node): + """return an astroid.If node as string""" + ifs = [f"if {node.test.accept(self)}:\n{self._stmt_list(node.body)}"] + if node.has_elif_block(): + ifs.append(f"el{self._stmt_list(node.orelse, indent=False)}") + elif node.orelse: + ifs.append(f"else:\n{self._stmt_list(node.orelse)}") + return "\n".join(ifs) + + def visit_ifexp(self, node): + """return an astroid.IfExp node as string""" + return "{} if {} else {}".format( + self._precedence_parens(node, node.body, is_left=True), + self._precedence_parens(node, node.test, is_left=True), + self._precedence_parens(node, node.orelse, is_left=False), + ) + + def visit_import(self, node): + """return an astroid.Import node as string""" + return f"import {_import_string(node.names)}" + + def visit_keyword(self, node): + """return an astroid.Keyword node as string""" + if node.arg is None: + return f"**{node.value.accept(self)}" + return f"{node.arg}={node.value.accept(self)}" + + def visit_lambda(self, node): + """return an astroid.Lambda node as string""" + args = node.args.accept(self) + body = node.body.accept(self) + if args: + return f"lambda {args}: {body}" + + return f"lambda: {body}" + + def visit_list(self, node): + """return an astroid.List node as string""" + return f"[{', '.join(child.accept(self) for child in node.elts)}]" + + def visit_listcomp(self, node): + """return an astroid.ListComp node as string""" + return "[{} {}]".format( + node.elt.accept(self), " ".join(n.accept(self) for n in node.generators) + ) + + def visit_module(self, node): + """return an astroid.Module node as string""" + docs = f'"""{node.doc_node.value}"""\n\n' if node.doc_node else "" + return docs + "\n".join(n.accept(self) for n in node.body) + "\n\n" + + def visit_name(self, node): + """return an astroid.Name node as string""" + return node.name + + def visit_namedexpr(self, node): + """Return an assignment expression node as string""" + target = node.target.accept(self) + value = node.value.accept(self) + return f"{target} := {value}" + + def visit_nonlocal(self, node): + """return an astroid.Nonlocal node as string""" + return f"nonlocal {', '.join(node.names)}" + + def visit_pass(self, node): + """return an astroid.Pass node as string""" + return "pass" + + def visit_raise(self, node): + """return an astroid.Raise node as string""" + if node.exc: + if node.cause: + return f"raise {node.exc.accept(self)} from {node.cause.accept(self)}" + return f"raise {node.exc.accept(self)}" + return "raise" + + def visit_return(self, node): + """return an astroid.Return node as string""" + if node.is_tuple_return() and len(node.value.elts) > 1: + elts = [child.accept(self) for child in node.value.elts] + return f"return {', '.join(elts)}" + + if node.value: + return f"return {node.value.accept(self)}" + + return "return" + + def visit_set(self, node): + """return an astroid.Set node as string""" + return "{%s}" % ", ".join(child.accept(self) for child in node.elts) + + def visit_setcomp(self, node): + """return an astroid.SetComp node as string""" + return "{{{} {}}}".format( + node.elt.accept(self), " ".join(n.accept(self) for n in node.generators) + ) + + def visit_slice(self, node): + """return an astroid.Slice node as string""" + lower = node.lower.accept(self) if node.lower else "" + upper = node.upper.accept(self) if node.upper else "" + step = node.step.accept(self) if node.step else "" + if step: + return f"{lower}:{upper}:{step}" + return f"{lower}:{upper}" + + def visit_subscript(self, node): + """return an astroid.Subscript node as string""" + idx = node.slice + if idx.__class__.__name__.lower() == "index": + idx = idx.value + idxstr = idx.accept(self) + if idx.__class__.__name__.lower() == "tuple" and idx.elts: + # Remove parenthesis in tuple and extended slice. + # a[(::1, 1:)] is not valid syntax. + idxstr = idxstr[1:-1] + return f"{self._precedence_parens(node, node.value)}[{idxstr}]" + + def visit_tryexcept(self, node): + """return an astroid.TryExcept node as string""" + trys = [f"try:\n{self._stmt_list(node.body)}"] + for handler in node.handlers: + trys.append(handler.accept(self)) + if node.orelse: + trys.append(f"else:\n{self._stmt_list(node.orelse)}") + return "\n".join(trys) + + def visit_tryfinally(self, node): + """return an astroid.TryFinally node as string""" + return "try:\n{}\nfinally:\n{}".format( + self._stmt_list(node.body), self._stmt_list(node.finalbody) + ) + + def visit_tuple(self, node): + """return an astroid.Tuple node as string""" + if len(node.elts) == 1: + return f"({node.elts[0].accept(self)}, )" + return f"({', '.join(child.accept(self) for child in node.elts)})" + + def visit_unaryop(self, node): + """return an astroid.UnaryOp node as string""" + if node.op == "not": + operator = "not " + else: + operator = node.op + return f"{operator}{self._precedence_parens(node, node.operand)}" + + def visit_while(self, node): + """return an astroid.While node as string""" + whiles = f"while {node.test.accept(self)}:\n{self._stmt_list(node.body)}" + if node.orelse: + whiles = f"{whiles}\nelse:\n{self._stmt_list(node.orelse)}" + return whiles + + def visit_with(self, node): # 'with' without 'as' is possible + """return an astroid.With node as string""" + items = ", ".join( + f"{expr.accept(self)}" + (v and f" as {v.accept(self)}" or "") + for expr, v in node.items + ) + return f"with {items}:\n{self._stmt_list(node.body)}" + + def visit_yield(self, node): + """yield an ast.Yield node as string""" + yi_val = (" " + node.value.accept(self)) if node.value else "" + expr = "yield" + yi_val + if node.parent.is_statement: + return expr + + return f"({expr})" + + def visit_yieldfrom(self, node): + """Return an astroid.YieldFrom node as string.""" + yi_val = (" " + node.value.accept(self)) if node.value else "" + expr = "yield from" + yi_val + if node.parent.is_statement: + return expr + + return f"({expr})" + + def visit_starred(self, node): + """return Starred node as string""" + return "*" + node.value.accept(self) + + def visit_match(self, node: "Match") -> str: + """Return an astroid.Match node as string.""" + return f"match {node.subject.accept(self)}:\n{self._stmt_list(node.cases)}" + + def visit_matchcase(self, node: "MatchCase") -> str: + """Return an astroid.MatchCase node as string.""" + guard_str = f" if {node.guard.accept(self)}" if node.guard else "" + return ( + f"case {node.pattern.accept(self)}{guard_str}:\n" + f"{self._stmt_list(node.body)}" + ) + + def visit_matchvalue(self, node: "MatchValue") -> str: + """Return an astroid.MatchValue node as string.""" + return node.value.accept(self) + + @staticmethod + def visit_matchsingleton(node: "MatchSingleton") -> str: + """Return an astroid.MatchSingleton node as string.""" + return str(node.value) + + def visit_matchsequence(self, node: "MatchSequence") -> str: + """Return an astroid.MatchSequence node as string.""" + if node.patterns is None: + return "[]" + return f"[{', '.join(p.accept(self) for p in node.patterns)}]" + + def visit_matchmapping(self, node: "MatchMapping") -> str: + """Return an astroid.MatchMapping node as string.""" + mapping_strings: List[str] = [] + if node.keys and node.patterns: + mapping_strings.extend( + f"{key.accept(self)}: {p.accept(self)}" + for key, p in zip(node.keys, node.patterns) + ) + if node.rest: + mapping_strings.append(f"**{node.rest.accept(self)}") + return f"{'{'}{', '.join(mapping_strings)}{'}'}" + + def visit_matchclass(self, node: "MatchClass") -> str: + """Return an astroid.MatchClass node as string.""" + if node.cls is None: + raise Exception(f"{node} does not have a 'cls' node") + class_strings: List[str] = [] + if node.patterns: + class_strings.extend(p.accept(self) for p in node.patterns) + if node.kwd_attrs and node.kwd_patterns: + for attr, pattern in zip(node.kwd_attrs, node.kwd_patterns): + class_strings.append(f"{attr}={pattern.accept(self)}") + return f"{node.cls.accept(self)}({', '.join(class_strings)})" + + def visit_matchstar(self, node: "MatchStar") -> str: + """Return an astroid.MatchStar node as string.""" + return f"*{node.name.accept(self) if node.name else '_'}" + + def visit_matchas(self, node: "MatchAs") -> str: + """Return an astroid.MatchAs node as string.""" + # pylint: disable=import-outside-toplevel + # Prevent circular dependency + from astroid.nodes.node_classes import MatchClass, MatchMapping, MatchSequence + + if isinstance(node.parent, (MatchSequence, MatchMapping, MatchClass)): + return node.name.accept(self) if node.name else "_" + return ( + f"{node.pattern.accept(self) if node.pattern else '_'}" + f"{f' as {node.name.accept(self)}' if node.name else ''}" + ) + + def visit_matchor(self, node: "MatchOr") -> str: + """Return an astroid.MatchOr node as string.""" + if node.patterns is None: + raise Exception(f"{node} does not have pattern nodes") + return " | ".join(p.accept(self) for p in node.patterns) + + # These aren't for real AST nodes, but for inference objects. + + def visit_frozenset(self, node): + return node.parent.accept(self) + + def visit_super(self, node): + return node.parent.accept(self) + + def visit_uninferable(self, node): + return str(node) + + def visit_property(self, node): + return node.function.accept(self) + + def visit_evaluatedobject(self, node): + return node.original.accept(self) + + def visit_unknown(self, node: "Unknown") -> str: + return str(node) + + +def _import_string(names): + """return a list of (name, asname) formatted as a string""" + _names = [] + for name, asname in names: + if asname is not None: + _names.append(f"{name} as {asname}") + else: + _names.append(name) + return ", ".join(_names) + + +# This sets the default indent to 4 spaces. +to_code = AsStringVisitor(" ") diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/const.py b/myenv/lib/python3.9/site-packages/astroid/nodes/const.py new file mode 100644 index 0000000..6782cc3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/const.py @@ -0,0 +1,27 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +OP_PRECEDENCE = { + op: precedence + for precedence, ops in enumerate( + [ + ["Lambda"], # lambda x: x + 1 + ["IfExp"], # 1 if True else 2 + ["or"], + ["and"], + ["not"], + ["Compare"], # in, not in, is, is not, <, <=, >, >=, !=, == + ["|"], + ["^"], + ["&"], + ["<<", ">>"], + ["+", "-"], + ["*", "@", "/", "//", "%"], + ["UnaryOp"], # +, -, ~ + ["**"], + ["Await"], + ] + ) + for op in ops +} diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/node_classes.py b/myenv/lib/python3.9/site-packages/astroid/nodes/node_classes.py new file mode 100644 index 0000000..c941690 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/node_classes.py @@ -0,0 +1,5443 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Module for some node classes. More nodes in scoped_nodes.py""" + +import abc +import itertools +import sys +import typing +import warnings +from functools import lru_cache +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Generator, + Optional, + Type, + TypeVar, + Union, +) + +from astroid import decorators, mixins, util +from astroid.bases import Instance, _infer_stmts +from astroid.const import Context +from astroid.context import InferenceContext +from astroid.exceptions import ( + AstroidIndexError, + AstroidTypeError, + InferenceError, + NoDefault, + ParentMissingError, +) +from astroid.manager import AstroidManager +from astroid.nodes.const import OP_PRECEDENCE +from astroid.nodes.node_ng import NodeNG + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if TYPE_CHECKING: + from astroid import nodes + from astroid.nodes import LocalsDictNodeNG + +if sys.version_info >= (3, 8) or TYPE_CHECKING: + # pylint: disable-next=ungrouped-imports + from functools import cached_property +else: + from astroid.decorators import cachedproperty as cached_property + + +def _is_const(value): + return isinstance(value, tuple(CONST_CLS)) + + +T_Nodes = TypeVar("T_Nodes", bound=NodeNG) + +AssignedStmtsPossibleNode = Union["List", "Tuple", "AssignName", "AssignAttr", None] +AssignedStmtsCall = Callable[ + [ + T_Nodes, + AssignedStmtsPossibleNode, + Optional[InferenceContext], + Optional[typing.List[int]], + ], + Any, +] + + +@decorators.raise_if_nothing_inferred +def unpack_infer(stmt, context=None): + """recursively generate nodes inferred by the given statement. + If the inferred value is a list or a tuple, recurse on the elements + """ + if isinstance(stmt, (List, Tuple)): + for elt in stmt.elts: + if elt is util.Uninferable: + yield elt + continue + yield from unpack_infer(elt, context) + return dict(node=stmt, context=context) + # if inferred is a final node, return it and stop + inferred = next(stmt.infer(context), util.Uninferable) + if inferred is stmt: + yield inferred + return dict(node=stmt, context=context) + # else, infer recursively, except Uninferable object that should be returned as is + for inferred in stmt.infer(context): + if inferred is util.Uninferable: + yield inferred + else: + yield from unpack_infer(inferred, context) + + return dict(node=stmt, context=context) + + +def are_exclusive(stmt1, stmt2, exceptions: Optional[typing.List[str]] = None) -> bool: + """return true if the two given statements are mutually exclusive + + `exceptions` may be a list of exception names. If specified, discard If + branches and check one of the statement is in an exception handler catching + one of the given exceptions. + + algorithm : + 1) index stmt1's parents + 2) climb among stmt2's parents until we find a common parent + 3) if the common parent is a If or TryExcept statement, look if nodes are + in exclusive branches + """ + # index stmt1's parents + stmt1_parents = {} + children = {} + previous = stmt1 + for node in stmt1.node_ancestors(): + stmt1_parents[node] = 1 + children[node] = previous + previous = node + # climb among stmt2's parents until we find a common parent + previous = stmt2 + for node in stmt2.node_ancestors(): + if node in stmt1_parents: + # if the common parent is a If or TryExcept statement, look if + # nodes are in exclusive branches + if isinstance(node, If) and exceptions is None: + if ( + node.locate_child(previous)[1] + is not node.locate_child(children[node])[1] + ): + return True + elif isinstance(node, TryExcept): + c2attr, c2node = node.locate_child(previous) + c1attr, c1node = node.locate_child(children[node]) + if c1node is not c2node: + first_in_body_caught_by_handlers = ( + c2attr == "handlers" + and c1attr == "body" + and previous.catch(exceptions) + ) + second_in_body_caught_by_handlers = ( + c2attr == "body" + and c1attr == "handlers" + and children[node].catch(exceptions) + ) + first_in_else_other_in_handlers = ( + c2attr == "handlers" and c1attr == "orelse" + ) + second_in_else_other_in_handlers = ( + c2attr == "orelse" and c1attr == "handlers" + ) + if any( + ( + first_in_body_caught_by_handlers, + second_in_body_caught_by_handlers, + first_in_else_other_in_handlers, + second_in_else_other_in_handlers, + ) + ): + return True + elif c2attr == "handlers" and c1attr == "handlers": + return previous is not children[node] + return False + previous = node + return False + + +# getitem() helpers. + +_SLICE_SENTINEL = object() + + +def _slice_value(index, context=None): + """Get the value of the given slice index.""" + + if isinstance(index, Const): + if isinstance(index.value, (int, type(None))): + return index.value + elif index is None: + return None + else: + # Try to infer what the index actually is. + # Since we can't return all the possible values, + # we'll stop at the first possible value. + try: + inferred = next(index.infer(context=context)) + except (InferenceError, StopIteration): + pass + else: + if isinstance(inferred, Const): + if isinstance(inferred.value, (int, type(None))): + return inferred.value + + # Use a sentinel, because None can be a valid + # value that this function can return, + # as it is the case for unspecified bounds. + return _SLICE_SENTINEL + + +def _infer_slice(node, context=None): + lower = _slice_value(node.lower, context) + upper = _slice_value(node.upper, context) + step = _slice_value(node.step, context) + if all(elem is not _SLICE_SENTINEL for elem in (lower, upper, step)): + return slice(lower, upper, step) + + raise AstroidTypeError( + message="Could not infer slice used in subscript", + node=node, + index=node.parent, + context=context, + ) + + +def _container_getitem(instance, elts, index, context=None): + """Get a slice or an item, using the given *index*, for the given sequence.""" + try: + if isinstance(index, Slice): + index_slice = _infer_slice(index, context=context) + new_cls = instance.__class__() + new_cls.elts = elts[index_slice] + new_cls.parent = instance.parent + return new_cls + if isinstance(index, Const): + return elts[index.value] + except IndexError as exc: + raise AstroidIndexError( + message="Index {index!s} out of range", + node=instance, + index=index, + context=context, + ) from exc + except TypeError as exc: + raise AstroidTypeError( + message="Type error {error!r}", node=instance, index=index, context=context + ) from exc + + raise AstroidTypeError(f"Could not use {index} as subscript index") + + +class Statement(NodeNG): + """Statement node adding a few attributes""" + + is_statement = True + """Whether this node indicates a statement.""" + + def next_sibling(self): + """The next sibling statement node. + + :returns: The next sibling statement node. + :rtype: NodeNG or None + """ + stmts = self.parent.child_sequence(self) + index = stmts.index(self) + try: + return stmts[index + 1] + except IndexError: + return None + + def previous_sibling(self): + """The previous sibling statement. + + :returns: The previous sibling statement node. + :rtype: NodeNG or None + """ + stmts = self.parent.child_sequence(self) + index = stmts.index(self) + if index >= 1: + return stmts[index - 1] + return None + + +class BaseContainer( + mixins.ParentAssignTypeMixin, NodeNG, Instance, metaclass=abc.ABCMeta +): + """Base class for Set, FrozenSet, Tuple and List.""" + + _astroid_fields = ("elts",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.elts: typing.List[NodeNG] = [] + """The elements in the node.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, elts: typing.List[NodeNG]) -> None: + """Do some setup after initialisation. + + :param elts: The list of elements the that node contains. + """ + self.elts = elts + + @classmethod + def from_elements(cls, elts=None): + """Create a node of this type from the given list of elements. + + :param elts: The list of elements that the node should contain. + :type elts: list(NodeNG) + + :returns: A new node containing the given elements. + :rtype: NodeNG + """ + node = cls() + if elts is None: + node.elts = [] + else: + node.elts = [const_factory(e) if _is_const(e) else e for e in elts] + return node + + def itered(self): + """An iterator over the elements this node contains. + + :returns: The contents of this node. + :rtype: iterable(NodeNG) + """ + return self.elts + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + :rtype: bool or Uninferable + """ + return bool(self.elts) + + @abc.abstractmethod + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + + def get_children(self): + yield from self.elts + + +class LookupMixIn: + """Mixin to look up a name in the right scope.""" + + @lru_cache(maxsize=None) # pylint: disable=cache-max-size-none # noqa + def lookup(self, name: str) -> typing.Tuple[str, typing.List[NodeNG]]: + """Lookup where the given variable is assigned. + + The lookup starts from self's scope. If self is not a frame itself + and the name is found in the inner frame locals, statements will be + filtered to remove ignorable statements according to self's location. + + :param name: The name of the variable to find assignments for. + + :returns: The scope node and the list of assignments associated to the + given name according to the scope where it has been found (locals, + globals or builtin). + """ + return self.scope().scope_lookup(self, name) + + def ilookup(self, name): + """Lookup the inferred values of the given variable. + + :param name: The variable name to find values for. + :type name: str + + :returns: The inferred values of the statements returned from + :meth:`lookup`. + :rtype: iterable + """ + frame, stmts = self.lookup(name) + context = InferenceContext() + return _infer_stmts(stmts, context, frame) + + +# Name classes + + +class AssignName( + mixins.NoChildrenMixin, LookupMixIn, mixins.ParentAssignTypeMixin, NodeNG +): + """Variation of :class:`ast.Assign` representing assignment to a name. + + An :class:`AssignName` is the name of something that is assigned to. + This includes variables defined in a function signature or in a loop. + + >>> import astroid + >>> node = astroid.extract_node('variable = range(10)') + >>> node + + >>> list(node.get_children()) + [, ] + >>> list(node.get_children())[0].as_string() + 'variable' + """ + + _other_fields = ("name",) + + @decorators.deprecate_default_argument_values(name="str") + def __init__( + self, + name: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param name: The name that is assigned to. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.name: Optional[str] = name + """The name that is assigned to.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + assigned_stmts: ClassVar[AssignedStmtsCall["AssignName"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + +class DelName( + mixins.NoChildrenMixin, LookupMixIn, mixins.ParentAssignTypeMixin, NodeNG +): + """Variation of :class:`ast.Delete` representing deletion of a name. + + A :class:`DelName` is the name of something that is deleted. + + >>> import astroid + >>> node = astroid.extract_node("del variable #@") + >>> list(node.get_children()) + [] + >>> list(node.get_children())[0].as_string() + 'variable' + """ + + _other_fields = ("name",) + + @decorators.deprecate_default_argument_values(name="str") + def __init__( + self, + name: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param name: The name that is being deleted. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.name: Optional[str] = name + """The name that is being deleted.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + +class Name(mixins.NoChildrenMixin, LookupMixIn, NodeNG): + """Class representing an :class:`ast.Name` node. + + A :class:`Name` node is something that is named, but not covered by + :class:`AssignName` or :class:`DelName`. + + >>> import astroid + >>> node = astroid.extract_node('range(10)') + >>> node + + >>> list(node.get_children()) + [, ] + >>> list(node.get_children())[0].as_string() + 'range' + """ + + _other_fields = ("name",) + + @decorators.deprecate_default_argument_values(name="str") + def __init__( + self, + name: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param name: The name that this node refers to. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.name: Optional[str] = name + """The name that this node refers to.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def _get_name_nodes(self): + yield self + + for child_node in self.get_children(): + yield from child_node._get_name_nodes() + + +class Arguments(mixins.AssignTypeMixin, NodeNG): + """Class representing an :class:`ast.arguments` node. + + An :class:`Arguments` node represents that arguments in a + function definition. + + >>> import astroid + >>> node = astroid.extract_node('def foo(bar): pass') + >>> node + + >>> node.args + + """ + + # Python 3.4+ uses a different approach regarding annotations, + # each argument is a new class, _ast.arg, which exposes an + # 'annotation' attribute. In astroid though, arguments are exposed + # as is in the Arguments node and the only way to expose annotations + # is by using something similar with Python 3.3: + # - we expose 'varargannotation' and 'kwargannotation' of annotations + # of varargs and kwargs. + # - we expose 'annotation', a list with annotations for + # for each normal argument. If an argument doesn't have an + # annotation, its value will be None. + _astroid_fields = ( + "args", + "defaults", + "kwonlyargs", + "posonlyargs", + "posonlyargs_annotations", + "kw_defaults", + "annotations", + "varargannotation", + "kwargannotation", + "kwonlyargs_annotations", + "type_comment_args", + "type_comment_kwonlyargs", + "type_comment_posonlyargs", + ) + + _other_fields = ("vararg", "kwarg") + + lineno: None + col_offset: None + end_lineno: None + end_col_offset: None + + def __init__( + self, + vararg: Optional[str] = None, + kwarg: Optional[str] = None, + parent: Optional[NodeNG] = None, + ) -> None: + """ + :param vararg: The name of the variable length arguments. + + :param kwarg: The name of the variable length keyword arguments. + + :param parent: The parent node in the syntax tree. + """ + super().__init__(parent=parent) + + self.vararg: Optional[str] = vararg # can be None + """The name of the variable length arguments.""" + + self.kwarg: Optional[str] = kwarg # can be None + """The name of the variable length keyword arguments.""" + + self.args: Optional[typing.List[AssignName]] + """The names of the required arguments. + + Can be None if the associated function does not have a retrievable + signature and the arguments are therefore unknown. + This happens with builtin functions implemented in C. + """ + + self.defaults: typing.List[NodeNG] + """The default values for arguments that can be passed positionally.""" + + self.kwonlyargs: typing.List[AssignName] + """The keyword arguments that cannot be passed positionally.""" + + self.posonlyargs: typing.List[AssignName] = [] + """The arguments that can only be passed positionally.""" + + self.kw_defaults: typing.List[Optional[NodeNG]] + """The default values for keyword arguments that cannot be passed positionally.""" + + self.annotations: typing.List[Optional[NodeNG]] + """The type annotations of arguments that can be passed positionally.""" + + self.posonlyargs_annotations: typing.List[Optional[NodeNG]] = [] + """The type annotations of arguments that can only be passed positionally.""" + + self.kwonlyargs_annotations: typing.List[Optional[NodeNG]] = [] + """The type annotations of arguments that cannot be passed positionally.""" + + self.type_comment_args: typing.List[Optional[NodeNG]] = [] + """The type annotation, passed by a type comment, of each argument. + + If an argument does not have a type comment, + the value for that argument will be None. + """ + + self.type_comment_kwonlyargs: typing.List[Optional[NodeNG]] = [] + """The type annotation, passed by a type comment, of each keyword only argument. + + If an argument does not have a type comment, + the value for that argument will be None. + """ + + self.type_comment_posonlyargs: typing.List[Optional[NodeNG]] = [] + """The type annotation, passed by a type comment, of each positional argument. + + If an argument does not have a type comment, + the value for that argument will be None. + """ + + self.varargannotation: Optional[NodeNG] = None # can be None + """The type annotation for the variable length arguments.""" + + self.kwargannotation: Optional[NodeNG] = None # can be None + """The type annotation for the variable length keyword arguments.""" + + # pylint: disable=too-many-arguments + def postinit( + self, + args: typing.List[AssignName], + defaults: typing.List[NodeNG], + kwonlyargs: typing.List[AssignName], + kw_defaults: typing.List[Optional[NodeNG]], + annotations: typing.List[Optional[NodeNG]], + posonlyargs: Optional[typing.List[AssignName]] = None, + kwonlyargs_annotations: Optional[typing.List[Optional[NodeNG]]] = None, + posonlyargs_annotations: Optional[typing.List[Optional[NodeNG]]] = None, + varargannotation: Optional[NodeNG] = None, + kwargannotation: Optional[NodeNG] = None, + type_comment_args: Optional[typing.List[Optional[NodeNG]]] = None, + type_comment_kwonlyargs: Optional[typing.List[Optional[NodeNG]]] = None, + type_comment_posonlyargs: Optional[typing.List[Optional[NodeNG]]] = None, + ) -> None: + """Do some setup after initialisation. + + :param args: The names of the required arguments. + + :param defaults: The default values for arguments that can be passed + positionally. + + :param kwonlyargs: The keyword arguments that cannot be passed + positionally. + + :param posonlyargs: The arguments that can only be passed + positionally. + + :param kw_defaults: The default values for keyword arguments that + cannot be passed positionally. + + :param annotations: The type annotations of arguments that can be + passed positionally. + + :param kwonlyargs_annotations: The type annotations of arguments that + cannot be passed positionally. This should always be passed in + Python 3. + + :param posonlyargs_annotations: The type annotations of arguments that + can only be passed positionally. This should always be passed in + Python 3. + + :param varargannotation: The type annotation for the variable length + arguments. + + :param kwargannotation: The type annotation for the variable length + keyword arguments. + + :param type_comment_args: The type annotation, + passed by a type comment, of each argument. + + :param type_comment_args: The type annotation, + passed by a type comment, of each keyword only argument. + + :param type_comment_args: The type annotation, + passed by a type comment, of each positional argument. + """ + self.args = args + self.defaults = defaults + self.kwonlyargs = kwonlyargs + if posonlyargs is not None: + self.posonlyargs = posonlyargs + self.kw_defaults = kw_defaults + self.annotations = annotations + if kwonlyargs_annotations is not None: + self.kwonlyargs_annotations = kwonlyargs_annotations + if posonlyargs_annotations is not None: + self.posonlyargs_annotations = posonlyargs_annotations + self.varargannotation = varargannotation + self.kwargannotation = kwargannotation + if type_comment_args is not None: + self.type_comment_args = type_comment_args + if type_comment_kwonlyargs is not None: + self.type_comment_kwonlyargs = type_comment_kwonlyargs + if type_comment_posonlyargs is not None: + self.type_comment_posonlyargs = type_comment_posonlyargs + + assigned_stmts: ClassVar[AssignedStmtsCall["Arguments"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def _infer_name(self, frame, name): + if self.parent is frame: + return name + return None + + @cached_property + def fromlineno(self): + """The first line that this node appears on in the source code. + + :type: int or None + """ + lineno = super().fromlineno + return max(lineno, self.parent.fromlineno or 0) + + @cached_property + def arguments(self): + """Get all the arguments for this node, including positional only and positional and keyword""" + return list(itertools.chain((self.posonlyargs or ()), self.args or ())) + + def format_args(self): + """Get the arguments formatted as string. + + :returns: The formatted arguments. + :rtype: str + """ + result = [] + positional_only_defaults = [] + positional_or_keyword_defaults = self.defaults + if self.defaults: + args = self.args or [] + positional_or_keyword_defaults = self.defaults[-len(args) :] + positional_only_defaults = self.defaults[: len(self.defaults) - len(args)] + + if self.posonlyargs: + result.append( + _format_args( + self.posonlyargs, + positional_only_defaults, + self.posonlyargs_annotations, + ) + ) + result.append("/") + if self.args: + result.append( + _format_args( + self.args, + positional_or_keyword_defaults, + getattr(self, "annotations", None), + ) + ) + if self.vararg: + result.append(f"*{self.vararg}") + if self.kwonlyargs: + if not self.vararg: + result.append("*") + result.append( + _format_args( + self.kwonlyargs, self.kw_defaults, self.kwonlyargs_annotations + ) + ) + if self.kwarg: + result.append(f"**{self.kwarg}") + return ", ".join(result) + + def default_value(self, argname): + """Get the default value for an argument. + + :param argname: The name of the argument to get the default value for. + :type argname: str + + :raises NoDefault: If there is no default value defined for the + given argument. + """ + args = self.arguments + index = _find_arg(argname, args)[0] + if index is not None: + idx = index - (len(args) - len(self.defaults)) + if idx >= 0: + return self.defaults[idx] + index = _find_arg(argname, self.kwonlyargs)[0] + if index is not None and self.kw_defaults[index] is not None: + return self.kw_defaults[index] + raise NoDefault(func=self.parent, name=argname) + + def is_argument(self, name): + """Check if the given name is defined in the arguments. + + :param name: The name to check for. + :type name: str + + :returns: True if the given name is defined in the arguments, + False otherwise. + :rtype: bool + """ + if name == self.vararg: + return True + if name == self.kwarg: + return True + return ( + self.find_argname(name, rec=True)[1] is not None + or self.kwonlyargs + and _find_arg(name, self.kwonlyargs, rec=True)[1] is not None + ) + + def find_argname(self, argname, rec=False): + """Get the index and :class:`AssignName` node for given name. + + :param argname: The name of the argument to search for. + :type argname: str + + :param rec: Whether or not to include arguments in unpacked tuples + in the search. + :type rec: bool + + :returns: The index and node for the argument. + :rtype: tuple(str or None, AssignName or None) + """ + if self.arguments: + return _find_arg(argname, self.arguments, rec) + return None, None + + def get_children(self): + yield from self.posonlyargs or () + + for elt in self.posonlyargs_annotations: + if elt is not None: + yield elt + + yield from self.args or () + + yield from self.defaults + yield from self.kwonlyargs + + for elt in self.kw_defaults: + if elt is not None: + yield elt + + for elt in self.annotations: + if elt is not None: + yield elt + + if self.varargannotation is not None: + yield self.varargannotation + + if self.kwargannotation is not None: + yield self.kwargannotation + + for elt in self.kwonlyargs_annotations: + if elt is not None: + yield elt + + +def _find_arg(argname, args, rec=False): + for i, arg in enumerate(args): + if isinstance(arg, Tuple): + if rec: + found = _find_arg(argname, arg.elts) + if found[0] is not None: + return found + elif arg.name == argname: + return i, arg + return None, None + + +def _format_args(args, defaults=None, annotations=None): + values = [] + if args is None: + return "" + if annotations is None: + annotations = [] + if defaults is not None: + default_offset = len(args) - len(defaults) + packed = itertools.zip_longest(args, annotations) + for i, (arg, annotation) in enumerate(packed): + if isinstance(arg, Tuple): + values.append(f"({_format_args(arg.elts)})") + else: + argname = arg.name + default_sep = "=" + if annotation is not None: + argname += ": " + annotation.as_string() + default_sep = " = " + values.append(argname) + + if defaults is not None and i >= default_offset: + if defaults[i - default_offset] is not None: + values[-1] += default_sep + defaults[i - default_offset].as_string() + return ", ".join(values) + + +class AssignAttr(mixins.ParentAssignTypeMixin, NodeNG): + """Variation of :class:`ast.Assign` representing assignment to an attribute. + + >>> import astroid + >>> node = astroid.extract_node('self.attribute = range(10)') + >>> node + + >>> list(node.get_children()) + [, ] + >>> list(node.get_children())[0].as_string() + 'self.attribute' + """ + + _astroid_fields = ("expr",) + _other_fields = ("attrname",) + + @decorators.deprecate_default_argument_values(attrname="str") + def __init__( + self, + attrname: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param attrname: The name of the attribute being assigned to. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.expr: Optional[NodeNG] = None + """What has the attribute that is being assigned to.""" + + self.attrname: Optional[str] = attrname + """The name of the attribute being assigned to.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, expr: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param expr: What has the attribute that is being assigned to. + """ + self.expr = expr + + assigned_stmts: ClassVar[AssignedStmtsCall["AssignAttr"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def get_children(self): + yield self.expr + + +class Assert(Statement): + """Class representing an :class:`ast.Assert` node. + + An :class:`Assert` node represents an assert statement. + + >>> import astroid + >>> node = astroid.extract_node('assert len(things) == 10, "Not enough things"') + >>> node + + """ + + _astroid_fields = ("test", "fail") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.test: Optional[NodeNG] = None + """The test that passes or fails the assertion.""" + + self.fail: Optional[NodeNG] = None # can be None + """The message shown when the assertion fails.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, test: Optional[NodeNG] = None, fail: Optional[NodeNG] = None + ) -> None: + """Do some setup after initialisation. + + :param test: The test that passes or fails the assertion. + + :param fail: The message shown when the assertion fails. + """ + self.fail = fail + self.test = test + + def get_children(self): + yield self.test + + if self.fail is not None: + yield self.fail + + +class Assign(mixins.AssignTypeMixin, Statement): + """Class representing an :class:`ast.Assign` node. + + An :class:`Assign` is a statement where something is explicitly + asssigned to. + + >>> import astroid + >>> node = astroid.extract_node('variable = range(10)') + >>> node + + """ + + _astroid_fields = ("targets", "value") + _other_other_fields = ("type_annotation",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.targets: typing.List[NodeNG] = [] + """What is being assigned to.""" + + self.value: Optional[NodeNG] = None + """The value being assigned to the variables.""" + + self.type_annotation: Optional[NodeNG] = None # can be None + """If present, this will contain the type annotation passed by a type comment""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + targets: Optional[typing.List[NodeNG]] = None, + value: Optional[NodeNG] = None, + type_annotation: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param targets: What is being assigned to. + :param value: The value being assigned to the variables. + :param type_annotation: + """ + if targets is not None: + self.targets = targets + self.value = value + self.type_annotation = type_annotation + + assigned_stmts: ClassVar[AssignedStmtsCall["Assign"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def get_children(self): + yield from self.targets + + yield self.value + + @decorators.cached + def _get_assign_nodes(self): + return [self] + list(self.value._get_assign_nodes()) + + def _get_yield_nodes_skip_lambdas(self): + yield from self.value._get_yield_nodes_skip_lambdas() + + +class AnnAssign(mixins.AssignTypeMixin, Statement): + """Class representing an :class:`ast.AnnAssign` node. + + An :class:`AnnAssign` is an assignment with a type annotation. + + >>> import astroid + >>> node = astroid.extract_node('variable: List[int] = range(10)') + >>> node + + """ + + _astroid_fields = ("target", "annotation", "value") + _other_fields = ("simple",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.target: Optional[NodeNG] = None + """What is being assigned to.""" + + self.annotation: Optional[NodeNG] = None + """The type annotation of what is being assigned to.""" + + self.value: Optional[NodeNG] = None # can be None + """The value being assigned to the variables.""" + + self.simple: Optional[int] = None + """Whether :attr:`target` is a pure name or a complex statement.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + target: NodeNG, + annotation: NodeNG, + simple: int, + value: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param target: What is being assigned to. + + :param annotation: The type annotation of what is being assigned to. + + :param simple: Whether :attr:`target` is a pure name + or a complex statement. + + :param value: The value being assigned to the variables. + """ + self.target = target + self.annotation = annotation + self.value = value + self.simple = simple + + assigned_stmts: ClassVar[AssignedStmtsCall["AnnAssign"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def get_children(self): + yield self.target + yield self.annotation + + if self.value is not None: + yield self.value + + +class AugAssign(mixins.AssignTypeMixin, Statement): + """Class representing an :class:`ast.AugAssign` node. + + An :class:`AugAssign` is an assignment paired with an operator. + + >>> import astroid + >>> node = astroid.extract_node('variable += 1') + >>> node + + """ + + _astroid_fields = ("target", "value") + _other_fields = ("op",) + + @decorators.deprecate_default_argument_values(op="str") + def __init__( + self, + op: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param op: The operator that is being combined with the assignment. + This includes the equals sign. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.target: Optional[NodeNG] = None + """What is being assigned to.""" + + self.op: Optional[str] = op + """The operator that is being combined with the assignment. + + This includes the equals sign. + """ + + self.value: Optional[NodeNG] = None + """The value being assigned to the variable.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, target: Optional[NodeNG] = None, value: Optional[NodeNG] = None + ) -> None: + """Do some setup after initialisation. + + :param target: What is being assigned to. + + :param value: The value being assigned to the variable. + """ + self.target = target + self.value = value + + assigned_stmts: ClassVar[AssignedStmtsCall["AugAssign"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + # This is set by inference.py + def _infer_augassign(self, context=None): + raise NotImplementedError + + def type_errors(self, context=None): + """Get a list of type errors which can occur during inference. + + Each TypeError is represented by a :class:`BadBinaryOperationMessage` , + which holds the original exception. + + :returns: The list of possible type errors. + :rtype: list(BadBinaryOperationMessage) + """ + try: + results = self._infer_augassign(context=context) + return [ + result + for result in results + if isinstance(result, util.BadBinaryOperationMessage) + ] + except InferenceError: + return [] + + def get_children(self): + yield self.target + yield self.value + + def _get_yield_nodes_skip_lambdas(self): + """An AugAssign node can contain a Yield node in the value""" + yield from self.value._get_yield_nodes_skip_lambdas() + yield from super()._get_yield_nodes_skip_lambdas() + + +class BinOp(NodeNG): + """Class representing an :class:`ast.BinOp` node. + + A :class:`BinOp` node is an application of a binary operator. + + >>> import astroid + >>> node = astroid.extract_node('a + b') + >>> node + + """ + + _astroid_fields = ("left", "right") + _other_fields = ("op",) + + @decorators.deprecate_default_argument_values(op="str") + def __init__( + self, + op: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param op: The operator. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.left: Optional[NodeNG] = None + """What is being applied to the operator on the left side.""" + + self.op: Optional[str] = op + """The operator.""" + + self.right: Optional[NodeNG] = None + """What is being applied to the operator on the right side.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, left: Optional[NodeNG] = None, right: Optional[NodeNG] = None + ) -> None: + """Do some setup after initialisation. + + :param left: What is being applied to the operator on the left side. + + :param right: What is being applied to the operator on the right side. + """ + self.left = left + self.right = right + + # This is set by inference.py + def _infer_binop(self, context=None): + raise NotImplementedError + + def type_errors(self, context=None): + """Get a list of type errors which can occur during inference. + + Each TypeError is represented by a :class:`BadBinaryOperationMessage`, + which holds the original exception. + + :returns: The list of possible type errors. + :rtype: list(BadBinaryOperationMessage) + """ + try: + results = self._infer_binop(context=context) + return [ + result + for result in results + if isinstance(result, util.BadBinaryOperationMessage) + ] + except InferenceError: + return [] + + def get_children(self): + yield self.left + yield self.right + + def op_precedence(self): + return OP_PRECEDENCE[self.op] + + def op_left_associative(self): + # 2**3**4 == 2**(3**4) + return self.op != "**" + + +class BoolOp(NodeNG): + """Class representing an :class:`ast.BoolOp` node. + + A :class:`BoolOp` is an application of a boolean operator. + + >>> import astroid + >>> node = astroid.extract_node('a and b') + >>> node + + """ + + _astroid_fields = ("values",) + _other_fields = ("op",) + + @decorators.deprecate_default_argument_values(op="str") + def __init__( + self, + op: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param op: The operator. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.op: Optional[str] = op + """The operator.""" + + self.values: typing.List[NodeNG] = [] + """The values being applied to the operator.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, values: Optional[typing.List[NodeNG]] = None) -> None: + """Do some setup after initialisation. + + :param values: The values being applied to the operator. + """ + if values is not None: + self.values = values + + def get_children(self): + yield from self.values + + def op_precedence(self): + return OP_PRECEDENCE[self.op] + + +class Break(mixins.NoChildrenMixin, Statement): + """Class representing an :class:`ast.Break` node. + + >>> import astroid + >>> node = astroid.extract_node('break') + >>> node + + """ + + +class Call(NodeNG): + """Class representing an :class:`ast.Call` node. + + A :class:`Call` node is a call to a function, method, etc. + + >>> import astroid + >>> node = astroid.extract_node('function()') + >>> node + + """ + + _astroid_fields = ("func", "args", "keywords") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.func: Optional[NodeNG] = None + """What is being called.""" + + self.args: typing.List[NodeNG] = [] + """The positional arguments being given to the call.""" + + self.keywords: typing.List["Keyword"] = [] + """The keyword arguments being given to the call.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + func: Optional[NodeNG] = None, + args: Optional[typing.List[NodeNG]] = None, + keywords: Optional[typing.List["Keyword"]] = None, + ) -> None: + """Do some setup after initialisation. + + :param func: What is being called. + + :param args: The positional arguments being given to the call. + + :param keywords: The keyword arguments being given to the call. + """ + self.func = func + if args is not None: + self.args = args + if keywords is not None: + self.keywords = keywords + + @property + def starargs(self) -> typing.List["Starred"]: + """The positional arguments that unpack something.""" + return [arg for arg in self.args if isinstance(arg, Starred)] + + @property + def kwargs(self) -> typing.List["Keyword"]: + """The keyword arguments that unpack something.""" + return [keyword for keyword in self.keywords if keyword.arg is None] + + def get_children(self): + yield self.func + + yield from self.args + + yield from self.keywords + + +class Compare(NodeNG): + """Class representing an :class:`ast.Compare` node. + + A :class:`Compare` node indicates a comparison. + + >>> import astroid + >>> node = astroid.extract_node('a <= b <= c') + >>> node + + >>> node.ops + [('<=', ), ('<=', )] + """ + + _astroid_fields = ("left", "ops") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.left: Optional[NodeNG] = None + """The value at the left being applied to a comparison operator.""" + + self.ops: typing.List[typing.Tuple[str, NodeNG]] = [] + """The remainder of the operators and their relevant right hand value.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + left: Optional[NodeNG] = None, + ops: Optional[typing.List[typing.Tuple[str, NodeNG]]] = None, + ) -> None: + """Do some setup after initialisation. + + :param left: The value at the left being applied to a comparison + operator. + + :param ops: The remainder of the operators + and their relevant right hand value. + """ + self.left = left + if ops is not None: + self.ops = ops + + def get_children(self): + """Get the child nodes below this node. + + Overridden to handle the tuple fields and skip returning the operator + strings. + + :returns: The children. + :rtype: iterable(NodeNG) + """ + yield self.left + for _, comparator in self.ops: + yield comparator # we don't want the 'op' + + def last_child(self): + """An optimized version of list(get_children())[-1] + + :returns: The last child. + :rtype: NodeNG + """ + # XXX maybe if self.ops: + return self.ops[-1][1] + # return self.left + + +class Comprehension(NodeNG): + """Class representing an :class:`ast.comprehension` node. + + A :class:`Comprehension` indicates the loop inside any type of + comprehension including generator expressions. + + >>> import astroid + >>> node = astroid.extract_node('[x for x in some_values]') + >>> list(node.get_children()) + [, ] + >>> list(node.get_children())[1].as_string() + 'for x in some_values' + """ + + _astroid_fields = ("target", "iter", "ifs") + _other_fields = ("is_async",) + + optional_assign = True + """Whether this node optionally assigns a variable.""" + + lineno: None + col_offset: None + end_lineno: None + end_col_offset: None + + def __init__(self, parent: Optional[NodeNG] = None) -> None: + """ + :param parent: The parent node in the syntax tree. + """ + self.target: Optional[NodeNG] = None + """What is assigned to by the comprehension.""" + + self.iter: Optional[NodeNG] = None + """What is iterated over by the comprehension.""" + + self.ifs: typing.List[NodeNG] = [] + """The contents of any if statements that filter the comprehension.""" + + self.is_async: Optional[bool] = None + """Whether this is an asynchronous comprehension or not.""" + + super().__init__(parent=parent) + + # pylint: disable=redefined-builtin; same name as builtin ast module. + def postinit( + self, + target: Optional[NodeNG] = None, + iter: Optional[NodeNG] = None, + ifs: Optional[typing.List[NodeNG]] = None, + is_async: Optional[bool] = None, + ) -> None: + """Do some setup after initialisation. + + :param target: What is assigned to by the comprehension. + + :param iter: What is iterated over by the comprehension. + + :param ifs: The contents of any if statements that filter + the comprehension. + + :param is_async: Whether this is an asynchronous comprehension or not. + """ + self.target = target + self.iter = iter + if ifs is not None: + self.ifs = ifs + self.is_async = is_async + + assigned_stmts: ClassVar[AssignedStmtsCall["Comprehension"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def assign_type(self): + """The type of assignment that this node performs. + + :returns: The assignment type. + :rtype: NodeNG + """ + return self + + def _get_filtered_stmts( + self, lookup_node, node, stmts, mystmt: Optional[Statement] + ): + """method used in filter_stmts""" + if self is mystmt: + if isinstance(lookup_node, (Const, Name)): + return [lookup_node], True + + elif self.statement(future=True) is mystmt: + # original node's statement is the assignment, only keeps + # current node (gen exp, list comp) + + return [node], True + + return stmts, False + + def get_children(self): + yield self.target + yield self.iter + + yield from self.ifs + + +class Const(mixins.NoChildrenMixin, NodeNG, Instance): + """Class representing any constant including num, str, bool, None, bytes. + + >>> import astroid + >>> node = astroid.extract_node('(5, "This is a string.", True, None, b"bytes")') + >>> node + + >>> list(node.get_children()) + [, + , + , + , + ] + """ + + _other_fields = ("value", "kind") + + def __init__( + self, + value: Any, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + kind: Optional[str] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param value: The value that the constant represents. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param kind: The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: Any = value + """The value that the constant represents.""" + + self.kind: Optional[str] = kind # can be None + """"The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def __getattr__(self, name): + # This is needed because of Proxy's __getattr__ method. + # Calling object.__new__ on this class without calling + # __init__ would result in an infinite loop otherwise + # since __getattr__ is called when an attribute doesn't + # exist and self._proxied indirectly calls self.value + # and Proxy __getattr__ calls self.value + if name == "value": + raise AttributeError + return super().__getattr__(name) + + def getitem(self, index, context=None): + """Get an item from this node if subscriptable. + + :param index: The node to use as a subscript index. + :type index: Const or Slice + + :raises AstroidTypeError: When the given index cannot be used as a + subscript index, or if this node is not subscriptable. + """ + if isinstance(index, Const): + index_value = index.value + elif isinstance(index, Slice): + index_value = _infer_slice(index, context=context) + + else: + raise AstroidTypeError( + f"Could not use type {type(index)} as subscript index" + ) + + try: + if isinstance(self.value, (str, bytes)): + return Const(self.value[index_value]) + except IndexError as exc: + raise AstroidIndexError( + message="Index {index!r} out of range", + node=self, + index=index, + context=context, + ) from exc + except TypeError as exc: + raise AstroidTypeError( + message="Type error {error!r}", node=self, index=index, context=context + ) from exc + + raise AstroidTypeError(f"{self!r} (value={self.value})") + + def has_dynamic_getattr(self): + """Check if the node has a custom __getattr__ or __getattribute__. + + :returns: True if the class has a custom + __getattr__ or __getattribute__, False otherwise. + For a :class:`Const` this is always ``False``. + :rtype: bool + """ + return False + + def itered(self): + """An iterator over the elements this node contains. + + :returns: The contents of this node. + :rtype: iterable(Const) + + :raises TypeError: If this node does not represent something that is iterable. + """ + if isinstance(self.value, str): + return [const_factory(elem) for elem in self.value] + raise TypeError(f"Cannot iterate over type {type(self.value)!r}") + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + return self._proxied.qname() + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + :rtype: bool + """ + return bool(self.value) + + +class Continue(mixins.NoChildrenMixin, Statement): + """Class representing an :class:`ast.Continue` node. + + >>> import astroid + >>> node = astroid.extract_node('continue') + >>> node + + """ + + +class Decorators(NodeNG): + """A node representing a list of decorators. + + A :class:`Decorators` is the decorators that are applied to + a method or function. + + >>> import astroid + >>> node = astroid.extract_node(''' + @property + def my_property(self): + return 3 + ''') + >>> node + + >>> list(node.get_children())[0] + + """ + + _astroid_fields = ("nodes",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.nodes: typing.List[NodeNG] + """The decorators that this node contains. + + :type: list(Name or Call) or None + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, nodes: typing.List[NodeNG]) -> None: + """Do some setup after initialisation. + + :param nodes: The decorators that this node contains. + :type nodes: list(Name or Call) + """ + self.nodes = nodes + + def scope(self) -> "LocalsDictNodeNG": + """The first parent node defining a new scope. + These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. + + :returns: The first parent scope node. + """ + # skip the function node to go directly to the upper level scope + if not self.parent: + raise ParentMissingError(target=self) + if not self.parent.parent: + raise ParentMissingError(target=self.parent) + return self.parent.parent.scope() + + def get_children(self): + yield from self.nodes + + +class DelAttr(mixins.ParentAssignTypeMixin, NodeNG): + """Variation of :class:`ast.Delete` representing deletion of an attribute. + + >>> import astroid + >>> node = astroid.extract_node('del self.attr') + >>> node + + >>> list(node.get_children())[0] + + """ + + _astroid_fields = ("expr",) + _other_fields = ("attrname",) + + @decorators.deprecate_default_argument_values(attrname="str") + def __init__( + self, + attrname: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param attrname: The name of the attribute that is being deleted. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.expr: Optional[NodeNG] = None + """The name that this node represents. + + :type: Name or None + """ + + self.attrname: Optional[str] = attrname + """The name of the attribute that is being deleted.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, expr: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param expr: The name that this node represents. + :type expr: Name or None + """ + self.expr = expr + + def get_children(self): + yield self.expr + + +class Delete(mixins.AssignTypeMixin, Statement): + """Class representing an :class:`ast.Delete` node. + + A :class:`Delete` is a ``del`` statement this is deleting something. + + >>> import astroid + >>> node = astroid.extract_node('del self.attr') + >>> node + + """ + + _astroid_fields = ("targets",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.targets: typing.List[NodeNG] = [] + """What is being deleted.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, targets: Optional[typing.List[NodeNG]] = None) -> None: + """Do some setup after initialisation. + + :param targets: What is being deleted. + """ + if targets is not None: + self.targets = targets + + def get_children(self): + yield from self.targets + + +class Dict(NodeNG, Instance): + """Class representing an :class:`ast.Dict` node. + + A :class:`Dict` is a dictionary that is created with ``{}`` syntax. + + >>> import astroid + >>> node = astroid.extract_node('{1: "1"}') + >>> node + + """ + + _astroid_fields = ("items",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.items: typing.List[typing.Tuple[NodeNG, NodeNG]] = [] + """The key-value pairs contained in the dictionary.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, items: typing.List[typing.Tuple[NodeNG, NodeNG]]) -> None: + """Do some setup after initialisation. + + :param items: The key-value pairs contained in the dictionary. + """ + self.items = items + + @classmethod + def from_elements(cls, items=None): + """Create a :class:`Dict` of constants from a live dictionary. + + :param items: The items to store in the node. + :type items: dict + + :returns: The created dictionary node. + :rtype: Dict + """ + node = cls() + if items is None: + node.items = [] + else: + node.items = [ + (const_factory(k), const_factory(v) if _is_const(v) else v) + for k, v in items.items() + # The keys need to be constants + if _is_const(k) + ] + return node + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + return "builtins.dict" + + def get_children(self): + """Get the key and value nodes below this node. + + Children are returned in the order that they are defined in the source + code, key first then the value. + + :returns: The children. + :rtype: iterable(NodeNG) + """ + for key, value in self.items: + yield key + yield value + + def last_child(self): + """An optimized version of list(get_children())[-1] + + :returns: The last child, or None if no children exist. + :rtype: NodeNG or None + """ + if self.items: + return self.items[-1][1] + return None + + def itered(self): + """An iterator over the keys this node contains. + + :returns: The keys of this node. + :rtype: iterable(NodeNG) + """ + return [key for (key, _) in self.items] + + def getitem(self, index, context=None): + """Get an item from this node. + + :param index: The node to use as a subscript index. + :type index: Const or Slice + + :raises AstroidTypeError: When the given index cannot be used as a + subscript index, or if this node is not subscriptable. + :raises AstroidIndexError: If the given index does not exist in the + dictionary. + """ + for key, value in self.items: + # TODO(cpopa): no support for overriding yet, {1:2, **{1: 3}}. + if isinstance(key, DictUnpack): + try: + return value.getitem(index, context) + except (AstroidTypeError, AstroidIndexError): + continue + for inferredkey in key.infer(context): + if inferredkey is util.Uninferable: + continue + if isinstance(inferredkey, Const) and isinstance(index, Const): + if inferredkey.value == index.value: + return value + + raise AstroidIndexError(index) + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + :rtype: bool + """ + return bool(self.items) + + +class Expr(Statement): + """Class representing an :class:`ast.Expr` node. + + An :class:`Expr` is any expression that does not have its value used or + stored. + + >>> import astroid + >>> node = astroid.extract_node('method()') + >>> node + + >>> node.parent + + """ + + _astroid_fields = ("value",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: Optional[NodeNG] = None + """What the expression does.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, value: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param value: What the expression does. + """ + self.value = value + + def get_children(self): + yield self.value + + def _get_yield_nodes_skip_lambdas(self): + if not self.value.is_lambda: + yield from self.value._get_yield_nodes_skip_lambdas() + + +class Ellipsis(mixins.NoChildrenMixin, NodeNG): # pylint: disable=redefined-builtin + """Class representing an :class:`ast.Ellipsis` node. + + An :class:`Ellipsis` is the ``...`` syntax. + + Deprecated since v2.6.0 - Use :class:`Const` instead. + Will be removed with the release v2.7.0 + """ + + +class EmptyNode(mixins.NoChildrenMixin, NodeNG): + """Holds an arbitrary object in the :attr:`LocalsDictNodeNG.locals`.""" + + object = None + + +class ExceptHandler(mixins.MultiLineBlockMixin, mixins.AssignTypeMixin, Statement): + """Class representing an :class:`ast.ExceptHandler`. node. + + An :class:`ExceptHandler` is an ``except`` block on a try-except. + + >>> import astroid + >>> node = astroid.extract_node(''' + try: + do_something() + except Exception as error: + print("Error!") + ''') + >>> node + + >>> node.handlers + [] + """ + + _astroid_fields = ("type", "name", "body") + _multi_line_block_fields = ("body",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.type: Optional[NodeNG] = None # can be None + """The types that the block handles. + + :type: Tuple or NodeNG or None + """ + + self.name: Optional[AssignName] = None # can be None + """The name that the caught exception is assigned to.""" + + self.body: typing.List[NodeNG] = [] + """The contents of the block.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + assigned_stmts: ClassVar[AssignedStmtsCall["ExceptHandler"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def get_children(self): + if self.type is not None: + yield self.type + + if self.name is not None: + yield self.name + + yield from self.body + + # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. + def postinit( + self, + type: Optional[NodeNG] = None, + name: Optional[AssignName] = None, + body: Optional[typing.List[NodeNG]] = None, + ) -> None: + """Do some setup after initialisation. + + :param type: The types that the block handles. + :type type: Tuple or NodeNG or None + + :param name: The name that the caught exception is assigned to. + + :param body:The contents of the block. + """ + self.type = type + self.name = name + if body is not None: + self.body = body + + @cached_property + def blockstart_tolineno(self): + """The line on which the beginning of this block ends. + + :type: int + """ + if self.name: + return self.name.tolineno + if self.type: + return self.type.tolineno + return self.lineno + + def catch(self, exceptions: Optional[typing.List[str]]) -> bool: + """Check if this node handles any of the given + + :param exceptions: The names of the exceptions to check for. + """ + if self.type is None or exceptions is None: + return True + return any(node.name in exceptions for node in self.type._get_name_nodes()) + + +class ExtSlice(NodeNG): + """Class representing an :class:`ast.ExtSlice` node. + + An :class:`ExtSlice` is a complex slice expression. + + Deprecated since v2.6.0 - Now part of the :class:`Subscript` node. + Will be removed with the release of v2.7.0 + """ + + +class For( + mixins.MultiLineBlockMixin, + mixins.BlockRangeMixIn, + mixins.AssignTypeMixin, + Statement, +): + """Class representing an :class:`ast.For` node. + + >>> import astroid + >>> node = astroid.extract_node('for thing in things: print(thing)') + >>> node + + """ + + _astroid_fields = ("target", "iter", "body", "orelse") + _other_other_fields = ("type_annotation",) + _multi_line_block_fields = ("body", "orelse") + + optional_assign = True + """Whether this node optionally assigns a variable. + + This is always ``True`` for :class:`For` nodes. + """ + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.target: Optional[NodeNG] = None + """What the loop assigns to.""" + + self.iter: Optional[NodeNG] = None + """What the loop iterates over.""" + + self.body: typing.List[NodeNG] = [] + """The contents of the body of the loop.""" + + self.orelse: typing.List[NodeNG] = [] + """The contents of the ``else`` block of the loop.""" + + self.type_annotation: Optional[NodeNG] = None # can be None + """If present, this will contain the type annotation passed by a type comment""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. + def postinit( + self, + target: Optional[NodeNG] = None, + iter: Optional[NodeNG] = None, + body: Optional[typing.List[NodeNG]] = None, + orelse: Optional[typing.List[NodeNG]] = None, + type_annotation: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param target: What the loop assigns to. + + :param iter: What the loop iterates over. + + :param body: The contents of the body of the loop. + + :param orelse: The contents of the ``else`` block of the loop. + """ + self.target = target + self.iter = iter + if body is not None: + self.body = body + if orelse is not None: + self.orelse = orelse + self.type_annotation = type_annotation + + assigned_stmts: ClassVar[AssignedStmtsCall["For"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + @cached_property + def blockstart_tolineno(self): + """The line on which the beginning of this block ends. + + :type: int + """ + return self.iter.tolineno + + def get_children(self): + yield self.target + yield self.iter + + yield from self.body + yield from self.orelse + + +class AsyncFor(For): + """Class representing an :class:`ast.AsyncFor` node. + + An :class:`AsyncFor` is an asynchronous :class:`For` built with + the ``async`` keyword. + + >>> import astroid + >>> node = astroid.extract_node(''' + async def func(things): + async for thing in things: + print(thing) + ''') + >>> node + + >>> node.body[0] + + """ + + +class Await(NodeNG): + """Class representing an :class:`ast.Await` node. + + An :class:`Await` is the ``await`` keyword. + + >>> import astroid + >>> node = astroid.extract_node(''' + async def func(things): + await other_func() + ''') + >>> node + + >>> node.body[0] + + >>> list(node.body[0].get_children())[0] + + """ + + _astroid_fields = ("value",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: Optional[NodeNG] = None + """What to wait for.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, value: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param value: What to wait for. + """ + self.value = value + + def get_children(self): + yield self.value + + +class ImportFrom(mixins.NoChildrenMixin, mixins.ImportFromMixin, Statement): + """Class representing an :class:`ast.ImportFrom` node. + + >>> import astroid + >>> node = astroid.extract_node('from my_package import my_module') + >>> node + + """ + + _other_fields = ("modname", "names", "level") + + def __init__( + self, + fromname: Optional[str], + names: typing.List[typing.Tuple[str, Optional[str]]], + level: Optional[int] = 0, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param fromname: The module that is being imported from. + + :param names: What is being imported from the module. + + :param level: The level of relative import. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.modname: Optional[str] = fromname # can be None + """The module that is being imported from. + + This is ``None`` for relative imports. + """ + + self.names: typing.List[typing.Tuple[str, Optional[str]]] = names + """What is being imported from the module. + + Each entry is a :class:`tuple` of the name being imported, + and the alias that the name is assigned to (if any). + """ + + # TODO When is 'level' None? + self.level: Optional[int] = level # can be None + """The level of relative import. + + Essentially this is the number of dots in the import. + This is always 0 for absolute imports. + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + +class Attribute(NodeNG): + """Class representing an :class:`ast.Attribute` node.""" + + _astroid_fields = ("expr",) + _other_fields = ("attrname",) + + @decorators.deprecate_default_argument_values(attrname="str") + def __init__( + self, + attrname: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param attrname: The name of the attribute. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.expr: Optional[NodeNG] = None + """The name that this node represents. + + :type: Name or None + """ + + self.attrname: Optional[str] = attrname + """The name of the attribute.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, expr: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param expr: The name that this node represents. + :type expr: Name or None + """ + self.expr = expr + + def get_children(self): + yield self.expr + + +class Global(mixins.NoChildrenMixin, Statement): + """Class representing an :class:`ast.Global` node. + + >>> import astroid + >>> node = astroid.extract_node('global a_global') + >>> node + + """ + + _other_fields = ("names",) + + def __init__( + self, + names: typing.List[str], + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param names: The names being declared as global. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.names: typing.List[str] = names + """The names being declared as global.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def _infer_name(self, frame, name): + return name + + +class If(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): + """Class representing an :class:`ast.If` node. + + >>> import astroid + >>> node = astroid.extract_node('if condition: print(True)') + >>> node + + """ + + _astroid_fields = ("test", "body", "orelse") + _multi_line_block_fields = ("body", "orelse") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.test: Optional[NodeNG] = None + """The condition that the statement tests.""" + + self.body: typing.List[NodeNG] = [] + """The contents of the block.""" + + self.orelse: typing.List[NodeNG] = [] + """The contents of the ``else`` block.""" + + self.is_orelse: bool = False + """Whether the if-statement is the orelse-block of another if statement.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + test: Optional[NodeNG] = None, + body: Optional[typing.List[NodeNG]] = None, + orelse: Optional[typing.List[NodeNG]] = None, + ) -> None: + """Do some setup after initialisation. + + :param test: The condition that the statement tests. + + :param body: The contents of the block. + + :param orelse: The contents of the ``else`` block. + """ + self.test = test + if body is not None: + self.body = body + if orelse is not None: + self.orelse = orelse + if isinstance(self.parent, If) and self in self.parent.orelse: + self.is_orelse = True + + @cached_property + def blockstart_tolineno(self): + """The line on which the beginning of this block ends. + + :type: int + """ + return self.test.tolineno + + def block_range(self, lineno): + """Get a range from the given line number to where this node ends. + + :param lineno: The line number to start the range at. + :type lineno: int + + :returns: The range of line numbers that this node belongs to, + starting at the given line number. + :rtype: tuple(int, int) + """ + if lineno == self.body[0].fromlineno: + return lineno, lineno + if lineno <= self.body[-1].tolineno: + return lineno, self.body[-1].tolineno + return self._elsed_block_range(lineno, self.orelse, self.body[0].fromlineno - 1) + + def get_children(self): + yield self.test + + yield from self.body + yield from self.orelse + + def has_elif_block(self): + return len(self.orelse) == 1 and isinstance(self.orelse[0], If) + + def _get_yield_nodes_skip_lambdas(self): + """An If node can contain a Yield node in the test""" + yield from self.test._get_yield_nodes_skip_lambdas() + yield from super()._get_yield_nodes_skip_lambdas() + + def is_sys_guard(self) -> bool: + """Return True if IF stmt is a sys.version_info guard. + + >>> import astroid + >>> node = astroid.extract_node(''' + import sys + if sys.version_info > (3, 8): + from typing import Literal + else: + from typing_extensions import Literal + ''') + >>> node.is_sys_guard() + True + """ + warnings.warn( + "The 'is_sys_guard' function is deprecated and will be removed in astroid 3.0.0 " + "It has been moved to pylint and can be imported from 'pylint.checkers.utils' " + "starting with pylint 2.12", + DeprecationWarning, + ) + if isinstance(self.test, Compare): + value = self.test.left + if isinstance(value, Subscript): + value = value.value + if isinstance(value, Attribute) and value.as_string() == "sys.version_info": + return True + + return False + + def is_typing_guard(self) -> bool: + """Return True if IF stmt is a typing guard. + + >>> import astroid + >>> node = astroid.extract_node(''' + from typing import TYPE_CHECKING + if TYPE_CHECKING: + from xyz import a + ''') + >>> node.is_typing_guard() + True + """ + warnings.warn( + "The 'is_typing_guard' function is deprecated and will be removed in astroid 3.0.0 " + "It has been moved to pylint and can be imported from 'pylint.checkers.utils' " + "starting with pylint 2.12", + DeprecationWarning, + ) + return isinstance( + self.test, (Name, Attribute) + ) and self.test.as_string().endswith("TYPE_CHECKING") + + +class IfExp(NodeNG): + """Class representing an :class:`ast.IfExp` node. + >>> import astroid + >>> node = astroid.extract_node('value if condition else other') + >>> node + + """ + + _astroid_fields = ("test", "body", "orelse") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.test: Optional[NodeNG] = None + """The condition that the statement tests.""" + + self.body: Optional[NodeNG] = None + """The contents of the block.""" + + self.orelse: Optional[NodeNG] = None + """The contents of the ``else`` block.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + test: Optional[NodeNG] = None, + body: Optional[NodeNG] = None, + orelse: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param test: The condition that the statement tests. + + :param body: The contents of the block. + + :param orelse: The contents of the ``else`` block. + """ + self.test = test + self.body = body + self.orelse = orelse + + def get_children(self): + yield self.test + yield self.body + yield self.orelse + + def op_left_associative(self): + # `1 if True else 2 if False else 3` is parsed as + # `1 if True else (2 if False else 3)` + return False + + +class Import(mixins.NoChildrenMixin, mixins.ImportFromMixin, Statement): + """Class representing an :class:`ast.Import` node. + >>> import astroid + >>> node = astroid.extract_node('import astroid') + >>> node + + """ + + _other_fields = ("names",) + + @decorators.deprecate_default_argument_values(names="list[tuple[str, str | None]]") + def __init__( + self, + names: Optional[typing.List[typing.Tuple[str, Optional[str]]]] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param names: The names being imported. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.names: typing.List[typing.Tuple[str, Optional[str]]] = names or [] + """The names being imported. + + Each entry is a :class:`tuple` of the name being imported, + and the alias that the name is assigned to (if any). + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + +class Index(NodeNG): + """Class representing an :class:`ast.Index` node. + + An :class:`Index` is a simple subscript. + + Deprecated since v2.6.0 - Now part of the :class:`Subscript` node. + Will be removed with the release of v2.7.0 + """ + + +class Keyword(NodeNG): + """Class representing an :class:`ast.keyword` node. + + >>> import astroid + >>> node = astroid.extract_node('function(a_kwarg=True)') + >>> node + + >>> node.keywords + [] + """ + + _astroid_fields = ("value",) + _other_fields = ("arg",) + + def __init__( + self, + arg: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param arg: The argument being assigned to. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.arg: Optional[str] = arg # can be None + """The argument being assigned to.""" + + self.value: Optional[NodeNG] = None + """The value being assigned to the keyword argument.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, value: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param value: The value being assigned to the keyword argument. + """ + self.value = value + + def get_children(self): + yield self.value + + +class List(BaseContainer): + """Class representing an :class:`ast.List` node. + + >>> import astroid + >>> node = astroid.extract_node('[1, 2, 3]') + >>> node + + """ + + _other_fields = ("ctx",) + + def __init__( + self, + ctx: Optional[Context] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param ctx: Whether the list is assigned to or loaded from. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.ctx: Optional[Context] = ctx + """Whether the list is assigned to or loaded from.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + assigned_stmts: ClassVar[AssignedStmtsCall["List"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + return "builtins.list" + + def getitem(self, index, context=None): + """Get an item from this node. + + :param index: The node to use as a subscript index. + :type index: Const or Slice + """ + return _container_getitem(self, self.elts, index, context=context) + + +class Nonlocal(mixins.NoChildrenMixin, Statement): + """Class representing an :class:`ast.Nonlocal` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + def function(): + nonlocal var + ''') + >>> node + + >>> node.body[0] + + """ + + _other_fields = ("names",) + + def __init__( + self, + names: typing.List[str], + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param names: The names being declared as not local. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.names: typing.List[str] = names + """The names being declared as not local.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def _infer_name(self, frame, name): + return name + + +class Pass(mixins.NoChildrenMixin, Statement): + """Class representing an :class:`ast.Pass` node. + + >>> import astroid + >>> node = astroid.extract_node('pass') + >>> node + + """ + + +class Raise(Statement): + """Class representing an :class:`ast.Raise` node. + + >>> import astroid + >>> node = astroid.extract_node('raise RuntimeError("Something bad happened!")') + >>> node + + """ + + _astroid_fields = ("exc", "cause") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.exc: Optional[NodeNG] = None # can be None + """What is being raised.""" + + self.cause: Optional[NodeNG] = None # can be None + """The exception being used to raise this one.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + exc: Optional[NodeNG] = None, + cause: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param exc: What is being raised. + + :param cause: The exception being used to raise this one. + """ + self.exc = exc + self.cause = cause + + def raises_not_implemented(self): + """Check if this node raises a :class:`NotImplementedError`. + + :returns: True if this node raises a :class:`NotImplementedError`, + False otherwise. + :rtype: bool + """ + if not self.exc: + return False + return any( + name.name == "NotImplementedError" for name in self.exc._get_name_nodes() + ) + + def get_children(self): + if self.exc is not None: + yield self.exc + + if self.cause is not None: + yield self.cause + + +class Return(Statement): + """Class representing an :class:`ast.Return` node. + + >>> import astroid + >>> node = astroid.extract_node('return True') + >>> node + + """ + + _astroid_fields = ("value",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: Optional[NodeNG] = None # can be None + """The value being returned.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, value: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param value: The value being returned. + """ + self.value = value + + def get_children(self): + if self.value is not None: + yield self.value + + def is_tuple_return(self): + return isinstance(self.value, Tuple) + + def _get_return_nodes_skip_functions(self): + yield self + + +class Set(BaseContainer): + """Class representing an :class:`ast.Set` node. + + >>> import astroid + >>> node = astroid.extract_node('{1, 2, 3}') + >>> node + + """ + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + return "builtins.set" + + +class Slice(NodeNG): + """Class representing an :class:`ast.Slice` node. + + >>> import astroid + >>> node = astroid.extract_node('things[1:3]') + >>> node + + >>> node.slice + + """ + + _astroid_fields = ("lower", "upper", "step") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.lower: Optional[NodeNG] = None # can be None + """The lower index in the slice.""" + + self.upper: Optional[NodeNG] = None # can be None + """The upper index in the slice.""" + + self.step: Optional[NodeNG] = None # can be None + """The step to take between indexes.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + lower: Optional[NodeNG] = None, + upper: Optional[NodeNG] = None, + step: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param lower: The lower index in the slice. + + :param upper: The upper index in the slice. + + :param step: The step to take between index. + """ + self.lower = lower + self.upper = upper + self.step = step + + def _wrap_attribute(self, attr): + """Wrap the empty attributes of the Slice in a Const node.""" + if not attr: + const = const_factory(attr) + const.parent = self + return const + return attr + + @cached_property + def _proxied(self): + builtins = AstroidManager().builtins_module + return builtins.getattr("slice")[0] + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + return "builtins.slice" + + def igetattr(self, attrname, context=None): + """Infer the possible values of the given attribute on the slice. + + :param attrname: The name of the attribute to infer. + :type attrname: str + + :returns: The inferred possible values. + :rtype: iterable(NodeNG) + """ + if attrname == "start": + yield self._wrap_attribute(self.lower) + elif attrname == "stop": + yield self._wrap_attribute(self.upper) + elif attrname == "step": + yield self._wrap_attribute(self.step) + else: + yield from self.getattr(attrname, context=context) + + def getattr(self, attrname, context=None): + return self._proxied.getattr(attrname, context) + + def get_children(self): + if self.lower is not None: + yield self.lower + + if self.upper is not None: + yield self.upper + + if self.step is not None: + yield self.step + + +class Starred(mixins.ParentAssignTypeMixin, NodeNG): + """Class representing an :class:`ast.Starred` node. + + >>> import astroid + >>> node = astroid.extract_node('*args') + >>> node + + """ + + _astroid_fields = ("value",) + _other_fields = ("ctx",) + + def __init__( + self, + ctx: Optional[Context] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param ctx: Whether the list is assigned to or loaded from. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: Optional[NodeNG] = None + """What is being unpacked.""" + + self.ctx: Optional[Context] = ctx + """Whether the starred item is assigned to or loaded from.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, value: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param value: What is being unpacked. + """ + self.value = value + + assigned_stmts: ClassVar[AssignedStmtsCall["Starred"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def get_children(self): + yield self.value + + +class Subscript(NodeNG): + """Class representing an :class:`ast.Subscript` node. + + >>> import astroid + >>> node = astroid.extract_node('things[1:3]') + >>> node + + """ + + _astroid_fields = ("value", "slice") + _other_fields = ("ctx",) + + def __init__( + self, + ctx: Optional[Context] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param ctx: Whether the subscripted item is assigned to or loaded from. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: Optional[NodeNG] = None + """What is being indexed.""" + + self.slice: Optional[NodeNG] = None + """The slice being used to lookup.""" + + self.ctx: Optional[Context] = ctx + """Whether the subscripted item is assigned to or loaded from.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. + def postinit( + self, value: Optional[NodeNG] = None, slice: Optional[NodeNG] = None + ) -> None: + """Do some setup after initialisation. + + :param value: What is being indexed. + + :param slice: The slice being used to lookup. + """ + self.value = value + self.slice = slice + + def get_children(self): + yield self.value + yield self.slice + + +class TryExcept(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): + """Class representing an :class:`ast.TryExcept` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + try: + do_something() + except Exception as error: + print("Error!") + ''') + >>> node + + """ + + _astroid_fields = ("body", "handlers", "orelse") + _multi_line_block_fields = ("body", "handlers", "orelse") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.body: typing.List[NodeNG] = [] + """The contents of the block to catch exceptions from.""" + + self.handlers: typing.List[ExceptHandler] = [] + """The exception handlers.""" + + self.orelse: typing.List[NodeNG] = [] + """The contents of the ``else`` block.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + body: Optional[typing.List[NodeNG]] = None, + handlers: Optional[typing.List[ExceptHandler]] = None, + orelse: Optional[typing.List[NodeNG]] = None, + ) -> None: + """Do some setup after initialisation. + + :param body: The contents of the block to catch exceptions from. + + :param handlers: The exception handlers. + + :param orelse: The contents of the ``else`` block. + """ + if body is not None: + self.body = body + if handlers is not None: + self.handlers = handlers + if orelse is not None: + self.orelse = orelse + + def _infer_name(self, frame, name): + return name + + def block_range(self, lineno): + """Get a range from the given line number to where this node ends. + + :param lineno: The line number to start the range at. + :type lineno: int + + :returns: The range of line numbers that this node belongs to, + starting at the given line number. + :rtype: tuple(int, int) + """ + last = None + for exhandler in self.handlers: + if exhandler.type and lineno == exhandler.type.fromlineno: + return lineno, lineno + if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: + return lineno, exhandler.body[-1].tolineno + if last is None: + last = exhandler.body[0].fromlineno - 1 + return self._elsed_block_range(lineno, self.orelse, last) + + def get_children(self): + yield from self.body + + yield from self.handlers or () + yield from self.orelse or () + + +class TryFinally(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): + """Class representing an :class:`ast.TryFinally` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + try: + do_something() + except Exception as error: + print("Error!") + finally: + print("Cleanup!") + ''') + >>> node + + """ + + _astroid_fields = ("body", "finalbody") + _multi_line_block_fields = ("body", "finalbody") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.body: typing.List[Union[NodeNG, TryExcept]] = [] + """The try-except that the finally is attached to.""" + + self.finalbody: typing.List[NodeNG] = [] + """The contents of the ``finally`` block.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + body: Optional[typing.List[Union[NodeNG, TryExcept]]] = None, + finalbody: Optional[typing.List[NodeNG]] = None, + ) -> None: + """Do some setup after initialisation. + + :param body: The try-except that the finally is attached to. + + :param finalbody: The contents of the ``finally`` block. + """ + if body is not None: + self.body = body + if finalbody is not None: + self.finalbody = finalbody + + def block_range(self, lineno): + """Get a range from the given line number to where this node ends. + + :param lineno: The line number to start the range at. + :type lineno: int + + :returns: The range of line numbers that this node belongs to, + starting at the given line number. + :rtype: tuple(int, int) + """ + child = self.body[0] + # py2.5 try: except: finally: + if ( + isinstance(child, TryExcept) + and child.fromlineno == self.fromlineno + and child.tolineno >= lineno > self.fromlineno + ): + return child.block_range(lineno) + return self._elsed_block_range(lineno, self.finalbody) + + def get_children(self): + yield from self.body + yield from self.finalbody + + +class Tuple(BaseContainer): + """Class representing an :class:`ast.Tuple` node. + + >>> import astroid + >>> node = astroid.extract_node('(1, 2, 3)') + >>> node + + """ + + _other_fields = ("ctx",) + + def __init__( + self, + ctx: Optional[Context] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param ctx: Whether the tuple is assigned to or loaded from. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.ctx: Optional[Context] = ctx + """Whether the tuple is assigned to or loaded from.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + assigned_stmts: ClassVar[AssignedStmtsCall["Tuple"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + return "builtins.tuple" + + def getitem(self, index, context=None): + """Get an item from this node. + + :param index: The node to use as a subscript index. + :type index: Const or Slice + """ + return _container_getitem(self, self.elts, index, context=context) + + +class UnaryOp(NodeNG): + """Class representing an :class:`ast.UnaryOp` node. + + >>> import astroid + >>> node = astroid.extract_node('-5') + >>> node + + """ + + _astroid_fields = ("operand",) + _other_fields = ("op",) + + @decorators.deprecate_default_argument_values(op="str") + def __init__( + self, + op: Optional[str] = None, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param op: The operator. + + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.op: Optional[str] = op + """The operator.""" + + self.operand: Optional[NodeNG] = None + """What the unary operator is applied to.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, operand: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param operand: What the unary operator is applied to. + """ + self.operand = operand + + # This is set by inference.py + def _infer_unaryop(self, context=None): + raise NotImplementedError + + def type_errors(self, context=None): + """Get a list of type errors which can occur during inference. + + Each TypeError is represented by a :class:`BadBinaryOperationMessage`, + which holds the original exception. + + :returns: The list of possible type errors. + :rtype: list(BadBinaryOperationMessage) + """ + try: + results = self._infer_unaryop(context=context) + return [ + result + for result in results + if isinstance(result, util.BadUnaryOperationMessage) + ] + except InferenceError: + return [] + + def get_children(self): + yield self.operand + + def op_precedence(self): + if self.op == "not": + return OP_PRECEDENCE[self.op] + + return super().op_precedence() + + +class While(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): + """Class representing an :class:`ast.While` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + while condition(): + print("True") + ''') + >>> node + + """ + + _astroid_fields = ("test", "body", "orelse") + _multi_line_block_fields = ("body", "orelse") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.test: Optional[NodeNG] = None + """The condition that the loop tests.""" + + self.body: typing.List[NodeNG] = [] + """The contents of the loop.""" + + self.orelse: typing.List[NodeNG] = [] + """The contents of the ``else`` block.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + test: Optional[NodeNG] = None, + body: Optional[typing.List[NodeNG]] = None, + orelse: Optional[typing.List[NodeNG]] = None, + ) -> None: + """Do some setup after initialisation. + + :param test: The condition that the loop tests. + + :param body: The contents of the loop. + + :param orelse: The contents of the ``else`` block. + """ + self.test = test + if body is not None: + self.body = body + if orelse is not None: + self.orelse = orelse + + @cached_property + def blockstart_tolineno(self): + """The line on which the beginning of this block ends. + + :type: int + """ + return self.test.tolineno + + def block_range(self, lineno): + """Get a range from the given line number to where this node ends. + + :param lineno: The line number to start the range at. + :type lineno: int + + :returns: The range of line numbers that this node belongs to, + starting at the given line number. + :rtype: tuple(int, int) + """ + return self._elsed_block_range(lineno, self.orelse) + + def get_children(self): + yield self.test + + yield from self.body + yield from self.orelse + + def _get_yield_nodes_skip_lambdas(self): + """A While node can contain a Yield node in the test""" + yield from self.test._get_yield_nodes_skip_lambdas() + yield from super()._get_yield_nodes_skip_lambdas() + + +class With( + mixins.MultiLineBlockMixin, + mixins.BlockRangeMixIn, + mixins.AssignTypeMixin, + Statement, +): + """Class representing an :class:`ast.With` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + with open(file_path) as file_: + print(file_.read()) + ''') + >>> node + + """ + + _astroid_fields = ("items", "body") + _other_other_fields = ("type_annotation",) + _multi_line_block_fields = ("body",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.items: typing.List[typing.Tuple[NodeNG, Optional[NodeNG]]] = [] + """The pairs of context managers and the names they are assigned to.""" + + self.body: typing.List[NodeNG] = [] + """The contents of the ``with`` block.""" + + self.type_annotation: Optional[NodeNG] = None # can be None + """If present, this will contain the type annotation passed by a type comment""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + items: Optional[typing.List[typing.Tuple[NodeNG, Optional[NodeNG]]]] = None, + body: Optional[typing.List[NodeNG]] = None, + type_annotation: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param items: The pairs of context managers and the names + they are assigned to. + + :param body: The contents of the ``with`` block. + """ + if items is not None: + self.items = items + if body is not None: + self.body = body + self.type_annotation = type_annotation + + assigned_stmts: ClassVar[AssignedStmtsCall["With"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + @cached_property + def blockstart_tolineno(self): + """The line on which the beginning of this block ends. + + :type: int + """ + return self.items[-1][0].tolineno + + def get_children(self): + """Get the child nodes below this node. + + :returns: The children. + :rtype: iterable(NodeNG) + """ + for expr, var in self.items: + yield expr + if var: + yield var + yield from self.body + + +class AsyncWith(With): + """Asynchronous ``with`` built with the ``async`` keyword.""" + + +class Yield(NodeNG): + """Class representing an :class:`ast.Yield` node. + + >>> import astroid + >>> node = astroid.extract_node('yield True') + >>> node + + """ + + _astroid_fields = ("value",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: Optional[NodeNG] = None # can be None + """The value to yield.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, value: Optional[NodeNG] = None) -> None: + """Do some setup after initialisation. + + :param value: The value to yield. + """ + self.value = value + + def get_children(self): + if self.value is not None: + yield self.value + + def _get_yield_nodes_skip_lambdas(self): + yield self + + +class YieldFrom(Yield): # TODO value is required, not optional + """Class representing an :class:`ast.YieldFrom` node.""" + + +class DictUnpack(mixins.NoChildrenMixin, NodeNG): + """Represents the unpacking of dicts into dicts using :pep:`448`.""" + + +class FormattedValue(NodeNG): + """Class representing an :class:`ast.FormattedValue` node. + + Represents a :pep:`498` format string. + + >>> import astroid + >>> node = astroid.extract_node('f"Format {type_}"') + >>> node + + >>> node.values + [, ] + """ + + _astroid_fields = ("value", "format_spec") + _other_fields = ("conversion",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.value: NodeNG + """The value to be formatted into the string.""" + + self.conversion: Optional[int] = None # can be None + """The type of formatting to be applied to the value. + + .. seealso:: + :class:`ast.FormattedValue` + """ + + self.format_spec: Optional[NodeNG] = None # can be None + """The formatting to be applied to the value. + + .. seealso:: + :class:`ast.FormattedValue` + + :type: JoinedStr or None + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + value: NodeNG, + conversion: Optional[int] = None, + format_spec: Optional[NodeNG] = None, + ) -> None: + """Do some setup after initialisation. + + :param value: The value to be formatted into the string. + + :param conversion: The type of formatting to be applied to the value. + + :param format_spec: The formatting to be applied to the value. + :type format_spec: JoinedStr or None + """ + self.value = value + self.conversion = conversion + self.format_spec = format_spec + + def get_children(self): + yield self.value + + if self.format_spec is not None: + yield self.format_spec + + +class JoinedStr(NodeNG): + """Represents a list of string expressions to be joined. + + >>> import astroid + >>> node = astroid.extract_node('f"Format {type_}"') + >>> node + + """ + + _astroid_fields = ("values",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.values: typing.List[NodeNG] = [] + """The string expressions to be joined. + + :type: list(FormattedValue or Const) + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, values: Optional[typing.List[NodeNG]] = None) -> None: + """Do some setup after initialisation. + + :param value: The string expressions to be joined. + + :type: list(FormattedValue or Const) + """ + if values is not None: + self.values = values + + def get_children(self): + yield from self.values + + +class NamedExpr(mixins.AssignTypeMixin, NodeNG): + """Represents the assignment from the assignment expression + + >>> import astroid + >>> module = astroid.parse('if a := 1: pass') + >>> module.body[0].test + + """ + + _astroid_fields = ("target", "value") + + optional_assign = True + """Whether this node optionally assigns a variable. + + Since NamedExpr are not always called they do not always assign.""" + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.target: NodeNG + """The assignment target + + :type: Name + """ + + self.value: NodeNG + """The value that gets assigned in the expression""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, target: NodeNG, value: NodeNG) -> None: + self.target = target + self.value = value + + assigned_stmts: ClassVar[AssignedStmtsCall["NamedExpr"]] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + def frame( + self, *, future: Literal[None, True] = None + ) -> Union["nodes.FunctionDef", "nodes.Module", "nodes.ClassDef", "nodes.Lambda"]: + """The first parent frame node. + + A frame node is a :class:`Module`, :class:`FunctionDef`, + or :class:`ClassDef`. + + :returns: The first parent frame node. + """ + if not self.parent: + raise ParentMissingError(target=self) + + # For certain parents NamedExpr evaluate to the scope of the parent + if isinstance(self.parent, (Arguments, Keyword, Comprehension)): + if not self.parent.parent: + raise ParentMissingError(target=self.parent) + if not self.parent.parent.parent: + raise ParentMissingError(target=self.parent.parent) + return self.parent.parent.parent.frame(future=True) + + return self.parent.frame(future=True) + + def scope(self) -> "LocalsDictNodeNG": + """The first parent node defining a new scope. + These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. + + :returns: The first parent scope node. + """ + if not self.parent: + raise ParentMissingError(target=self) + + # For certain parents NamedExpr evaluate to the scope of the parent + if isinstance(self.parent, (Arguments, Keyword, Comprehension)): + if not self.parent.parent: + raise ParentMissingError(target=self.parent) + if not self.parent.parent.parent: + raise ParentMissingError(target=self.parent.parent) + return self.parent.parent.parent.scope() + + return self.parent.scope() + + def set_local(self, name: str, stmt: AssignName) -> None: + """Define that the given name is declared in the given statement node. + NamedExpr's in Arguments, Keyword or Comprehension are evaluated in their + parent's parent scope. So we add to their frame's locals. + + .. seealso:: :meth:`scope` + + :param name: The name that is being defined. + + :param stmt: The statement that defines the given name. + """ + self.frame(future=True).set_local(name, stmt) + + +class Unknown(mixins.AssignTypeMixin, NodeNG): + """This node represents a node in a constructed AST where + introspection is not possible. At the moment, it's only used in + the args attribute of FunctionDef nodes where function signature + introspection failed. + """ + + name = "Unknown" + + def qname(self): + return "Unknown" + + def _infer(self, context=None, **kwargs): + """Inference on an Unknown node immediately terminates.""" + yield util.Uninferable + + +class EvaluatedObject(NodeNG): + """Contains an object that has already been inferred + + This class is useful to pre-evaluate a particular node, + with the resulting class acting as the non-evaluated node. + """ + + name = "EvaluatedObject" + _astroid_fields = ("original",) + _other_fields = ("value",) + + def __init__( + self, original: NodeNG, value: Union[NodeNG, Type[util.Uninferable]] + ) -> None: + self.original: NodeNG = original + """The original node that has already been evaluated""" + + self.value: Union[NodeNG, Type[util.Uninferable]] = value + """The inferred value""" + + super().__init__( + lineno=self.original.lineno, + col_offset=self.original.col_offset, + parent=self.original.parent, + ) + + def infer(self, context=None, **kwargs): + yield self.value + + +# Pattern matching ####################################################### + + +class Match(Statement): + """Class representing a :class:`ast.Match` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case 200: + ... + case _: + ... + ''') + >>> node + + """ + + _astroid_fields = ("subject", "cases") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.subject: NodeNG + self.cases: typing.List["MatchCase"] + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + *, + subject: NodeNG, + cases: typing.List["MatchCase"], + ) -> None: + self.subject = subject + self.cases = cases + + +class Pattern(NodeNG): + """Base class for all Pattern nodes.""" + + +class MatchCase(mixins.MultiLineBlockMixin, NodeNG): + """Class representing a :class:`ast.match_case` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case 200: + ... + ''') + >>> node.cases[0] + + """ + + _astroid_fields = ("pattern", "guard", "body") + _multi_line_block_fields = ("body",) + + lineno: None + col_offset: None + end_lineno: None + end_col_offset: None + + def __init__(self, *, parent: Optional[NodeNG] = None) -> None: + self.pattern: Pattern + self.guard: Optional[NodeNG] + self.body: typing.List[NodeNG] + super().__init__(parent=parent) + + def postinit( + self, + *, + pattern: Pattern, + guard: Optional[NodeNG], + body: typing.List[NodeNG], + ) -> None: + self.pattern = pattern + self.guard = guard + self.body = body + + +class MatchValue(Pattern): + """Class representing a :class:`ast.MatchValue` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case 200: + ... + ''') + >>> node.cases[0].pattern + + """ + + _astroid_fields = ("value",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.value: NodeNG + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, *, value: NodeNG) -> None: + self.value = value + + +class MatchSingleton(Pattern): + """Class representing a :class:`ast.MatchSingleton` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case True: + ... + case False: + ... + case None: + ... + ''') + >>> node.cases[0].pattern + + >>> node.cases[1].pattern + + >>> node.cases[2].pattern + + """ + + _other_fields = ("value",) + + def __init__( + self, + *, + value: Literal[True, False, None], + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + ) -> None: + self.value = value + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + +class MatchSequence(Pattern): + """Class representing a :class:`ast.MatchSequence` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case [1, 2]: + ... + case (1, 2, *_): + ... + ''') + >>> node.cases[0].pattern + + >>> node.cases[1].pattern + + """ + + _astroid_fields = ("patterns",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.patterns: typing.List[Pattern] + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, *, patterns: typing.List[Pattern]) -> None: + self.patterns = patterns + + +class MatchMapping(mixins.AssignTypeMixin, Pattern): + """Class representing a :class:`ast.MatchMapping` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case {1: "Hello", 2: "World", 3: _, **rest}: + ... + ''') + >>> node.cases[0].pattern + + """ + + _astroid_fields = ("keys", "patterns", "rest") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.keys: typing.List[NodeNG] + self.patterns: typing.List[Pattern] + self.rest: Optional[AssignName] + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + *, + keys: typing.List[NodeNG], + patterns: typing.List[Pattern], + rest: Optional[AssignName], + ) -> None: + self.keys = keys + self.patterns = patterns + self.rest = rest + + assigned_stmts: ClassVar[ + Callable[ + [ + "MatchMapping", + AssignName, + Optional[InferenceContext], + None, + ], + Generator[NodeNG, None, None], + ] + ] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + +class MatchClass(Pattern): + """Class representing a :class:`ast.MatchClass` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case Point2D(0, 0): + ... + case Point3D(x=0, y=0, z=0): + ... + ''') + >>> node.cases[0].pattern + + >>> node.cases[1].pattern + + """ + + _astroid_fields = ("cls", "patterns", "kwd_patterns") + _other_fields = ("kwd_attrs",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.cls: NodeNG + self.patterns: typing.List[Pattern] + self.kwd_attrs: typing.List[str] + self.kwd_patterns: typing.List[Pattern] + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + *, + cls: NodeNG, + patterns: typing.List[Pattern], + kwd_attrs: typing.List[str], + kwd_patterns: typing.List[Pattern], + ) -> None: + self.cls = cls + self.patterns = patterns + self.kwd_attrs = kwd_attrs + self.kwd_patterns = kwd_patterns + + +class MatchStar(mixins.AssignTypeMixin, Pattern): + """Class representing a :class:`ast.MatchStar` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case [1, *_]: + ... + ''') + >>> node.cases[0].pattern.patterns[1] + + """ + + _astroid_fields = ("name",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.name: Optional[AssignName] + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, *, name: Optional[AssignName]) -> None: + self.name = name + + assigned_stmts: ClassVar[ + Callable[ + [ + "MatchStar", + AssignName, + Optional[InferenceContext], + None, + ], + Generator[NodeNG, None, None], + ] + ] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + +class MatchAs(mixins.AssignTypeMixin, Pattern): + """Class representing a :class:`ast.MatchAs` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case [1, a]: + ... + case {'key': b}: + ... + case Point2D(0, 0) as c: + ... + case d: + ... + ''') + >>> node.cases[0].pattern.patterns[1] + + >>> node.cases[1].pattern.patterns[0] + + >>> node.cases[2].pattern + + >>> node.cases[3].pattern + + """ + + _astroid_fields = ("pattern", "name") + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.pattern: Optional[Pattern] + self.name: Optional[AssignName] + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit( + self, + *, + pattern: Optional[Pattern], + name: Optional[AssignName], + ) -> None: + self.pattern = pattern + self.name = name + + assigned_stmts: ClassVar[ + Callable[ + [ + "MatchAs", + AssignName, + Optional[InferenceContext], + None, + ], + Generator[NodeNG, None, None], + ] + ] + """Returns the assigned statement (non inferred) according to the assignment type. + See astroid/protocols.py for actual implementation. + """ + + +class MatchOr(Pattern): + """Class representing a :class:`ast.MatchOr` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + match x: + case 400 | 401 | 402: + ... + ''') + >>> node.cases[0].pattern + + """ + + _astroid_fields = ("patterns",) + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional[NodeNG] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + self.patterns: typing.List[Pattern] + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, *, patterns: typing.List[Pattern]) -> None: + self.patterns = patterns + + +# constants ############################################################## + +CONST_CLS = { + list: List, + tuple: Tuple, + dict: Dict, + set: Set, + type(None): Const, + type(NotImplemented): Const, + type(...): Const, +} + + +def _update_const_classes(): + """update constant classes, so the keys of CONST_CLS can be reused""" + klasses = (bool, int, float, complex, str, bytes) + for kls in klasses: + CONST_CLS[kls] = Const + + +_update_const_classes() + + +def _two_step_initialization(cls, value): + instance = cls() + instance.postinit(value) + return instance + + +def _dict_initialization(cls, value): + if isinstance(value, dict): + value = tuple(value.items()) + return _two_step_initialization(cls, value) + + +_CONST_CLS_CONSTRUCTORS = { + List: _two_step_initialization, + Tuple: _two_step_initialization, + Dict: _dict_initialization, + Set: _two_step_initialization, + Const: lambda cls, value: cls(value), +} + + +def const_factory(value): + """return an astroid node for a python value""" + # XXX we should probably be stricter here and only consider stuff in + # CONST_CLS or do better treatment: in case where value is not in CONST_CLS, + # we should rather recall the builder on this value than returning an empty + # node (another option being that const_factory shouldn't be called with something + # not in CONST_CLS) + assert not isinstance(value, NodeNG) + + # Hack for ignoring elements of a sequence + # or a mapping, in order to avoid transforming + # each element to an AST. This is fixed in 2.0 + # and this approach is a temporary hack. + if isinstance(value, (list, set, tuple, dict)): + elts = [] + else: + elts = value + + try: + initializer_cls = CONST_CLS[value.__class__] + initializer = _CONST_CLS_CONSTRUCTORS[initializer_cls] + return initializer(initializer_cls, elts) + except (KeyError, AttributeError): + node = EmptyNode() + node.object = value + return node diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/node_ng.py b/myenv/lib/python3.9/site-packages/astroid/nodes/node_ng.py new file mode 100644 index 0000000..db249af --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/node_ng.py @@ -0,0 +1,814 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import pprint +import sys +import typing +import warnings +from functools import singledispatch as _singledispatch +from typing import ( + TYPE_CHECKING, + ClassVar, + Iterator, + List, + Optional, + Tuple, + Type, + TypeVar, + Union, + cast, + overload, +) + +from astroid import decorators, util +from astroid.exceptions import ( + AstroidError, + InferenceError, + ParentMissingError, + StatementMissing, + UseInferenceDefault, +) +from astroid.manager import AstroidManager +from astroid.nodes.as_string import AsStringVisitor +from astroid.nodes.const import OP_PRECEDENCE +from astroid.nodes.utils import Position +from astroid.typing import InferFn + +if TYPE_CHECKING: + from astroid import nodes + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if sys.version_info >= (3, 8) or TYPE_CHECKING: + # pylint: disable-next=ungrouped-imports + from functools import cached_property +else: + # pylint: disable-next=ungrouped-imports + from astroid.decorators import cachedproperty as cached_property + +# Types for 'NodeNG.nodes_of_class()' +T_Nodes = TypeVar("T_Nodes", bound="NodeNG") +T_Nodes2 = TypeVar("T_Nodes2", bound="NodeNG") +T_Nodes3 = TypeVar("T_Nodes3", bound="NodeNG") +SkipKlassT = Union[None, Type["NodeNG"], Tuple[Type["NodeNG"], ...]] + + +class NodeNG: + """A node of the new Abstract Syntax Tree (AST). + + This is the base class for all Astroid node classes. + """ + + is_statement: ClassVar[bool] = False + """Whether this node indicates a statement.""" + optional_assign: ClassVar[ + bool + ] = False # True for For (and for Comprehension if py <3.0) + """Whether this node optionally assigns a variable. + + This is for loop assignments because loop won't necessarily perform an + assignment if the loop has no iterations. + This is also the case from comprehensions in Python 2. + """ + is_function: ClassVar[bool] = False # True for FunctionDef nodes + """Whether this node indicates a function.""" + is_lambda: ClassVar[bool] = False + + # Attributes below are set by the builder module or by raw factories + _astroid_fields: ClassVar[typing.Tuple[str, ...]] = () + """Node attributes that contain child nodes. + + This is redefined in most concrete classes. + """ + _other_fields: ClassVar[typing.Tuple[str, ...]] = () + """Node attributes that do not contain child nodes.""" + _other_other_fields: ClassVar[typing.Tuple[str, ...]] = () + """Attributes that contain AST-dependent fields.""" + # instance specific inference function infer(node, context) + _explicit_inference: Optional[InferFn] = None + + def __init__( + self, + lineno: Optional[int] = None, + col_offset: Optional[int] = None, + parent: Optional["NodeNG"] = None, + *, + end_lineno: Optional[int] = None, + end_col_offset: Optional[int] = None, + ) -> None: + """ + :param lineno: The line that this node appears on in the source code. + + :param col_offset: The column that this node appears on in the + source code. + + :param parent: The parent node in the syntax tree. + + :param end_lineno: The last line this node appears on in the source code. + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + """ + self.lineno: Optional[int] = lineno + """The line that this node appears on in the source code.""" + + self.col_offset: Optional[int] = col_offset + """The column that this node appears on in the source code.""" + + self.parent: Optional["NodeNG"] = parent + """The parent node in the syntax tree.""" + + self.end_lineno: Optional[int] = end_lineno + """The last line this node appears on in the source code.""" + + self.end_col_offset: Optional[int] = end_col_offset + """The end column this node appears on in the source code. + Note: This is after the last symbol. + """ + + self.position: Optional[Position] = None + """Position of keyword(s) and name. Used as fallback for block nodes + which might not provide good enough positional information. + E.g. ClassDef, FunctionDef. + """ + + def infer(self, context=None, **kwargs): + """Get a generator of the inferred values. + + This is the main entry point to the inference system. + + .. seealso:: :ref:`inference` + + If the instance has some explicit inference function set, it will be + called instead of the default interface. + + :returns: The inferred values. + :rtype: iterable + """ + if context is not None: + context = context.extra_context.get(self, context) + if self._explicit_inference is not None: + # explicit_inference is not bound, give it self explicitly + try: + # pylint: disable=not-callable + results = list(self._explicit_inference(self, context, **kwargs)) + if context is not None: + context.nodes_inferred += len(results) + yield from results + return + except UseInferenceDefault: + pass + + if not context: + # nodes_inferred? + yield from self._infer(context=context, **kwargs) + return + + key = (self, context.lookupname, context.callcontext, context.boundnode) + if key in context.inferred: + yield from context.inferred[key] + return + + generator = self._infer(context=context, **kwargs) + results = [] + + # Limit inference amount to help with performance issues with + # exponentially exploding possible results. + limit = AstroidManager().max_inferable_values + for i, result in enumerate(generator): + if i >= limit or (context.nodes_inferred > context.max_inferred): + uninferable = util.Uninferable + results.append(uninferable) + yield uninferable + break + results.append(result) + yield result + context.nodes_inferred += 1 + + # Cache generated results for subsequent inferences of the + # same node using the same context + context.inferred[key] = tuple(results) + return + + def _repr_name(self) -> str: + """Get a name for nice representation. + + This is either :attr:`name`, :attr:`attrname`, or the empty string. + + :returns: The nice name. + :rtype: str + """ + if all(name not in self._astroid_fields for name in ("name", "attrname")): + return getattr(self, "name", "") or getattr(self, "attrname", "") + return "" + + def __str__(self) -> str: + rname = self._repr_name() + cname = type(self).__name__ + if rname: + string = "%(cname)s.%(rname)s(%(fields)s)" + alignment = len(cname) + len(rname) + 2 + else: + string = "%(cname)s(%(fields)s)" + alignment = len(cname) + 1 + result = [] + for field in self._other_fields + self._astroid_fields: + value = getattr(self, field) + width = 80 - len(field) - alignment + lines = pprint.pformat(value, indent=2, width=width).splitlines(True) + + inner = [lines[0]] + for line in lines[1:]: + inner.append(" " * alignment + line) + result.append(f"{field}={''.join(inner)}") + + return string % { + "cname": cname, + "rname": rname, + "fields": (",\n" + " " * alignment).join(result), + } + + def __repr__(self) -> str: + rname = self._repr_name() + if rname: + string = "<%(cname)s.%(rname)s l.%(lineno)s at 0x%(id)x>" + else: + string = "<%(cname)s l.%(lineno)s at 0x%(id)x>" + return string % { + "cname": type(self).__name__, + "rname": rname, + "lineno": self.fromlineno, + "id": id(self), + } + + def accept(self, visitor): + """Visit this node using the given visitor.""" + func = getattr(visitor, "visit_" + self.__class__.__name__.lower()) + return func(self) + + def get_children(self) -> Iterator["NodeNG"]: + """Get the child nodes below this node.""" + for field in self._astroid_fields: + attr = getattr(self, field) + if attr is None: + continue + if isinstance(attr, (list, tuple)): + yield from attr + else: + yield attr + yield from () + + def last_child(self) -> Optional["NodeNG"]: + """An optimized version of list(get_children())[-1]""" + for field in self._astroid_fields[::-1]: + attr = getattr(self, field) + if not attr: # None or empty list / tuple + continue + if isinstance(attr, (list, tuple)): + return attr[-1] + return attr + return None + + def node_ancestors(self) -> Iterator["NodeNG"]: + """Yield parent, grandparent, etc until there are no more.""" + parent = self.parent + while parent is not None: + yield parent + parent = parent.parent + + def parent_of(self, node): + """Check if this node is the parent of the given node. + + :param node: The node to check if it is the child. + :type node: NodeNG + + :returns: True if this node is the parent of the given node, + False otherwise. + :rtype: bool + """ + return any(self is parent for parent in node.node_ancestors()) + + @overload + def statement( + self, *, future: None = ... + ) -> Union["nodes.Statement", "nodes.Module"]: + ... + + @overload + def statement(self, *, future: Literal[True]) -> "nodes.Statement": + ... + + def statement( + self, *, future: Literal[None, True] = None + ) -> Union["nodes.Statement", "nodes.Module"]: + """The first parent node, including self, marked as statement node. + + TODO: Deprecate the future parameter and only raise StatementMissing and return + nodes.Statement + + :raises AttributeError: If self has no parent attribute + :raises StatementMissing: If self has no parent attribute and future is True + """ + if self.is_statement: + return cast("nodes.Statement", self) + if not self.parent: + if future: + raise StatementMissing(target=self) + warnings.warn( + "In astroid 3.0.0 NodeNG.statement() will return either a nodes.Statement " + "or raise a StatementMissing exception. AttributeError will no longer be raised. " + "This behaviour can already be triggered " + "by passing 'future=True' to a statement() call.", + DeprecationWarning, + ) + raise AttributeError(f"{self} object has no attribute 'parent'") + return self.parent.statement(future=future) + + def frame( + self, *, future: Literal[None, True] = None + ) -> Union["nodes.FunctionDef", "nodes.Module", "nodes.ClassDef", "nodes.Lambda"]: + """The first parent frame node. + + A frame node is a :class:`Module`, :class:`FunctionDef`, + :class:`ClassDef` or :class:`Lambda`. + + :returns: The first parent frame node. + """ + if self.parent is None: + if future: + raise ParentMissingError(target=self) + warnings.warn( + "In astroid 3.0.0 NodeNG.frame() will return either a Frame node, " + "or raise ParentMissingError. AttributeError will no longer be raised. " + "This behaviour can already be triggered " + "by passing 'future=True' to a frame() call.", + DeprecationWarning, + ) + raise AttributeError(f"{self} object has no attribute 'parent'") + + return self.parent.frame(future=future) + + def scope(self) -> "nodes.LocalsDictNodeNG": + """The first parent node defining a new scope. + These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. + + :returns: The first parent scope node. + """ + if not self.parent: + raise ParentMissingError(target=self) + return self.parent.scope() + + def root(self): + """Return the root node of the syntax tree. + + :returns: The root node. + :rtype: Module + """ + if self.parent: + return self.parent.root() + return self + + def child_sequence(self, child): + """Search for the sequence that contains this child. + + :param child: The child node to search sequences for. + :type child: NodeNG + + :returns: The sequence containing the given child node. + :rtype: iterable(NodeNG) + + :raises AstroidError: If no sequence could be found that contains + the given child. + """ + for field in self._astroid_fields: + node_or_sequence = getattr(self, field) + if node_or_sequence is child: + return [node_or_sequence] + # /!\ compiler.ast Nodes have an __iter__ walking over child nodes + if ( + isinstance(node_or_sequence, (tuple, list)) + and child in node_or_sequence + ): + return node_or_sequence + + msg = "Could not find %s in %s's children" + raise AstroidError(msg % (repr(child), repr(self))) + + def locate_child(self, child): + """Find the field of this node that contains the given child. + + :param child: The child node to search fields for. + :type child: NodeNG + + :returns: A tuple of the name of the field that contains the child, + and the sequence or node that contains the child node. + :rtype: tuple(str, iterable(NodeNG) or NodeNG) + + :raises AstroidError: If no field could be found that contains + the given child. + """ + for field in self._astroid_fields: + node_or_sequence = getattr(self, field) + # /!\ compiler.ast Nodes have an __iter__ walking over child nodes + if child is node_or_sequence: + return field, child + if ( + isinstance(node_or_sequence, (tuple, list)) + and child in node_or_sequence + ): + return field, node_or_sequence + msg = "Could not find %s in %s's children" + raise AstroidError(msg % (repr(child), repr(self))) + + # FIXME : should we merge child_sequence and locate_child ? locate_child + # is only used in are_exclusive, child_sequence one time in pylint. + + def next_sibling(self): + """The next sibling statement node. + + :returns: The next sibling statement node. + :rtype: NodeNG or None + """ + return self.parent.next_sibling() + + def previous_sibling(self): + """The previous sibling statement. + + :returns: The previous sibling statement node. + :rtype: NodeNG or None + """ + return self.parent.previous_sibling() + + # these are lazy because they're relatively expensive to compute for every + # single node, and they rarely get looked at + + @cached_property + def fromlineno(self) -> Optional[int]: + """The first line that this node appears on in the source code.""" + if self.lineno is None: + return self._fixed_source_line() + return self.lineno + + @cached_property + def tolineno(self) -> Optional[int]: + """The last line that this node appears on in the source code.""" + if self.end_lineno is not None: + return self.end_lineno + if not self._astroid_fields: + # can't have children + last_child = None + else: + last_child = self.last_child() + if last_child is None: + return self.fromlineno + return last_child.tolineno + + def _fixed_source_line(self) -> Optional[int]: + """Attempt to find the line that this node appears on. + + We need this method since not all nodes have :attr:`lineno` set. + """ + line = self.lineno + _node: Optional[NodeNG] = self + try: + while line is None: + _node = next(_node.get_children()) + line = _node.lineno + except StopIteration: + _node = self.parent + while _node and line is None: + line = _node.lineno + _node = _node.parent + return line + + def block_range(self, lineno): + """Get a range from the given line number to where this node ends. + + :param lineno: The line number to start the range at. + :type lineno: int + + :returns: The range of line numbers that this node belongs to, + starting at the given line number. + :rtype: tuple(int, int or None) + """ + return lineno, self.tolineno + + def set_local(self, name, stmt): + """Define that the given name is declared in the given statement node. + + This definition is stored on the parent scope node. + + .. seealso:: :meth:`scope` + + :param name: The name that is being defined. + :type name: str + + :param stmt: The statement that defines the given name. + :type stmt: NodeNG + """ + self.parent.set_local(name, stmt) + + @overload + def nodes_of_class( + self, + klass: Type[T_Nodes], + skip_klass: SkipKlassT = None, + ) -> Iterator[T_Nodes]: + ... + + @overload + def nodes_of_class( + self, + klass: Tuple[Type[T_Nodes], Type[T_Nodes2]], + skip_klass: SkipKlassT = None, + ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2]]: + ... + + @overload + def nodes_of_class( + self, + klass: Tuple[Type[T_Nodes], Type[T_Nodes2], Type[T_Nodes3]], + skip_klass: SkipKlassT = None, + ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2], Iterator[T_Nodes3]]: + ... + + @overload + def nodes_of_class( + self, + klass: Tuple[Type[T_Nodes], ...], + skip_klass: SkipKlassT = None, + ) -> Iterator[T_Nodes]: + ... + + def nodes_of_class( # type: ignore[misc] # mypy doesn't correctly recognize the overloads + self, + klass: Union[ + Type[T_Nodes], + Tuple[Type[T_Nodes], Type[T_Nodes2]], + Tuple[Type[T_Nodes], Type[T_Nodes2], Type[T_Nodes3]], + Tuple[Type[T_Nodes], ...], + ], + skip_klass: SkipKlassT = None, + ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2], Iterator[T_Nodes3]]: + """Get the nodes (including this one or below) of the given types. + + :param klass: The types of node to search for. + + :param skip_klass: The types of node to ignore. This is useful to ignore + subclasses of :attr:`klass`. + + :returns: The node of the given types. + """ + if isinstance(self, klass): + yield self + + if skip_klass is None: + for child_node in self.get_children(): + yield from child_node.nodes_of_class(klass, skip_klass) + + return + + for child_node in self.get_children(): + if isinstance(child_node, skip_klass): + continue + yield from child_node.nodes_of_class(klass, skip_klass) + + @decorators.cached + def _get_assign_nodes(self): + return [] + + def _get_name_nodes(self): + for child_node in self.get_children(): + yield from child_node._get_name_nodes() + + def _get_return_nodes_skip_functions(self): + yield from () + + def _get_yield_nodes_skip_lambdas(self): + yield from () + + def _infer_name(self, frame, name): + # overridden for ImportFrom, Import, Global, TryExcept and Arguments + pass + + def _infer(self, context=None): + """we don't know how to resolve a statement by default""" + # this method is overridden by most concrete classes + raise InferenceError( + "No inference function for {node!r}.", node=self, context=context + ) + + def inferred(self): + """Get a list of the inferred values. + + .. seealso:: :ref:`inference` + + :returns: The inferred values. + :rtype: list + """ + return list(self.infer()) + + def instantiate_class(self): + """Instantiate an instance of the defined class. + + .. note:: + + On anything other than a :class:`ClassDef` this will return self. + + :returns: An instance of the defined class. + :rtype: object + """ + return self + + def has_base(self, node): + """Check if this node inherits from the given type. + + :param node: The node defining the base to look for. + Usually this is a :class:`Name` node. + :type node: NodeNG + """ + return False + + def callable(self): + """Whether this node defines something that is callable. + + :returns: True if this defines something that is callable, + False otherwise. + :rtype: bool + """ + return False + + def eq(self, value): + return False + + def as_string(self) -> str: + """Get the source code that this node represents.""" + return AsStringVisitor()(self) + + def repr_tree( + self, + ids=False, + include_linenos=False, + ast_state=False, + indent=" ", + max_depth=0, + max_width=80, + ) -> str: + """Get a string representation of the AST from this node. + + :param ids: If true, includes the ids with the node type names. + :type ids: bool + + :param include_linenos: If true, includes the line numbers and + column offsets. + :type include_linenos: bool + + :param ast_state: If true, includes information derived from + the whole AST like local and global variables. + :type ast_state: bool + + :param indent: A string to use to indent the output string. + :type indent: str + + :param max_depth: If set to a positive integer, won't return + nodes deeper than max_depth in the string. + :type max_depth: int + + :param max_width: Attempt to format the output string to stay + within this number of characters, but can exceed it under some + circumstances. Only positive integer values are valid, the default is 80. + :type max_width: int + + :returns: The string representation of the AST. + :rtype: str + """ + + @_singledispatch + def _repr_tree(node, result, done, cur_indent="", depth=1): + """Outputs a representation of a non-tuple/list, non-node that's + contained within an AST, including strings. + """ + lines = pprint.pformat( + node, width=max(max_width - len(cur_indent), 1) + ).splitlines(True) + result.append(lines[0]) + result.extend([cur_indent + line for line in lines[1:]]) + return len(lines) != 1 + + # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch + @_repr_tree.register(tuple) + @_repr_tree.register(list) + def _repr_seq(node, result, done, cur_indent="", depth=1): + """Outputs a representation of a sequence that's contained within an AST.""" + cur_indent += indent + result.append("[") + if not node: + broken = False + elif len(node) == 1: + broken = _repr_tree(node[0], result, done, cur_indent, depth) + elif len(node) == 2: + broken = _repr_tree(node[0], result, done, cur_indent, depth) + if not broken: + result.append(", ") + else: + result.append(",\n") + result.append(cur_indent) + broken = _repr_tree(node[1], result, done, cur_indent, depth) or broken + else: + result.append("\n") + result.append(cur_indent) + for child in node[:-1]: + _repr_tree(child, result, done, cur_indent, depth) + result.append(",\n") + result.append(cur_indent) + _repr_tree(node[-1], result, done, cur_indent, depth) + broken = True + result.append("]") + return broken + + # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch + @_repr_tree.register(NodeNG) + def _repr_node(node, result, done, cur_indent="", depth=1): + """Outputs a strings representation of an astroid node.""" + if node in done: + result.append( + indent + f" max_depth: + result.append("...") + return False + depth += 1 + cur_indent += indent + if ids: + result.append(f"{type(node).__name__}<0x{id(node):x}>(\n") + else: + result.append(f"{type(node).__name__}(") + fields = [] + if include_linenos: + fields.extend(("lineno", "col_offset")) + fields.extend(node._other_fields) + fields.extend(node._astroid_fields) + if ast_state: + fields.extend(node._other_other_fields) + if not fields: + broken = False + elif len(fields) == 1: + result.append(f"{fields[0]}=") + broken = _repr_tree( + getattr(node, fields[0]), result, done, cur_indent, depth + ) + else: + result.append("\n") + result.append(cur_indent) + for field in fields[:-1]: + # TODO: Remove this after removal of the 'doc' attribute + if field == "doc": + continue + result.append(f"{field}=") + _repr_tree(getattr(node, field), result, done, cur_indent, depth) + result.append(",\n") + result.append(cur_indent) + result.append(f"{fields[-1]}=") + _repr_tree(getattr(node, fields[-1]), result, done, cur_indent, depth) + broken = True + result.append(")") + return broken + + result: List[str] = [] + _repr_tree(self, result, set()) + return "".join(result) + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + The boolean value of a node can have three + possible values: + + * False: For instance, empty data structures, + False, empty strings, instances which return + explicitly False from the __nonzero__ / __bool__ + method. + * True: Most of constructs are True by default: + classes, functions, modules etc + * Uninferable: The inference engine is uncertain of the + node's value. + + :returns: The boolean value of this node. + :rtype: bool or Uninferable + """ + return util.Uninferable + + def op_precedence(self): + # Look up by class name or default to highest precedence + return OP_PRECEDENCE.get(self.__class__.__name__, len(OP_PRECEDENCE)) + + def op_left_associative(self): + # Everything is left associative except `**` and IfExp + return True diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/__init__.py b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/__init__.py new file mode 100644 index 0000000..816bd83 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/__init__.py @@ -0,0 +1,43 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""This module contains all classes that are considered a "scoped" node and anything related. +A scope node is a node that opens a new local scope in the language definition: +Module, ClassDef, FunctionDef (and Lambda, GeneratorExp, DictComp and SetComp to some extent). +""" + +from astroid.nodes.scoped_nodes.mixin import ComprehensionScope, LocalsDictNodeNG +from astroid.nodes.scoped_nodes.scoped_nodes import ( + AsyncFunctionDef, + ClassDef, + DictComp, + FunctionDef, + GeneratorExp, + Lambda, + ListComp, + Module, + SetComp, + _is_metaclass, + function_to_method, + get_wrapping_class, +) +from astroid.nodes.scoped_nodes.utils import builtin_lookup + +__all__ = ( + "AsyncFunctionDef", + "ClassDef", + "ComprehensionScope", + "DictComp", + "FunctionDef", + "GeneratorExp", + "Lambda", + "ListComp", + "LocalsDictNodeNG", + "Module", + "SetComp", + "builtin_lookup", + "function_to_method", + "get_wrapping_class", + "_is_metaclass", +) diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/mixin.py b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/mixin.py new file mode 100644 index 0000000..bb1e76f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/mixin.py @@ -0,0 +1,171 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""This module contains mixin classes for scoped nodes.""" + +from typing import TYPE_CHECKING, Dict, List, TypeVar + +from astroid.filter_statements import _filter_stmts +from astroid.nodes import node_classes, scoped_nodes +from astroid.nodes.scoped_nodes.utils import builtin_lookup + +if TYPE_CHECKING: + from astroid import nodes + +_T = TypeVar("_T") + + +class LocalsDictNodeNG(node_classes.LookupMixIn, node_classes.NodeNG): + """this class provides locals handling common to Module, FunctionDef + and ClassDef nodes, including a dict like interface for direct access + to locals information + """ + + # attributes below are set by the builder module or by raw factories + + locals: Dict[str, List["nodes.NodeNG"]] = {} + """A map of the name of a local variable to the node defining the local.""" + + def qname(self): + """Get the 'qualified' name of the node. + + For example: module.name, module.class.name ... + + :returns: The qualified name. + :rtype: str + """ + # pylint: disable=no-member; github.com/pycqa/astroid/issues/278 + if self.parent is None: + return self.name + return f"{self.parent.frame(future=True).qname()}.{self.name}" + + def scope(self: _T) -> _T: + """The first parent node defining a new scope. + + :returns: The first parent scope node. + :rtype: Module or FunctionDef or ClassDef or Lambda or GenExpr + """ + return self + + def _scope_lookup(self, node, name, offset=0): + """XXX method for interfacing the scope lookup""" + try: + stmts = _filter_stmts(node, self.locals[name], self, offset) + except KeyError: + stmts = () + if stmts: + return self, stmts + + # Handle nested scopes: since class names do not extend to nested + # scopes (e.g., methods), we find the next enclosing non-class scope + pscope = self.parent and self.parent.scope() + while pscope is not None: + if not isinstance(pscope, scoped_nodes.ClassDef): + return pscope.scope_lookup(node, name) + pscope = pscope.parent and pscope.parent.scope() + + # self is at the top level of a module, or is enclosed only by ClassDefs + return builtin_lookup(name) + + def set_local(self, name, stmt): + """Define that the given name is declared in the given statement node. + + .. seealso:: :meth:`scope` + + :param name: The name that is being defined. + :type name: str + + :param stmt: The statement that defines the given name. + :type stmt: NodeNG + """ + # assert not stmt in self.locals.get(name, ()), (self, stmt) + self.locals.setdefault(name, []).append(stmt) + + __setitem__ = set_local + + def _append_node(self, child): + """append a child, linking it in the tree""" + # pylint: disable=no-member; depending by the class + # which uses the current class as a mixin or base class. + # It's rewritten in 2.0, so it makes no sense for now + # to spend development time on it. + self.body.append(child) + child.parent = self + + def add_local_node(self, child_node, name=None): + """Append a child that should alter the locals of this scope node. + + :param child_node: The child node that will alter locals. + :type child_node: NodeNG + + :param name: The name of the local that will be altered by + the given child node. + :type name: str or None + """ + if name != "__class__": + # add __class__ node as a child will cause infinite recursion later! + self._append_node(child_node) + self.set_local(name or child_node.name, child_node) + + def __getitem__(self, item: str) -> "nodes.NodeNG": + """The first node the defines the given local. + + :param item: The name of the locally defined object. + + :raises KeyError: If the name is not defined. + """ + return self.locals[item][0] + + def __iter__(self): + """Iterate over the names of locals defined in this scoped node. + + :returns: The names of the defined locals. + :rtype: iterable(str) + """ + return iter(self.keys()) + + def keys(self): + """The names of locals defined in this scoped node. + + :returns: The names of the defined locals. + :rtype: list(str) + """ + return list(self.locals.keys()) + + def values(self): + """The nodes that define the locals in this scoped node. + + :returns: The nodes that define locals. + :rtype: list(NodeNG) + """ + # pylint: disable=consider-using-dict-items + # It look like this class override items/keys/values, + # probably not worth the headache + return [self[key] for key in self.keys()] + + def items(self): + """Get the names of the locals and the node that defines the local. + + :returns: The names of locals and their associated node. + :rtype: list(tuple(str, NodeNG)) + """ + return list(zip(self.keys(), self.values())) + + def __contains__(self, name): + """Check if a local is defined in this scope. + + :param name: The name of the local to check for. + :type name: str + + :returns: True if this node has a local of the given name, + False otherwise. + :rtype: bool + """ + return name in self.locals + + +class ComprehensionScope(LocalsDictNodeNG): + """Scoping for different types of comprehensions.""" + + scope_lookup = LocalsDictNodeNG._scope_lookup diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py new file mode 100644 index 0000000..b3358d9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py @@ -0,0 +1,3122 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +This module contains the classes for "scoped" node, i.e. which are opening a +new local scope in the language definition : Module, ClassDef, FunctionDef (and +Lambda, GeneratorExp, DictComp and SetComp to some extent). +""" +import io +import itertools +import os +import sys +import typing +import warnings +from typing import TYPE_CHECKING, Dict, List, Optional, Set, TypeVar, Union, overload + +from astroid import bases +from astroid import decorators as decorators_mod +from astroid import mixins, util +from astroid.const import IS_PYPY, PY38, PY38_PLUS, PY39_PLUS +from astroid.context import ( + CallContext, + InferenceContext, + bind_context_to_node, + copy_context, +) +from astroid.exceptions import ( + AstroidBuildingError, + AstroidTypeError, + AttributeInferenceError, + DuplicateBasesError, + InconsistentMroError, + InferenceError, + MroError, + StatementMissing, + TooManyLevelsError, +) +from astroid.interpreter.dunder_lookup import lookup +from astroid.interpreter.objectmodel import ClassModel, FunctionModel, ModuleModel +from astroid.manager import AstroidManager +from astroid.nodes import Arguments, Const, NodeNG, node_classes +from astroid.nodes.scoped_nodes.mixin import ComprehensionScope, LocalsDictNodeNG +from astroid.nodes.scoped_nodes.utils import builtin_lookup +from astroid.nodes.utils import Position + +if sys.version_info >= (3, 6, 2): + from typing import NoReturn +else: + from typing_extensions import NoReturn + + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if sys.version_info >= (3, 8) or TYPE_CHECKING: + from functools import cached_property +else: + # pylint: disable-next=ungrouped-imports + from astroid.decorators import cachedproperty as cached_property + + +ITER_METHODS = ("__iter__", "__getitem__") +EXCEPTION_BASE_CLASSES = frozenset({"Exception", "BaseException"}) +objects = util.lazy_import("objects") +BUILTIN_DESCRIPTORS = frozenset( + {"classmethod", "staticmethod", "builtins.classmethod", "builtins.staticmethod"} +) + +T = TypeVar("T") + + +def _c3_merge(sequences, cls, context): + """Merges MROs in *sequences* to a single MRO using the C3 algorithm. + + Adapted from http://www.python.org/download/releases/2.3/mro/. + + """ + result = [] + while True: + sequences = [s for s in sequences if s] # purge empty sequences + if not sequences: + return result + for s1 in sequences: # find merge candidates among seq heads + candidate = s1[0] + for s2 in sequences: + if candidate in s2[1:]: + candidate = None + break # reject the current head, it appears later + else: + break + if not candidate: + # Show all the remaining bases, which were considered as + # candidates for the next mro sequence. + raise InconsistentMroError( + message="Cannot create a consistent method resolution order " + "for MROs {mros} of class {cls!r}.", + mros=sequences, + cls=cls, + context=context, + ) + + result.append(candidate) + # remove the chosen candidate + for seq in sequences: + if seq[0] == candidate: + del seq[0] + return None + + +def clean_typing_generic_mro(sequences: List[List["ClassDef"]]) -> None: + """A class can inherit from typing.Generic directly, as base, + and as base of bases. The merged MRO must however only contain the last entry. + To prepare for _c3_merge, remove some typing.Generic entries from + sequences if multiple are present. + + This method will check if Generic is in inferred_bases and also + part of bases_mro. If true, remove it from inferred_bases + as well as its entry the bases_mro. + + Format sequences: [[self]] + bases_mro + [inferred_bases] + """ + bases_mro = sequences[1:-1] + inferred_bases = sequences[-1] + # Check if Generic is part of inferred_bases + for i, base in enumerate(inferred_bases): + if base.qname() == "typing.Generic": + position_in_inferred_bases = i + break + else: + return + # Check if also part of bases_mro + # Ignore entry for typing.Generic + for i, seq in enumerate(bases_mro): + if i == position_in_inferred_bases: + continue + if any(base.qname() == "typing.Generic" for base in seq): + break + else: + return + # Found multiple Generics in mro, remove entry from inferred_bases + # and the corresponding one from bases_mro + inferred_bases.pop(position_in_inferred_bases) + bases_mro.pop(position_in_inferred_bases) + + +def clean_duplicates_mro(sequences, cls, context): + for sequence in sequences: + names = [ + (node.lineno, node.qname()) if node.name else None for node in sequence + ] + last_index = dict(map(reversed, enumerate(names))) + if names and names[0] is not None and last_index[names[0]] != 0: + raise DuplicateBasesError( + message="Duplicates found in MROs {mros} for {cls!r}.", + mros=sequences, + cls=cls, + context=context, + ) + yield [ + node + for i, (node, name) in enumerate(zip(sequence, names)) + if name is None or last_index[name] == i + ] + + +def function_to_method(n, klass): + if isinstance(n, FunctionDef): + if n.type == "classmethod": + return bases.BoundMethod(n, klass) + if n.type == "property": + return n + if n.type != "staticmethod": + return bases.UnboundMethod(n) + return n + + +class Module(LocalsDictNodeNG): + """Class representing an :class:`ast.Module` node. + + >>> import astroid + >>> node = astroid.extract_node('import astroid') + >>> node + + >>> node.parent + + """ + + _astroid_fields = ("doc_node", "body") + + fromlineno: Literal[0] = 0 + """The first line that this node appears on in the source code.""" + + lineno: Literal[0] = 0 + """The line that this node appears on in the source code.""" + + # attributes below are set by the builder module or by raw factories + + file_bytes: Union[str, bytes, None] = None + """The string/bytes that this ast was built from.""" + + file_encoding: Optional[str] = None + """The encoding of the source file. + + This is used to get unicode out of a source file. + Python 2 only. + """ + + special_attributes = ModuleModel() + """The names of special attributes that this module has.""" + + # names of module attributes available through the global scope + scope_attrs = {"__name__", "__doc__", "__file__", "__path__", "__package__"} + """The names of module attributes available through the global scope.""" + + _other_fields = ( + "name", + "doc", + "file", + "path", + "package", + "pure_python", + "future_imports", + ) + _other_other_fields = ("locals", "globals") + + col_offset: None + end_lineno: None + end_col_offset: None + parent: None + + @decorators_mod.deprecate_arguments(doc="Use the postinit arg 'doc_node' instead") + def __init__( + self, + name: str, + doc: Optional[str] = None, + file: Optional[str] = None, + path: Optional[List[str]] = None, + package: Optional[bool] = None, + parent: None = None, + pure_python: Optional[bool] = True, + ) -> None: + """ + :param name: The name of the module. + + :param doc: The module docstring. + + :param file: The path to the file that this ast has been extracted from. + + :param path: + + :param package: Whether the node represents a package or a module. + + :param parent: The parent node in the syntax tree. + + :param pure_python: Whether the ast was built from source. + """ + self.name = name + """The name of the module.""" + + self._doc = doc + """The module docstring.""" + + self.file = file + """The path to the file that this ast has been extracted from. + + This will be ``None`` when the representation has been built from a + built-in module. + """ + + self.path = path + + self.package = package + """Whether the node represents a package or a module.""" + + self.pure_python = pure_python + """Whether the ast was built from source.""" + + self.globals: Dict[str, List[node_classes.NodeNG]] + """A map of the name of a global variable to the node defining the global.""" + + self.locals = self.globals = {} + """A map of the name of a local variable to the node defining the local.""" + + self.body: Optional[List[node_classes.NodeNG]] = [] + """The contents of the module.""" + + self.doc_node: Optional[Const] = None + """The doc node associated with this node.""" + + self.future_imports: Set[str] = set() + """The imports from ``__future__``.""" + + super().__init__(lineno=0, parent=parent) + + # pylint: enable=redefined-builtin + + def postinit(self, body=None, *, doc_node: Optional[Const] = None): + """Do some setup after initialisation. + + :param body: The contents of the module. + :type body: list(NodeNG) or None + :param doc_node: The doc node associated with this node. + """ + self.body = body + self.doc_node = doc_node + if doc_node: + self._doc = doc_node.value + + @property + def doc(self) -> Optional[str]: + """The module docstring.""" + warnings.warn( + "The 'Module.doc' attribute is deprecated, " + "use 'Module.doc_node' instead.", + DeprecationWarning, + ) + return self._doc + + @doc.setter + def doc(self, value: Optional[str]) -> None: + warnings.warn( + "Setting the 'Module.doc' attribute is deprecated, " + "use 'Module.doc_node' instead.", + DeprecationWarning, + ) + self._doc = value + + def _get_stream(self): + if self.file_bytes is not None: + return io.BytesIO(self.file_bytes) + if self.file is not None: + # pylint: disable=consider-using-with + stream = open(self.file, "rb") + return stream + return None + + def stream(self): + """Get a stream to the underlying file or bytes. + + :type: file or io.BytesIO or None + """ + return self._get_stream() + + def block_range(self, lineno): + """Get a range from where this node starts to where this node ends. + + :param lineno: Unused. + :type lineno: int + + :returns: The range of line numbers that this node belongs to. + :rtype: tuple(int, int) + """ + return self.fromlineno, self.tolineno + + def scope_lookup(self, node, name, offset=0): + """Lookup where the given variable is assigned. + + :param node: The node to look for assignments up to. + Any assignments after the given node are ignored. + :type node: NodeNG + + :param name: The name of the variable to find assignments for. + :type name: str + + :param offset: The line offset to filter statements up to. + :type offset: int + + :returns: This scope node and the list of assignments associated to the + given name according to the scope where it has been found (locals, + globals or builtin). + :rtype: tuple(str, list(NodeNG)) + """ + if name in self.scope_attrs and name not in self.locals: + try: + return self, self.getattr(name) + except AttributeInferenceError: + return self, () + return self._scope_lookup(node, name, offset) + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + return "builtins.module" + + def display_type(self): + """A human readable type of this node. + + :returns: The type of this node. + :rtype: str + """ + return "Module" + + def getattr(self, name, context=None, ignore_locals=False): + if not name: + raise AttributeInferenceError(target=self, attribute=name, context=context) + + result = [] + name_in_locals = name in self.locals + + if name in self.special_attributes and not ignore_locals and not name_in_locals: + result = [self.special_attributes.lookup(name)] + elif not ignore_locals and name_in_locals: + result = self.locals[name] + elif self.package: + try: + result = [self.import_module(name, relative_only=True)] + except (AstroidBuildingError, SyntaxError) as exc: + raise AttributeInferenceError( + target=self, attribute=name, context=context + ) from exc + result = [n for n in result if not isinstance(n, node_classes.DelName)] + if result: + return result + raise AttributeInferenceError(target=self, attribute=name, context=context) + + def igetattr(self, name, context=None): + """Infer the possible values of the given variable. + + :param name: The name of the variable to infer. + :type name: str + + :returns: The inferred possible values. + :rtype: iterable(NodeNG) or None + """ + # set lookup name since this is necessary to infer on import nodes for + # instance + context = copy_context(context) + context.lookupname = name + try: + return bases._infer_stmts(self.getattr(name, context), context, frame=self) + except AttributeInferenceError as error: + raise InferenceError( + str(error), target=self, attribute=name, context=context + ) from error + + def fully_defined(self): + """Check if this module has been build from a .py file. + + If so, the module contains a complete representation, + including the code. + + :returns: True if the module has been built from a .py file. + :rtype: bool + """ + return self.file is not None and self.file.endswith(".py") + + @overload + def statement(self, *, future: None = ...) -> "Module": + ... + + @overload + def statement(self, *, future: Literal[True]) -> NoReturn: + ... + + def statement( + self, *, future: Literal[None, True] = None + ) -> Union["NoReturn", "Module"]: + """The first parent node, including self, marked as statement node. + + When called on a :class:`Module` with the future parameter this raises an error. + + TODO: Deprecate the future parameter and only raise StatementMissing + + :raises StatementMissing: If no self has no parent attribute and future is True + """ + if future: + raise StatementMissing(target=self) + warnings.warn( + "In astroid 3.0.0 NodeNG.statement() will return either a nodes.Statement " + "or raise a StatementMissing exception. nodes.Module will no longer be " + "considered a statement. This behaviour can already be triggered " + "by passing 'future=True' to a statement() call.", + DeprecationWarning, + ) + return self + + def previous_sibling(self): + """The previous sibling statement. + + :returns: The previous sibling statement node. + :rtype: NodeNG or None + """ + + def next_sibling(self): + """The next sibling statement node. + + :returns: The next sibling statement node. + :rtype: NodeNG or None + """ + + _absolute_import_activated = True + + def absolute_import_activated(self): + """Whether :pep:`328` absolute import behaviour has been enabled. + + :returns: True if :pep:`328` has been enabled, False otherwise. + :rtype: bool + """ + return self._absolute_import_activated + + def import_module(self, modname, relative_only=False, level=None): + """Get the ast for a given module as if imported from this module. + + :param modname: The name of the module to "import". + :type modname: str + + :param relative_only: Whether to only consider relative imports. + :type relative_only: bool + + :param level: The level of relative import. + :type level: int or None + + :returns: The imported module ast. + :rtype: NodeNG + """ + if relative_only and level is None: + level = 0 + absmodname = self.relative_to_absolute_name(modname, level) + + try: + return AstroidManager().ast_from_module_name(absmodname) + except AstroidBuildingError: + # we only want to import a sub module or package of this module, + # skip here + if relative_only: + raise + return AstroidManager().ast_from_module_name(modname) + + def relative_to_absolute_name(self, modname: str, level: int) -> str: + """Get the absolute module name for a relative import. + + The relative import can be implicit or explicit. + + :param modname: The module name to convert. + + :param level: The level of relative import. + + :returns: The absolute module name. + + :raises TooManyLevelsError: When the relative import refers to a + module too far above this one. + """ + # XXX this returns non sens when called on an absolute import + # like 'pylint.checkers.astroid.utils' + # XXX doesn't return absolute name if self.name isn't absolute name + if self.absolute_import_activated() and level is None: + return modname + if level: + if self.package: + level = level - 1 + package_name = self.name.rsplit(".", level)[0] + elif ( + self.path + and not os.path.exists(os.path.dirname(self.path[0]) + "/__init__.py") + and os.path.exists( + os.path.dirname(self.path[0]) + "/" + modname.split(".")[0] + ) + ): + level = level - 1 + package_name = "" + else: + package_name = self.name.rsplit(".", level)[0] + if level and self.name.count(".") < level: + raise TooManyLevelsError(level=level, name=self.name) + + elif self.package: + package_name = self.name + else: + package_name = self.name.rsplit(".", 1)[0] + + if package_name: + if not modname: + return package_name + return f"{package_name}.{modname}" + return modname + + def wildcard_import_names(self): + """The list of imported names when this module is 'wildcard imported'. + + It doesn't include the '__builtins__' name which is added by the + current CPython implementation of wildcard imports. + + :returns: The list of imported names. + :rtype: list(str) + """ + # We separate the different steps of lookup in try/excepts + # to avoid catching too many Exceptions + default = [name for name in self.keys() if not name.startswith("_")] + try: + all_values = self["__all__"] + except KeyError: + return default + + try: + explicit = next(all_values.assigned_stmts()) + except (InferenceError, StopIteration): + return default + except AttributeError: + # not an assignment node + # XXX infer? + return default + + # Try our best to detect the exported name. + inferred = [] + try: + explicit = next(explicit.infer()) + except (InferenceError, StopIteration): + return default + if not isinstance(explicit, (node_classes.Tuple, node_classes.List)): + return default + + def str_const(node): + return isinstance(node, node_classes.Const) and isinstance(node.value, str) + + for node in explicit.elts: + if str_const(node): + inferred.append(node.value) + else: + try: + inferred_node = next(node.infer()) + except (InferenceError, StopIteration): + continue + if str_const(inferred_node): + inferred.append(inferred_node.value) + return inferred + + def public_names(self): + """The list of the names that are publicly available in this module. + + :returns: The list of public names. + :rtype: list(str) + """ + return [name for name in self.keys() if not name.startswith("_")] + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`Module` this is always ``True``. + :rtype: bool + """ + return True + + def get_children(self): + yield from self.body + + def frame(self: T, *, future: Literal[None, True] = None) -> T: + """The node's frame node. + + A frame node is a :class:`Module`, :class:`FunctionDef`, + :class:`ClassDef` or :class:`Lambda`. + + :returns: The node itself. + """ + return self + + +class GeneratorExp(ComprehensionScope): + """Class representing an :class:`ast.GeneratorExp` node. + + >>> import astroid + >>> node = astroid.extract_node('(thing for thing in things if thing)') + >>> node + + """ + + _astroid_fields = ("elt", "generators") + _other_other_fields = ("locals",) + elt = None + """The element that forms the output of the expression. + + :type: NodeNG or None + """ + generators = None + """The generators that are looped through. + + :type: list(Comprehension) or None + """ + + def __init__( + self, + lineno=None, + col_offset=None, + parent=None, + *, + end_lineno=None, + end_col_offset=None, + ): + """ + :param lineno: The line that this node appears on in the source code. + :type lineno: int or None + + :param col_offset: The column that this node appears on in the + source code. + :type col_offset: int or None + + :param parent: The parent node in the syntax tree. + :type parent: NodeNG or None + + :param end_lineno: The last line this node appears on in the source code. + :type end_lineno: Optional[int] + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + :type end_col_offset: Optional[int] + """ + self.locals = {} + """A map of the name of a local variable to the node defining the local. + + :type: dict(str, NodeNG) + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, elt=None, generators=None): + """Do some setup after initialisation. + + :param elt: The element that forms the output of the expression. + :type elt: NodeNG or None + + :param generators: The generators that are looped through. + :type generators: list(Comprehension) or None + """ + self.elt = elt + if generators is None: + self.generators = [] + else: + self.generators = generators + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`GeneratorExp` this is always ``True``. + :rtype: bool + """ + return True + + def get_children(self): + yield self.elt + + yield from self.generators + + +class DictComp(ComprehensionScope): + """Class representing an :class:`ast.DictComp` node. + + >>> import astroid + >>> node = astroid.extract_node('{k:v for k, v in things if k > v}') + >>> node + + """ + + _astroid_fields = ("key", "value", "generators") + _other_other_fields = ("locals",) + key = None + """What produces the keys. + + :type: NodeNG or None + """ + value = None + """What produces the values. + + :type: NodeNG or None + """ + generators = None + """The generators that are looped through. + + :type: list(Comprehension) or None + """ + + def __init__( + self, + lineno=None, + col_offset=None, + parent=None, + *, + end_lineno=None, + end_col_offset=None, + ): + """ + :param lineno: The line that this node appears on in the source code. + :type lineno: int or None + + :param col_offset: The column that this node appears on in the + source code. + :type col_offset: int or None + + :param parent: The parent node in the syntax tree. + :type parent: NodeNG or None + + :param end_lineno: The last line this node appears on in the source code. + :type end_lineno: Optional[int] + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + :type end_col_offset: Optional[int] + """ + self.locals = {} + """A map of the name of a local variable to the node defining the local. + + :type: dict(str, NodeNG) + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, key=None, value=None, generators=None): + """Do some setup after initialisation. + + :param key: What produces the keys. + :type key: NodeNG or None + + :param value: What produces the values. + :type value: NodeNG or None + + :param generators: The generators that are looped through. + :type generators: list(Comprehension) or None + """ + self.key = key + self.value = value + if generators is None: + self.generators = [] + else: + self.generators = generators + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`DictComp` this is always :class:`Uninferable`. + :rtype: Uninferable + """ + return util.Uninferable + + def get_children(self): + yield self.key + yield self.value + + yield from self.generators + + +class SetComp(ComprehensionScope): + """Class representing an :class:`ast.SetComp` node. + + >>> import astroid + >>> node = astroid.extract_node('{thing for thing in things if thing}') + >>> node + + """ + + _astroid_fields = ("elt", "generators") + _other_other_fields = ("locals",) + elt = None + """The element that forms the output of the expression. + + :type: NodeNG or None + """ + generators = None + """The generators that are looped through. + + :type: list(Comprehension) or None + """ + + def __init__( + self, + lineno=None, + col_offset=None, + parent=None, + *, + end_lineno=None, + end_col_offset=None, + ): + """ + :param lineno: The line that this node appears on in the source code. + :type lineno: int or None + + :param col_offset: The column that this node appears on in the + source code. + :type col_offset: int or None + + :param parent: The parent node in the syntax tree. + :type parent: NodeNG or None + + :param end_lineno: The last line this node appears on in the source code. + :type end_lineno: Optional[int] + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + :type end_col_offset: Optional[int] + """ + self.locals = {} + """A map of the name of a local variable to the node defining the local. + + :type: dict(str, NodeNG) + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, elt=None, generators=None): + """Do some setup after initialisation. + + :param elt: The element that forms the output of the expression. + :type elt: NodeNG or None + + :param generators: The generators that are looped through. + :type generators: list(Comprehension) or None + """ + self.elt = elt + if generators is None: + self.generators = [] + else: + self.generators = generators + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`SetComp` this is always :class:`Uninferable`. + :rtype: Uninferable + """ + return util.Uninferable + + def get_children(self): + yield self.elt + + yield from self.generators + + +class ListComp(ComprehensionScope): + """Class representing an :class:`ast.ListComp` node. + + >>> import astroid + >>> node = astroid.extract_node('[thing for thing in things if thing]') + >>> node + + """ + + _astroid_fields = ("elt", "generators") + _other_other_fields = ("locals",) + + elt = None + """The element that forms the output of the expression. + + :type: NodeNG or None + """ + + generators = None + """The generators that are looped through. + + :type: list(Comprehension) or None + """ + + def __init__( + self, + lineno=None, + col_offset=None, + parent=None, + *, + end_lineno=None, + end_col_offset=None, + ): + self.locals = {} + """A map of the name of a local variable to the node defining it. + + :type: dict(str, NodeNG) + """ + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, elt=None, generators=None): + """Do some setup after initialisation. + + :param elt: The element that forms the output of the expression. + :type elt: NodeNG or None + + :param generators: The generators that are looped through. + :type generators: list(Comprehension) or None + """ + self.elt = elt + self.generators = generators + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`ListComp` this is always :class:`Uninferable`. + :rtype: Uninferable + """ + return util.Uninferable + + def get_children(self): + yield self.elt + + yield from self.generators + + +def _infer_decorator_callchain(node): + """Detect decorator call chaining and see if the end result is a + static or a classmethod. + """ + if not isinstance(node, FunctionDef): + return None + if not node.parent: + return None + try: + result = next(node.infer_call_result(node.parent), None) + except InferenceError: + return None + if isinstance(result, bases.Instance): + result = result._proxied + if isinstance(result, ClassDef): + if result.is_subtype_of("builtins.classmethod"): + return "classmethod" + if result.is_subtype_of("builtins.staticmethod"): + return "staticmethod" + if isinstance(result, FunctionDef): + if not result.decorators: + return None + # Determine if this function is decorated with one of the builtin descriptors we want. + for decorator in result.decorators.nodes: + if isinstance(decorator, node_classes.Name): + if decorator.name in BUILTIN_DESCRIPTORS: + return decorator.name + if ( + isinstance(decorator, node_classes.Attribute) + and isinstance(decorator.expr, node_classes.Name) + and decorator.expr.name == "builtins" + and decorator.attrname in BUILTIN_DESCRIPTORS + ): + return decorator.attrname + return None + + +class Lambda(mixins.FilterStmtsMixin, LocalsDictNodeNG): + """Class representing an :class:`ast.Lambda` node. + + >>> import astroid + >>> node = astroid.extract_node('lambda arg: arg + 1') + >>> node + l.1 at 0x7f23b2e41518> + """ + + _astroid_fields = ("args", "body") + _other_other_fields = ("locals",) + name = "" + is_lambda = True + special_attributes = FunctionModel() + """The names of special attributes that this function has.""" + + def implicit_parameters(self): + return 0 + + # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod' + @property + def type(self): + """Whether this is a method or function. + + :returns: 'method' if this is a method, 'function' otherwise. + :rtype: str + """ + if self.args.arguments and self.args.arguments[0].name == "self": + if isinstance(self.parent.scope(), ClassDef): + return "method" + return "function" + + def __init__( + self, + lineno=None, + col_offset=None, + parent=None, + *, + end_lineno=None, + end_col_offset=None, + ): + """ + :param lineno: The line that this node appears on in the source code. + :type lineno: int or None + + :param col_offset: The column that this node appears on in the + source code. + :type col_offset: int or None + + :param parent: The parent node in the syntax tree. + :type parent: NodeNG or None + + :param end_lineno: The last line this node appears on in the source code. + :type end_lineno: Optional[int] + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + :type end_col_offset: Optional[int] + """ + self.locals = {} + """A map of the name of a local variable to the node defining it. + + :type: dict(str, NodeNG) + """ + + self.args: Arguments + """The arguments that the function takes.""" + + self.body = [] + """The contents of the function body. + + :type: list(NodeNG) + """ + + self.instance_attrs: Dict[str, List[NodeNG]] = {} + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + + def postinit(self, args: Arguments, body): + """Do some setup after initialisation. + + :param args: The arguments that the function takes. + + :param body: The contents of the function body. + :type body: list(NodeNG) + """ + self.args = args + self.body = body + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + if "method" in self.type: + return "builtins.instancemethod" + return "builtins.function" + + def display_type(self): + """A human readable type of this node. + + :returns: The type of this node. + :rtype: str + """ + if "method" in self.type: + return "Method" + return "Function" + + def callable(self): + """Whether this node defines something that is callable. + + :returns: True if this defines something that is callable, + False otherwise. + For a :class:`Lambda` this is always ``True``. + :rtype: bool + """ + return True + + def argnames(self) -> List[str]: + """Get the names of each of the arguments, including that + of the collections of variable-length arguments ("args", "kwargs", + etc.), as well as positional-only and keyword-only arguments. + + :returns: The names of the arguments. + :rtype: list(str) + """ + if self.args.arguments: # maybe None with builtin functions + names = _rec_get_names(self.args.arguments) + else: + names = [] + if self.args.vararg: + names.append(self.args.vararg) + names += [elt.name for elt in self.args.kwonlyargs] + if self.args.kwarg: + names.append(self.args.kwarg) + return names + + def infer_call_result(self, caller, context=None): + """Infer what the function returns when called. + + :param caller: Unused + :type caller: object + """ + # pylint: disable=no-member; github.com/pycqa/astroid/issues/291 + # args is in fact redefined later on by postinit. Can't be changed + # to None due to a strong interaction between Lambda and FunctionDef. + return self.body.infer(context) + + def scope_lookup(self, node, name, offset=0): + """Lookup where the given names is assigned. + + :param node: The node to look for assignments up to. + Any assignments after the given node are ignored. + :type node: NodeNG + + :param name: The name to find assignments for. + :type name: str + + :param offset: The line offset to filter statements up to. + :type offset: int + + :returns: This scope node and the list of assignments associated to the + given name according to the scope where it has been found (locals, + globals or builtin). + :rtype: tuple(str, list(NodeNG)) + """ + if node in self.args.defaults or node in self.args.kw_defaults: + frame = self.parent.frame(future=True) + # line offset to avoid that def func(f=func) resolve the default + # value to the defined function + offset = -1 + else: + # check this is not used in function decorators + frame = self + return frame._scope_lookup(node, name, offset) + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`Lambda` this is always ``True``. + :rtype: bool + """ + return True + + def get_children(self): + yield self.args + yield self.body + + def frame(self: T, *, future: Literal[None, True] = None) -> T: + """The node's frame node. + + A frame node is a :class:`Module`, :class:`FunctionDef`, + :class:`ClassDef` or :class:`Lambda`. + + :returns: The node itself. + """ + return self + + def getattr( + self, name: str, context: Optional[InferenceContext] = None + ) -> List[NodeNG]: + if not name: + raise AttributeInferenceError(target=self, attribute=name, context=context) + + found_attrs = [] + if name in self.instance_attrs: + found_attrs = self.instance_attrs[name] + if name in self.special_attributes: + found_attrs.append(self.special_attributes.lookup(name)) + if found_attrs: + return found_attrs + raise AttributeInferenceError(target=self, attribute=name) + + +class FunctionDef(mixins.MultiLineBlockMixin, node_classes.Statement, Lambda): + """Class representing an :class:`ast.FunctionDef`. + + >>> import astroid + >>> node = astroid.extract_node(''' + ... def my_func(arg): + ... return arg + 1 + ... ''') + >>> node + + """ + + _astroid_fields = ("decorators", "args", "returns", "doc_node", "body") + _multi_line_block_fields = ("body",) + returns = None + decorators: Optional[node_classes.Decorators] = None + """The decorators that are applied to this method or function.""" + + is_function = True + """Whether this node indicates a function. + + For a :class:`FunctionDef` this is always ``True``. + + :type: bool + """ + type_annotation = None + """If present, this will contain the type annotation passed by a type comment + + :type: NodeNG or None + """ + type_comment_args = None + """ + If present, this will contain the type annotation for arguments + passed by a type comment + """ + type_comment_returns = None + """If present, this will contain the return type annotation, passed by a type comment""" + # attributes below are set by the builder module or by raw factories + _other_fields = ("name", "doc", "position") + _other_other_fields = ( + "locals", + "_type", + "type_comment_returns", + "type_comment_args", + ) + _type = None + + @decorators_mod.deprecate_arguments(doc="Use the postinit arg 'doc_node' instead") + def __init__( + self, + name=None, + doc: Optional[str] = None, + lineno=None, + col_offset=None, + parent=None, + *, + end_lineno=None, + end_col_offset=None, + ): + """ + :param name: The name of the function. + :type name: str or None + + :param doc: The function docstring. + + :param lineno: The line that this node appears on in the source code. + :type lineno: int or None + + :param col_offset: The column that this node appears on in the + source code. + :type col_offset: int or None + + :param parent: The parent node in the syntax tree. + :type parent: NodeNG or None + + :param end_lineno: The last line this node appears on in the source code. + :type end_lineno: Optional[int] + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + :type end_col_offset: Optional[int] + """ + self.name = name + """The name of the function. + + :type name: str or None + """ + + self._doc = doc + """The function docstring.""" + + self.doc_node: Optional[Const] = None + """The doc node associated with this node.""" + + self.instance_attrs = {} + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + if parent: + frame = parent.frame(future=True) + frame.set_local(name, self) + + # pylint: disable=arguments-differ; different than Lambdas + def postinit( + self, + args: Arguments, + body, + decorators: Optional[node_classes.Decorators] = None, + returns=None, + type_comment_returns=None, + type_comment_args=None, + *, + position: Optional[Position] = None, + doc_node: Optional[Const] = None, + ): + """Do some setup after initialisation. + + :param args: The arguments that the function takes. + + :param body: The contents of the function body. + :type body: list(NodeNG) + + :param decorators: The decorators that are applied to this + method or function. + :type decorators: Decorators or None + :params type_comment_returns: + The return type annotation passed via a type comment. + :params type_comment_args: + The args type annotation passed via a type comment. + :params position: + Position of function keyword(s) and name. + :param doc_node: + The doc node associated with this node. + """ + self.args = args + self.body = body + self.decorators = decorators + self.returns = returns + self.type_comment_returns = type_comment_returns + self.type_comment_args = type_comment_args + self.position = position + self.doc_node = doc_node + if doc_node: + self._doc = doc_node.value + + @property + def doc(self) -> Optional[str]: + """The function docstring.""" + warnings.warn( + "The 'FunctionDef.doc' attribute is deprecated, " + "use 'FunctionDef.doc_node' instead.", + DeprecationWarning, + ) + return self._doc + + @doc.setter + def doc(self, value: Optional[str]) -> None: + warnings.warn( + "Setting the 'FunctionDef.doc' attribute is deprecated, " + "use 'FunctionDef.doc_node' instead.", + DeprecationWarning, + ) + self._doc = value + + @cached_property + def extra_decorators(self) -> List[node_classes.Call]: + """The extra decorators that this function can have. + + Additional decorators are considered when they are used as + assignments, as in ``method = staticmethod(method)``. + The property will return all the callables that are used for + decoration. + """ + frame = self.parent.frame(future=True) + if not isinstance(frame, ClassDef): + return [] + + decorators: List[node_classes.Call] = [] + for assign in frame._get_assign_nodes(): + if isinstance(assign.value, node_classes.Call) and isinstance( + assign.value.func, node_classes.Name + ): + for assign_node in assign.targets: + if not isinstance(assign_node, node_classes.AssignName): + # Support only `name = callable(name)` + continue + + if assign_node.name != self.name: + # Interested only in the assignment nodes that + # decorates the current method. + continue + try: + meth = frame[self.name] + except KeyError: + continue + else: + # Must be a function and in the same frame as the + # original method. + if ( + isinstance(meth, FunctionDef) + and assign_node.frame(future=True) == frame + ): + decorators.append(assign.value) + return decorators + + @cached_property + def type( + self, + ): # pylint: disable=invalid-overridden-method,too-many-return-statements + """The function type for this node. + + Possible values are: method, function, staticmethod, classmethod. + + :type: str + """ + for decorator in self.extra_decorators: + if decorator.func.name in BUILTIN_DESCRIPTORS: + return decorator.func.name + + frame = self.parent.frame(future=True) + type_name = "function" + if isinstance(frame, ClassDef): + if self.name == "__new__": + return "classmethod" + if self.name == "__init_subclass__": + return "classmethod" + if self.name == "__class_getitem__": + return "classmethod" + + type_name = "method" + + if not self.decorators: + return type_name + + for node in self.decorators.nodes: + if isinstance(node, node_classes.Name): + if node.name in BUILTIN_DESCRIPTORS: + return node.name + if ( + isinstance(node, node_classes.Attribute) + and isinstance(node.expr, node_classes.Name) + and node.expr.name == "builtins" + and node.attrname in BUILTIN_DESCRIPTORS + ): + return node.attrname + + if isinstance(node, node_classes.Call): + # Handle the following case: + # @some_decorator(arg1, arg2) + # def func(...) + # + try: + current = next(node.func.infer()) + except (InferenceError, StopIteration): + continue + _type = _infer_decorator_callchain(current) + if _type is not None: + return _type + + try: + for inferred in node.infer(): + # Check to see if this returns a static or a class method. + _type = _infer_decorator_callchain(inferred) + if _type is not None: + return _type + + if not isinstance(inferred, ClassDef): + continue + for ancestor in inferred.ancestors(): + if not isinstance(ancestor, ClassDef): + continue + if ancestor.is_subtype_of("builtins.classmethod"): + return "classmethod" + if ancestor.is_subtype_of("builtins.staticmethod"): + return "staticmethod" + except InferenceError: + pass + return type_name + + @cached_property + def fromlineno(self) -> Optional[int]: + """The first line that this node appears on in the source code.""" + # lineno is the line number of the first decorator, we want the def + # statement lineno. Similar to 'ClassDef.fromlineno' + lineno = self.lineno + if self.decorators is not None: + lineno += sum( + node.tolineno - node.lineno + 1 for node in self.decorators.nodes + ) + + return lineno + + @cached_property + def blockstart_tolineno(self): + """The line on which the beginning of this block ends. + + :type: int + """ + return self.args.tolineno + + def implicit_parameters(self) -> Literal[0, 1]: + return 1 if self.is_bound() else 0 + + def block_range(self, lineno): + """Get a range from the given line number to where this node ends. + + :param lineno: Unused. + :type lineno: int + + :returns: The range of line numbers that this node belongs to, + :rtype: tuple(int, int) + """ + return self.fromlineno, self.tolineno + + def igetattr(self, name, context=None): + """Inferred getattr, which returns an iterator of inferred statements.""" + try: + return bases._infer_stmts(self.getattr(name, context), context, frame=self) + except AttributeInferenceError as error: + raise InferenceError( + str(error), target=self, attribute=name, context=context + ) from error + + def is_method(self): + """Check if this function node represents a method. + + :returns: True if this is a method, False otherwise. + :rtype: bool + """ + # check we are defined in a ClassDef, because this is usually expected + # (e.g. pylint...) when is_method() return True + return self.type != "function" and isinstance( + self.parent.frame(future=True), ClassDef + ) + + @decorators_mod.cached + def decoratornames(self, context=None): + """Get the qualified names of each of the decorators on this function. + + :param context: + An inference context that can be passed to inference functions + :returns: The names of the decorators. + :rtype: set(str) + """ + result = set() + decoratornodes = [] + if self.decorators is not None: + decoratornodes += self.decorators.nodes + decoratornodes += self.extra_decorators + for decnode in decoratornodes: + try: + for infnode in decnode.infer(context=context): + result.add(infnode.qname()) + except InferenceError: + continue + return result + + def is_bound(self): + """Check if the function is bound to an instance or class. + + :returns: True if the function is bound to an instance or class, + False otherwise. + :rtype: bool + """ + return self.type in {"method", "classmethod"} + + def is_abstract(self, pass_is_abstract=True, any_raise_is_abstract=False): + """Check if the method is abstract. + + A method is considered abstract if any of the following is true: + * The only statement is 'raise NotImplementedError' + * The only statement is 'raise ' and any_raise_is_abstract is True + * The only statement is 'pass' and pass_is_abstract is True + * The method is annotated with abc.astractproperty/abc.abstractmethod + + :returns: True if the method is abstract, False otherwise. + :rtype: bool + """ + if self.decorators: + for node in self.decorators.nodes: + try: + inferred = next(node.infer()) + except (InferenceError, StopIteration): + continue + if inferred and inferred.qname() in { + "abc.abstractproperty", + "abc.abstractmethod", + }: + return True + + for child_node in self.body: + if isinstance(child_node, node_classes.Raise): + if any_raise_is_abstract: + return True + if child_node.raises_not_implemented(): + return True + return pass_is_abstract and isinstance(child_node, node_classes.Pass) + # empty function is the same as function with a single "pass" statement + if pass_is_abstract: + return True + + def is_generator(self): + """Check if this is a generator function. + + :returns: True is this is a generator function, False otherwise. + :rtype: bool + """ + return bool(next(self._get_yield_nodes_skip_lambdas(), False)) + + def infer_yield_result(self, context=None): + """Infer what the function yields when called + + :returns: What the function yields + :rtype: iterable(NodeNG or Uninferable) or None + """ + # pylint: disable=not-an-iterable + # https://github.com/PyCQA/astroid/issues/1015 + for yield_ in self.nodes_of_class(node_classes.Yield): + if yield_.value is None: + const = node_classes.Const(None) + const.parent = yield_ + const.lineno = yield_.lineno + yield const + elif yield_.scope() == self: + yield from yield_.value.infer(context=context) + + def infer_call_result(self, caller=None, context=None): + """Infer what the function returns when called. + + :returns: What the function returns. + :rtype: iterable(NodeNG or Uninferable) or None + """ + if self.is_generator(): + if isinstance(self, AsyncFunctionDef): + generator_cls = bases.AsyncGenerator + else: + generator_cls = bases.Generator + result = generator_cls(self, generator_initial_context=context) + yield result + return + # This is really a gigantic hack to work around metaclass generators + # that return transient class-generating functions. Pylint's AST structure + # cannot handle a base class object that is only used for calling __new__, + # but does not contribute to the inheritance structure itself. We inject + # a fake class into the hierarchy here for several well-known metaclass + # generators, and filter it out later. + if ( + self.name == "with_metaclass" + and len(self.args.args) == 1 + and self.args.vararg is not None + ): + metaclass = next(caller.args[0].infer(context), None) + if isinstance(metaclass, ClassDef): + try: + class_bases = [next(arg.infer(context)) for arg in caller.args[1:]] + except StopIteration as e: + raise InferenceError(node=caller.args[1:], context=context) from e + new_class = ClassDef(name="temporary_class") + new_class.hide = True + new_class.parent = self + new_class.postinit( + bases=[base for base in class_bases if base != util.Uninferable], + body=[], + decorators=[], + metaclass=metaclass, + ) + yield new_class + return + returns = self._get_return_nodes_skip_functions() + + first_return = next(returns, None) + if not first_return: + if self.body: + if self.is_abstract(pass_is_abstract=True, any_raise_is_abstract=True): + yield util.Uninferable + else: + yield node_classes.Const(None) + return + + raise InferenceError("The function does not have any return statements") + + for returnnode in itertools.chain((first_return,), returns): + if returnnode.value is None: + yield node_classes.Const(None) + else: + try: + yield from returnnode.value.infer(context) + except InferenceError: + yield util.Uninferable + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`FunctionDef` this is always ``True``. + :rtype: bool + """ + return True + + def get_children(self): + if self.decorators is not None: + yield self.decorators + + yield self.args + + if self.returns is not None: + yield self.returns + + yield from self.body + + def scope_lookup(self, node, name, offset=0): + """Lookup where the given name is assigned.""" + if name == "__class__": + # __class__ is an implicit closure reference created by the compiler + # if any methods in a class body refer to either __class__ or super. + # In our case, we want to be able to look it up in the current scope + # when `__class__` is being used. + frame = self.parent.frame(future=True) + if isinstance(frame, ClassDef): + return self, [frame] + return super().scope_lookup(node, name, offset) + + def frame(self: T, *, future: Literal[None, True] = None) -> T: + """The node's frame node. + + A frame node is a :class:`Module`, :class:`FunctionDef`, + :class:`ClassDef` or :class:`Lambda`. + + :returns: The node itself. + """ + return self + + +class AsyncFunctionDef(FunctionDef): + """Class representing an :class:`ast.FunctionDef` node. + + A :class:`AsyncFunctionDef` is an asynchronous function + created with the `async` keyword. + + >>> import astroid + >>> node = astroid.extract_node(''' + async def func(things): + async for thing in things: + print(thing) + ''') + >>> node + + >>> node.body[0] + + """ + + +def _rec_get_names(args, names: Optional[List[str]] = None) -> List[str]: + """return a list of all argument names""" + if names is None: + names = [] + for arg in args: + if isinstance(arg, node_classes.Tuple): + _rec_get_names(arg.elts, names) + else: + names.append(arg.name) + return names + + +def _is_metaclass(klass, seen=None): + """Return if the given class can be + used as a metaclass. + """ + if klass.name == "type": + return True + if seen is None: + seen = set() + for base in klass.bases: + try: + for baseobj in base.infer(): + baseobj_name = baseobj.qname() + if baseobj_name in seen: + continue + + seen.add(baseobj_name) + if isinstance(baseobj, bases.Instance): + # not abstract + return False + if baseobj is util.Uninferable: + continue + if baseobj is klass: + continue + if not isinstance(baseobj, ClassDef): + continue + if baseobj._type == "metaclass": + return True + if _is_metaclass(baseobj, seen): + return True + except InferenceError: + continue + return False + + +def _class_type(klass, ancestors=None): + """return a ClassDef node type to differ metaclass and exception + from 'regular' classes + """ + # XXX we have to store ancestors in case we have an ancestor loop + if klass._type is not None: + return klass._type + if _is_metaclass(klass): + klass._type = "metaclass" + elif klass.name.endswith("Exception"): + klass._type = "exception" + else: + if ancestors is None: + ancestors = set() + klass_name = klass.qname() + if klass_name in ancestors: + # XXX we are in loop ancestors, and have found no type + klass._type = "class" + return "class" + ancestors.add(klass_name) + for base in klass.ancestors(recurs=False): + name = _class_type(base, ancestors) + if name != "class": + if name == "metaclass" and not _is_metaclass(klass): + # don't propagate it if the current class + # can't be a metaclass + continue + klass._type = base.type + break + if klass._type is None: + klass._type = "class" + return klass._type + + +def get_wrapping_class(node): + """Get the class that wraps the given node. + + We consider that a class wraps a node if the class + is a parent for the said node. + + :returns: The class that wraps the given node + :rtype: ClassDef or None + """ + + klass = node.frame(future=True) + while klass is not None and not isinstance(klass, ClassDef): + if klass.parent is None: + klass = None + else: + klass = klass.parent.frame(future=True) + return klass + + +# pylint: disable=too-many-instance-attributes +class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG, node_classes.Statement): + """Class representing an :class:`ast.ClassDef` node. + + >>> import astroid + >>> node = astroid.extract_node(''' + class Thing: + def my_meth(self, arg): + return arg + self.offset + ''') + >>> node + + """ + + # some of the attributes below are set by the builder module or + # by a raw factories + + # a dictionary of class instances attributes + _astroid_fields = ("decorators", "bases", "keywords", "doc_node", "body") # name + + decorators = None + """The decorators that are applied to this class. + + :type: Decorators or None + """ + special_attributes = ClassModel() + """The names of special attributes that this class has. + + :type: objectmodel.ClassModel + """ + + _type = None + _metaclass_hack = False + hide = False + type = property( + _class_type, + doc=( + "The class type for this node.\n\n" + "Possible values are: class, metaclass, exception.\n\n" + ":type: str" + ), + ) + _other_fields = ("name", "doc", "is_dataclass", "position") + _other_other_fields = ("locals", "_newstyle") + _newstyle = None + + @decorators_mod.deprecate_arguments(doc="Use the postinit arg 'doc_node' instead") + def __init__( + self, + name=None, + doc: Optional[str] = None, + lineno=None, + col_offset=None, + parent=None, + *, + end_lineno=None, + end_col_offset=None, + ): + """ + :param name: The name of the class. + :type name: str or None + + :param doc: The class docstring. + + :param lineno: The line that this node appears on in the source code. + :type lineno: int or None + + :param col_offset: The column that this node appears on in the + source code. + :type col_offset: int or None + + :param parent: The parent node in the syntax tree. + :type parent: NodeNG or None + + :param end_lineno: The last line this node appears on in the source code. + :type end_lineno: Optional[int] + + :param end_col_offset: The end column this node appears on in the + source code. Note: This is after the last symbol. + :type end_col_offset: Optional[int] + """ + self.instance_attrs = {} + self.locals = {} + """A map of the name of a local variable to the node defining it. + + :type: dict(str, NodeNG) + """ + + self.keywords = [] + """The keywords given to the class definition. + + This is usually for :pep:`3115` style metaclass declaration. + + :type: list(Keyword) or None + """ + + self.bases = [] + """What the class inherits from. + + :type: list(NodeNG) + """ + + self.body = [] + """The contents of the class body. + + :type: list(NodeNG) + """ + + self.name = name + """The name of the class. + + :type name: str or None + """ + + self._doc = doc + """The class docstring.""" + + self.doc_node: Optional[Const] = None + """The doc node associated with this node.""" + + self.is_dataclass: bool = False + """Whether this class is a dataclass.""" + + super().__init__( + lineno=lineno, + col_offset=col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + if parent is not None: + parent.frame(future=True).set_local(name, self) + + for local_name, node in self.implicit_locals(): + self.add_local_node(node, local_name) + + @property + def doc(self) -> Optional[str]: + """The class docstring.""" + warnings.warn( + "The 'ClassDef.doc' attribute is deprecated, " + "use 'ClassDef.doc_node' instead.", + DeprecationWarning, + ) + return self._doc + + @doc.setter + def doc(self, value: Optional[str]) -> None: + warnings.warn( + "Setting the 'ClassDef.doc' attribute is deprecated, " + "use 'ClassDef.doc_node.value' instead.", + DeprecationWarning, + ) + self._doc = value + + def implicit_parameters(self): + return 1 + + def implicit_locals(self): + """Get implicitly defined class definition locals. + + :returns: the the name and Const pair for each local + :rtype: tuple(tuple(str, node_classes.Const), ...) + """ + locals_ = (("__module__", self.special_attributes.attr___module__),) + # __qualname__ is defined in PEP3155 + locals_ += (("__qualname__", self.special_attributes.attr___qualname__),) + return locals_ + + # pylint: disable=redefined-outer-name + def postinit( + self, + bases, + body, + decorators, + newstyle=None, + metaclass=None, + keywords=None, + *, + position: Optional[Position] = None, + doc_node: Optional[Const] = None, + ): + """Do some setup after initialisation. + + :param bases: What the class inherits from. + :type bases: list(NodeNG) + + :param body: The contents of the class body. + :type body: list(NodeNG) + + :param decorators: The decorators that are applied to this class. + :type decorators: Decorators or None + + :param newstyle: Whether this is a new style class or not. + :type newstyle: bool or None + + :param metaclass: The metaclass of this class. + :type metaclass: NodeNG or None + + :param keywords: The keywords given to the class definition. + :type keywords: list(Keyword) or None + + :param position: Position of class keyword and name. + + :param doc_node: The doc node associated with this node. + """ + if keywords is not None: + self.keywords = keywords + self.bases = bases + self.body = body + self.decorators = decorators + if newstyle is not None: + self._newstyle = newstyle + if metaclass is not None: + self._metaclass = metaclass + self.position = position + self.doc_node = doc_node + if doc_node: + self._doc = doc_node.value + + def _newstyle_impl(self, context=None): + if context is None: + context = InferenceContext() + if self._newstyle is not None: + return self._newstyle + for base in self.ancestors(recurs=False, context=context): + if base._newstyle_impl(context): + self._newstyle = True + break + klass = self.declared_metaclass() + # could be any callable, we'd need to infer the result of klass(name, + # bases, dict). punt if it's not a class node. + if klass is not None and isinstance(klass, ClassDef): + self._newstyle = klass._newstyle_impl(context) + if self._newstyle is None: + self._newstyle = False + return self._newstyle + + _newstyle = None + newstyle = property( + _newstyle_impl, + doc=("Whether this is a new style class or not\n\n" ":type: bool or None"), + ) + + @cached_property + def fromlineno(self) -> Optional[int]: + """The first line that this node appears on in the source code.""" + if not PY38_PLUS or PY38 and IS_PYPY: + # For Python < 3.8 the lineno is the line number of the first decorator. + # We want the class statement lineno. Similar to 'FunctionDef.fromlineno' + lineno = self.lineno + if self.decorators is not None: + lineno += sum( + node.tolineno - node.lineno + 1 for node in self.decorators.nodes + ) + + return lineno + return super().fromlineno + + @cached_property + def blockstart_tolineno(self): + """The line on which the beginning of this block ends. + + :type: int + """ + if self.bases: + return self.bases[-1].tolineno + + return self.fromlineno + + def block_range(self, lineno): + """Get a range from the given line number to where this node ends. + + :param lineno: Unused. + :type lineno: int + + :returns: The range of line numbers that this node belongs to, + :rtype: tuple(int, int) + """ + return self.fromlineno, self.tolineno + + def pytype(self): + """Get the name of the type that this node represents. + + :returns: The name of the type. + :rtype: str + """ + if self.newstyle: + return "builtins.type" + return "builtins.classobj" + + def display_type(self): + """A human readable type of this node. + + :returns: The type of this node. + :rtype: str + """ + return "Class" + + def callable(self): + """Whether this node defines something that is callable. + + :returns: True if this defines something that is callable, + False otherwise. + For a :class:`ClassDef` this is always ``True``. + :rtype: bool + """ + return True + + def is_subtype_of(self, type_name, context=None): + """Whether this class is a subtype of the given type. + + :param type_name: The name of the type of check against. + :type type_name: str + + :returns: True if this class is a subtype of the given type, + False otherwise. + :rtype: bool + """ + if self.qname() == type_name: + return True + + return any(anc.qname() == type_name for anc in self.ancestors(context=context)) + + def _infer_type_call(self, caller, context): + try: + name_node = next(caller.args[0].infer(context)) + except StopIteration as e: + raise InferenceError(node=caller.args[0], context=context) from e + if isinstance(name_node, node_classes.Const) and isinstance( + name_node.value, str + ): + name = name_node.value + else: + return util.Uninferable + + result = ClassDef(name) + + # Get the bases of the class. + try: + class_bases = next(caller.args[1].infer(context)) + except StopIteration as e: + raise InferenceError(node=caller.args[1], context=context) from e + if isinstance(class_bases, (node_classes.Tuple, node_classes.List)): + bases = [] + for base in class_bases.itered(): + inferred = next(base.infer(context=context), None) + if inferred: + bases.append( + node_classes.EvaluatedObject(original=base, value=inferred) + ) + result.bases = bases + else: + # There is currently no AST node that can represent an 'unknown' + # node (Uninferable is not an AST node), therefore we simply return Uninferable here + # although we know at least the name of the class. + return util.Uninferable + + # Get the members of the class + try: + members = next(caller.args[2].infer(context)) + except (InferenceError, StopIteration): + members = None + + if members and isinstance(members, node_classes.Dict): + for attr, value in members.items: + if isinstance(attr, node_classes.Const) and isinstance(attr.value, str): + result.locals[attr.value] = [value] + + result.parent = caller.parent + return result + + def infer_call_result(self, caller, context=None): + """infer what a class is returning when called""" + if self.is_subtype_of("builtins.type", context) and len(caller.args) == 3: + result = self._infer_type_call(caller, context) + yield result + return + + dunder_call = None + try: + metaclass = self.metaclass(context=context) + if metaclass is not None: + dunder_call = next(metaclass.igetattr("__call__", context)) + except (AttributeInferenceError, StopIteration): + pass + + if dunder_call and dunder_call.qname() != "builtins.type.__call__": + # Call type.__call__ if not set metaclass + # (since type is the default metaclass) + context = bind_context_to_node(context, self) + context.callcontext.callee = dunder_call + yield from dunder_call.infer_call_result(caller, context) + else: + yield self.instantiate_class() + + def scope_lookup(self, node, name, offset=0): + """Lookup where the given name is assigned. + + :param node: The node to look for assignments up to. + Any assignments after the given node are ignored. + :type node: NodeNG + + :param name: The name to find assignments for. + :type name: str + + :param offset: The line offset to filter statements up to. + :type offset: int + + :returns: This scope node and the list of assignments associated to the + given name according to the scope where it has been found (locals, + globals or builtin). + :rtype: tuple(str, list(NodeNG)) + """ + # If the name looks like a builtin name, just try to look + # into the upper scope of this class. We might have a + # decorator that it's poorly named after a builtin object + # inside this class. + lookup_upper_frame = ( + isinstance(node.parent, node_classes.Decorators) + and name in AstroidManager().builtins_module + ) + if ( + any(node == base or base.parent_of(node) for base in self.bases) + or lookup_upper_frame + ): + # Handle the case where we have either a name + # in the bases of a class, which exists before + # the actual definition or the case where we have + # a Getattr node, with that name. + # + # name = ... + # class A(name): + # def name(self): ... + # + # import name + # class A(name.Name): + # def name(self): ... + + frame = self.parent.frame(future=True) + # line offset to avoid that class A(A) resolve the ancestor to + # the defined class + offset = -1 + else: + frame = self + return frame._scope_lookup(node, name, offset) + + @property + def basenames(self): + """The names of the parent classes + + Names are given in the order they appear in the class definition. + + :type: list(str) + """ + return [bnode.as_string() for bnode in self.bases] + + def ancestors(self, recurs=True, context=None): + """Iterate over the base classes in prefixed depth first order. + + :param recurs: Whether to recurse or return direct ancestors only. + :type recurs: bool + + :returns: The base classes + :rtype: iterable(NodeNG) + """ + # FIXME: should be possible to choose the resolution order + # FIXME: inference make infinite loops possible here + yielded = {self} + if context is None: + context = InferenceContext() + if not self.bases and self.qname() != "builtins.object": + yield builtin_lookup("object")[1][0] + return + + for stmt in self.bases: + with context.restore_path(): + try: + for baseobj in stmt.infer(context): + if not isinstance(baseobj, ClassDef): + if isinstance(baseobj, bases.Instance): + baseobj = baseobj._proxied + else: + continue + if not baseobj.hide: + if baseobj in yielded: + continue + yielded.add(baseobj) + yield baseobj + if not recurs: + continue + for grandpa in baseobj.ancestors(recurs=True, context=context): + if grandpa is self: + # This class is the ancestor of itself. + break + if grandpa in yielded: + continue + yielded.add(grandpa) + yield grandpa + except InferenceError: + continue + + def local_attr_ancestors(self, name, context=None): + """Iterate over the parents that define the given name. + + :param name: The name to find definitions for. + :type name: str + + :returns: The parents that define the given name. + :rtype: iterable(NodeNG) + """ + # Look up in the mro if we can. This will result in the + # attribute being looked up just as Python does it. + try: + ancestors = self.mro(context)[1:] + except MroError: + # Fallback to use ancestors, we can't determine + # a sane MRO. + ancestors = self.ancestors(context=context) + for astroid in ancestors: + if name in astroid: + yield astroid + + def instance_attr_ancestors(self, name, context=None): + """Iterate over the parents that define the given name as an attribute. + + :param name: The name to find definitions for. + :type name: str + + :returns: The parents that define the given name as + an instance attribute. + :rtype: iterable(NodeNG) + """ + for astroid in self.ancestors(context=context): + if name in astroid.instance_attrs: + yield astroid + + def has_base(self, node): + """Whether this class directly inherits from the given node. + + :param node: The node to check for. + :type node: NodeNG + + :returns: True if this class directly inherits from the given node. + :rtype: bool + """ + return node in self.bases + + def local_attr(self, name, context=None): + """Get the list of assign nodes associated to the given name. + + Assignments are looked for in both this class and in parents. + + :returns: The list of assignments to the given name. + :rtype: list(NodeNG) + + :raises AttributeInferenceError: If no attribute with this name + can be found in this class or parent classes. + """ + result = [] + if name in self.locals: + result = self.locals[name] + else: + class_node = next(self.local_attr_ancestors(name, context), None) + if class_node: + result = class_node.locals[name] + result = [n for n in result if not isinstance(n, node_classes.DelAttr)] + if result: + return result + raise AttributeInferenceError(target=self, attribute=name, context=context) + + def instance_attr(self, name, context=None): + """Get the list of nodes associated to the given attribute name. + + Assignments are looked for in both this class and in parents. + + :returns: The list of assignments to the given name. + :rtype: list(NodeNG) + + :raises AttributeInferenceError: If no attribute with this name + can be found in this class or parent classes. + """ + # Return a copy, so we don't modify self.instance_attrs, + # which could lead to infinite loop. + values = list(self.instance_attrs.get(name, [])) + # get all values from parents + for class_node in self.instance_attr_ancestors(name, context): + values += class_node.instance_attrs[name] + values = [n for n in values if not isinstance(n, node_classes.DelAttr)] + if values: + return values + raise AttributeInferenceError(target=self, attribute=name, context=context) + + def instantiate_class(self): + """Get an :class:`Instance` of the :class:`ClassDef` node. + + :returns: An :class:`Instance` of the :class:`ClassDef` node, + or self if this is not possible. + :rtype: Instance or ClassDef + """ + try: + if any(cls.name in EXCEPTION_BASE_CLASSES for cls in self.mro()): + # Subclasses of exceptions can be exception instances + return objects.ExceptionInstance(self) + except MroError: + pass + return bases.Instance(self) + + def getattr(self, name, context=None, class_context=True): + """Get an attribute from this class, using Python's attribute semantic. + + This method doesn't look in the :attr:`instance_attrs` dictionary + since it is done by an :class:`Instance` proxy at inference time. + It may return an :class:`Uninferable` object if + the attribute has not been + found, but a ``__getattr__`` or ``__getattribute__`` method is defined. + If ``class_context`` is given, then it is considered that the + attribute is accessed from a class context, + e.g. ClassDef.attribute, otherwise it might have been accessed + from an instance as well. If ``class_context`` is used in that + case, then a lookup in the implicit metaclass and the explicit + metaclass will be done. + + :param name: The attribute to look for. + :type name: str + + :param class_context: Whether the attribute can be accessed statically. + :type class_context: bool + + :returns: The attribute. + :rtype: list(NodeNG) + + :raises AttributeInferenceError: If the attribute cannot be inferred. + """ + if not name: + raise AttributeInferenceError(target=self, attribute=name, context=context) + + values = self.locals.get(name, []) + if name in self.special_attributes and class_context and not values: + result = [self.special_attributes.lookup(name)] + if name == "__bases__": + # Need special treatment, since they are mutable + # and we need to return all the values. + result += values + return result + + # don't modify the list in self.locals! + values = list(values) + for classnode in self.ancestors(recurs=True, context=context): + values += classnode.locals.get(name, []) + + if class_context: + values += self._metaclass_lookup_attribute(name, context) + + if not values: + raise AttributeInferenceError(target=self, attribute=name, context=context) + + # Look for AnnAssigns, which are not attributes in the purest sense. + for value in values: + if isinstance(value, node_classes.AssignName): + stmt = value.statement(future=True) + if isinstance(stmt, node_classes.AnnAssign) and stmt.value is None: + raise AttributeInferenceError( + target=self, attribute=name, context=context + ) + return values + + def _metaclass_lookup_attribute(self, name, context): + """Search the given name in the implicit and the explicit metaclass.""" + attrs = set() + implicit_meta = self.implicit_metaclass() + context = copy_context(context) + metaclass = self.metaclass(context=context) + for cls in (implicit_meta, metaclass): + if cls and cls != self and isinstance(cls, ClassDef): + cls_attributes = self._get_attribute_from_metaclass(cls, name, context) + attrs.update(set(cls_attributes)) + return attrs + + def _get_attribute_from_metaclass(self, cls, name, context): + try: + attrs = cls.getattr(name, context=context, class_context=True) + except AttributeInferenceError: + return + + for attr in bases._infer_stmts(attrs, context, frame=cls): + if not isinstance(attr, FunctionDef): + yield attr + continue + + if isinstance(attr, objects.Property): + yield attr + continue + if attr.type == "classmethod": + # If the method is a classmethod, then it will + # be bound to the metaclass, not to the class + # from where the attribute is retrieved. + # get_wrapping_class could return None, so just + # default to the current class. + frame = get_wrapping_class(attr) or self + yield bases.BoundMethod(attr, frame) + elif attr.type == "staticmethod": + yield attr + else: + yield bases.BoundMethod(attr, self) + + def igetattr(self, name, context=None, class_context=True): + """Infer the possible values of the given variable. + + :param name: The name of the variable to infer. + :type name: str + + :returns: The inferred possible values. + :rtype: iterable(NodeNG or Uninferable) + """ + # set lookup name since this is necessary to infer on import nodes for + # instance + context = copy_context(context) + context.lookupname = name + + metaclass = self.metaclass(context=context) + try: + attributes = self.getattr(name, context, class_context=class_context) + # If we have more than one attribute, make sure that those starting from + # the second one are from the same scope. This is to account for modifications + # to the attribute happening *after* the attribute's definition (e.g. AugAssigns on lists) + if len(attributes) > 1: + first_attr, attributes = attributes[0], attributes[1:] + first_scope = first_attr.scope() + attributes = [first_attr] + [ + attr + for attr in attributes + if attr.parent and attr.parent.scope() == first_scope + ] + + for inferred in bases._infer_stmts(attributes, context, frame=self): + # yield Uninferable object instead of descriptors when necessary + if not isinstance(inferred, node_classes.Const) and isinstance( + inferred, bases.Instance + ): + try: + inferred._proxied.getattr("__get__", context) + except AttributeInferenceError: + yield inferred + else: + yield util.Uninferable + elif isinstance(inferred, objects.Property): + function = inferred.function + if not class_context: + # Through an instance so we can solve the property + yield from function.infer_call_result( + caller=self, context=context + ) + # If we're in a class context, we need to determine if the property + # was defined in the metaclass (a derived class must be a subclass of + # the metaclass of all its bases), in which case we can resolve the + # property. If not, i.e. the property is defined in some base class + # instead, then we return the property object + elif metaclass and function.parent.scope() is metaclass: + # Resolve a property as long as it is not accessed through + # the class itself. + yield from function.infer_call_result( + caller=self, context=context + ) + else: + yield inferred + else: + yield function_to_method(inferred, self) + except AttributeInferenceError as error: + if not name.startswith("__") and self.has_dynamic_getattr(context): + # class handle some dynamic attributes, return a Uninferable object + yield util.Uninferable + else: + raise InferenceError( + str(error), target=self, attribute=name, context=context + ) from error + + def has_dynamic_getattr(self, context=None): + """Check if the class has a custom __getattr__ or __getattribute__. + + If any such method is found and it is not from + builtins, nor from an extension module, then the function + will return True. + + :returns: True if the class has a custom + __getattr__ or __getattribute__, False otherwise. + :rtype: bool + """ + + def _valid_getattr(node): + root = node.root() + return root.name != "builtins" and getattr(root, "pure_python", None) + + try: + return _valid_getattr(self.getattr("__getattr__", context)[0]) + except AttributeInferenceError: + # if self.newstyle: XXX cause an infinite recursion error + try: + getattribute = self.getattr("__getattribute__", context)[0] + return _valid_getattr(getattribute) + except AttributeInferenceError: + pass + return False + + def getitem(self, index, context=None): + """Return the inference of a subscript. + + This is basically looking up the method in the metaclass and calling it. + + :returns: The inferred value of a subscript to this class. + :rtype: NodeNG + + :raises AstroidTypeError: If this class does not define a + ``__getitem__`` method. + """ + try: + methods = lookup(self, "__getitem__") + except AttributeInferenceError as exc: + if isinstance(self, ClassDef): + # subscripting a class definition may be + # achieved thanks to __class_getitem__ method + # which is a classmethod defined in the class + # that supports subscript and not in the metaclass + try: + methods = self.getattr("__class_getitem__") + # Here it is assumed that the __class_getitem__ node is + # a FunctionDef. One possible improvement would be to deal + # with more generic inference. + except AttributeInferenceError: + raise AstroidTypeError(node=self, context=context) from exc + else: + raise AstroidTypeError(node=self, context=context) from exc + + method = methods[0] + + # Create a new callcontext for providing index as an argument. + new_context = bind_context_to_node(context, self) + new_context.callcontext = CallContext(args=[index], callee=method) + + try: + return next(method.infer_call_result(self, new_context), util.Uninferable) + except AttributeError: + # Starting with python3.9, builtin types list, dict etc... + # are subscriptable thanks to __class_getitem___ classmethod. + # However in such case the method is bound to an EmptyNode and + # EmptyNode doesn't have infer_call_result method yielding to + # AttributeError + if ( + isinstance(method, node_classes.EmptyNode) + and self.name in {"list", "dict", "set", "tuple", "frozenset"} + and PY39_PLUS + ): + return self + raise + except InferenceError: + return util.Uninferable + + def methods(self): + """Iterate over all of the method defined in this class and its parents. + + :returns: The methods defined on the class. + :rtype: iterable(FunctionDef) + """ + done = {} + for astroid in itertools.chain(iter((self,)), self.ancestors()): + for meth in astroid.mymethods(): + if meth.name in done: + continue + done[meth.name] = None + yield meth + + def mymethods(self): + """Iterate over all of the method defined in this class only. + + :returns: The methods defined on the class. + :rtype: iterable(FunctionDef) + """ + for member in self.values(): + if isinstance(member, FunctionDef): + yield member + + def implicit_metaclass(self): + """Get the implicit metaclass of the current class. + + For newstyle classes, this will return an instance of builtins.type. + For oldstyle classes, it will simply return None, since there's + no implicit metaclass there. + + :returns: The metaclass. + :rtype: builtins.type or None + """ + if self.newstyle: + return builtin_lookup("type")[1][0] + return None + + _metaclass = None + + def declared_metaclass(self, context=None): + """Return the explicit declared metaclass for the current class. + + An explicit declared metaclass is defined + either by passing the ``metaclass`` keyword argument + in the class definition line (Python 3) or (Python 2) by + having a ``__metaclass__`` class attribute, or if there are + no explicit bases but there is a global ``__metaclass__`` variable. + + :returns: The metaclass of this class, + or None if one could not be found. + :rtype: NodeNG or None + """ + for base in self.bases: + try: + for baseobj in base.infer(context=context): + if isinstance(baseobj, ClassDef) and baseobj.hide: + self._metaclass = baseobj._metaclass + self._metaclass_hack = True + break + except InferenceError: + pass + + if self._metaclass: + # Expects this from Py3k TreeRebuilder + try: + return next( + node + for node in self._metaclass.infer(context=context) + if node is not util.Uninferable + ) + except (InferenceError, StopIteration): + return None + + return None + + def _find_metaclass(self, seen=None, context=None): + if seen is None: + seen = set() + seen.add(self) + + klass = self.declared_metaclass(context=context) + if klass is None: + for parent in self.ancestors(context=context): + if parent not in seen: + klass = parent._find_metaclass(seen) + if klass is not None: + break + return klass + + def metaclass(self, context=None): + """Get the metaclass of this class. + + If this class does not define explicitly a metaclass, + then the first defined metaclass in ancestors will be used + instead. + + :returns: The metaclass of this class. + :rtype: NodeNG or None + """ + return self._find_metaclass(context=context) + + def has_metaclass_hack(self): + return self._metaclass_hack + + def _islots(self): + """Return an iterator with the inferred slots.""" + if "__slots__" not in self.locals: + return None + for slots in self.igetattr("__slots__"): + # check if __slots__ is a valid type + for meth in ITER_METHODS: + try: + slots.getattr(meth) + break + except AttributeInferenceError: + continue + else: + continue + + if isinstance(slots, node_classes.Const): + # a string. Ignore the following checks, + # but yield the node, only if it has a value + if slots.value: + yield slots + continue + if not hasattr(slots, "itered"): + # we can't obtain the values, maybe a .deque? + continue + + if isinstance(slots, node_classes.Dict): + values = [item[0] for item in slots.items] + else: + values = slots.itered() + if values is util.Uninferable: + continue + if not values: + # Stop the iteration, because the class + # has an empty list of slots. + return values + + for elt in values: + try: + for inferred in elt.infer(): + if inferred is util.Uninferable: + continue + if not isinstance( + inferred, node_classes.Const + ) or not isinstance(inferred.value, str): + continue + if not inferred.value: + continue + yield inferred + except InferenceError: + continue + + return None + + def _slots(self): + if not self.newstyle: + raise NotImplementedError( + "The concept of slots is undefined for old-style classes." + ) + + slots = self._islots() + try: + first = next(slots) + except StopIteration as exc: + # The class doesn't have a __slots__ definition or empty slots. + if exc.args and exc.args[0] not in ("", None): + return exc.args[0] + return None + return [first] + list(slots) + + # Cached, because inferring them all the time is expensive + @decorators_mod.cached + def slots(self): + """Get all the slots for this node. + + :returns: The names of slots for this class. + If the class doesn't define any slot, through the ``__slots__`` + variable, then this function will return a None. + Also, it will return None in the case the slots were not inferred. + :rtype: list(str) or None + """ + + def grouped_slots( + mro: List["ClassDef"], + ) -> typing.Iterator[Optional[node_classes.NodeNG]]: + # Not interested in object, since it can't have slots. + for cls in mro[:-1]: + try: + cls_slots = cls._slots() + except NotImplementedError: + continue + if cls_slots is not None: + yield from cls_slots + else: + yield None + + if not self.newstyle: + raise NotImplementedError( + "The concept of slots is undefined for old-style classes." + ) + + try: + mro = self.mro() + except MroError as e: + raise NotImplementedError( + "Cannot get slots while parsing mro fails." + ) from e + + slots = list(grouped_slots(mro)) + if not all(slot is not None for slot in slots): + return None + + return sorted(set(slots), key=lambda item: item.value) + + def _inferred_bases(self, context=None): + # Similar with .ancestors, but the difference is when one base is inferred, + # only the first object is wanted. That's because + # we aren't interested in superclasses, as in the following + # example: + # + # class SomeSuperClass(object): pass + # class SomeClass(SomeSuperClass): pass + # class Test(SomeClass): pass + # + # Inferring SomeClass from the Test's bases will give + # us both SomeClass and SomeSuperClass, but we are interested + # only in SomeClass. + + if context is None: + context = InferenceContext() + if not self.bases and self.qname() != "builtins.object": + yield builtin_lookup("object")[1][0] + return + + for stmt in self.bases: + try: + # Find the first non-None inferred base value + baseobj = next( + b + for b in stmt.infer(context=context.clone()) + if not (isinstance(b, Const) and b.value is None) + ) + except (InferenceError, StopIteration): + continue + if isinstance(baseobj, bases.Instance): + baseobj = baseobj._proxied + if not isinstance(baseobj, ClassDef): + continue + if not baseobj.hide: + yield baseobj + else: + yield from baseobj.bases + + def _compute_mro(self, context=None): + inferred_bases = list(self._inferred_bases(context=context)) + bases_mro = [] + for base in inferred_bases: + if base is self: + continue + + try: + mro = base._compute_mro(context=context) + bases_mro.append(mro) + except NotImplementedError: + # Some classes have in their ancestors both newstyle and + # old style classes. For these we can't retrieve the .mro, + # although in Python it's possible, since the class we are + # currently working is in fact new style. + # So, we fallback to ancestors here. + ancestors = list(base.ancestors(context=context)) + bases_mro.append(ancestors) + + unmerged_mro = [[self]] + bases_mro + [inferred_bases] + unmerged_mro = list(clean_duplicates_mro(unmerged_mro, self, context)) + clean_typing_generic_mro(unmerged_mro) + return _c3_merge(unmerged_mro, self, context) + + def mro(self, context=None) -> List["ClassDef"]: + """Get the method resolution order, using C3 linearization. + + :returns: The list of ancestors, sorted by the mro. + :rtype: list(NodeNG) + :raises DuplicateBasesError: Duplicate bases in the same class base + :raises InconsistentMroError: A class' MRO is inconsistent + """ + return self._compute_mro(context=context) + + def bool_value(self, context=None): + """Determine the boolean value of this node. + + :returns: The boolean value of this node. + For a :class:`ClassDef` this is always ``True``. + :rtype: bool + """ + return True + + def get_children(self): + if self.decorators is not None: + yield self.decorators + + yield from self.bases + if self.keywords is not None: + yield from self.keywords + yield from self.body + + @decorators_mod.cached + def _get_assign_nodes(self): + children_assign_nodes = ( + child_node._get_assign_nodes() for child_node in self.body + ) + return list(itertools.chain.from_iterable(children_assign_nodes)) + + def frame(self: T, *, future: Literal[None, True] = None) -> T: + """The node's frame node. + + A frame node is a :class:`Module`, :class:`FunctionDef`, + :class:`ClassDef` or :class:`Lambda`. + + :returns: The node itself. + """ + return self diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/utils.py b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/utils.py new file mode 100644 index 0000000..272bdad --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/scoped_nodes/utils.py @@ -0,0 +1,36 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +This module contains utility functions for scoped nodes. +""" + +import builtins +from typing import TYPE_CHECKING, Sequence, Tuple + +from astroid.manager import AstroidManager + +if TYPE_CHECKING: + from astroid import nodes + + +_builtin_astroid: "nodes.Module | None" = None + + +def builtin_lookup(name: str) -> Tuple["nodes.Module", Sequence["nodes.NodeNG"]]: + """Lookup a name in the builtin module. + + Return the list of matching statements and the ast for the builtin module + """ + # pylint: disable-next=global-statement + global _builtin_astroid + if _builtin_astroid is None: + _builtin_astroid = AstroidManager().ast_from_module(builtins) + if name == "__dict__": + return _builtin_astroid, () + try: + stmts: Sequence["nodes.NodeNG"] = _builtin_astroid.locals[name] + except KeyError: + stmts = () + return _builtin_astroid, stmts diff --git a/myenv/lib/python3.9/site-packages/astroid/nodes/utils.py b/myenv/lib/python3.9/site-packages/astroid/nodes/utils.py new file mode 100644 index 0000000..5afa718 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/nodes/utils.py @@ -0,0 +1,14 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +from typing import NamedTuple + + +class Position(NamedTuple): + """Position with line and column information.""" + + lineno: int + col_offset: int + end_lineno: int + end_col_offset: int diff --git a/myenv/lib/python3.9/site-packages/astroid/objects.py b/myenv/lib/python3.9/site-packages/astroid/objects.py new file mode 100644 index 0000000..416602e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/objects.py @@ -0,0 +1,329 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +""" +Inference objects are a way to represent composite AST nodes, +which are used only as inference results, so they can't be found in the +original AST tree. For instance, inferring the following frozenset use, +leads to an inferred FrozenSet: + + Call(func=Name('frozenset'), args=Tuple(...)) +""" + +import sys +from typing import TYPE_CHECKING + +from astroid import bases, decorators, util +from astroid.exceptions import ( + AttributeInferenceError, + InferenceError, + MroError, + SuperError, +) +from astroid.manager import AstroidManager +from astroid.nodes import node_classes, scoped_nodes + +objectmodel = util.lazy_import("interpreter.objectmodel") + +if sys.version_info >= (3, 8) or TYPE_CHECKING: + from functools import cached_property +else: + from astroid.decorators import cachedproperty as cached_property + + +class FrozenSet(node_classes.BaseContainer): + """class representing a FrozenSet composite node""" + + def pytype(self): + return "builtins.frozenset" + + def _infer(self, context=None): + yield self + + @cached_property + def _proxied(self): # pylint: disable=method-hidden + ast_builtins = AstroidManager().builtins_module + return ast_builtins.getattr("frozenset")[0] + + +class Super(node_classes.NodeNG): + """Proxy class over a super call. + + This class offers almost the same behaviour as Python's super, + which is MRO lookups for retrieving attributes from the parents. + + The *mro_pointer* is the place in the MRO from where we should + start looking, not counting it. *mro_type* is the object which + provides the MRO, it can be both a type or an instance. + *self_class* is the class where the super call is, while + *scope* is the function where the super call is. + """ + + # pylint: disable=unnecessary-lambda + special_attributes = util.lazy_descriptor(lambda: objectmodel.SuperModel()) + + def __init__(self, mro_pointer, mro_type, self_class, scope): + self.type = mro_type + self.mro_pointer = mro_pointer + self._class_based = False + self._self_class = self_class + self._scope = scope + super().__init__() + + def _infer(self, context=None): + yield self + + def super_mro(self): + """Get the MRO which will be used to lookup attributes in this super.""" + if not isinstance(self.mro_pointer, scoped_nodes.ClassDef): + raise SuperError( + "The first argument to super must be a subtype of " + "type, not {mro_pointer}.", + super_=self, + ) + + if isinstance(self.type, scoped_nodes.ClassDef): + # `super(type, type)`, most likely in a class method. + self._class_based = True + mro_type = self.type + else: + mro_type = getattr(self.type, "_proxied", None) + if not isinstance(mro_type, (bases.Instance, scoped_nodes.ClassDef)): + raise SuperError( + "The second argument to super must be an " + "instance or subtype of type, not {type}.", + super_=self, + ) + + if not mro_type.newstyle: + raise SuperError("Unable to call super on old-style classes.", super_=self) + + mro = mro_type.mro() + if self.mro_pointer not in mro: + raise SuperError( + "The second argument to super must be an " + "instance or subtype of type, not {type}.", + super_=self, + ) + + index = mro.index(self.mro_pointer) + return mro[index + 1 :] + + @cached_property + def _proxied(self): + ast_builtins = AstroidManager().builtins_module + return ast_builtins.getattr("super")[0] + + def pytype(self): + return "builtins.super" + + def display_type(self): + return "Super of" + + @property + def name(self): + """Get the name of the MRO pointer.""" + return self.mro_pointer.name + + def qname(self): + return "super" + + def igetattr(self, name, context=None): + """Retrieve the inferred values of the given attribute name.""" + + if name in self.special_attributes: + yield self.special_attributes.lookup(name) + return + + try: + mro = self.super_mro() + # Don't let invalid MROs or invalid super calls + # leak out as is from this function. + except SuperError as exc: + raise AttributeInferenceError( + ( + "Lookup for {name} on {target!r} because super call {super!r} " + "is invalid." + ), + target=self, + attribute=name, + context=context, + super_=exc.super_, + ) from exc + except MroError as exc: + raise AttributeInferenceError( + ( + "Lookup for {name} on {target!r} failed because {cls!r} has an " + "invalid MRO." + ), + target=self, + attribute=name, + context=context, + mros=exc.mros, + cls=exc.cls, + ) from exc + found = False + for cls in mro: + if name not in cls.locals: + continue + + found = True + for inferred in bases._infer_stmts([cls[name]], context, frame=self): + if not isinstance(inferred, scoped_nodes.FunctionDef): + yield inferred + continue + + # We can obtain different descriptors from a super depending + # on what we are accessing and where the super call is. + if inferred.type == "classmethod": + yield bases.BoundMethod(inferred, cls) + elif self._scope.type == "classmethod" and inferred.type == "method": + yield inferred + elif self._class_based or inferred.type == "staticmethod": + yield inferred + elif isinstance(inferred, Property): + function = inferred.function + try: + yield from function.infer_call_result( + caller=self, context=context + ) + except InferenceError: + yield util.Uninferable + elif bases._is_property(inferred): + # TODO: support other descriptors as well. + try: + yield from inferred.infer_call_result(self, context) + except InferenceError: + yield util.Uninferable + else: + yield bases.BoundMethod(inferred, cls) + + if not found: + raise AttributeInferenceError(target=self, attribute=name, context=context) + + def getattr(self, name, context=None): + return list(self.igetattr(name, context=context)) + + +class ExceptionInstance(bases.Instance): + """Class for instances of exceptions + + It has special treatment for some of the exceptions's attributes, + which are transformed at runtime into certain concrete objects, such as + the case of .args. + """ + + @cached_property + def special_attributes(self): + qname = self.qname() + instance = objectmodel.BUILTIN_EXCEPTIONS.get( + qname, objectmodel.ExceptionInstanceModel + ) + return instance()(self) + + +class DictInstance(bases.Instance): + """Special kind of instances for dictionaries + + This instance knows the underlying object model of the dictionaries, which means + that methods such as .values or .items can be properly inferred. + """ + + # pylint: disable=unnecessary-lambda + special_attributes = util.lazy_descriptor(lambda: objectmodel.DictModel()) + + +# Custom objects tailored for dictionaries, which are used to +# disambiguate between the types of Python 2 dict's method returns +# and Python 3 (where they return set like objects). +class DictItems(bases.Proxy): + __str__ = node_classes.NodeNG.__str__ + __repr__ = node_classes.NodeNG.__repr__ + + +class DictKeys(bases.Proxy): + __str__ = node_classes.NodeNG.__str__ + __repr__ = node_classes.NodeNG.__repr__ + + +class DictValues(bases.Proxy): + __str__ = node_classes.NodeNG.__str__ + __repr__ = node_classes.NodeNG.__repr__ + + +class PartialFunction(scoped_nodes.FunctionDef): + """A class representing partial function obtained via functools.partial""" + + @decorators.deprecate_arguments(doc="Use the postinit arg 'doc_node' instead") + def __init__( + self, call, name=None, doc=None, lineno=None, col_offset=None, parent=None + ): + # TODO: Pass end_lineno and end_col_offset as well + super().__init__(name, lineno=lineno, col_offset=col_offset, parent=None) + # Assigned directly to prevent triggering the DeprecationWarning. + self._doc = doc + # A typical FunctionDef automatically adds its name to the parent scope, + # but a partial should not, so defer setting parent until after init + self.parent = parent + self.filled_args = call.positional_arguments[1:] + self.filled_keywords = call.keyword_arguments + + wrapped_function = call.positional_arguments[0] + inferred_wrapped_function = next(wrapped_function.infer()) + if isinstance(inferred_wrapped_function, PartialFunction): + self.filled_args = inferred_wrapped_function.filled_args + self.filled_args + self.filled_keywords = { + **inferred_wrapped_function.filled_keywords, + **self.filled_keywords, + } + + self.filled_positionals = len(self.filled_args) + + def infer_call_result(self, caller=None, context=None): + if context: + current_passed_keywords = { + keyword for (keyword, _) in context.callcontext.keywords + } + for keyword, value in self.filled_keywords.items(): + if keyword not in current_passed_keywords: + context.callcontext.keywords.append((keyword, value)) + + call_context_args = context.callcontext.args or [] + context.callcontext.args = self.filled_args + call_context_args + + return super().infer_call_result(caller=caller, context=context) + + def qname(self): + return self.__class__.__name__ + + +# TODO: Hack to solve the circular import problem between node_classes and objects +# This is not needed in 2.0, which has a cleaner design overall +node_classes.Dict.__bases__ = (node_classes.NodeNG, DictInstance) + + +class Property(scoped_nodes.FunctionDef): + """Class representing a Python property""" + + @decorators.deprecate_arguments(doc="Use the postinit arg 'doc_node' instead") + def __init__( + self, function, name=None, doc=None, lineno=None, col_offset=None, parent=None + ): + self.function = function + super().__init__(name, lineno=lineno, col_offset=col_offset, parent=parent) + # Assigned directly to prevent triggering the DeprecationWarning. + self._doc = doc + + # pylint: disable=unnecessary-lambda + special_attributes = util.lazy_descriptor(lambda: objectmodel.PropertyModel()) + type = "property" + + def pytype(self): + return "builtins.property" + + def infer_call_result(self, caller=None, context=None): + raise InferenceError("Properties are not callable") + + def infer(self, context=None, **kwargs): + return iter((self,)) diff --git a/myenv/lib/python3.9/site-packages/astroid/protocols.py b/myenv/lib/python3.9/site-packages/astroid/protocols.py new file mode 100644 index 0000000..f1fcec0 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/protocols.py @@ -0,0 +1,894 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""this module contains a set of functions to handle python protocols for nodes +where it makes sense. +""" + +import collections +import itertools +import operator as operator_mod +from typing import Any, Generator, List, Optional, Union + +from astroid import arguments, bases, decorators, helpers, nodes, util +from astroid.const import Context +from astroid.context import InferenceContext, copy_context +from astroid.exceptions import ( + AstroidIndexError, + AstroidTypeError, + AttributeInferenceError, + InferenceError, + NoDefault, +) +from astroid.nodes import node_classes + +raw_building = util.lazy_import("raw_building") +objects = util.lazy_import("objects") + + +def _reflected_name(name): + return "__r" + name[2:] + + +def _augmented_name(name): + return "__i" + name[2:] + + +_CONTEXTLIB_MGR = "contextlib.contextmanager" +BIN_OP_METHOD = { + "+": "__add__", + "-": "__sub__", + "/": "__truediv__", + "//": "__floordiv__", + "*": "__mul__", + "**": "__pow__", + "%": "__mod__", + "&": "__and__", + "|": "__or__", + "^": "__xor__", + "<<": "__lshift__", + ">>": "__rshift__", + "@": "__matmul__", +} + +REFLECTED_BIN_OP_METHOD = { + key: _reflected_name(value) for (key, value) in BIN_OP_METHOD.items() +} +AUGMENTED_OP_METHOD = { + key + "=": _augmented_name(value) for (key, value) in BIN_OP_METHOD.items() +} + +UNARY_OP_METHOD = { + "+": "__pos__", + "-": "__neg__", + "~": "__invert__", + "not": None, # XXX not '__nonzero__' +} +_UNARY_OPERATORS = { + "+": operator_mod.pos, + "-": operator_mod.neg, + "~": operator_mod.invert, + "not": operator_mod.not_, +} + + +def _infer_unary_op(obj, op): + func = _UNARY_OPERATORS[op] + value = func(obj) + return nodes.const_factory(value) + + +nodes.Tuple.infer_unary_op = lambda self, op: _infer_unary_op(tuple(self.elts), op) +nodes.List.infer_unary_op = lambda self, op: _infer_unary_op(self.elts, op) +nodes.Set.infer_unary_op = lambda self, op: _infer_unary_op(set(self.elts), op) +nodes.Const.infer_unary_op = lambda self, op: _infer_unary_op(self.value, op) +nodes.Dict.infer_unary_op = lambda self, op: _infer_unary_op(dict(self.items), op) + +# Binary operations + +BIN_OP_IMPL = { + "+": lambda a, b: a + b, + "-": lambda a, b: a - b, + "/": lambda a, b: a / b, + "//": lambda a, b: a // b, + "*": lambda a, b: a * b, + "**": lambda a, b: a**b, + "%": lambda a, b: a % b, + "&": lambda a, b: a & b, + "|": lambda a, b: a | b, + "^": lambda a, b: a ^ b, + "<<": lambda a, b: a << b, + ">>": lambda a, b: a >> b, + "@": operator_mod.matmul, +} +for _KEY, _IMPL in list(BIN_OP_IMPL.items()): + BIN_OP_IMPL[_KEY + "="] = _IMPL + + +@decorators.yes_if_nothing_inferred +def const_infer_binary_op(self, opnode, operator, other, context, _): + not_implemented = nodes.Const(NotImplemented) + if isinstance(other, nodes.Const): + try: + impl = BIN_OP_IMPL[operator] + try: + yield nodes.const_factory(impl(self.value, other.value)) + except TypeError: + # ArithmeticError is not enough: float >> float is a TypeError + yield not_implemented + except Exception: # pylint: disable=broad-except + yield util.Uninferable + except TypeError: + yield not_implemented + elif isinstance(self.value, str) and operator == "%": + # TODO(cpopa): implement string interpolation later on. + yield util.Uninferable + else: + yield not_implemented + + +nodes.Const.infer_binary_op = const_infer_binary_op + + +def _multiply_seq_by_int(self, opnode, other, context): + node = self.__class__(parent=opnode) + filtered_elts = ( + helpers.safe_infer(elt, context) or util.Uninferable + for elt in self.elts + if elt is not util.Uninferable + ) + node.elts = list(filtered_elts) * other.value + return node + + +def _filter_uninferable_nodes(elts, context): + for elt in elts: + if elt is util.Uninferable: + yield nodes.Unknown() + else: + for inferred in elt.infer(context): + if inferred is not util.Uninferable: + yield inferred + else: + yield nodes.Unknown() + + +@decorators.yes_if_nothing_inferred +def tl_infer_binary_op( + self, + opnode: nodes.BinOp, + operator: str, + other: nodes.NodeNG, + context: InferenceContext, + method: nodes.FunctionDef, +) -> Generator[nodes.NodeNG, None, None]: + """Infer a binary operation on a tuple or list. + + The instance on which the binary operation is performed is a tuple + or list. This refers to the left-hand side of the operation, so: + 'tuple() + 1' or '[] + A()' + """ + # For tuples and list the boundnode is no longer the tuple or list instance + context.boundnode = None + not_implemented = nodes.Const(NotImplemented) + if isinstance(other, self.__class__) and operator == "+": + node = self.__class__(parent=opnode) + node.elts = list( + itertools.chain( + _filter_uninferable_nodes(self.elts, context), + _filter_uninferable_nodes(other.elts, context), + ) + ) + yield node + elif isinstance(other, nodes.Const) and operator == "*": + if not isinstance(other.value, int): + yield not_implemented + return + yield _multiply_seq_by_int(self, opnode, other, context) + elif isinstance(other, bases.Instance) and operator == "*": + # Verify if the instance supports __index__. + as_index = helpers.class_instance_as_index(other) + if not as_index: + yield util.Uninferable + else: + yield _multiply_seq_by_int(self, opnode, as_index, context) + else: + yield not_implemented + + +nodes.Tuple.infer_binary_op = tl_infer_binary_op +nodes.List.infer_binary_op = tl_infer_binary_op + + +@decorators.yes_if_nothing_inferred +def instance_class_infer_binary_op(self, opnode, operator, other, context, method): + return method.infer_call_result(self, context) + + +bases.Instance.infer_binary_op = instance_class_infer_binary_op +nodes.ClassDef.infer_binary_op = instance_class_infer_binary_op + + +# assignment ################################################################## + +"""the assigned_stmts method is responsible to return the assigned statement +(e.g. not inferred) according to the assignment type. + +The `assign_path` argument is used to record the lhs path of the original node. +For instance if we want assigned statements for 'c' in 'a, (b,c)', assign_path +will be [1, 1] once arrived to the Assign node. + +The `context` argument is the current inference context which should be given +to any intermediary inference necessary. +""" + + +def _resolve_looppart(parts, assign_path, context): + """recursive function to resolve multiple assignments on loops""" + assign_path = assign_path[:] + index = assign_path.pop(0) + for part in parts: + if part is util.Uninferable: + continue + if not hasattr(part, "itered"): + continue + try: + itered = part.itered() + except TypeError: + continue + for stmt in itered: + index_node = nodes.Const(index) + try: + assigned = stmt.getitem(index_node, context) + except (AttributeError, AstroidTypeError, AstroidIndexError): + continue + if not assign_path: + # we achieved to resolved the assignment path, + # don't infer the last part + yield assigned + elif assigned is util.Uninferable: + break + else: + # we are not yet on the last part of the path + # search on each possibly inferred value + try: + yield from _resolve_looppart( + assigned.infer(context), assign_path, context + ) + except InferenceError: + break + + +@decorators.raise_if_nothing_inferred +def for_assigned_stmts( + self: Union[nodes.For, nodes.Comprehension], + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + if isinstance(self, nodes.AsyncFor) or getattr(self, "is_async", False): + # Skip inferring of async code for now + return dict(node=self, unknown=node, assign_path=assign_path, context=context) + if assign_path is None: + for lst in self.iter.infer(context): + if isinstance(lst, (nodes.Tuple, nodes.List)): + yield from lst.elts + else: + yield from _resolve_looppart(self.iter.infer(context), assign_path, context) + return dict(node=self, unknown=node, assign_path=assign_path, context=context) + + +nodes.For.assigned_stmts = for_assigned_stmts +nodes.Comprehension.assigned_stmts = for_assigned_stmts + + +def sequence_assigned_stmts( + self: Union[nodes.Tuple, nodes.List], + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + if assign_path is None: + assign_path = [] + try: + index = self.elts.index(node) + except ValueError as exc: + raise InferenceError( + "Tried to retrieve a node {node!r} which does not exist", + node=self, + assign_path=assign_path, + context=context, + ) from exc + + assign_path.insert(0, index) + return self.parent.assigned_stmts( + node=self, context=context, assign_path=assign_path + ) + + +nodes.Tuple.assigned_stmts = sequence_assigned_stmts +nodes.List.assigned_stmts = sequence_assigned_stmts + + +def assend_assigned_stmts( + self: Union[nodes.AssignName, nodes.AssignAttr], + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + return self.parent.assigned_stmts(node=self, context=context) + + +nodes.AssignName.assigned_stmts = assend_assigned_stmts +nodes.AssignAttr.assigned_stmts = assend_assigned_stmts + + +def _arguments_infer_argname(self, name, context): + # arguments information may be missing, in which case we can't do anything + # more + if not (self.arguments or self.vararg or self.kwarg): + yield util.Uninferable + return + + functype = self.parent.type + # first argument of instance/class method + if ( + self.arguments + and getattr(self.arguments[0], "name", None) == name + and functype != "staticmethod" + ): + cls = self.parent.parent.scope() + is_metaclass = isinstance(cls, nodes.ClassDef) and cls.type == "metaclass" + # If this is a metaclass, then the first argument will always + # be the class, not an instance. + if context.boundnode and isinstance(context.boundnode, bases.Instance): + cls = context.boundnode._proxied + if is_metaclass or functype == "classmethod": + yield cls + return + if functype == "method": + yield cls.instantiate_class() + return + + if context and context.callcontext: + callee = context.callcontext.callee + while hasattr(callee, "_proxied"): + callee = callee._proxied + if getattr(callee, "name", None) == self.parent.name: + call_site = arguments.CallSite(context.callcontext, context.extra_context) + yield from call_site.infer_argument(self.parent, name, context) + return + + if name == self.vararg: + vararg = nodes.const_factory(()) + vararg.parent = self + if not self.arguments and self.parent.name == "__init__": + cls = self.parent.parent.scope() + vararg.elts = [cls.instantiate_class()] + yield vararg + return + if name == self.kwarg: + kwarg = nodes.const_factory({}) + kwarg.parent = self + yield kwarg + return + # if there is a default value, yield it. And then yield Uninferable to reflect + # we can't guess given argument value + try: + context = copy_context(context) + yield from self.default_value(name).infer(context) + yield util.Uninferable + except NoDefault: + yield util.Uninferable + + +def arguments_assigned_stmts( + self: nodes.Arguments, + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + if context.callcontext: + callee = context.callcontext.callee + while hasattr(callee, "_proxied"): + callee = callee._proxied + else: + callee = None + if ( + context.callcontext + and node + and getattr(callee, "name", None) == node.frame(future=True).name + ): + # reset call context/name + callcontext = context.callcontext + context = copy_context(context) + context.callcontext = None + args = arguments.CallSite(callcontext, context=context) + return args.infer_argument(self.parent, node.name, context) + return _arguments_infer_argname(self, node.name, context) + + +nodes.Arguments.assigned_stmts = arguments_assigned_stmts + + +@decorators.raise_if_nothing_inferred +def assign_assigned_stmts( + self: Union[nodes.AugAssign, nodes.Assign, nodes.AnnAssign], + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + if not assign_path: + yield self.value + return None + yield from _resolve_assignment_parts( + self.value.infer(context), assign_path, context + ) + + return dict(node=self, unknown=node, assign_path=assign_path, context=context) + + +def assign_annassigned_stmts( + self: nodes.AnnAssign, + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + for inferred in assign_assigned_stmts(self, node, context, assign_path): + if inferred is None: + yield util.Uninferable + else: + yield inferred + + +nodes.Assign.assigned_stmts = assign_assigned_stmts +nodes.AnnAssign.assigned_stmts = assign_annassigned_stmts +nodes.AugAssign.assigned_stmts = assign_assigned_stmts + + +def _resolve_assignment_parts(parts, assign_path, context): + """recursive function to resolve multiple assignments""" + assign_path = assign_path[:] + index = assign_path.pop(0) + for part in parts: + assigned = None + if isinstance(part, nodes.Dict): + # A dictionary in an iterating context + try: + assigned, _ = part.items[index] + except IndexError: + return + + elif hasattr(part, "getitem"): + index_node = nodes.Const(index) + try: + assigned = part.getitem(index_node, context) + except (AstroidTypeError, AstroidIndexError): + return + + if not assigned: + return + + if not assign_path: + # we achieved to resolved the assignment path, don't infer the + # last part + yield assigned + elif assigned is util.Uninferable: + return + else: + # we are not yet on the last part of the path search on each + # possibly inferred value + try: + yield from _resolve_assignment_parts( + assigned.infer(context), assign_path, context + ) + except InferenceError: + return + + +@decorators.raise_if_nothing_inferred +def excepthandler_assigned_stmts( + self: nodes.ExceptHandler, + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + for assigned in node_classes.unpack_infer(self.type): + if isinstance(assigned, nodes.ClassDef): + assigned = objects.ExceptionInstance(assigned) + + yield assigned + return dict(node=self, unknown=node, assign_path=assign_path, context=context) + + +nodes.ExceptHandler.assigned_stmts = excepthandler_assigned_stmts + + +def _infer_context_manager(self, mgr, context): + try: + inferred = next(mgr.infer(context=context)) + except StopIteration as e: + raise InferenceError(node=mgr) from e + if isinstance(inferred, bases.Generator): + # Check if it is decorated with contextlib.contextmanager. + func = inferred.parent + if not func.decorators: + raise InferenceError( + "No decorators found on inferred generator %s", node=func + ) + + for decorator_node in func.decorators.nodes: + decorator = next(decorator_node.infer(context=context), None) + if isinstance(decorator, nodes.FunctionDef): + if decorator.qname() == _CONTEXTLIB_MGR: + break + else: + # It doesn't interest us. + raise InferenceError(node=func) + try: + yield next(inferred.infer_yield_types()) + except StopIteration as e: + raise InferenceError(node=func) from e + + elif isinstance(inferred, bases.Instance): + try: + enter = next(inferred.igetattr("__enter__", context=context)) + except (InferenceError, AttributeInferenceError, StopIteration) as exc: + raise InferenceError(node=inferred) from exc + if not isinstance(enter, bases.BoundMethod): + raise InferenceError(node=enter) + yield from enter.infer_call_result(self, context) + else: + raise InferenceError(node=mgr) + + +@decorators.raise_if_nothing_inferred +def with_assigned_stmts( + self: nodes.With, + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + """Infer names and other nodes from a *with* statement. + + This enables only inference for name binding in a *with* statement. + For instance, in the following code, inferring `func` will return + the `ContextManager` class, not whatever ``__enter__`` returns. + We are doing this intentionally, because we consider that the context + manager result is whatever __enter__ returns and what it is binded + using the ``as`` keyword. + + class ContextManager(object): + def __enter__(self): + return 42 + with ContextManager() as f: + pass + + # ContextManager().infer() will return ContextManager + # f.infer() will return 42. + + Arguments: + self: nodes.With + node: The target of the assignment, `as (a, b)` in `with foo as (a, b)`. + context: Inference context used for caching already inferred objects + assign_path: + A list of indices, where each index specifies what item to fetch from + the inference results. + """ + try: + mgr = next(mgr for (mgr, vars) in self.items if vars == node) + except StopIteration: + return None + if assign_path is None: + yield from _infer_context_manager(self, mgr, context) + else: + for result in _infer_context_manager(self, mgr, context): + # Walk the assign_path and get the item at the final index. + obj = result + for index in assign_path: + if not hasattr(obj, "elts"): + raise InferenceError( + "Wrong type ({targets!r}) for {node!r} assignment", + node=self, + targets=node, + assign_path=assign_path, + context=context, + ) + try: + obj = obj.elts[index] + except IndexError as exc: + raise InferenceError( + "Tried to infer a nonexistent target with index {index} " + "in {node!r}.", + node=self, + targets=node, + assign_path=assign_path, + context=context, + ) from exc + except TypeError as exc: + raise InferenceError( + "Tried to unpack a non-iterable value " "in {node!r}.", + node=self, + targets=node, + assign_path=assign_path, + context=context, + ) from exc + yield obj + return dict(node=self, unknown=node, assign_path=assign_path, context=context) + + +nodes.With.assigned_stmts = with_assigned_stmts + + +@decorators.raise_if_nothing_inferred +def named_expr_assigned_stmts( + self: nodes.NamedExpr, + node: node_classes.AssignedStmtsPossibleNode, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + """Infer names and other nodes from an assignment expression""" + if self.target == node: + yield from self.value.infer(context=context) + else: + raise InferenceError( + "Cannot infer NamedExpr node {node!r}", + node=self, + assign_path=assign_path, + context=context, + ) + + +nodes.NamedExpr.assigned_stmts = named_expr_assigned_stmts + + +@decorators.yes_if_nothing_inferred +def starred_assigned_stmts( + self: nodes.Starred, + node: node_classes.AssignedStmtsPossibleNode = None, + context: Optional[InferenceContext] = None, + assign_path: Optional[List[int]] = None, +) -> Any: + """ + Arguments: + self: nodes.Starred + node: a node related to the current underlying Node. + context: Inference context used for caching already inferred objects + assign_path: + A list of indices, where each index specifies what item to fetch from + the inference results. + """ + # pylint: disable=too-many-locals,too-many-statements + def _determine_starred_iteration_lookups(starred, target, lookups): + # Determine the lookups for the rhs of the iteration + itered = target.itered() + for index, element in enumerate(itered): + if ( + isinstance(element, nodes.Starred) + and element.value.name == starred.value.name + ): + lookups.append((index, len(itered))) + break + if isinstance(element, nodes.Tuple): + lookups.append((index, len(element.itered()))) + _determine_starred_iteration_lookups(starred, element, lookups) + + stmt = self.statement(future=True) + if not isinstance(stmt, (nodes.Assign, nodes.For)): + raise InferenceError( + "Statement {stmt!r} enclosing {node!r} " "must be an Assign or For node.", + node=self, + stmt=stmt, + unknown=node, + context=context, + ) + + if context is None: + context = InferenceContext() + + if isinstance(stmt, nodes.Assign): + value = stmt.value + lhs = stmt.targets[0] + if not isinstance(lhs, nodes.BaseContainer): + yield util.Uninferable + return + + if sum(1 for _ in lhs.nodes_of_class(nodes.Starred)) > 1: + raise InferenceError( + "Too many starred arguments in the " " assignment targets {lhs!r}.", + node=self, + targets=lhs, + unknown=node, + context=context, + ) + + try: + rhs = next(value.infer(context)) + except (InferenceError, StopIteration): + yield util.Uninferable + return + if rhs is util.Uninferable or not hasattr(rhs, "itered"): + yield util.Uninferable + return + + try: + elts = collections.deque(rhs.itered()) + except TypeError: + yield util.Uninferable + return + + # Unpack iteratively the values from the rhs of the assignment, + # until the find the starred node. What will remain will + # be the list of values which the Starred node will represent + # This is done in two steps, from left to right to remove + # anything before the starred node and from right to left + # to remove anything after the starred node. + + for index, left_node in enumerate(lhs.elts): + if not isinstance(left_node, nodes.Starred): + if not elts: + break + elts.popleft() + continue + lhs_elts = collections.deque(reversed(lhs.elts[index:])) + for right_node in lhs_elts: + if not isinstance(right_node, nodes.Starred): + if not elts: + break + elts.pop() + continue + + # We're done unpacking. + packed = nodes.List( + ctx=Context.Store, + parent=self, + lineno=lhs.lineno, + col_offset=lhs.col_offset, + ) + packed.postinit(elts=list(elts)) + yield packed + break + + if isinstance(stmt, nodes.For): + try: + inferred_iterable = next(stmt.iter.infer(context=context)) + except (InferenceError, StopIteration): + yield util.Uninferable + return + if inferred_iterable is util.Uninferable or not hasattr( + inferred_iterable, "itered" + ): + yield util.Uninferable + return + try: + itered = inferred_iterable.itered() + except TypeError: + yield util.Uninferable + return + + target = stmt.target + + if not isinstance(target, nodes.Tuple): + raise InferenceError( + "Could not make sense of this, the target must be a tuple", + context=context, + ) + + lookups = [] + _determine_starred_iteration_lookups(self, target, lookups) + if not lookups: + raise InferenceError( + "Could not make sense of this, needs at least a lookup", context=context + ) + + # Make the last lookup a slice, since that what we want for a Starred node + last_element_index, last_element_length = lookups[-1] + is_starred_last = last_element_index == (last_element_length - 1) + + lookup_slice = slice( + last_element_index, + None if is_starred_last else (last_element_length - last_element_index), + ) + lookups[-1] = lookup_slice + + for element in itered: + + # We probably want to infer the potential values *for each* element in an + # iterable, but we can't infer a list of all values, when only a list of + # step values are expected: + # + # for a, *b in [...]: + # b + # + # *b* should now point to just the elements at that particular iteration step, + # which astroid can't know about. + + found_element = None + for lookup in lookups: + if not hasattr(element, "itered"): + break + if not isinstance(lookup, slice): + # Grab just the index, not the whole length + lookup = lookup[0] + try: + itered_inner_element = element.itered() + element = itered_inner_element[lookup] + except IndexError: + break + except TypeError: + # Most likely the itered() call failed, cannot make sense of this + yield util.Uninferable + return + else: + found_element = element + + unpacked = nodes.List( + ctx=Context.Store, + parent=self, + lineno=self.lineno, + col_offset=self.col_offset, + ) + unpacked.postinit(elts=found_element or []) + yield unpacked + return + + yield util.Uninferable + + +nodes.Starred.assigned_stmts = starred_assigned_stmts + + +@decorators.yes_if_nothing_inferred +def match_mapping_assigned_stmts( + self: nodes.MatchMapping, + node: nodes.AssignName, + context: Optional[InferenceContext] = None, + assign_path: None = None, +) -> Generator[nodes.NodeNG, None, None]: + """Return empty generator (return -> raises StopIteration) so inferred value + is Uninferable. + """ + return + yield + + +nodes.MatchMapping.assigned_stmts = match_mapping_assigned_stmts + + +@decorators.yes_if_nothing_inferred +def match_star_assigned_stmts( + self: nodes.MatchStar, + node: nodes.AssignName, + context: Optional[InferenceContext] = None, + assign_path: None = None, +) -> Generator[nodes.NodeNG, None, None]: + """Return empty generator (return -> raises StopIteration) so inferred value + is Uninferable. + """ + return + yield + + +nodes.MatchStar.assigned_stmts = match_star_assigned_stmts + + +@decorators.yes_if_nothing_inferred +def match_as_assigned_stmts( + self: nodes.MatchAs, + node: nodes.AssignName, + context: Optional[InferenceContext] = None, + assign_path: None = None, +) -> Generator[nodes.NodeNG, None, None]: + """Infer MatchAs as the Match subject if it's the only MatchCase pattern + else raise StopIteration to yield Uninferable. + """ + if ( + isinstance(self.parent, nodes.MatchCase) + and isinstance(self.parent.parent, nodes.Match) + and self.pattern is None + ): + yield self.parent.parent.subject + + +nodes.MatchAs.assigned_stmts = match_as_assigned_stmts diff --git a/myenv/lib/python3.9/site-packages/astroid/raw_building.py b/myenv/lib/python3.9/site-packages/astroid/raw_building.py new file mode 100644 index 0000000..bcc414b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/raw_building.py @@ -0,0 +1,508 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""this module contains a set of functions to create astroid trees from scratch +(build_* functions) or from living object (object_build_* functions) +""" + +import builtins +import inspect +import os +import sys +import types +import warnings +from typing import Iterable, List, Optional + +from astroid import bases, nodes +from astroid.manager import AstroidManager +from astroid.nodes import node_classes + +# the keys of CONST_CLS eg python builtin types +_CONSTANTS = tuple(node_classes.CONST_CLS) +_BUILTINS = vars(builtins) +TYPE_NONE = type(None) +TYPE_NOTIMPLEMENTED = type(NotImplemented) +TYPE_ELLIPSIS = type(...) + + +def _attach_local_node(parent, node, name): + node.name = name # needed by add_local_node + parent.add_local_node(node) + + +def _add_dunder_class(func, member): + """Add a __class__ member to the given func node, if we can determine it.""" + python_cls = member.__class__ + cls_name = getattr(python_cls, "__name__", None) + if not cls_name: + return + cls_bases = [ancestor.__name__ for ancestor in python_cls.__bases__] + ast_klass = build_class(cls_name, cls_bases, python_cls.__doc__) + func.instance_attrs["__class__"] = [ast_klass] + + +_marker = object() + + +def attach_dummy_node(node, name, runtime_object=_marker): + """create a dummy node and register it in the locals of the given + node with the specified name + """ + enode = nodes.EmptyNode() + enode.object = runtime_object + _attach_local_node(node, enode, name) + + +def _has_underlying_object(self): + return self.object is not None and self.object is not _marker + + +nodes.EmptyNode.has_underlying_object = _has_underlying_object + + +def attach_const_node(node, name, value): + """create a Const node and register it in the locals of the given + node with the specified name + """ + if name not in node.special_attributes: + _attach_local_node(node, nodes.const_factory(value), name) + + +def attach_import_node(node, modname, membername): + """create a ImportFrom node and register it in the locals of the given + node with the specified name + """ + from_node = nodes.ImportFrom(modname, [(membername, None)]) + _attach_local_node(node, from_node, membername) + + +def build_module(name: str, doc: Optional[str] = None) -> nodes.Module: + """create and initialize an astroid Module node""" + node = nodes.Module(name, pure_python=False, package=False) + node.postinit( + body=[], + doc_node=nodes.Const(value=doc) if doc else None, + ) + return node + + +def build_class( + name: str, basenames: Iterable[str] = (), doc: Optional[str] = None +) -> nodes.ClassDef: + """Create and initialize an astroid ClassDef node.""" + node = nodes.ClassDef(name) + node.postinit( + bases=[nodes.Name(name=base, parent=node) for base in basenames], + body=[], + decorators=None, + doc_node=nodes.Const(value=doc) if doc else None, + ) + return node + + +def build_function( + name, + args: Optional[List[str]] = None, + posonlyargs: Optional[List[str]] = None, + defaults=None, + doc: Optional[str] = None, + kwonlyargs: Optional[List[str]] = None, +) -> nodes.FunctionDef: + """create and initialize an astroid FunctionDef node""" + # first argument is now a list of decorators + func = nodes.FunctionDef(name) + argsnode = nodes.Arguments(parent=func) + argsnode.postinit( + args=[nodes.AssignName(name=arg, parent=argsnode) for arg in args or ()], + defaults=[], + kwonlyargs=[ + nodes.AssignName(name=arg, parent=argsnode) for arg in kwonlyargs or () + ], + kw_defaults=[], + annotations=[], + posonlyargs=[ + nodes.AssignName(name=arg, parent=argsnode) for arg in posonlyargs or () + ], + ) + func.postinit( + args=argsnode, + body=[], + doc_node=nodes.Const(value=doc) if doc else None, + ) + for default in defaults or (): + argsnode.defaults.append(nodes.const_factory(default)) + argsnode.defaults[-1].parent = argsnode + if args: + register_arguments(func) + return func + + +def build_from_import(fromname, names): + """create and initialize an astroid ImportFrom import statement""" + return nodes.ImportFrom(fromname, [(name, None) for name in names]) + + +def register_arguments(func, args=None): + """add given arguments to local + + args is a list that may contains nested lists + (i.e. def func(a, (b, c, d)): ...) + """ + if args is None: + args = func.args.args + if func.args.vararg: + func.set_local(func.args.vararg, func.args) + if func.args.kwarg: + func.set_local(func.args.kwarg, func.args) + for arg in args: + if isinstance(arg, nodes.AssignName): + func.set_local(arg.name, arg) + else: + register_arguments(func, arg.elts) + + +def object_build_class(node, member, localname): + """create astroid for a living class object""" + basenames = [base.__name__ for base in member.__bases__] + return _base_class_object_build(node, member, basenames, localname=localname) + + +def object_build_function(node, member, localname): + """create astroid for a living function object""" + signature = inspect.signature(member) + args = [] + defaults = [] + posonlyargs = [] + kwonlyargs = [] + for param_name, param in signature.parameters.items(): + if param.kind == inspect.Parameter.POSITIONAL_ONLY: + posonlyargs.append(param_name) + elif param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD: + args.append(param_name) + elif param.kind == inspect.Parameter.VAR_POSITIONAL: + args.append(param_name) + elif param.kind == inspect.Parameter.VAR_KEYWORD: + args.append(param_name) + elif param.kind == inspect.Parameter.KEYWORD_ONLY: + kwonlyargs.append(param_name) + if param.default is not inspect._empty: + defaults.append(param.default) + func = build_function( + getattr(member, "__name__", None) or localname, + args, + posonlyargs, + defaults, + member.__doc__, + ) + node.add_local_node(func, localname) + + +def object_build_datadescriptor(node, member, name): + """create astroid for a living data descriptor object""" + return _base_class_object_build(node, member, [], name) + + +def object_build_methoddescriptor(node, member, localname): + """create astroid for a living method descriptor object""" + # FIXME get arguments ? + func = build_function( + getattr(member, "__name__", None) or localname, doc=member.__doc__ + ) + # set node's arguments to None to notice that we have no information, not + # and empty argument list + func.args.args = None + node.add_local_node(func, localname) + _add_dunder_class(func, member) + + +def _base_class_object_build(node, member, basenames, name=None, localname=None): + """create astroid for a living class object, with a given set of base names + (e.g. ancestors) + """ + klass = build_class( + name or getattr(member, "__name__", None) or localname, + basenames, + member.__doc__, + ) + klass._newstyle = isinstance(member, type) + node.add_local_node(klass, localname) + try: + # limit the instantiation trick since it's too dangerous + # (such as infinite test execution...) + # this at least resolves common case such as Exception.args, + # OSError.errno + if issubclass(member, Exception): + instdict = member().__dict__ + else: + raise TypeError + except TypeError: + pass + else: + for item_name, obj in instdict.items(): + valnode = nodes.EmptyNode() + valnode.object = obj + valnode.parent = klass + valnode.lineno = 1 + klass.instance_attrs[item_name] = [valnode] + return klass + + +def _build_from_function(node, name, member, module): + # verify this is not an imported function + try: + code = member.__code__ + except AttributeError: + # Some implementations don't provide the code object, + # such as Jython. + code = None + filename = getattr(code, "co_filename", None) + if filename is None: + assert isinstance(member, object) + object_build_methoddescriptor(node, member, name) + elif filename != getattr(module, "__file__", None): + attach_dummy_node(node, name, member) + else: + object_build_function(node, member, name) + + +def _safe_has_attribute(obj, member): + try: + return hasattr(obj, member) + except Exception: # pylint: disable=broad-except + return False + + +class InspectBuilder: + """class for building nodes from living object + + this is actually a really minimal representation, including only Module, + FunctionDef and ClassDef nodes and some others as guessed. + """ + + def __init__(self, manager_instance=None): + self._manager = manager_instance or AstroidManager() + self._done = {} + self._module = None + + def inspect_build( + self, + module: types.ModuleType, + modname: Optional[str] = None, + path: Optional[str] = None, + ) -> nodes.Module: + """build astroid from a living module (i.e. using inspect) + this is used when there is no python source code available (either + because it's a built-in module or because the .py is not available) + """ + self._module = module + if modname is None: + modname = module.__name__ + try: + node = build_module(modname, module.__doc__) + except AttributeError: + # in jython, java modules have no __doc__ (see #109562) + node = build_module(modname) + node.file = node.path = os.path.abspath(path) if path else path + node.name = modname + self._manager.cache_module(node) + node.package = hasattr(module, "__path__") + self._done = {} + self.object_build(node, module) + return node + + def object_build(self, node, obj): + """recursive method which create a partial ast from real objects + (only function, class, and method are handled) + """ + if obj in self._done: + return self._done[obj] + self._done[obj] = node + for name in dir(obj): + try: + with warnings.catch_warnings(): + warnings.simplefilter("error") + member = getattr(obj, name) + except (AttributeError, DeprecationWarning): + # damned ExtensionClass.Base, I know you're there ! + attach_dummy_node(node, name) + continue + if inspect.ismethod(member): + member = member.__func__ + if inspect.isfunction(member): + _build_from_function(node, name, member, self._module) + elif inspect.isbuiltin(member): + if self.imported_member(node, member, name): + continue + object_build_methoddescriptor(node, member, name) + elif inspect.isclass(member): + if self.imported_member(node, member, name): + continue + if member in self._done: + class_node = self._done[member] + if class_node not in node.locals.get(name, ()): + node.add_local_node(class_node, name) + else: + class_node = object_build_class(node, member, name) + # recursion + self.object_build(class_node, member) + if name == "__class__" and class_node.parent is None: + class_node.parent = self._done[self._module] + elif inspect.ismethoddescriptor(member): + assert isinstance(member, object) + object_build_methoddescriptor(node, member, name) + elif inspect.isdatadescriptor(member): + assert isinstance(member, object) + object_build_datadescriptor(node, member, name) + elif isinstance(member, _CONSTANTS): + attach_const_node(node, name, member) + elif inspect.isroutine(member): + # This should be called for Jython, where some builtin + # methods aren't caught by isbuiltin branch. + _build_from_function(node, name, member, self._module) + elif _safe_has_attribute(member, "__all__"): + module = build_module(name) + _attach_local_node(node, module, name) + # recursion + self.object_build(module, member) + else: + # create an empty node so that the name is actually defined + attach_dummy_node(node, name, member) + return None + + def imported_member(self, node, member, name: str) -> bool: + """verify this is not an imported class or handle it""" + # /!\ some classes like ExtensionClass doesn't have a __module__ + # attribute ! Also, this may trigger an exception on badly built module + # (see http://www.logilab.org/ticket/57299 for instance) + try: + modname = getattr(member, "__module__", None) + except TypeError: + modname = None + if modname is None: + if name in {"__new__", "__subclasshook__"}: + # Python 2.5.1 (r251:54863, Sep 1 2010, 22:03:14) + # >>> print object.__new__.__module__ + # None + modname = builtins.__name__ + else: + attach_dummy_node(node, name, member) + return True + + # On PyPy during bootstrapping we infer _io while _module is + # builtins. In CPython _io names itself io, see http://bugs.python.org/issue18602 + # Therefore, this basically checks whether we are not in PyPy. + if modname == "_io" and not self._module.__name__ == "builtins": + return False + + real_name = {"gtk": "gtk_gtk"}.get(modname, modname) + + if real_name != self._module.__name__: + # check if it sounds valid and then add an import node, else use a + # dummy node + try: + getattr(sys.modules[modname], name) + except (KeyError, AttributeError): + attach_dummy_node(node, name, member) + else: + attach_import_node(node, modname, name) + return True + return False + + +# astroid bootstrapping ###################################################### + +_CONST_PROXY = {} + + +def _set_proxied(const): + # TODO : find a nicer way to handle this situation; + return _CONST_PROXY[const.value.__class__] + + +def _astroid_bootstrapping(): + """astroid bootstrapping the builtins module""" + # this boot strapping is necessary since we need the Const nodes to + # inspect_build builtins, and then we can proxy Const + builder = InspectBuilder() + astroid_builtin = builder.inspect_build(builtins) + + for cls, node_cls in node_classes.CONST_CLS.items(): + if cls is TYPE_NONE: + proxy = build_class("NoneType") + proxy.parent = astroid_builtin + elif cls is TYPE_NOTIMPLEMENTED: + proxy = build_class("NotImplementedType") + proxy.parent = astroid_builtin + elif cls is TYPE_ELLIPSIS: + proxy = build_class("Ellipsis") + proxy.parent = astroid_builtin + else: + proxy = astroid_builtin.getattr(cls.__name__)[0] + if cls in (dict, list, set, tuple): + node_cls._proxied = proxy + else: + _CONST_PROXY[cls] = proxy + + # Set the builtin module as parent for some builtins. + nodes.Const._proxied = property(_set_proxied) + + _GeneratorType = nodes.ClassDef(types.GeneratorType.__name__) + _GeneratorType.parent = astroid_builtin + generator_doc_node = ( + nodes.Const(value=types.GeneratorType.__doc__) + if types.GeneratorType.__doc__ + else None + ) + _GeneratorType.postinit( + bases=[], + body=[], + decorators=None, + doc_node=generator_doc_node, + ) + bases.Generator._proxied = _GeneratorType + builder.object_build(bases.Generator._proxied, types.GeneratorType) + + if hasattr(types, "AsyncGeneratorType"): + _AsyncGeneratorType = nodes.ClassDef(types.AsyncGeneratorType.__name__) + _AsyncGeneratorType.parent = astroid_builtin + async_generator_doc_node = ( + nodes.Const(value=types.AsyncGeneratorType.__doc__) + if types.AsyncGeneratorType.__doc__ + else None + ) + _AsyncGeneratorType.postinit( + bases=[], + body=[], + decorators=None, + doc_node=async_generator_doc_node, + ) + bases.AsyncGenerator._proxied = _AsyncGeneratorType + builder.object_build(bases.AsyncGenerator._proxied, types.AsyncGeneratorType) + builtin_types = ( + types.GetSetDescriptorType, + types.GeneratorType, + types.MemberDescriptorType, + TYPE_NONE, + TYPE_NOTIMPLEMENTED, + types.FunctionType, + types.MethodType, + types.BuiltinFunctionType, + types.ModuleType, + types.TracebackType, + ) + for _type in builtin_types: + if _type.__name__ not in astroid_builtin: + klass = nodes.ClassDef(_type.__name__) + klass.parent = astroid_builtin + klass.postinit( + bases=[], + body=[], + decorators=None, + doc_node=nodes.Const(value=_type.__doc__) if _type.__doc__ else None, + ) + builder.object_build(klass, _type) + astroid_builtin[_type.__name__] = klass + + +_astroid_bootstrapping() diff --git a/myenv/lib/python3.9/site-packages/astroid/rebuilder.py b/myenv/lib/python3.9/site-packages/astroid/rebuilder.py new file mode 100644 index 0000000..a04d973 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/rebuilder.py @@ -0,0 +1,2119 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""this module contains utilities for rebuilding an _ast tree in +order to get a single Astroid representation +""" + +import ast +import sys +import token +import tokenize +from io import StringIO +from tokenize import TokenInfo, generate_tokens +from typing import ( + Callable, + Dict, + Generator, + List, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, + overload, +) + +from astroid import nodes +from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment +from astroid.const import IS_PYPY, PY36, PY38, PY38_PLUS, PY39_PLUS, Context +from astroid.manager import AstroidManager +from astroid.nodes import NodeNG +from astroid.nodes.utils import Position + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + + +REDIRECT: Final[Dict[str, str]] = { + "arguments": "Arguments", + "comprehension": "Comprehension", + "ListCompFor": "Comprehension", + "GenExprFor": "Comprehension", + "excepthandler": "ExceptHandler", + "keyword": "Keyword", + "match_case": "MatchCase", +} + + +T_Doc = TypeVar( + "T_Doc", + "ast.Module", + "ast.ClassDef", + Union["ast.FunctionDef", "ast.AsyncFunctionDef"], +) +T_Function = TypeVar("T_Function", nodes.FunctionDef, nodes.AsyncFunctionDef) +T_For = TypeVar("T_For", nodes.For, nodes.AsyncFor) +T_With = TypeVar("T_With", nodes.With, nodes.AsyncWith) +NodesWithDocsType = Union[nodes.Module, nodes.ClassDef, nodes.FunctionDef] + + +# noinspection PyMethodMayBeStatic +class TreeRebuilder: + """Rebuilds the _ast tree to become an Astroid tree""" + + def __init__( + self, + manager: AstroidManager, + parser_module: Optional[ParserModule] = None, + data: Optional[str] = None, + ) -> None: + self._manager = manager + self._data = data.split("\n") if data else None + self._global_names: List[Dict[str, List[nodes.Global]]] = [] + self._import_from_nodes: List[nodes.ImportFrom] = [] + self._delayed_assattr: List[nodes.AssignAttr] = [] + self._visit_meths: Dict[ + Type["ast.AST"], Callable[["ast.AST", NodeNG], NodeNG] + ] = {} + + if parser_module is None: + self._parser_module = get_parser_module() + else: + self._parser_module = parser_module + self._module = self._parser_module.module + + def _get_doc(self, node: T_Doc) -> Tuple[T_Doc, Optional["ast.Constant | ast.Str"]]: + """Return the doc ast node.""" + try: + if node.body and isinstance(node.body[0], self._module.Expr): + first_value = node.body[0].value + if isinstance(first_value, self._module.Str) or ( + PY38_PLUS + and isinstance(first_value, self._module.Constant) + and isinstance(first_value.value, str) + ): + doc_ast_node = first_value + node.body = node.body[1:] + # The ast parser of python < 3.8 sets col_offset of multi-line strings to -1 + # as it is unable to determine the value correctly. We reset this to None. + if doc_ast_node.col_offset == -1: + doc_ast_node.col_offset = None + return node, doc_ast_node + except IndexError: + pass # ast built from scratch + return node, None + + def _get_context( + self, + node: Union[ + "ast.Attribute", + "ast.List", + "ast.Name", + "ast.Subscript", + "ast.Starred", + "ast.Tuple", + ], + ) -> Context: + return self._parser_module.context_classes.get(type(node.ctx), Context.Load) + + def _get_position_info( + self, + node: Union["ast.ClassDef", "ast.FunctionDef", "ast.AsyncFunctionDef"], + parent: Union[nodes.ClassDef, nodes.FunctionDef, nodes.AsyncFunctionDef], + ) -> Optional[Position]: + """Return position information for ClassDef and FunctionDef nodes. + + In contrast to AST positions, these only include the actual keyword(s) + and the class / function name. + + >>> @decorator + >>> async def some_func(var: int) -> None: + >>> ^^^^^^^^^^^^^^^^^^^ + """ + if not self._data: + return None + end_lineno: Optional[int] = getattr(node, "end_lineno", None) + if node.body: + end_lineno = node.body[0].lineno + # pylint: disable-next=unsubscriptable-object + data = "\n".join(self._data[node.lineno - 1 : end_lineno]) + + start_token: Optional[TokenInfo] = None + keyword_tokens: Tuple[int, ...] = (token.NAME,) + if isinstance(parent, nodes.AsyncFunctionDef): + search_token = "async" + if PY36: + # In Python 3.6, the token type for 'async' was 'ASYNC' + # In Python 3.7, the type was changed to 'NAME' and 'ASYNC' removed + # Python 3.8 added it back. However, if we use it unconditionally + # we would break 3.7. + keyword_tokens = (token.NAME, token.ASYNC) + elif isinstance(parent, nodes.FunctionDef): + search_token = "def" + else: + search_token = "class" + + for t in generate_tokens(StringIO(data).readline): + if ( + start_token is not None + and t.type == token.NAME + and t.string == node.name + ): + break + if t.type in keyword_tokens: + if t.string == search_token: + start_token = t + continue + if t.string in {"def"}: + continue + start_token = None + else: + return None + + # pylint: disable=undefined-loop-variable + return Position( + lineno=node.lineno + start_token.start[0] - 1, + col_offset=start_token.start[1], + end_lineno=node.lineno + t.end[0] - 1, + end_col_offset=t.end[1], + ) + + def _fix_doc_node_position(self, node: NodesWithDocsType) -> None: + """Fix start and end position of doc nodes for Python < 3.8.""" + if not self._data or not node.doc_node or node.lineno is None: + return + if PY38_PLUS: + return + + lineno = node.lineno or 1 # lineno of modules is 0 + end_range: Optional[int] = node.doc_node.lineno + if IS_PYPY and not PY39_PLUS: + end_range = None + # pylint: disable-next=unsubscriptable-object + data = "\n".join(self._data[lineno - 1 : end_range]) + + found_start, found_end = False, False + open_brackets = 0 + skip_token: Set[int] = {token.NEWLINE, token.INDENT} + if PY36: + skip_token.update((tokenize.NL, tokenize.COMMENT)) + else: + # token.NL and token.COMMENT were added in 3.7 + skip_token.update((token.NL, token.COMMENT)) + + if isinstance(node, nodes.Module): + found_end = True + + for t in generate_tokens(StringIO(data).readline): + if found_end is False: + if ( + found_start is False + and t.type == token.NAME + and t.string in {"def", "class"} + ): + found_start = True + elif found_start is True and t.type == token.OP: + if t.exact_type == token.COLON and open_brackets == 0: + found_end = True + elif t.exact_type == token.LPAR: + open_brackets += 1 + elif t.exact_type == token.RPAR: + open_brackets -= 1 + continue + if t.type in skip_token: + continue + if t.type == token.STRING: + break + return + else: + return + + # pylint: disable=undefined-loop-variable + node.doc_node.lineno = lineno + t.start[0] - 1 + node.doc_node.col_offset = t.start[1] + node.doc_node.end_lineno = lineno + t.end[0] - 1 + node.doc_node.end_col_offset = t.end[1] + + def _reset_end_lineno(self, newnode: nodes.NodeNG) -> None: + """Reset end_lineno and end_col_offset attributes for PyPy 3.8. + + For some nodes, these are either set to -1 or only partially assigned. + To keep consistency across astroid and pylint, reset all. + + This has been fixed in PyPy 3.9. + For reference, an (incomplete) list of nodes with issues: + - ClassDef - For + - FunctionDef - While + - Call - If + - Decorators - TryExcept + - With - TryFinally + - Assign + """ + newnode.end_lineno = None + newnode.end_col_offset = None + for child_node in newnode.get_children(): + self._reset_end_lineno(child_node) + + def visit_module( + self, node: "ast.Module", modname: str, modpath: str, package: bool + ) -> nodes.Module: + """visit a Module node by returning a fresh instance of it + + Note: Method not called by 'visit' + """ + node, doc_ast_node = self._get_doc(node) + newnode = nodes.Module( + name=modname, + file=modpath, + path=[modpath], + package=package, + parent=None, + ) + newnode.postinit( + [self.visit(child, newnode) for child in node.body], + doc_node=self.visit(doc_ast_node, newnode), + ) + self._fix_doc_node_position(newnode) + if IS_PYPY and PY38: + self._reset_end_lineno(newnode) + return newnode + + @overload + def visit(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName: + ... + + @overload + def visit(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments: + ... + + @overload + def visit(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert: + ... + + @overload + def visit( + self, node: "ast.AsyncFunctionDef", parent: NodeNG + ) -> nodes.AsyncFunctionDef: + ... + + @overload + def visit(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor: + ... + + @overload + def visit(self, node: "ast.Await", parent: NodeNG) -> nodes.Await: + ... + + @overload + def visit(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith: + ... + + @overload + def visit(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign: + ... + + @overload + def visit(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign: + ... + + @overload + def visit(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign: + ... + + @overload + def visit(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp: + ... + + @overload + def visit(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp: + ... + + @overload + def visit(self, node: "ast.Break", parent: NodeNG) -> nodes.Break: + ... + + @overload + def visit(self, node: "ast.Call", parent: NodeNG) -> nodes.Call: + ... + + @overload + def visit(self, node: "ast.ClassDef", parent: NodeNG) -> nodes.ClassDef: + ... + + @overload + def visit(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue: + ... + + @overload + def visit(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare: + ... + + @overload + def visit(self, node: "ast.comprehension", parent: NodeNG) -> nodes.Comprehension: + ... + + @overload + def visit(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete: + ... + + @overload + def visit(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict: + ... + + @overload + def visit(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp: + ... + + @overload + def visit(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr: + ... + + @overload + def visit(self, node: "ast.ExceptHandler", parent: NodeNG) -> nodes.ExceptHandler: + ... + + @overload + def visit(self, node: "ast.For", parent: NodeNG) -> nodes.For: + ... + + @overload + def visit(self, node: "ast.ImportFrom", parent: NodeNG) -> nodes.ImportFrom: + ... + + @overload + def visit(self, node: "ast.FunctionDef", parent: NodeNG) -> nodes.FunctionDef: + ... + + @overload + def visit(self, node: "ast.GeneratorExp", parent: NodeNG) -> nodes.GeneratorExp: + ... + + @overload + def visit(self, node: "ast.Attribute", parent: NodeNG) -> nodes.Attribute: + ... + + @overload + def visit(self, node: "ast.Global", parent: NodeNG) -> nodes.Global: + ... + + @overload + def visit(self, node: "ast.If", parent: NodeNG) -> nodes.If: + ... + + @overload + def visit(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp: + ... + + @overload + def visit(self, node: "ast.Import", parent: NodeNG) -> nodes.Import: + ... + + @overload + def visit(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr: + ... + + @overload + def visit(self, node: "ast.FormattedValue", parent: NodeNG) -> nodes.FormattedValue: + ... + + if sys.version_info >= (3, 8): + + @overload + def visit(self, node: "ast.NamedExpr", parent: NodeNG) -> nodes.NamedExpr: + ... + + if sys.version_info < (3, 9): + # Not used in Python 3.9+ + @overload + def visit(self, node: "ast.ExtSlice", parent: nodes.Subscript) -> nodes.Tuple: + ... + + @overload + def visit(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG: + ... + + @overload + def visit(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword: + ... + + @overload + def visit(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda: + ... + + @overload + def visit(self, node: "ast.List", parent: NodeNG) -> nodes.List: + ... + + @overload + def visit(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp: + ... + + @overload + def visit( + self, node: "ast.Name", parent: NodeNG + ) -> Union[nodes.Name, nodes.Const, nodes.AssignName, nodes.DelName]: + ... + + @overload + def visit(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal: + ... + + if sys.version_info < (3, 8): + # Not used in Python 3.8+ + @overload + def visit(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const: + ... + + @overload + def visit(self, node: "ast.NameConstant", parent: NodeNG) -> nodes.Const: + ... + + @overload + def visit(self, node: "ast.Str", parent: NodeNG) -> nodes.Const: + ... + + @overload + def visit(self, node: "ast.Bytes", parent: NodeNG) -> nodes.Const: + ... + + @overload + def visit(self, node: "ast.Num", parent: NodeNG) -> nodes.Const: + ... + + @overload + def visit(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const: + ... + + @overload + def visit(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass: + ... + + @overload + def visit(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise: + ... + + @overload + def visit(self, node: "ast.Return", parent: NodeNG) -> nodes.Return: + ... + + @overload + def visit(self, node: "ast.Set", parent: NodeNG) -> nodes.Set: + ... + + @overload + def visit(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp: + ... + + @overload + def visit(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice: + ... + + @overload + def visit(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript: + ... + + @overload + def visit(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred: + ... + + @overload + def visit( + self, node: "ast.Try", parent: NodeNG + ) -> Union[nodes.TryExcept, nodes.TryFinally]: + ... + + @overload + def visit(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple: + ... + + @overload + def visit(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp: + ... + + @overload + def visit(self, node: "ast.While", parent: NodeNG) -> nodes.While: + ... + + @overload + def visit(self, node: "ast.With", parent: NodeNG) -> nodes.With: + ... + + @overload + def visit(self, node: "ast.Yield", parent: NodeNG) -> nodes.Yield: + ... + + @overload + def visit(self, node: "ast.YieldFrom", parent: NodeNG) -> nodes.YieldFrom: + ... + + if sys.version_info >= (3, 10): + + @overload + def visit(self, node: "ast.Match", parent: NodeNG) -> nodes.Match: + ... + + @overload + def visit(self, node: "ast.match_case", parent: NodeNG) -> nodes.MatchCase: + ... + + @overload + def visit(self, node: "ast.MatchValue", parent: NodeNG) -> nodes.MatchValue: + ... + + @overload + def visit( + self, node: "ast.MatchSingleton", parent: NodeNG + ) -> nodes.MatchSingleton: + ... + + @overload + def visit( + self, node: "ast.MatchSequence", parent: NodeNG + ) -> nodes.MatchSequence: + ... + + @overload + def visit(self, node: "ast.MatchMapping", parent: NodeNG) -> nodes.MatchMapping: + ... + + @overload + def visit(self, node: "ast.MatchClass", parent: NodeNG) -> nodes.MatchClass: + ... + + @overload + def visit(self, node: "ast.MatchStar", parent: NodeNG) -> nodes.MatchStar: + ... + + @overload + def visit(self, node: "ast.MatchAs", parent: NodeNG) -> nodes.MatchAs: + ... + + @overload + def visit(self, node: "ast.MatchOr", parent: NodeNG) -> nodes.MatchOr: + ... + + @overload + def visit(self, node: "ast.pattern", parent: NodeNG) -> nodes.Pattern: + ... + + @overload + def visit(self, node: "ast.AST", parent: NodeNG) -> NodeNG: + ... + + @overload + def visit(self, node: None, parent: NodeNG) -> None: + ... + + def visit(self, node: Optional["ast.AST"], parent: NodeNG) -> Optional[NodeNG]: + if node is None: + return None + cls = node.__class__ + if cls in self._visit_meths: + visit_method = self._visit_meths[cls] + else: + cls_name = cls.__name__ + visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower() + visit_method = getattr(self, visit_name) + self._visit_meths[cls] = visit_method + return visit_method(node, parent) + + def _save_assignment(self, node: Union[nodes.AssignName, nodes.DelName]) -> None: + """save assignment situation since node.parent is not available yet""" + if self._global_names and node.name in self._global_names[-1]: + node.root().set_local(node.name, node) + else: + assert node.parent + node.parent.set_local(node.name, node) + + def visit_arg(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName: + """visit an arg node by returning a fresh AssName instance""" + return self.visit_assignname(node, parent, node.arg) + + def visit_arguments(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments: + """visit an Arguments node by returning a fresh instance of it""" + vararg: Optional[str] = None + kwarg: Optional[str] = None + newnode = nodes.Arguments( + node.vararg.arg if node.vararg else None, + node.kwarg.arg if node.kwarg else None, + parent, + ) + args = [self.visit(child, newnode) for child in node.args] + defaults = [self.visit(child, newnode) for child in node.defaults] + varargannotation: Optional[NodeNG] = None + kwargannotation: Optional[NodeNG] = None + posonlyargs: List[nodes.AssignName] = [] + if node.vararg: + vararg = node.vararg.arg + varargannotation = self.visit(node.vararg.annotation, newnode) + if node.kwarg: + kwarg = node.kwarg.arg + kwargannotation = self.visit(node.kwarg.annotation, newnode) + + if PY38: + # In Python 3.8 'end_lineno' and 'end_col_offset' + # for 'kwonlyargs' don't include the annotation. + for arg in node.kwonlyargs: + if arg.annotation is not None: + arg.end_lineno = arg.annotation.end_lineno + arg.end_col_offset = arg.annotation.end_col_offset + + kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs] + kw_defaults = [self.visit(child, newnode) for child in node.kw_defaults] + annotations = [self.visit(arg.annotation, newnode) for arg in node.args] + kwonlyargs_annotations = [ + self.visit(arg.annotation, newnode) for arg in node.kwonlyargs + ] + + posonlyargs_annotations: List[Optional[NodeNG]] = [] + if PY38_PLUS: + posonlyargs = [self.visit(child, newnode) for child in node.posonlyargs] + posonlyargs_annotations = [ + self.visit(arg.annotation, newnode) for arg in node.posonlyargs + ] + type_comment_args = [ + self.check_type_comment(child, parent=newnode) for child in node.args + ] + type_comment_kwonlyargs = [ + self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs + ] + type_comment_posonlyargs: List[Optional[NodeNG]] = [] + if PY38_PLUS: + type_comment_posonlyargs = [ + self.check_type_comment(child, parent=newnode) + for child in node.posonlyargs + ] + + newnode.postinit( + args=args, + defaults=defaults, + kwonlyargs=kwonlyargs, + posonlyargs=posonlyargs, + kw_defaults=kw_defaults, + annotations=annotations, + kwonlyargs_annotations=kwonlyargs_annotations, + posonlyargs_annotations=posonlyargs_annotations, + varargannotation=varargannotation, + kwargannotation=kwargannotation, + type_comment_args=type_comment_args, + type_comment_kwonlyargs=type_comment_kwonlyargs, + type_comment_posonlyargs=type_comment_posonlyargs, + ) + # save argument names in locals: + assert newnode.parent + if vararg: + newnode.parent.set_local(vararg, newnode) + if kwarg: + newnode.parent.set_local(kwarg, newnode) + return newnode + + def visit_assert(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert: + """visit a Assert node by returning a fresh instance of it""" + newnode = nodes.Assert( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + msg: Optional[NodeNG] = None + if node.msg: + msg = self.visit(node.msg, newnode) + newnode.postinit(self.visit(node.test, newnode), msg) + return newnode + + def check_type_comment( + self, + node: Union[ + "ast.Assign", + "ast.arg", + "ast.For", + "ast.AsyncFor", + "ast.With", + "ast.AsyncWith", + ], + parent: Union[ + nodes.Assign, + nodes.Arguments, + nodes.For, + nodes.AsyncFor, + nodes.With, + nodes.AsyncWith, + ], + ) -> Optional[NodeNG]: + type_comment = getattr(node, "type_comment", None) # Added in Python 3.8 + if not type_comment: + return None + + try: + type_comment_ast = self._parser_module.parse(type_comment) + except SyntaxError: + # Invalid type comment, just skip it. + return None + + type_object = self.visit(type_comment_ast.body[0], parent=parent) + if not isinstance(type_object, nodes.Expr): + return None + + return type_object.value + + def check_function_type_comment( + self, node: Union["ast.FunctionDef", "ast.AsyncFunctionDef"], parent: NodeNG + ) -> Optional[Tuple[Optional[NodeNG], List[NodeNG]]]: + type_comment = getattr(node, "type_comment", None) # Added in Python 3.8 + if not type_comment: + return None + + try: + type_comment_ast = parse_function_type_comment(type_comment) + except SyntaxError: + # Invalid type comment, just skip it. + return None + + if not type_comment_ast: + return None + + returns: Optional[NodeNG] = None + argtypes: List[NodeNG] = [ + self.visit(elem, parent) for elem in (type_comment_ast.argtypes or []) + ] + if type_comment_ast.returns: + returns = self.visit(type_comment_ast.returns, parent) + + return returns, argtypes + + def visit_asyncfunctiondef( + self, node: "ast.AsyncFunctionDef", parent: NodeNG + ) -> nodes.AsyncFunctionDef: + return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent) + + def visit_asyncfor(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor: + return self._visit_for(nodes.AsyncFor, node, parent) + + def visit_await(self, node: "ast.Await", parent: NodeNG) -> nodes.Await: + newnode = nodes.Await( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit(value=self.visit(node.value, newnode)) + return newnode + + def visit_asyncwith(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith: + return self._visit_with(nodes.AsyncWith, node, parent) + + def visit_assign(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign: + """visit a Assign node by returning a fresh instance of it""" + newnode = nodes.Assign( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + type_annotation = self.check_type_comment(node, parent=newnode) + newnode.postinit( + targets=[self.visit(child, newnode) for child in node.targets], + value=self.visit(node.value, newnode), + type_annotation=type_annotation, + ) + return newnode + + def visit_annassign(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign: + """visit an AnnAssign node by returning a fresh instance of it""" + newnode = nodes.AnnAssign( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + target=self.visit(node.target, newnode), + annotation=self.visit(node.annotation, newnode), + simple=node.simple, + value=self.visit(node.value, newnode), + ) + return newnode + + @overload + def visit_assignname( + self, node: "ast.AST", parent: NodeNG, node_name: str + ) -> nodes.AssignName: + ... + + @overload + def visit_assignname( + self, node: "ast.AST", parent: NodeNG, node_name: None + ) -> None: + ... + + def visit_assignname( + self, node: "ast.AST", parent: NodeNG, node_name: Optional[str] + ) -> Optional[nodes.AssignName]: + """visit a node and return a AssignName node + + Note: Method not called by 'visit' + """ + if node_name is None: + return None + newnode = nodes.AssignName( + name=node_name, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + self._save_assignment(newnode) + return newnode + + def visit_augassign(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign: + """visit a AugAssign node by returning a fresh instance of it""" + newnode = nodes.AugAssign( + op=self._parser_module.bin_op_classes[type(node.op)] + "=", + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.target, newnode), self.visit(node.value, newnode) + ) + return newnode + + def visit_binop(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp: + """visit a BinOp node by returning a fresh instance of it""" + newnode = nodes.BinOp( + op=self._parser_module.bin_op_classes[type(node.op)], + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.left, newnode), self.visit(node.right, newnode) + ) + return newnode + + def visit_boolop(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp: + """visit a BoolOp node by returning a fresh instance of it""" + newnode = nodes.BoolOp( + op=self._parser_module.bool_op_classes[type(node.op)], + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit([self.visit(child, newnode) for child in node.values]) + return newnode + + def visit_break(self, node: "ast.Break", parent: NodeNG) -> nodes.Break: + """visit a Break node by returning a fresh instance of it""" + return nodes.Break( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + + def visit_call(self, node: "ast.Call", parent: NodeNG) -> nodes.Call: + """visit a CallFunc node by returning a fresh instance of it""" + newnode = nodes.Call( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + func=self.visit(node.func, newnode), + args=[self.visit(child, newnode) for child in node.args], + keywords=[self.visit(child, newnode) for child in node.keywords], + ) + return newnode + + def visit_classdef( + self, node: "ast.ClassDef", parent: NodeNG, newstyle: bool = True + ) -> nodes.ClassDef: + """visit a ClassDef node to become astroid""" + node, doc_ast_node = self._get_doc(node) + newnode = nodes.ClassDef( + name=node.name, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + metaclass = None + for keyword in node.keywords: + if keyword.arg == "metaclass": + metaclass = self.visit(keyword, newnode).value + break + decorators = self.visit_decorators(node, newnode) + newnode.postinit( + [self.visit(child, newnode) for child in node.bases], + [self.visit(child, newnode) for child in node.body], + decorators, + newstyle, + metaclass, + [ + self.visit(kwd, newnode) + for kwd in node.keywords + if kwd.arg != "metaclass" + ], + position=self._get_position_info(node, newnode), + doc_node=self.visit(doc_ast_node, newnode), + ) + self._fix_doc_node_position(newnode) + return newnode + + def visit_continue(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue: + """visit a Continue node by returning a fresh instance of it""" + return nodes.Continue( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + + def visit_compare(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare: + """visit a Compare node by returning a fresh instance of it""" + newnode = nodes.Compare( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.left, newnode), + [ + ( + self._parser_module.cmp_op_classes[op.__class__], + self.visit(expr, newnode), + ) + for (op, expr) in zip(node.ops, node.comparators) + ], + ) + return newnode + + def visit_comprehension( + self, node: "ast.comprehension", parent: NodeNG + ) -> nodes.Comprehension: + """visit a Comprehension node by returning a fresh instance of it""" + newnode = nodes.Comprehension(parent) + newnode.postinit( + self.visit(node.target, newnode), + self.visit(node.iter, newnode), + [self.visit(child, newnode) for child in node.ifs], + bool(node.is_async), + ) + return newnode + + def visit_decorators( + self, + node: Union["ast.ClassDef", "ast.FunctionDef", "ast.AsyncFunctionDef"], + parent: NodeNG, + ) -> Optional[nodes.Decorators]: + """visit a Decorators node by returning a fresh instance of it + + Note: Method not called by 'visit' + """ + if not node.decorator_list: + return None + # /!\ node is actually an _ast.FunctionDef node while + # parent is an astroid.nodes.FunctionDef node + if sys.version_info >= (3, 8): + # Set the line number of the first decorator for Python 3.8+. + lineno = node.decorator_list[0].lineno + end_lineno = node.decorator_list[-1].end_lineno + end_col_offset = node.decorator_list[-1].end_col_offset + else: + lineno = node.lineno + end_lineno = None + end_col_offset = None + newnode = nodes.Decorators( + lineno=lineno, + col_offset=node.col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + newnode.postinit([self.visit(child, newnode) for child in node.decorator_list]) + return newnode + + def visit_delete(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete: + """visit a Delete node by returning a fresh instance of it""" + newnode = nodes.Delete( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit([self.visit(child, newnode) for child in node.targets]) + return newnode + + def _visit_dict_items( + self, node: "ast.Dict", parent: NodeNG, newnode: nodes.Dict + ) -> Generator[Tuple[NodeNG, NodeNG], None, None]: + for key, value in zip(node.keys, node.values): + rebuilt_key: NodeNG + rebuilt_value = self.visit(value, newnode) + if not key: + # Extended unpacking + rebuilt_key = nodes.DictUnpack( + lineno=rebuilt_value.lineno, + col_offset=rebuilt_value.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(rebuilt_value, "end_lineno", None), + end_col_offset=getattr(rebuilt_value, "end_col_offset", None), + parent=parent, + ) + else: + rebuilt_key = self.visit(key, newnode) + yield rebuilt_key, rebuilt_value + + def visit_dict(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict: + """visit a Dict node by returning a fresh instance of it""" + newnode = nodes.Dict( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + items = list(self._visit_dict_items(node, parent, newnode)) + newnode.postinit(items) + return newnode + + def visit_dictcomp(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp: + """visit a DictComp node by returning a fresh instance of it""" + newnode = nodes.DictComp( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.key, newnode), + self.visit(node.value, newnode), + [self.visit(child, newnode) for child in node.generators], + ) + return newnode + + def visit_expr(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr: + """visit a Expr node by returning a fresh instance of it""" + newnode = nodes.Expr( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit(self.visit(node.value, newnode)) + return newnode + + def visit_excepthandler( + self, node: "ast.ExceptHandler", parent: NodeNG + ) -> nodes.ExceptHandler: + """visit an ExceptHandler node by returning a fresh instance of it""" + newnode = nodes.ExceptHandler( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.type, newnode), + self.visit_assignname(node, newnode, node.name), + [self.visit(child, newnode) for child in node.body], + ) + return newnode + + @overload + def _visit_for( + self, cls: Type[nodes.For], node: "ast.For", parent: NodeNG + ) -> nodes.For: + ... + + @overload + def _visit_for( + self, cls: Type[nodes.AsyncFor], node: "ast.AsyncFor", parent: NodeNG + ) -> nodes.AsyncFor: + ... + + def _visit_for( + self, cls: Type[T_For], node: Union["ast.For", "ast.AsyncFor"], parent: NodeNG + ) -> T_For: + """visit a For node by returning a fresh instance of it""" + col_offset = node.col_offset + if IS_PYPY and not PY39_PLUS and isinstance(node, ast.AsyncFor) and self._data: + # pylint: disable-next=unsubscriptable-object + col_offset = self._data[node.lineno - 1].index("async") + + newnode = cls( + lineno=node.lineno, + col_offset=col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + type_annotation = self.check_type_comment(node, parent=newnode) + newnode.postinit( + target=self.visit(node.target, newnode), + iter=self.visit(node.iter, newnode), + body=[self.visit(child, newnode) for child in node.body], + orelse=[self.visit(child, newnode) for child in node.orelse], + type_annotation=type_annotation, + ) + return newnode + + def visit_for(self, node: "ast.For", parent: NodeNG) -> nodes.For: + return self._visit_for(nodes.For, node, parent) + + def visit_importfrom( + self, node: "ast.ImportFrom", parent: NodeNG + ) -> nodes.ImportFrom: + """visit an ImportFrom node by returning a fresh instance of it""" + names = [(alias.name, alias.asname) for alias in node.names] + newnode = nodes.ImportFrom( + fromname=node.module or "", + names=names, + level=node.level or None, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + # store From names to add them to locals after building + self._import_from_nodes.append(newnode) + return newnode + + @overload + def _visit_functiondef( + self, cls: Type[nodes.FunctionDef], node: "ast.FunctionDef", parent: NodeNG + ) -> nodes.FunctionDef: + ... + + @overload + def _visit_functiondef( + self, + cls: Type[nodes.AsyncFunctionDef], + node: "ast.AsyncFunctionDef", + parent: NodeNG, + ) -> nodes.AsyncFunctionDef: + ... + + def _visit_functiondef( + self, + cls: Type[T_Function], + node: Union["ast.FunctionDef", "ast.AsyncFunctionDef"], + parent: NodeNG, + ) -> T_Function: + """visit an FunctionDef node to become astroid""" + self._global_names.append({}) + node, doc_ast_node = self._get_doc(node) + + lineno = node.lineno + if PY38_PLUS and node.decorator_list: + # Python 3.8 sets the line number of a decorated function + # to be the actual line number of the function, but the + # previous versions expected the decorator's line number instead. + # We reset the function's line number to that of the + # first decorator to maintain backward compatibility. + # It's not ideal but this discrepancy was baked into + # the framework for *years*. + lineno = node.decorator_list[0].lineno + + newnode = cls( + name=node.name, + lineno=lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + decorators = self.visit_decorators(node, newnode) + returns: Optional[NodeNG] + if node.returns: + returns = self.visit(node.returns, newnode) + else: + returns = None + + type_comment_args = type_comment_returns = None + type_comment_annotation = self.check_function_type_comment(node, newnode) + if type_comment_annotation: + type_comment_returns, type_comment_args = type_comment_annotation + newnode.postinit( + args=self.visit(node.args, newnode), + body=[self.visit(child, newnode) for child in node.body], + decorators=decorators, + returns=returns, + type_comment_returns=type_comment_returns, + type_comment_args=type_comment_args, + position=self._get_position_info(node, newnode), + doc_node=self.visit(doc_ast_node, newnode), + ) + if IS_PYPY and PY36 and newnode.position: + # PyPy: col_offset in Python 3.6 doesn't include 'async', + # use position.col_offset instead. + newnode.col_offset = newnode.position.col_offset + self._fix_doc_node_position(newnode) + self._global_names.pop() + return newnode + + def visit_functiondef( + self, node: "ast.FunctionDef", parent: NodeNG + ) -> nodes.FunctionDef: + return self._visit_functiondef(nodes.FunctionDef, node, parent) + + def visit_generatorexp( + self, node: "ast.GeneratorExp", parent: NodeNG + ) -> nodes.GeneratorExp: + """visit a GeneratorExp node by returning a fresh instance of it""" + newnode = nodes.GeneratorExp( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.elt, newnode), + [self.visit(child, newnode) for child in node.generators], + ) + return newnode + + def visit_attribute( + self, node: "ast.Attribute", parent: NodeNG + ) -> Union[nodes.Attribute, nodes.AssignAttr, nodes.DelAttr]: + """visit an Attribute node by returning a fresh instance of it""" + context = self._get_context(node) + newnode: Union[nodes.Attribute, nodes.AssignAttr, nodes.DelAttr] + if context == Context.Del: + # FIXME : maybe we should reintroduce and visit_delattr ? + # for instance, deactivating assign_ctx + newnode = nodes.DelAttr( + attrname=node.attr, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + elif context == Context.Store: + # pylint: disable=redefined-variable-type + newnode = nodes.AssignAttr( + attrname=node.attr, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + # Prohibit a local save if we are in an ExceptHandler. + if not isinstance(parent, nodes.ExceptHandler): + # mypy doesn't recognize that newnode has to be AssignAttr because it doesn't support ParamSpec + # See https://github.com/python/mypy/issues/8645 + self._delayed_assattr.append(newnode) # type: ignore[arg-type] + else: + newnode = nodes.Attribute( + attrname=node.attr, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit(self.visit(node.value, newnode)) + return newnode + + def visit_global(self, node: "ast.Global", parent: NodeNG) -> nodes.Global: + """visit a Global node to become astroid""" + newnode = nodes.Global( + names=node.names, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + if self._global_names: # global at the module level, no effect + for name in node.names: + self._global_names[-1].setdefault(name, []).append(newnode) + return newnode + + def visit_if(self, node: "ast.If", parent: NodeNG) -> nodes.If: + """visit an If node by returning a fresh instance of it""" + newnode = nodes.If( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.test, newnode), + [self.visit(child, newnode) for child in node.body], + [self.visit(child, newnode) for child in node.orelse], + ) + return newnode + + def visit_ifexp(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp: + """visit a IfExp node by returning a fresh instance of it""" + newnode = nodes.IfExp( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.test, newnode), + self.visit(node.body, newnode), + self.visit(node.orelse, newnode), + ) + return newnode + + def visit_import(self, node: "ast.Import", parent: NodeNG) -> nodes.Import: + """visit a Import node by returning a fresh instance of it""" + names = [(alias.name, alias.asname) for alias in node.names] + newnode = nodes.Import( + names=names, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + # save import names in parent's locals: + for (name, asname) in newnode.names: + name = asname or name + parent.set_local(name.split(".")[0], newnode) + return newnode + + def visit_joinedstr(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr: + newnode = nodes.JoinedStr( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit([self.visit(child, newnode) for child in node.values]) + return newnode + + def visit_formattedvalue( + self, node: "ast.FormattedValue", parent: NodeNG + ) -> nodes.FormattedValue: + newnode = nodes.FormattedValue( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.value, newnode), + node.conversion, + self.visit(node.format_spec, newnode), + ) + return newnode + + if sys.version_info >= (3, 8): + + def visit_namedexpr( + self, node: "ast.NamedExpr", parent: NodeNG + ) -> nodes.NamedExpr: + newnode = nodes.NamedExpr( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.target, newnode), self.visit(node.value, newnode) + ) + return newnode + + if sys.version_info < (3, 9): + # Not used in Python 3.9+. + def visit_extslice( + self, node: "ast.ExtSlice", parent: nodes.Subscript + ) -> nodes.Tuple: + """visit an ExtSlice node by returning a fresh instance of Tuple""" + # ExtSlice doesn't have lineno or col_offset information + newnode = nodes.Tuple(ctx=Context.Load, parent=parent) + newnode.postinit([self.visit(dim, newnode) for dim in node.dims]) + return newnode + + def visit_index(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG: + """visit a Index node by returning a fresh instance of NodeNG""" + return self.visit(node.value, parent) + + def visit_keyword(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword: + """visit a Keyword node by returning a fresh instance of it""" + newnode = nodes.Keyword( + arg=node.arg, + # position attributes added in 3.9 + lineno=getattr(node, "lineno", None), + col_offset=getattr(node, "col_offset", None), + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit(self.visit(node.value, newnode)) + return newnode + + def visit_lambda(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda: + """visit a Lambda node by returning a fresh instance of it""" + newnode = nodes.Lambda( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit(self.visit(node.args, newnode), self.visit(node.body, newnode)) + return newnode + + def visit_list(self, node: "ast.List", parent: NodeNG) -> nodes.List: + """visit a List node by returning a fresh instance of it""" + context = self._get_context(node) + newnode = nodes.List( + ctx=context, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit([self.visit(child, newnode) for child in node.elts]) + return newnode + + def visit_listcomp(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp: + """visit a ListComp node by returning a fresh instance of it""" + newnode = nodes.ListComp( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.elt, newnode), + [self.visit(child, newnode) for child in node.generators], + ) + return newnode + + def visit_name( + self, node: "ast.Name", parent: NodeNG + ) -> Union[nodes.Name, nodes.AssignName, nodes.DelName]: + """visit a Name node by returning a fresh instance of it""" + context = self._get_context(node) + newnode: Union[nodes.Name, nodes.AssignName, nodes.DelName] + if context == Context.Del: + newnode = nodes.DelName( + name=node.id, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + elif context == Context.Store: + # pylint: disable=redefined-variable-type + newnode = nodes.AssignName( + name=node.id, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + else: + newnode = nodes.Name( + name=node.id, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + # XXX REMOVE me : + if context in (Context.Del, Context.Store): # 'Aug' ?? + newnode = cast(Union[nodes.AssignName, nodes.DelName], newnode) + self._save_assignment(newnode) + return newnode + + def visit_nonlocal(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal: + """visit a Nonlocal node and return a new instance of it""" + return nodes.Nonlocal( + names=node.names, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + + def visit_constant(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const: + """visit a Constant node by returning a fresh instance of Const""" + return nodes.Const( + value=node.value, + kind=node.kind, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + + if sys.version_info < (3, 8): + # Not used in Python 3.8+. + def visit_ellipsis(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const: + """visit an Ellipsis node by returning a fresh instance of Const""" + return nodes.Const( + value=Ellipsis, + lineno=node.lineno, + col_offset=node.col_offset, + parent=parent, + ) + + def visit_nameconstant( + self, node: "ast.NameConstant", parent: NodeNG + ) -> nodes.Const: + # For singleton values True / False / None + return nodes.Const( + node.value, + node.lineno, + node.col_offset, + parent, + ) + + def visit_str( + self, node: Union["ast.Str", "ast.Bytes"], parent: NodeNG + ) -> nodes.Const: + """visit a String/Bytes node by returning a fresh instance of Const""" + return nodes.Const( + node.s, + node.lineno, + node.col_offset, + parent, + ) + + visit_bytes = visit_str + + def visit_num(self, node: "ast.Num", parent: NodeNG) -> nodes.Const: + """visit a Num node by returning a fresh instance of Const""" + return nodes.Const( + node.n, + node.lineno, + node.col_offset, + parent, + ) + + def visit_pass(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass: + """visit a Pass node by returning a fresh instance of it""" + return nodes.Pass( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + + def visit_raise(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise: + """visit a Raise node by returning a fresh instance of it""" + newnode = nodes.Raise( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + # no traceback; anyway it is not used in Pylint + newnode.postinit( + exc=self.visit(node.exc, newnode), + cause=self.visit(node.cause, newnode), + ) + return newnode + + def visit_return(self, node: "ast.Return", parent: NodeNG) -> nodes.Return: + """visit a Return node by returning a fresh instance of it""" + newnode = nodes.Return( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + if node.value is not None: + newnode.postinit(self.visit(node.value, newnode)) + return newnode + + def visit_set(self, node: "ast.Set", parent: NodeNG) -> nodes.Set: + """visit a Set node by returning a fresh instance of it""" + newnode = nodes.Set( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit([self.visit(child, newnode) for child in node.elts]) + return newnode + + def visit_setcomp(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp: + """visit a SetComp node by returning a fresh instance of it""" + newnode = nodes.SetComp( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.elt, newnode), + [self.visit(child, newnode) for child in node.generators], + ) + return newnode + + def visit_slice(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice: + """visit a Slice node by returning a fresh instance of it""" + newnode = nodes.Slice( + # position attributes added in 3.9 + lineno=getattr(node, "lineno", None), + col_offset=getattr(node, "col_offset", None), + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + lower=self.visit(node.lower, newnode), + upper=self.visit(node.upper, newnode), + step=self.visit(node.step, newnode), + ) + return newnode + + def visit_subscript(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript: + """visit a Subscript node by returning a fresh instance of it""" + context = self._get_context(node) + newnode = nodes.Subscript( + ctx=context, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.value, newnode), self.visit(node.slice, newnode) + ) + return newnode + + def visit_starred(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred: + """visit a Starred node and return a new instance of it""" + context = self._get_context(node) + newnode = nodes.Starred( + ctx=context, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit(self.visit(node.value, newnode)) + return newnode + + def visit_tryexcept(self, node: "ast.Try", parent: NodeNG) -> nodes.TryExcept: + """visit a TryExcept node by returning a fresh instance of it""" + if sys.version_info >= (3, 8): + # TryExcept excludes the 'finally' but that will be included in the + # end_lineno from 'node'. Therefore, we check all non 'finally' + # children to find the correct end_lineno and column. + end_lineno = node.end_lineno + end_col_offset = node.end_col_offset + all_children: List["ast.AST"] = [*node.body, *node.handlers, *node.orelse] + for child in reversed(all_children): + end_lineno = child.end_lineno + end_col_offset = child.end_col_offset + break + newnode = nodes.TryExcept( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=end_lineno, + end_col_offset=end_col_offset, + parent=parent, + ) + else: + newnode = nodes.TryExcept(node.lineno, node.col_offset, parent) + newnode.postinit( + [self.visit(child, newnode) for child in node.body], + [self.visit(child, newnode) for child in node.handlers], + [self.visit(child, newnode) for child in node.orelse], + ) + return newnode + + def visit_try( + self, node: "ast.Try", parent: NodeNG + ) -> Union[nodes.TryExcept, nodes.TryFinally, None]: + # python 3.3 introduce a new Try node replacing + # TryFinally/TryExcept nodes + if node.finalbody: + newnode = nodes.TryFinally( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + body: List[Union[NodeNG, nodes.TryExcept]] + if node.handlers: + body = [self.visit_tryexcept(node, newnode)] + else: + body = [self.visit(child, newnode) for child in node.body] + newnode.postinit(body, [self.visit(n, newnode) for n in node.finalbody]) + return newnode + if node.handlers: + return self.visit_tryexcept(node, parent) + return None + + def visit_tuple(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple: + """visit a Tuple node by returning a fresh instance of it""" + context = self._get_context(node) + newnode = nodes.Tuple( + ctx=context, + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit([self.visit(child, newnode) for child in node.elts]) + return newnode + + def visit_unaryop(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp: + """visit a UnaryOp node by returning a fresh instance of it""" + newnode = nodes.UnaryOp( + op=self._parser_module.unary_op_classes[node.op.__class__], + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit(self.visit(node.operand, newnode)) + return newnode + + def visit_while(self, node: "ast.While", parent: NodeNG) -> nodes.While: + """visit a While node by returning a fresh instance of it""" + newnode = nodes.While( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + newnode.postinit( + self.visit(node.test, newnode), + [self.visit(child, newnode) for child in node.body], + [self.visit(child, newnode) for child in node.orelse], + ) + return newnode + + @overload + def _visit_with( + self, cls: Type[nodes.With], node: "ast.With", parent: NodeNG + ) -> nodes.With: + ... + + @overload + def _visit_with( + self, cls: Type[nodes.AsyncWith], node: "ast.AsyncWith", parent: NodeNG + ) -> nodes.AsyncWith: + ... + + def _visit_with( + self, + cls: Type[T_With], + node: Union["ast.With", "ast.AsyncWith"], + parent: NodeNG, + ) -> T_With: + col_offset = node.col_offset + if IS_PYPY and not PY39_PLUS and isinstance(node, ast.AsyncWith) and self._data: + # pylint: disable-next=unsubscriptable-object + col_offset = self._data[node.lineno - 1].index("async") + + newnode = cls( + lineno=node.lineno, + col_offset=col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + + def visit_child(child: "ast.withitem") -> Tuple[NodeNG, Optional[NodeNG]]: + expr = self.visit(child.context_expr, newnode) + var = self.visit(child.optional_vars, newnode) + return expr, var + + type_annotation = self.check_type_comment(node, parent=newnode) + newnode.postinit( + items=[visit_child(child) for child in node.items], + body=[self.visit(child, newnode) for child in node.body], + type_annotation=type_annotation, + ) + return newnode + + def visit_with(self, node: "ast.With", parent: NodeNG) -> NodeNG: + return self._visit_with(nodes.With, node, parent) + + def visit_yield(self, node: "ast.Yield", parent: NodeNG) -> NodeNG: + """visit a Yield node by returning a fresh instance of it""" + newnode = nodes.Yield( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + if node.value is not None: + newnode.postinit(self.visit(node.value, newnode)) + return newnode + + def visit_yieldfrom(self, node: "ast.YieldFrom", parent: NodeNG) -> NodeNG: + newnode = nodes.YieldFrom( + lineno=node.lineno, + col_offset=node.col_offset, + # end_lineno and end_col_offset added in 3.8 + end_lineno=getattr(node, "end_lineno", None), + end_col_offset=getattr(node, "end_col_offset", None), + parent=parent, + ) + if node.value is not None: + newnode.postinit(self.visit(node.value, newnode)) + return newnode + + if sys.version_info >= (3, 10): + + def visit_match(self, node: "ast.Match", parent: NodeNG) -> nodes.Match: + newnode = nodes.Match( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + newnode.postinit( + subject=self.visit(node.subject, newnode), + cases=[self.visit(case, newnode) for case in node.cases], + ) + return newnode + + def visit_matchcase( + self, node: "ast.match_case", parent: NodeNG + ) -> nodes.MatchCase: + newnode = nodes.MatchCase(parent=parent) + newnode.postinit( + pattern=self.visit(node.pattern, newnode), + guard=self.visit(node.guard, newnode), + body=[self.visit(child, newnode) for child in node.body], + ) + return newnode + + def visit_matchvalue( + self, node: "ast.MatchValue", parent: NodeNG + ) -> nodes.MatchValue: + newnode = nodes.MatchValue( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + newnode.postinit(value=self.visit(node.value, newnode)) + return newnode + + def visit_matchsingleton( + self, node: "ast.MatchSingleton", parent: NodeNG + ) -> nodes.MatchSingleton: + return nodes.MatchSingleton( + value=node.value, + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + + def visit_matchsequence( + self, node: "ast.MatchSequence", parent: NodeNG + ) -> nodes.MatchSequence: + newnode = nodes.MatchSequence( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + newnode.postinit( + patterns=[self.visit(pattern, newnode) for pattern in node.patterns] + ) + return newnode + + def visit_matchmapping( + self, node: "ast.MatchMapping", parent: NodeNG + ) -> nodes.MatchMapping: + newnode = nodes.MatchMapping( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + # Add AssignName node for 'node.name' + # https://bugs.python.org/issue43994 + newnode.postinit( + keys=[self.visit(child, newnode) for child in node.keys], + patterns=[self.visit(pattern, newnode) for pattern in node.patterns], + rest=self.visit_assignname(node, newnode, node.rest), + ) + return newnode + + def visit_matchclass( + self, node: "ast.MatchClass", parent: NodeNG + ) -> nodes.MatchClass: + newnode = nodes.MatchClass( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + newnode.postinit( + cls=self.visit(node.cls, newnode), + patterns=[self.visit(pattern, newnode) for pattern in node.patterns], + kwd_attrs=node.kwd_attrs, + kwd_patterns=[ + self.visit(pattern, newnode) for pattern in node.kwd_patterns + ], + ) + return newnode + + def visit_matchstar( + self, node: "ast.MatchStar", parent: NodeNG + ) -> nodes.MatchStar: + newnode = nodes.MatchStar( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + # Add AssignName node for 'node.name' + # https://bugs.python.org/issue43994 + newnode.postinit(name=self.visit_assignname(node, newnode, node.name)) + return newnode + + def visit_matchas(self, node: "ast.MatchAs", parent: NodeNG) -> nodes.MatchAs: + newnode = nodes.MatchAs( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + # Add AssignName node for 'node.name' + # https://bugs.python.org/issue43994 + newnode.postinit( + pattern=self.visit(node.pattern, newnode), + name=self.visit_assignname(node, newnode, node.name), + ) + return newnode + + def visit_matchor(self, node: "ast.MatchOr", parent: NodeNG) -> nodes.MatchOr: + newnode = nodes.MatchOr( + lineno=node.lineno, + col_offset=node.col_offset, + end_lineno=node.end_lineno, + end_col_offset=node.end_col_offset, + parent=parent, + ) + newnode.postinit( + patterns=[self.visit(pattern, newnode) for pattern in node.patterns] + ) + return newnode diff --git a/myenv/lib/python3.9/site-packages/astroid/scoped_nodes.py b/myenv/lib/python3.9/site-packages/astroid/scoped_nodes.py new file mode 100644 index 0000000..677f892 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/scoped_nodes.py @@ -0,0 +1,33 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +# pylint: disable=unused-import + +import warnings + +from astroid.nodes.scoped_nodes import ( + AsyncFunctionDef, + ClassDef, + ComprehensionScope, + DictComp, + FunctionDef, + GeneratorExp, + Lambda, + ListComp, + LocalsDictNodeNG, + Module, + SetComp, + _is_metaclass, + builtin_lookup, + function_to_method, + get_wrapping_class, +) + +# We cannot create a __all__ here because it would create a circular import +# Please remove astroid/scoped_nodes.py|astroid/node_classes.py in autoflake +# exclude when removing this file. +warnings.warn( + "The 'astroid.scoped_nodes' module is deprecated and will be replaced by 'astroid.nodes' in astroid 3.0.0", + DeprecationWarning, +) diff --git a/myenv/lib/python3.9/site-packages/astroid/test_utils.py b/myenv/lib/python3.9/site-packages/astroid/test_utils.py new file mode 100644 index 0000000..2ab7383 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/test_utils.py @@ -0,0 +1,76 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +"""Utility functions for test code that uses astroid ASTs as input.""" +import contextlib +import functools +import sys +import warnings +from typing import Callable, Tuple + +import pytest + +from astroid import manager, nodes, transforms + + +def require_version(minver: str = "0.0.0", maxver: str = "4.0.0") -> Callable: + """Compare version of python interpreter to the given one. + Skip the test if older. + """ + + def parse(python_version: str) -> Tuple[int, ...]: + try: + return tuple(int(v) for v in python_version.split(".")) + except ValueError as e: + msg = f"{python_version} is not a correct version : should be X.Y[.Z]." + raise ValueError(msg) from e + + min_version = parse(minver) + max_version = parse(maxver) + + def check_require_version(f): + current: Tuple[int, int, int] = sys.version_info[:3] + if min_version < current <= max_version: + return f + + version: str = ".".join(str(v) for v in sys.version_info) + + @functools.wraps(f) + def new_f(*args, **kwargs): + if current <= min_version: + pytest.skip(f"Needs Python > {minver}. Current version is {version}.") + elif current > max_version: + pytest.skip(f"Needs Python <= {maxver}. Current version is {version}.") + + return new_f + + return check_require_version + + +def get_name_node(start_from, name, index=0): + return [n for n in start_from.nodes_of_class(nodes.Name) if n.name == name][index] + + +@contextlib.contextmanager +def enable_warning(warning): + warnings.simplefilter("always", warning) + try: + yield + finally: + # Reset it to default value, so it will take + # into account the values from the -W flag. + warnings.simplefilter("default", warning) + + +def brainless_manager(): + m = manager.AstroidManager() + # avoid caching into the AstroidManager borg since we get problems + # with other tests : + m.__dict__ = {} + m._failed_import_hooks = [] + m.astroid_cache = {} + m._mod_file_cache = {} + m._transform = transforms.TransformVisitor() + m.extension_package_whitelist = {} + return m diff --git a/myenv/lib/python3.9/site-packages/astroid/transforms.py b/myenv/lib/python3.9/site-packages/astroid/transforms.py new file mode 100644 index 0000000..2fc8935 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/transforms.py @@ -0,0 +1,88 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import collections +from typing import TYPE_CHECKING + +from astroid.context import _invalidate_cache + +if TYPE_CHECKING: + from astroid import NodeNG + + +class TransformVisitor: + """A visitor for handling transforms. + + The standard approach of using it is to call + :meth:`~visit` with an *astroid* module and the class + will take care of the rest, walking the tree and running the + transforms for each encountered node. + """ + + def __init__(self): + self.transforms = collections.defaultdict(list) + + def _transform(self, node: "NodeNG") -> "NodeNG": + """Call matching transforms for the given node if any and return the + transformed node. + """ + cls = node.__class__ + if cls not in self.transforms: + # no transform registered for this class of node + return node + + transforms = self.transforms[cls] + for transform_func, predicate in transforms: + if predicate is None or predicate(node): + ret = transform_func(node) + # if the transformation function returns something, it's + # expected to be a replacement for the node + if ret is not None: + _invalidate_cache() + node = ret + if ret.__class__ != cls: + # Can no longer apply the rest of the transforms. + break + return node + + def _visit(self, node): + if hasattr(node, "_astroid_fields"): + for name in node._astroid_fields: + value = getattr(node, name) + visited = self._visit_generic(value) + if visited != value: + setattr(node, name, visited) + return self._transform(node) + + def _visit_generic(self, node): + if isinstance(node, list): + return [self._visit_generic(child) for child in node] + if isinstance(node, tuple): + return tuple(self._visit_generic(child) for child in node) + if not node or isinstance(node, str): + return node + + return self._visit(node) + + def register_transform(self, node_class, transform, predicate=None): + """Register `transform(node)` function to be applied on the given + astroid's `node_class` if `predicate` is None or returns true + when called with the node as argument. + + The transform function may return a value which is then used to + substitute the original node in the tree. + """ + self.transforms[node_class].append((transform, predicate)) + + def unregister_transform(self, node_class, transform, predicate=None): + """Unregister the given transform.""" + self.transforms[node_class].remove((transform, predicate)) + + def visit(self, module): + """Walk the given astroid *tree* and transform each encountered node + + Only the nodes which have transforms registered will actually + be replaced or changed. + """ + return self._visit(module) diff --git a/myenv/lib/python3.9/site-packages/astroid/typing.py b/myenv/lib/python3.9/site-packages/astroid/typing.py new file mode 100644 index 0000000..32d01dd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/typing.py @@ -0,0 +1,27 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import sys +from typing import TYPE_CHECKING, Any, Callable + +if TYPE_CHECKING: + from astroid import nodes + from astroid.context import InferenceContext + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + + +class InferenceErrorInfo(TypedDict): + """Store additional Inference error information + raised with StopIteration exception. + """ + + node: "nodes.NodeNG" + context: "InferenceContext | None" + + +InferFn = Callable[..., Any] diff --git a/myenv/lib/python3.9/site-packages/astroid/util.py b/myenv/lib/python3.9/site-packages/astroid/util.py new file mode 100644 index 0000000..b071285 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/astroid/util.py @@ -0,0 +1,147 @@ +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html +# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE +# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt + +import importlib +import warnings + +import lazy_object_proxy + + +def lazy_descriptor(obj): + class DescriptorProxy(lazy_object_proxy.Proxy): + def __get__(self, instance, owner=None): + return self.__class__.__get__(self, instance) + + return DescriptorProxy(obj) + + +def lazy_import(module_name): + return lazy_object_proxy.Proxy( + lambda: importlib.import_module("." + module_name, "astroid") + ) + + +@object.__new__ +class Uninferable: + """Special inference object, which is returned when inference fails.""" + + def __repr__(self): + return "Uninferable" + + __str__ = __repr__ + + def __getattribute__(self, name): + if name == "next": + raise AttributeError("next method should not be called") + if name.startswith("__") and name.endswith("__"): + return object.__getattribute__(self, name) + if name == "accept": + return object.__getattribute__(self, name) + return self + + def __call__(self, *args, **kwargs): + return self + + def __bool__(self): + return False + + __nonzero__ = __bool__ + + def accept(self, visitor): + return visitor.visit_uninferable(self) + + +class BadOperationMessage: + """Object which describes a TypeError occurred somewhere in the inference chain + + This is not an exception, but a container object which holds the types and + the error which occurred. + """ + + +class BadUnaryOperationMessage(BadOperationMessage): + """Object which describes operational failures on UnaryOps.""" + + def __init__(self, operand, op, error): + self.operand = operand + self.op = op + self.error = error + + @property + def _object_type_helper(self): + helpers = lazy_import("helpers") + return helpers.object_type + + def _object_type(self, obj): + objtype = self._object_type_helper(obj) + if objtype is Uninferable: + return None + + return objtype + + def __str__(self): + if hasattr(self.operand, "name"): + operand_type = self.operand.name + else: + object_type = self._object_type(self.operand) + if hasattr(object_type, "name"): + operand_type = object_type.name + else: + # Just fallback to as_string + operand_type = object_type.as_string() + + msg = "bad operand type for unary {}: {}" + return msg.format(self.op, operand_type) + + +class BadBinaryOperationMessage(BadOperationMessage): + """Object which describes type errors for BinOps.""" + + def __init__(self, left_type, op, right_type): + self.left_type = left_type + self.right_type = right_type + self.op = op + + def __str__(self): + msg = "unsupported operand type(s) for {}: {!r} and {!r}" + return msg.format(self.op, self.left_type.name, self.right_type.name) + + +def _instancecheck(cls, other): + wrapped = cls.__wrapped__ + other_cls = other.__class__ + is_instance_of = wrapped is other_cls or issubclass(other_cls, wrapped) + warnings.warn( + "%r is deprecated and slated for removal in astroid " + "2.0, use %r instead" % (cls.__class__.__name__, wrapped.__name__), + PendingDeprecationWarning, + stacklevel=2, + ) + return is_instance_of + + +def proxy_alias(alias_name, node_type): + """Get a Proxy from the given name to the given node type.""" + proxy = type( + alias_name, + (lazy_object_proxy.Proxy,), + { + "__class__": object.__dict__["__class__"], + "__instancecheck__": _instancecheck, + }, + ) + return proxy(lambda: node_type) + + +def check_warnings_filter() -> bool: + """Return True if any other than the default DeprecationWarning filter is enabled. + + https://docs.python.org/3/library/warnings.html#default-warning-filter + """ + return any( + issubclass(DeprecationWarning, filter[2]) + and filter[0] != "ignore" + and filter[3] != "__main__" + for filter in warnings.filters + ) diff --git a/myenv/lib/python3.9/site-packages/attr/__init__.py b/myenv/lib/python3.9/site-packages/attr/__init__.py new file mode 100644 index 0000000..f95c96d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/__init__.py @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import sys + +from functools import partial + +from . import converters, exceptions, filters, setters, validators +from ._cmp import cmp_using +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__ = "21.4.0" +__version_info__ = VersionInfo._from_version_string(__version__) + +__title__ = "attrs" +__description__ = "Classes Without Boilerplate" +__url__ = "https://www.attrs.org/" +__uri__ = __url__ +__doc__ = __description__ + " <" + __uri__ + ">" + +__author__ = "Hynek Schlawack" +__email__ = "hs@ox.cx" + +__license__ = "MIT" +__copyright__ = "Copyright (c) 2015 Hynek Schlawack" + + +s = attributes = attrs +ib = attr = attrib +dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) + +__all__ = [ + "Attribute", + "Factory", + "NOTHING", + "asdict", + "assoc", + "astuple", + "attr", + "attrib", + "attributes", + "attrs", + "cmp_using", + "converters", + "evolve", + "exceptions", + "fields", + "fields_dict", + "filters", + "get_run_validators", + "has", + "ib", + "make_class", + "resolve_types", + "s", + "set_run_validators", + "setters", + "validate", + "validators", +] + +if sys.version_info[:2] >= (3, 6): + from ._next_gen import define, field, frozen, mutable # noqa: F401 + + __all__.extend(("define", "field", "frozen", "mutable")) diff --git a/myenv/lib/python3.9/site-packages/attr/__init__.pyi b/myenv/lib/python3.9/site-packages/attr/__init__.pyi new file mode 100644 index 0000000..c0a2126 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/__init__.pyi @@ -0,0 +1,484 @@ +import sys + +from typing import ( + Any, + Callable, + Dict, + Generic, + List, + Mapping, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +# `import X as X` is required to make these public +from . import converters as converters +from . import exceptions as exceptions +from . import filters as filters +from . import setters as setters +from . import validators as validators +from ._version_info import VersionInfo + +__version__: str +__version_info__: VersionInfo +__title__: str +__description__: str +__url__: str +__uri__: str +__author__: str +__email__: str +__license__: str +__copyright__: str + +_T = TypeVar("_T") +_C = TypeVar("_C", bound=type) + +_EqOrderType = Union[bool, Callable[[Any], Any]] +_ValidatorType = Callable[[Any, Attribute[_T], _T], Any] +_ConverterType = Callable[[Any], Any] +_FilterType = Callable[[Attribute[_T], _T], bool] +_ReprType = Callable[[Any], str] +_ReprArgType = Union[bool, _ReprType] +_OnSetAttrType = Callable[[Any, Attribute[Any], Any], Any] +_OnSetAttrArgType = Union[ + _OnSetAttrType, List[_OnSetAttrType], setters._NoOpType +] +_FieldTransformer = Callable[ + [type, List[Attribute[Any]]], List[Attribute[Any]] +] +_CompareWithType = Callable[[Any, Any], bool] +# FIXME: in reality, if multiple validators are passed they must be in a list +# or tuple, but those are invariant and so would prevent subtypes of +# _ValidatorType from working when passed in a list or tuple. +_ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]] + +# _make -- + +NOTHING: object + +# NOTE: Factory lies about its return type to make this possible: +# `x: List[int] # = Factory(list)` +# Work around mypy issue #4554 in the common case by using an overload. +if sys.version_info >= (3, 8): + from typing import Literal + @overload + def Factory(factory: Callable[[], _T]) -> _T: ... + @overload + def Factory( + factory: Callable[[Any], _T], + takes_self: Literal[True], + ) -> _T: ... + @overload + def Factory( + factory: Callable[[], _T], + takes_self: Literal[False], + ) -> _T: ... + +else: + @overload + def Factory(factory: Callable[[], _T]) -> _T: ... + @overload + def Factory( + factory: Union[Callable[[Any], _T], Callable[[], _T]], + takes_self: bool = ..., + ) -> _T: ... + +# Static type inference support via __dataclass_transform__ implemented as per: +# https://github.com/microsoft/pyright/blob/1.1.135/specs/dataclass_transforms.md +# This annotation must be applied to all overloads of "define" and "attrs" +# +# NOTE: This is a typing construct and does not exist at runtime. Extensions +# wrapping attrs decorators should declare a separate __dataclass_transform__ +# signature in the extension module using the specification linked above to +# provide pyright support. +def __dataclass_transform__( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + field_descriptors: Tuple[Union[type, Callable[..., Any]], ...] = (()), +) -> Callable[[_T], _T]: ... + +class Attribute(Generic[_T]): + name: str + default: Optional[_T] + validator: Optional[_ValidatorType[_T]] + repr: _ReprArgType + cmp: _EqOrderType + eq: _EqOrderType + order: _EqOrderType + hash: Optional[bool] + init: bool + converter: Optional[_ConverterType] + metadata: Dict[Any, Any] + type: Optional[Type[_T]] + kw_only: bool + on_setattr: _OnSetAttrType + def evolve(self, **changes: Any) -> "Attribute[Any]": ... + +# NOTE: We had several choices for the annotation to use for type arg: +# 1) Type[_T] +# - Pros: Handles simple cases correctly +# - Cons: Might produce less informative errors in the case of conflicting +# TypeVars e.g. `attr.ib(default='bad', type=int)` +# 2) Callable[..., _T] +# - Pros: Better error messages than #1 for conflicting TypeVars +# - Cons: Terrible error messages for validator checks. +# e.g. attr.ib(type=int, validator=validate_str) +# -> error: Cannot infer function type argument +# 3) type (and do all of the work in the mypy plugin) +# - Pros: Simple here, and we could customize the plugin with our own errors. +# - Cons: Would need to write mypy plugin code to handle all the cases. +# We chose option #1. + +# `attr` lies about its return type to make the following possible: +# attr() -> Any +# attr(8) -> int +# attr(validator=) -> Whatever the callable expects. +# This makes this type of assignments possible: +# x: int = attr(8) +# +# This form catches explicit None or no default but with no other arguments +# returns Any. +@overload +def attrib( + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: None = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def attrib( + default: None = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: Optional[Type[_T]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def attrib( + default: _T, + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: Optional[Type[_T]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def attrib( + default: Optional[_T] = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: object = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... +@overload +def field( + *, + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def field( + *, + default: None = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def field( + *, + default: _T, + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def field( + *, + default: Optional[_T] = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., +) -> Any: ... +@overload +@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field)) +def attrs( + maybe_cls: _C, + these: Optional[Dict[str, Any]] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field)) +def attrs( + maybe_cls: None = ..., + these: Optional[Dict[str, Any]] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... +@overload +@__dataclass_transform__(field_descriptors=(attrib, field)) +def define( + maybe_cls: _C, + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@__dataclass_transform__(field_descriptors=(attrib, field)) +def define( + maybe_cls: None = ..., + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... + +mutable = define +frozen = define # they differ only in their defaults + +# TODO: add support for returning NamedTuple from the mypy plugin +class _Fields(Tuple[Attribute[Any], ...]): + def __getattr__(self, name: str) -> Attribute[Any]: ... + +def fields(cls: type) -> _Fields: ... +def fields_dict(cls: type) -> Dict[str, Attribute[Any]]: ... +def validate(inst: Any) -> None: ... +def resolve_types( + cls: _C, + globalns: Optional[Dict[str, Any]] = ..., + localns: Optional[Dict[str, Any]] = ..., + attribs: Optional[List[Attribute[Any]]] = ..., +) -> _C: ... + +# TODO: add support for returning a proper attrs class from the mypy plugin +# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', +# [attr.ib()])` is valid +def make_class( + name: str, + attrs: Union[List[str], Tuple[str, ...], Dict[str, Any]], + bases: Tuple[type, ...] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + collect_by_mro: bool = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., +) -> type: ... + +# _funcs -- + +# TODO: add support for returning TypedDict from the mypy plugin +# FIXME: asdict/astuple do not honor their factory args. Waiting on one of +# these: +# https://github.com/python/mypy/issues/4236 +# https://github.com/python/typing/issues/253 +# XXX: remember to fix attrs.asdict/astuple too! +def asdict( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + dict_factory: Type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: Optional[bool] = ..., +) -> Dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + tuple_factory: Type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> Tuple[Any, ...]: ... +def has(cls: type) -> bool: ... +def assoc(inst: _T, **changes: Any) -> _T: ... +def evolve(inst: _T, **changes: Any) -> _T: ... + +# _config -- + +def set_run_validators(run: bool) -> None: ... +def get_run_validators() -> bool: ... + +# aliases -- + +s = attributes = attrs +ib = attr = attrib +dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/myenv/lib/python3.9/site-packages/attr/_cmp.py b/myenv/lib/python3.9/site-packages/attr/_cmp.py new file mode 100644 index 0000000..6cffa4d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_cmp.py @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import functools + +from ._compat import new_class +from ._make import _make_ne + + +_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} + + +def cmp_using( + eq=None, + lt=None, + le=None, + gt=None, + ge=None, + require_same_type=True, + class_name="Comparable", +): + """ + Create a class that can be passed into `attr.ib`'s ``eq``, ``order``, and + ``cmp`` arguments to customize field comparison. + + The resulting class will have a full set of ordering methods if + at least one of ``{lt, le, gt, ge}`` and ``eq`` are provided. + + :param Optional[callable] eq: `callable` used to evaluate equality + of two objects. + :param Optional[callable] lt: `callable` used to evaluate whether + one object is less than another object. + :param Optional[callable] le: `callable` used to evaluate whether + one object is less than or equal to another object. + :param Optional[callable] gt: `callable` used to evaluate whether + one object is greater than another object. + :param Optional[callable] ge: `callable` used to evaluate whether + one object is greater than or equal to another object. + + :param bool require_same_type: When `True`, equality and ordering methods + will return `NotImplemented` if objects are not of the same type. + + :param Optional[str] class_name: Name of class. Defaults to 'Comparable'. + + See `comparison` for more details. + + .. versionadded:: 21.1.0 + """ + + body = { + "__slots__": ["value"], + "__init__": _make_init(), + "_requirements": [], + "_is_comparable_to": _is_comparable_to, + } + + # Add operations. + num_order_functions = 0 + has_eq_function = False + + if eq is not None: + has_eq_function = True + body["__eq__"] = _make_operator("eq", eq) + body["__ne__"] = _make_ne() + + if lt is not None: + num_order_functions += 1 + body["__lt__"] = _make_operator("lt", lt) + + if le is not None: + num_order_functions += 1 + body["__le__"] = _make_operator("le", le) + + if gt is not None: + num_order_functions += 1 + body["__gt__"] = _make_operator("gt", gt) + + if ge is not None: + num_order_functions += 1 + body["__ge__"] = _make_operator("ge", ge) + + type_ = new_class(class_name, (object,), {}, lambda ns: ns.update(body)) + + # Add same type requirement. + if require_same_type: + type_._requirements.append(_check_same_type) + + # Add total ordering if at least one operation was defined. + if 0 < num_order_functions < 4: + if not has_eq_function: + # functools.total_ordering requires __eq__ to be defined, + # so raise early error here to keep a nice stack. + raise ValueError( + "eq must be define is order to complete ordering from " + "lt, le, gt, ge." + ) + type_ = functools.total_ordering(type_) + + return type_ + + +def _make_init(): + """ + Create __init__ method. + """ + + def __init__(self, value): + """ + Initialize object with *value*. + """ + self.value = value + + return __init__ + + +def _make_operator(name, func): + """ + Create operator method. + """ + + def method(self, other): + if not self._is_comparable_to(other): + return NotImplemented + + result = func(self.value, other.value) + if result is NotImplemented: + return NotImplemented + + return result + + method.__name__ = "__%s__" % (name,) + method.__doc__ = "Return a %s b. Computed by attrs." % ( + _operation_names[name], + ) + + return method + + +def _is_comparable_to(self, other): + """ + Check whether `other` is comparable to `self`. + """ + for func in self._requirements: + if not func(self, other): + return False + return True + + +def _check_same_type(self, other): + """ + Return True if *self* and *other* are of the same type, False otherwise. + """ + return other.value.__class__ is self.value.__class__ diff --git a/myenv/lib/python3.9/site-packages/attr/_cmp.pyi b/myenv/lib/python3.9/site-packages/attr/_cmp.pyi new file mode 100644 index 0000000..e71aaff --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_cmp.pyi @@ -0,0 +1,13 @@ +from typing import Type + +from . import _CompareWithType + +def cmp_using( + eq: Optional[_CompareWithType], + lt: Optional[_CompareWithType], + le: Optional[_CompareWithType], + gt: Optional[_CompareWithType], + ge: Optional[_CompareWithType], + require_same_type: bool, + class_name: str, +) -> Type: ... diff --git a/myenv/lib/python3.9/site-packages/attr/_compat.py b/myenv/lib/python3.9/site-packages/attr/_compat.py new file mode 100644 index 0000000..dc0cb02 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_compat.py @@ -0,0 +1,261 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import platform +import sys +import threading +import types +import warnings + + +PY2 = sys.version_info[0] == 2 +PYPY = platform.python_implementation() == "PyPy" +PY36 = sys.version_info[:2] >= (3, 6) +HAS_F_STRINGS = PY36 +PY310 = sys.version_info[:2] >= (3, 10) + + +if PYPY or PY36: + ordered_dict = dict +else: + from collections import OrderedDict + + ordered_dict = OrderedDict + + +if PY2: + from collections import Mapping, Sequence + + from UserDict import IterableUserDict + + # We 'bundle' isclass instead of using inspect as importing inspect is + # fairly expensive (order of 10-15 ms for a modern machine in 2016) + def isclass(klass): + return isinstance(klass, (type, types.ClassType)) + + def new_class(name, bases, kwds, exec_body): + """ + A minimal stub of types.new_class that we need for make_class. + """ + ns = {} + exec_body(ns) + + return type(name, bases, ns) + + # TYPE is used in exceptions, repr(int) is different on Python 2 and 3. + TYPE = "type" + + def iteritems(d): + return d.iteritems() + + # Python 2 is bereft of a read-only dict proxy, so we make one! + class ReadOnlyDict(IterableUserDict): + """ + Best-effort read-only dict wrapper. + """ + + def __setitem__(self, key, val): + # We gently pretend we're a Python 3 mappingproxy. + raise TypeError( + "'mappingproxy' object does not support item assignment" + ) + + def update(self, _): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'update'" + ) + + def __delitem__(self, _): + # We gently pretend we're a Python 3 mappingproxy. + raise TypeError( + "'mappingproxy' object does not support item deletion" + ) + + def clear(self): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'clear'" + ) + + def pop(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'pop'" + ) + + def popitem(self): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'popitem'" + ) + + def setdefault(self, key, default=None): + # We gently pretend we're a Python 3 mappingproxy. + raise AttributeError( + "'mappingproxy' object has no attribute 'setdefault'" + ) + + def __repr__(self): + # Override to be identical to the Python 3 version. + return "mappingproxy(" + repr(self.data) + ")" + + def metadata_proxy(d): + res = ReadOnlyDict() + res.data.update(d) # We blocked update, so we have to do it like this. + return res + + def just_warn(*args, **kw): # pragma: no cover + """ + We only warn on Python 3 because we are not aware of any concrete + consequences of not setting the cell on Python 2. + """ + +else: # Python 3 and later. + from collections.abc import Mapping, Sequence # noqa + + def just_warn(*args, **kw): + """ + We only warn on Python 3 because we are not aware of any concrete + consequences of not setting the cell on Python 2. + """ + warnings.warn( + "Running interpreter doesn't sufficiently support code object " + "introspection. Some features like bare super() or accessing " + "__class__ will not work with slotted classes.", + RuntimeWarning, + stacklevel=2, + ) + + def isclass(klass): + return isinstance(klass, type) + + TYPE = "class" + + def iteritems(d): + return d.items() + + new_class = types.new_class + + def metadata_proxy(d): + return types.MappingProxyType(dict(d)) + + +def make_set_closure_cell(): + """Return a function of two arguments (cell, value) which sets + the value stored in the closure cell `cell` to `value`. + """ + # pypy makes this easy. (It also supports the logic below, but + # why not do the easy/fast thing?) + if PYPY: + + def set_closure_cell(cell, value): + cell.__setstate__((value,)) + + return set_closure_cell + + # Otherwise gotta do it the hard way. + + # Create a function that will set its first cellvar to `value`. + def set_first_cellvar_to(value): + x = value + return + + # This function will be eliminated as dead code, but + # not before its reference to `x` forces `x` to be + # represented as a closure cell rather than a local. + def force_x_to_be_a_cell(): # pragma: no cover + return x + + try: + # Extract the code object and make sure our assumptions about + # the closure behavior are correct. + if PY2: + co = set_first_cellvar_to.func_code + else: + co = set_first_cellvar_to.__code__ + if co.co_cellvars != ("x",) or co.co_freevars != (): + raise AssertionError # pragma: no cover + + # Convert this code object to a code object that sets the + # function's first _freevar_ (not cellvar) to the argument. + if sys.version_info >= (3, 8): + # CPython 3.8+ has an incompatible CodeType signature + # (added a posonlyargcount argument) but also added + # CodeType.replace() to do this without counting parameters. + set_first_freevar_code = co.replace( + co_cellvars=co.co_freevars, co_freevars=co.co_cellvars + ) + else: + args = [co.co_argcount] + if not PY2: + args.append(co.co_kwonlyargcount) + args.extend( + [ + co.co_nlocals, + co.co_stacksize, + co.co_flags, + co.co_code, + co.co_consts, + co.co_names, + co.co_varnames, + co.co_filename, + co.co_name, + co.co_firstlineno, + co.co_lnotab, + # These two arguments are reversed: + co.co_cellvars, + co.co_freevars, + ] + ) + set_first_freevar_code = types.CodeType(*args) + + def set_closure_cell(cell, value): + # Create a function using the set_first_freevar_code, + # whose first closure cell is `cell`. Calling it will + # change the value of that cell. + setter = types.FunctionType( + set_first_freevar_code, {}, "setter", (), (cell,) + ) + # And call it to set the cell. + setter(value) + + # Make sure it works on this interpreter: + def make_func_with_cell(): + x = None + + def func(): + return x # pragma: no cover + + return func + + if PY2: + cell = make_func_with_cell().func_closure[0] + else: + cell = make_func_with_cell().__closure__[0] + set_closure_cell(cell, 100) + if cell.cell_contents != 100: + raise AssertionError # pragma: no cover + + except Exception: + return just_warn + else: + return set_closure_cell + + +set_closure_cell = make_set_closure_cell() + +# Thread-local global to track attrs instances which are already being repr'd. +# This is needed because there is no other (thread-safe) way to pass info +# about the instances that are already being repr'd through the call stack +# in order to ensure we don't perform infinite recursion. +# +# For instance, if an instance contains a dict which contains that instance, +# we need to know that we're already repr'ing the outside instance from within +# the dict's repr() call. +# +# This lives here rather than in _make.py so that the functions in _make.py +# don't have a direct reference to the thread-local in their globals dict. +# If they have such a reference, it breaks cloudpickle. +repr_context = threading.local() diff --git a/myenv/lib/python3.9/site-packages/attr/_config.py b/myenv/lib/python3.9/site-packages/attr/_config.py new file mode 100644 index 0000000..fc9be29 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_config.py @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +__all__ = ["set_run_validators", "get_run_validators"] + +_run_validators = True + + +def set_run_validators(run): + """ + Set whether or not validators are run. By default, they are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` + instead. + """ + if not isinstance(run, bool): + raise TypeError("'run' must be bool.") + global _run_validators + _run_validators = run + + +def get_run_validators(): + """ + Return whether or not validators are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` + instead. + """ + return _run_validators diff --git a/myenv/lib/python3.9/site-packages/attr/_funcs.py b/myenv/lib/python3.9/site-packages/attr/_funcs.py new file mode 100644 index 0000000..4c90085 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_funcs.py @@ -0,0 +1,422 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import copy + +from ._compat import iteritems +from ._make import NOTHING, _obj_setattr, fields +from .exceptions import AttrsAttributeNotFoundError + + +def asdict( + inst, + recurse=True, + filter=None, + dict_factory=dict, + retain_collection_types=False, + value_serializer=None, +): + """ + Return the ``attrs`` attribute values of *inst* as a dict. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the `attrs.Attribute` as the first argument and the + value as the second argument. + :param callable dict_factory: A callable to produce dictionaries from. For + example, to produce ordered dictionaries instead of normal Python + dictionaries, pass in ``collections.OrderedDict``. + :param bool retain_collection_types: Do not convert to ``list`` when + encountering an attribute whose type is ``tuple`` or ``set``. Only + meaningful if ``recurse`` is ``True``. + :param Optional[callable] value_serializer: A hook that is called for every + attribute or dict key/value. It receives the current instance, field + and value and must return the (updated) value. The hook is run *after* + the optional *filter* has been applied. + + :rtype: return type of *dict_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.0.0 *dict_factory* + .. versionadded:: 16.1.0 *retain_collection_types* + .. versionadded:: 20.3.0 *value_serializer* + .. versionadded:: 21.3.0 If a dict has a collection for a key, it is + serialized as a tuple. + """ + attrs = fields(inst.__class__) + rv = dict_factory() + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + + if value_serializer is not None: + v = value_serializer(inst, a, v) + + if recurse is True: + if has(v.__class__): + rv[a.name] = asdict( + v, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain_collection_types is True else list + rv[a.name] = cf( + [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in v + ] + ) + elif isinstance(v, dict): + df = dict_factory + rv[a.name] = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in iteritems(v) + ) + else: + rv[a.name] = v + else: + rv[a.name] = v + return rv + + +def _asdict_anything( + val, + is_key, + filter, + dict_factory, + retain_collection_types, + value_serializer, +): + """ + ``asdict`` only works on attrs instances, this works on anything. + """ + if getattr(val.__class__, "__attrs_attrs__", None) is not None: + # Attrs class. + rv = asdict( + val, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(val, (tuple, list, set, frozenset)): + if retain_collection_types is True: + cf = val.__class__ + elif is_key: + cf = tuple + else: + cf = list + + rv = cf( + [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in val + ] + ) + elif isinstance(val, dict): + df = dict_factory + rv = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in iteritems(val) + ) + else: + rv = val + if value_serializer is not None: + rv = value_serializer(None, None, rv) + + return rv + + +def astuple( + inst, + recurse=True, + filter=None, + tuple_factory=tuple, + retain_collection_types=False, +): + """ + Return the ``attrs`` attribute values of *inst* as a tuple. + + Optionally recurse into other ``attrs``-decorated classes. + + :param inst: Instance of an ``attrs``-decorated class. + :param bool recurse: Recurse into classes that are also + ``attrs``-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the `attrs.Attribute` as the first argument and the + value as the second argument. + :param callable tuple_factory: A callable to produce tuples from. For + example, to produce lists instead of tuples. + :param bool retain_collection_types: Do not convert to ``list`` + or ``dict`` when encountering an attribute which type is + ``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is + ``True``. + + :rtype: return type of *tuple_factory* + + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 16.2.0 + """ + attrs = fields(inst.__class__) + rv = [] + retain = retain_collection_types # Very long. :/ + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + if recurse is True: + if has(v.__class__): + rv.append( + astuple( + v, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain is True else list + rv.append( + cf( + [ + astuple( + j, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(j.__class__) + else j + for j in v + ] + ) + ) + elif isinstance(v, dict): + df = v.__class__ if retain is True else dict + rv.append( + df( + ( + astuple( + kk, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(kk.__class__) + else kk, + astuple( + vv, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(vv.__class__) + else vv, + ) + for kk, vv in iteritems(v) + ) + ) + else: + rv.append(v) + else: + rv.append(v) + + return rv if tuple_factory is list else tuple_factory(rv) + + +def has(cls): + """ + Check whether *cls* is a class with ``attrs`` attributes. + + :param type cls: Class to introspect. + :raise TypeError: If *cls* is not a class. + + :rtype: bool + """ + return getattr(cls, "__attrs_attrs__", None) is not None + + +def assoc(inst, **changes): + """ + Copy *inst* and apply *changes*. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise attr.exceptions.AttrsAttributeNotFoundError: If *attr_name* couldn't + be found on *cls*. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. deprecated:: 17.1.0 + Use `attrs.evolve` instead if you can. + This function will not be removed du to the slightly different approach + compared to `attrs.evolve`. + """ + import warnings + + warnings.warn( + "assoc is deprecated and will be removed after 2018/01.", + DeprecationWarning, + stacklevel=2, + ) + new = copy.copy(inst) + attrs = fields(inst.__class__) + for k, v in iteritems(changes): + a = getattr(attrs, k, NOTHING) + if a is NOTHING: + raise AttrsAttributeNotFoundError( + "{k} is not an attrs attribute on {cl}.".format( + k=k, cl=new.__class__ + ) + ) + _obj_setattr(new, k, v) + return new + + +def evolve(inst, **changes): + """ + Create a new instance, based on *inst* with *changes* applied. + + :param inst: Instance of a class with ``attrs`` attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise TypeError: If *attr_name* couldn't be found in the class + ``__init__``. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + .. versionadded:: 17.1.0 + """ + cls = inst.__class__ + attrs = fields(cls) + for a in attrs: + if not a.init: + continue + attr_name = a.name # To deal with private attributes. + init_name = attr_name if attr_name[0] != "_" else attr_name[1:] + if init_name not in changes: + changes[init_name] = getattr(inst, attr_name) + + return cls(**changes) + + +def resolve_types(cls, globalns=None, localns=None, attribs=None): + """ + Resolve any strings and forward annotations in type annotations. + + This is only required if you need concrete types in `Attribute`'s *type* + field. In other words, you don't need to resolve your types if you only + use them for static type checking. + + With no arguments, names will be looked up in the module in which the class + was created. If this is not what you want, e.g. if the name only exists + inside a method, you may pass *globalns* or *localns* to specify other + dictionaries in which to look up these names. See the docs of + `typing.get_type_hints` for more details. + + :param type cls: Class to resolve. + :param Optional[dict] globalns: Dictionary containing global variables. + :param Optional[dict] localns: Dictionary containing local variables. + :param Optional[list] attribs: List of attribs for the given class. + This is necessary when calling from inside a ``field_transformer`` + since *cls* is not an ``attrs`` class yet. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class and you didn't pass any attribs. + :raise NameError: If types cannot be resolved because of missing variables. + + :returns: *cls* so you can use this function also as a class decorator. + Please note that you have to apply it **after** `attrs.define`. That + means the decorator has to come in the line **before** `attrs.define`. + + .. versionadded:: 20.1.0 + .. versionadded:: 21.1.0 *attribs* + + """ + # Since calling get_type_hints is expensive we cache whether we've + # done it already. + if getattr(cls, "__attrs_types_resolved__", None) != cls: + import typing + + hints = typing.get_type_hints(cls, globalns=globalns, localns=localns) + for field in fields(cls) if attribs is None else attribs: + if field.name in hints: + # Since fields have been frozen we must work around it. + _obj_setattr(field, "type", hints[field.name]) + # We store the class we resolved so that subclasses know they haven't + # been resolved. + cls.__attrs_types_resolved__ = cls + + # Return the class so you can use it as a decorator too. + return cls diff --git a/myenv/lib/python3.9/site-packages/attr/_make.py b/myenv/lib/python3.9/site-packages/attr/_make.py new file mode 100644 index 0000000..d46f8a3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_make.py @@ -0,0 +1,3173 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +import copy +import inspect +import linecache +import sys +import warnings + +from operator import itemgetter + +# We need to import _compat itself in addition to the _compat members to avoid +# having the thread-local in the globals here. +from . import _compat, _config, setters +from ._compat import ( + HAS_F_STRINGS, + PY2, + PY310, + PYPY, + isclass, + iteritems, + metadata_proxy, + new_class, + ordered_dict, + set_closure_cell, +) +from .exceptions import ( + DefaultAlreadySetError, + FrozenInstanceError, + NotAnAttrsClassError, + PythonTooOldError, + UnannotatedAttributeError, +) + + +if not PY2: + import typing + + +# This is used at least twice, so cache it here. +_obj_setattr = object.__setattr__ +_init_converter_pat = "__attr_converter_%s" +_init_factory_pat = "__attr_factory_{}" +_tuple_property_pat = ( + " {attr_name} = _attrs_property(_attrs_itemgetter({index}))" +) +_classvar_prefixes = ( + "typing.ClassVar", + "t.ClassVar", + "ClassVar", + "typing_extensions.ClassVar", +) +# we don't use a double-underscore prefix because that triggers +# name mangling when trying to create a slot for the field +# (when slots=True) +_hash_cache_field = "_attrs_cached_hash" + +_empty_metadata_singleton = metadata_proxy({}) + +# Unique object for unequivocal getattr() defaults. +_sentinel = object() + +_ng_default_on_setattr = setters.pipe(setters.convert, setters.validate) + + +class _Nothing(object): + """ + Sentinel class to indicate the lack of a value when ``None`` is ambiguous. + + ``_Nothing`` is a singleton. There is only ever one of it. + + .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. + """ + + _singleton = None + + def __new__(cls): + if _Nothing._singleton is None: + _Nothing._singleton = super(_Nothing, cls).__new__(cls) + return _Nothing._singleton + + def __repr__(self): + return "NOTHING" + + def __bool__(self): + return False + + def __len__(self): + return 0 # __bool__ for Python 2 + + +NOTHING = _Nothing() +""" +Sentinel to indicate the lack of a value when ``None`` is ambiguous. +""" + + +class _CacheHashWrapper(int): + """ + An integer subclass that pickles / copies as None + + This is used for non-slots classes with ``cache_hash=True``, to avoid + serializing a potentially (even likely) invalid hash value. Since ``None`` + is the default value for uncalculated hashes, whenever this is copied, + the copy's value for the hash should automatically reset. + + See GH #613 for more details. + """ + + if PY2: + # For some reason `type(None)` isn't callable in Python 2, but we don't + # actually need a constructor for None objects, we just need any + # available function that returns None. + def __reduce__(self, _none_constructor=getattr, _args=(0, "", None)): + return _none_constructor, _args + + else: + + def __reduce__(self, _none_constructor=type(None), _args=()): + return _none_constructor, _args + + +def attrib( + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, +): + """ + Create a new attribute on a class. + + .. warning:: + + Does *not* do anything unless the class is also decorated with + `attr.s`! + + :param default: A value that is used if an ``attrs``-generated ``__init__`` + is used and no value is passed while instantiating or the attribute is + excluded using ``init=False``. + + If the value is an instance of `attrs.Factory`, its callable will be + used to construct a new value (useful for mutable data types like lists + or dicts). + + If a default is not set (or set manually to `attrs.NOTHING`), a value + *must* be supplied when instantiating; otherwise a `TypeError` + will be raised. + + The default can also be set using decorator notation as shown below. + + :type default: Any value + + :param callable factory: Syntactic sugar for + ``default=attr.Factory(factory)``. + + :param validator: `callable` that is called by ``attrs``-generated + ``__init__`` methods after the instance has been initialized. They + receive the initialized instance, the :func:`~attrs.Attribute`, and the + passed value. + + The return value is *not* inspected so the validator has to throw an + exception itself. + + If a `list` is passed, its items are treated as validators and must + all pass. + + Validators can be globally disabled and re-enabled using + `get_run_validators`. + + The validator can also be set using decorator notation as shown below. + + :type validator: `callable` or a `list` of `callable`\\ s. + + :param repr: Include this attribute in the generated ``__repr__`` + method. If ``True``, include the attribute; if ``False``, omit it. By + default, the built-in ``repr()`` function is used. To override how the + attribute value is formatted, pass a ``callable`` that takes a single + value and returns a string. Note that the resulting string is used + as-is, i.e. it will be used directly *instead* of calling ``repr()`` + (the default). + :type repr: a `bool` or a `callable` to use a custom function. + + :param eq: If ``True`` (default), include this attribute in the + generated ``__eq__`` and ``__ne__`` methods that check two instances + for equality. To override how the attribute value is compared, + pass a ``callable`` that takes a single value and returns the value + to be compared. + :type eq: a `bool` or a `callable`. + + :param order: If ``True`` (default), include this attributes in the + generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. + To override how the attribute value is ordered, + pass a ``callable`` that takes a single value and returns the value + to be ordered. + :type order: a `bool` or a `callable`. + + :param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the + same value. Must not be mixed with *eq* or *order*. + :type cmp: a `bool` or a `callable`. + + :param Optional[bool] hash: Include this attribute in the generated + ``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This + is the correct behavior according the Python spec. Setting this value + to anything else than ``None`` is *discouraged*. + :param bool init: Include this attribute in the generated ``__init__`` + method. It is possible to set this to ``False`` and set a default + value. In that case this attributed is unconditionally initialized + with the specified default value or factory. + :param callable converter: `callable` that is called by + ``attrs``-generated ``__init__`` methods to convert attribute's value + to the desired format. It is given the passed-in value, and the + returned value will be used as the new value of the attribute. The + value is converted before being passed to the validator, if any. + :param metadata: An arbitrary mapping, to be used by third-party + components. See `extending_metadata`. + :param type: The type of the attribute. In Python 3.6 or greater, the + preferred method to specify the type is using a variable annotation + (see `PEP 526 `_). + This argument is provided for backward compatibility. + Regardless of the approach used, the type will be stored on + ``Attribute.type``. + + Please note that ``attrs`` doesn't do anything with this metadata by + itself. You can use it as part of your own code or for + `static type checking `. + :param kw_only: Make this attribute keyword-only (Python 3+) + in the generated ``__init__`` (if ``init`` is ``False``, this + parameter is ignored). + :param on_setattr: Allows to overwrite the *on_setattr* setting from + `attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used. + Set to `attrs.setters.NO_OP` to run **no** `setattr` hooks for this + attribute -- regardless of the setting in `attr.s`. + :type on_setattr: `callable`, or a list of callables, or `None`, or + `attrs.setters.NO_OP` + + .. versionadded:: 15.2.0 *convert* + .. versionadded:: 16.3.0 *metadata* + .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. + .. versionchanged:: 17.1.0 + *hash* is ``None`` and therefore mirrors *eq* by default. + .. versionadded:: 17.3.0 *type* + .. deprecated:: 17.4.0 *convert* + .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated + *convert* to achieve consistency with other noun-based arguments. + .. versionadded:: 18.1.0 + ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. + .. versionadded:: 18.2.0 *kw_only* + .. versionchanged:: 19.2.0 *convert* keyword argument removed. + .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 + .. versionchanged:: 21.1.0 + *eq*, *order*, and *cmp* also accept a custom callable + .. versionchanged:: 21.1.0 *cmp* undeprecated + """ + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq, order, True + ) + + if hash is not None and hash is not True and hash is not False: + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) + + if factory is not None: + if default is not NOTHING: + raise ValueError( + "The `default` and `factory` arguments are mutually " + "exclusive." + ) + if not callable(factory): + raise ValueError("The `factory` argument must be a callable.") + default = Factory(factory) + + if metadata is None: + metadata = {} + + # Apply syntactic sugar by auto-wrapping. + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + if validator and isinstance(validator, (list, tuple)): + validator = and_(*validator) + + if converter and isinstance(converter, (list, tuple)): + converter = pipe(*converter) + + return _CountingAttr( + default=default, + validator=validator, + repr=repr, + cmp=None, + hash=hash, + init=init, + converter=converter, + metadata=metadata, + type=type, + kw_only=kw_only, + eq=eq, + eq_key=eq_key, + order=order, + order_key=order_key, + on_setattr=on_setattr, + ) + + +def _compile_and_eval(script, globs, locs=None, filename=""): + """ + "Exec" the script with the given global (globs) and local (locs) variables. + """ + bytecode = compile(script, filename, "exec") + eval(bytecode, globs, locs) + + +def _make_method(name, script, filename, globs=None): + """ + Create the method with the script given and return the method object. + """ + locs = {} + if globs is None: + globs = {} + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + count = 1 + base_filename = filename + while True: + linecache_tuple = ( + len(script), + None, + script.splitlines(True), + filename, + ) + old_val = linecache.cache.setdefault(filename, linecache_tuple) + if old_val == linecache_tuple: + break + else: + filename = "{}-{}>".format(base_filename[:-1], count) + count += 1 + + _compile_and_eval(script, globs, locs, filename) + + return locs[name] + + +def _make_attr_tuple_class(cls_name, attr_names): + """ + Create a tuple subclass to hold `Attribute`s for an `attrs` class. + + The subclass is a bare tuple with properties for names. + + class MyClassAttributes(tuple): + __slots__ = () + x = property(itemgetter(0)) + """ + attr_class_name = "{}Attributes".format(cls_name) + attr_class_template = [ + "class {}(tuple):".format(attr_class_name), + " __slots__ = ()", + ] + if attr_names: + for i, attr_name in enumerate(attr_names): + attr_class_template.append( + _tuple_property_pat.format(index=i, attr_name=attr_name) + ) + else: + attr_class_template.append(" pass") + globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property} + _compile_and_eval("\n".join(attr_class_template), globs) + return globs[attr_class_name] + + +# Tuple class for extracted attributes from a class definition. +# `base_attrs` is a subset of `attrs`. +_Attributes = _make_attr_tuple_class( + "_Attributes", + [ + # all attributes to build dunder methods for + "attrs", + # attributes that have been inherited + "base_attrs", + # map inherited attributes to their originating classes + "base_attrs_map", + ], +) + + +def _is_class_var(annot): + """ + Check whether *annot* is a typing.ClassVar. + + The string comparison hack is used to avoid evaluating all string + annotations which would put attrs-based classes at a performance + disadvantage compared to plain old classes. + """ + annot = str(annot) + + # Annotation can be quoted. + if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): + annot = annot[1:-1] + + return annot.startswith(_classvar_prefixes) + + +def _has_own_attribute(cls, attrib_name): + """ + Check whether *cls* defines *attrib_name* (and doesn't just inherit it). + + Requires Python 3. + """ + attr = getattr(cls, attrib_name, _sentinel) + if attr is _sentinel: + return False + + for base_cls in cls.__mro__[1:]: + a = getattr(base_cls, attrib_name, None) + if attr is a: + return False + + return True + + +def _get_annotations(cls): + """ + Get annotations for *cls*. + """ + if _has_own_attribute(cls, "__annotations__"): + return cls.__annotations__ + + return {} + + +def _counter_getter(e): + """ + Key function for sorting to avoid re-creating a lambda for every class. + """ + return e[1].counter + + +def _collect_base_attrs(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in reversed(cls.__mro__[1:-1]): + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.inherited or a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + # For each name, only keep the freshest definition i.e. the furthest at the + # back. base_attr_map is fine because it gets overwritten with every new + # instance. + filtered = [] + seen = set() + for a in reversed(base_attrs): + if a.name in seen: + continue + filtered.insert(0, a) + seen.add(a.name) + + return filtered, base_attr_map + + +def _collect_base_attrs_broken(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + + N.B. *taken_attr_names* will be mutated. + + Adhere to the old incorrect behavior. + + Notably it collects from the front and considers inherited attributes which + leads to the buggy behavior reported in #428. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in cls.__mro__[1:-1]: + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) + taken_attr_names.add(a.name) + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + return base_attrs, base_attr_map + + +def _transform_attrs( + cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer +): + """ + Transform all `_CountingAttr`s on a class into `Attribute`s. + + If *these* is passed, use that and don't look for them on the class. + + *collect_by_mro* is True, collect them in the correct MRO order, otherwise + use the old -- incorrect -- order. See #428. + + Return an `_Attributes`. + """ + cd = cls.__dict__ + anns = _get_annotations(cls) + + if these is not None: + ca_list = [(name, ca) for name, ca in iteritems(these)] + + if not isinstance(these, ordered_dict): + ca_list.sort(key=_counter_getter) + elif auto_attribs is True: + ca_names = { + name + for name, attr in cd.items() + if isinstance(attr, _CountingAttr) + } + ca_list = [] + annot_names = set() + for attr_name, type in anns.items(): + if _is_class_var(type): + continue + annot_names.add(attr_name) + a = cd.get(attr_name, NOTHING) + + if not isinstance(a, _CountingAttr): + if a is NOTHING: + a = attrib() + else: + a = attrib(default=a) + ca_list.append((attr_name, a)) + + unannotated = ca_names - annot_names + if len(unannotated) > 0: + raise UnannotatedAttributeError( + "The following `attr.ib`s lack a type annotation: " + + ", ".join( + sorted(unannotated, key=lambda n: cd.get(n).counter) + ) + + "." + ) + else: + ca_list = sorted( + ( + (name, attr) + for name, attr in cd.items() + if isinstance(attr, _CountingAttr) + ), + key=lambda e: e[1].counter, + ) + + own_attrs = [ + Attribute.from_counting_attr( + name=attr_name, ca=ca, type=anns.get(attr_name) + ) + for attr_name, ca in ca_list + ] + + if collect_by_mro: + base_attrs, base_attr_map = _collect_base_attrs( + cls, {a.name for a in own_attrs} + ) + else: + base_attrs, base_attr_map = _collect_base_attrs_broken( + cls, {a.name for a in own_attrs} + ) + + if kw_only: + own_attrs = [a.evolve(kw_only=True) for a in own_attrs] + base_attrs = [a.evolve(kw_only=True) for a in base_attrs] + + attrs = base_attrs + own_attrs + + # Mandatory vs non-mandatory attr order only matters when they are part of + # the __init__ signature and when they aren't kw_only (which are moved to + # the end and can be mandatory or non-mandatory in any order, as they will + # be specified as keyword args anyway). Check the order of those attrs: + had_default = False + for a in (a for a in attrs if a.init is not False and a.kw_only is False): + if had_default is True and a.default is NOTHING: + raise ValueError( + "No mandatory attributes allowed after an attribute with a " + "default value or factory. Attribute in question: %r" % (a,) + ) + + if had_default is False and a.default is not NOTHING: + had_default = True + + if field_transformer is not None: + attrs = field_transformer(cls, attrs) + + # Create AttrsClass *after* applying the field_transformer since it may + # add or remove attributes! + attr_names = [a.name for a in attrs] + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + + return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map)) + + +if PYPY: + + def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + if isinstance(self, BaseException) and name in ( + "__cause__", + "__context__", + ): + BaseException.__setattr__(self, name, value) + return + + raise FrozenInstanceError() + +else: + + def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + raise FrozenInstanceError() + + +def _frozen_delattrs(self, name): + """ + Attached to frozen classes as __delattr__. + """ + raise FrozenInstanceError() + + +class _ClassBuilder(object): + """ + Iteratively build *one* class. + """ + + __slots__ = ( + "_attr_names", + "_attrs", + "_base_attr_map", + "_base_names", + "_cache_hash", + "_cls", + "_cls_dict", + "_delete_attribs", + "_frozen", + "_has_pre_init", + "_has_post_init", + "_is_exc", + "_on_setattr", + "_slots", + "_weakref_slot", + "_wrote_own_setattr", + "_has_custom_setattr", + ) + + def __init__( + self, + cls, + these, + slots, + frozen, + weakref_slot, + getstate_setstate, + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_custom_setattr, + field_transformer, + ): + attrs, base_attrs, base_map = _transform_attrs( + cls, + these, + auto_attribs, + kw_only, + collect_by_mro, + field_transformer, + ) + + self._cls = cls + self._cls_dict = dict(cls.__dict__) if slots else {} + self._attrs = attrs + self._base_names = set(a.name for a in base_attrs) + self._base_attr_map = base_map + self._attr_names = tuple(a.name for a in attrs) + self._slots = slots + self._frozen = frozen + self._weakref_slot = weakref_slot + self._cache_hash = cache_hash + self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) + self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) + self._delete_attribs = not bool(these) + self._is_exc = is_exc + self._on_setattr = on_setattr + + self._has_custom_setattr = has_custom_setattr + self._wrote_own_setattr = False + + self._cls_dict["__attrs_attrs__"] = self._attrs + + if frozen: + self._cls_dict["__setattr__"] = _frozen_setattrs + self._cls_dict["__delattr__"] = _frozen_delattrs + + self._wrote_own_setattr = True + elif on_setattr in ( + _ng_default_on_setattr, + setters.validate, + setters.convert, + ): + has_validator = has_converter = False + for a in attrs: + if a.validator is not None: + has_validator = True + if a.converter is not None: + has_converter = True + + if has_validator and has_converter: + break + if ( + ( + on_setattr == _ng_default_on_setattr + and not (has_validator or has_converter) + ) + or (on_setattr == setters.validate and not has_validator) + or (on_setattr == setters.convert and not has_converter) + ): + # If class-level on_setattr is set to convert + validate, but + # there's no field to convert or validate, pretend like there's + # no on_setattr. + self._on_setattr = None + + if getstate_setstate: + ( + self._cls_dict["__getstate__"], + self._cls_dict["__setstate__"], + ) = self._make_getstate_setstate() + + def __repr__(self): + return "<_ClassBuilder(cls={cls})>".format(cls=self._cls.__name__) + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + + Builder cannot be used after calling this method. + """ + if self._slots is True: + return self._create_slots_class() + else: + return self._patch_original_class() + + def _patch_original_class(self): + """ + Apply accumulated methods and return the class. + """ + cls = self._cls + base_names = self._base_names + + # Clean class of attribute definitions (`attr.ib()`s). + if self._delete_attribs: + for name in self._attr_names: + if ( + name not in base_names + and getattr(cls, name, _sentinel) is not _sentinel + ): + try: + delattr(cls, name) + except AttributeError: + # This can happen if a base class defines a class + # variable and we want to set an attribute with the + # same name by using only a type annotation. + pass + + # Attach our dunder methods. + for name, value in self._cls_dict.items(): + setattr(cls, name, value) + + # If we've inherited an attrs __setattr__ and don't write our own, + # reset it to object's. + if not self._wrote_own_setattr and getattr( + cls, "__attrs_own_setattr__", False + ): + cls.__attrs_own_setattr__ = False + + if not self._has_custom_setattr: + cls.__setattr__ = object.__setattr__ + + return cls + + def _create_slots_class(self): + """ + Build and return a new class with a `__slots__` attribute. + """ + cd = { + k: v + for k, v in iteritems(self._cls_dict) + if k not in tuple(self._attr_names) + ("__dict__", "__weakref__") + } + + # If our class doesn't have its own implementation of __setattr__ + # (either from the user or by us), check the bases, if one of them has + # an attrs-made __setattr__, that needs to be reset. We don't walk the + # MRO because we only care about our immediate base classes. + # XXX: This can be confused by subclassing a slotted attrs class with + # XXX: a non-attrs class and subclass the resulting class with an attrs + # XXX: class. See `test_slotted_confused` for details. For now that's + # XXX: OK with us. + if not self._wrote_own_setattr: + cd["__attrs_own_setattr__"] = False + + if not self._has_custom_setattr: + for base_cls in self._cls.__bases__: + if base_cls.__dict__.get("__attrs_own_setattr__", False): + cd["__setattr__"] = object.__setattr__ + break + + # Traverse the MRO to collect existing slots + # and check for an existing __weakref__. + existing_slots = dict() + weakref_inherited = False + for base_cls in self._cls.__mro__[1:-1]: + if base_cls.__dict__.get("__weakref__", None) is not None: + weakref_inherited = True + existing_slots.update( + { + name: getattr(base_cls, name) + for name in getattr(base_cls, "__slots__", []) + } + ) + + base_names = set(self._base_names) + + names = self._attr_names + if ( + self._weakref_slot + and "__weakref__" not in getattr(self._cls, "__slots__", ()) + and "__weakref__" not in names + and not weakref_inherited + ): + names += ("__weakref__",) + + # We only add the names of attributes that aren't inherited. + # Setting __slots__ to inherited attributes wastes memory. + slot_names = [name for name in names if name not in base_names] + # There are slots for attributes from current class + # that are defined in parent classes. + # As their descriptors may be overriden by a child class, + # we collect them here and update the class dict + reused_slots = { + slot: slot_descriptor + for slot, slot_descriptor in iteritems(existing_slots) + if slot in slot_names + } + slot_names = [name for name in slot_names if name not in reused_slots] + cd.update(reused_slots) + if self._cache_hash: + slot_names.append(_hash_cache_field) + cd["__slots__"] = tuple(slot_names) + + qualname = getattr(self._cls, "__qualname__", None) + if qualname is not None: + cd["__qualname__"] = qualname + + # Create new class based on old class and our methods. + cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) + + # The following is a fix for + # . On Python 3, + # if a method mentions `__class__` or uses the no-arg super(), the + # compiler will bake a reference to the class in the method itself + # as `method.__closure__`. Since we replace the class with a + # clone, we rewrite these references so it keeps working. + for item in cls.__dict__.values(): + if isinstance(item, (classmethod, staticmethod)): + # Class- and staticmethods hide their functions inside. + # These might need to be rewritten as well. + closure_cells = getattr(item.__func__, "__closure__", None) + elif isinstance(item, property): + # Workaround for property `super()` shortcut (PY3-only). + # There is no universal way for other descriptors. + closure_cells = getattr(item.fget, "__closure__", None) + else: + closure_cells = getattr(item, "__closure__", None) + + if not closure_cells: # Catch None or the empty list. + continue + for cell in closure_cells: + try: + match = cell.cell_contents is self._cls + except ValueError: # ValueError: Cell is empty + pass + else: + if match: + set_closure_cell(cell, cls) + + return cls + + def add_repr(self, ns): + self._cls_dict["__repr__"] = self._add_method_dunders( + _make_repr(self._attrs, ns, self._cls) + ) + return self + + def add_str(self): + repr = self._cls_dict.get("__repr__") + if repr is None: + raise ValueError( + "__str__ can only be generated if a __repr__ exists." + ) + + def __str__(self): + return self.__repr__() + + self._cls_dict["__str__"] = self._add_method_dunders(__str__) + return self + + def _make_getstate_setstate(self): + """ + Create custom __setstate__ and __getstate__ methods. + """ + # __weakref__ is not writable. + state_attr_names = tuple( + an for an in self._attr_names if an != "__weakref__" + ) + + def slots_getstate(self): + """ + Automatically created by attrs. + """ + return tuple(getattr(self, name) for name in state_attr_names) + + hash_caching_enabled = self._cache_hash + + def slots_setstate(self, state): + """ + Automatically created by attrs. + """ + __bound_setattr = _obj_setattr.__get__(self, Attribute) + for name, value in zip(state_attr_names, state): + __bound_setattr(name, value) + + # The hash code cache is not included when the object is + # serialized, but it still needs to be initialized to None to + # indicate that the first call to __hash__ should be a cache + # miss. + if hash_caching_enabled: + __bound_setattr(_hash_cache_field, None) + + return slots_getstate, slots_setstate + + def make_unhashable(self): + self._cls_dict["__hash__"] = None + return self + + def add_hash(self): + self._cls_dict["__hash__"] = self._add_method_dunders( + _make_hash( + self._cls, + self._attrs, + frozen=self._frozen, + cache_hash=self._cache_hash, + ) + ) + + return self + + def add_init(self): + self._cls_dict["__init__"] = self._add_method_dunders( + _make_init( + self._cls, + self._attrs, + self._has_pre_init, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=False, + ) + ) + + return self + + def add_match_args(self): + self._cls_dict["__match_args__"] = tuple( + field.name + for field in self._attrs + if field.init and not field.kw_only + ) + + def add_attrs_init(self): + self._cls_dict["__attrs_init__"] = self._add_method_dunders( + _make_init( + self._cls, + self._attrs, + self._has_pre_init, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=True, + ) + ) + + return self + + def add_eq(self): + cd = self._cls_dict + + cd["__eq__"] = self._add_method_dunders( + _make_eq(self._cls, self._attrs) + ) + cd["__ne__"] = self._add_method_dunders(_make_ne()) + + return self + + def add_order(self): + cd = self._cls_dict + + cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( + self._add_method_dunders(meth) + for meth in _make_order(self._cls, self._attrs) + ) + + return self + + def add_setattr(self): + if self._frozen: + return self + + sa_attrs = {} + for a in self._attrs: + on_setattr = a.on_setattr or self._on_setattr + if on_setattr and on_setattr is not setters.NO_OP: + sa_attrs[a.name] = a, on_setattr + + if not sa_attrs: + return self + + if self._has_custom_setattr: + # We need to write a __setattr__ but there already is one! + raise ValueError( + "Can't combine custom __setattr__ with on_setattr hooks." + ) + + # docstring comes from _add_method_dunders + def __setattr__(self, name, val): + try: + a, hook = sa_attrs[name] + except KeyError: + nval = val + else: + nval = hook(self, a, val) + + _obj_setattr(self, name, nval) + + self._cls_dict["__attrs_own_setattr__"] = True + self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) + self._wrote_own_setattr = True + + return self + + def _add_method_dunders(self, method): + """ + Add __module__ and __qualname__ to a *method* if possible. + """ + try: + method.__module__ = self._cls.__module__ + except AttributeError: + pass + + try: + method.__qualname__ = ".".join( + (self._cls.__qualname__, method.__name__) + ) + except AttributeError: + pass + + try: + method.__doc__ = "Method generated by attrs for class %s." % ( + self._cls.__qualname__, + ) + except AttributeError: + pass + + return method + + +_CMP_DEPRECATION = ( + "The usage of `cmp` is deprecated and will be removed on or after " + "2021-06-01. Please use `eq` and `order` instead." +) + + +def _determine_attrs_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + raise ValueError("Don't mix `cmp` with `eq' and `order`.") + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + return cmp, cmp + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq = default_eq + + if order is None: + order = eq + + if eq is False and order is True: + raise ValueError("`order` can only be True if `eq` is True too.") + + return eq, order + + +def _determine_attrib_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + raise ValueError("Don't mix `cmp` with `eq' and `order`.") + + def decide_callable_or_boolean(value): + """ + Decide whether a key function is used. + """ + if callable(value): + value, key = True, value + else: + key = None + return value, key + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + cmp, cmp_key = decide_callable_or_boolean(cmp) + return cmp, cmp_key, cmp, cmp_key + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq, eq_key = default_eq, None + else: + eq, eq_key = decide_callable_or_boolean(eq) + + if order is None: + order, order_key = eq, eq_key + else: + order, order_key = decide_callable_or_boolean(order) + + if eq is False and order is True: + raise ValueError("`order` can only be True if `eq` is True too.") + + return eq, eq_key, order, order_key + + +def _determine_whether_to_implement( + cls, flag, auto_detect, dunders, default=True +): + """ + Check whether we should implement a set of methods for *cls*. + + *flag* is the argument passed into @attr.s like 'init', *auto_detect* the + same as passed into @attr.s and *dunders* is a tuple of attribute names + whose presence signal that the user has implemented it themselves. + + Return *default* if no reason for either for or against is found. + + auto_detect must be False on Python 2. + """ + if flag is True or flag is False: + return flag + + if flag is None and auto_detect is False: + return default + + # Logically, flag is None and auto_detect is True here. + for dunder in dunders: + if _has_own_attribute(cls, dunder): + return False + + return default + + +def attrs( + maybe_cls=None, + these=None, + repr_ns=None, + repr=None, + cmp=None, + hash=None, + init=None, + slots=False, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=False, + kw_only=False, + cache_hash=False, + auto_exc=False, + eq=None, + order=None, + auto_detect=False, + collect_by_mro=False, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, +): + r""" + A class decorator that adds `dunder + `_\ -methods according to the + specified attributes using `attr.ib` or the *these* argument. + + :param these: A dictionary of name to `attr.ib` mappings. This is + useful to avoid the definition of your attributes within the class body + because you can't (e.g. if you want to add ``__repr__`` methods to + Django models) or don't want to. + + If *these* is not ``None``, ``attrs`` will *not* search the class body + for attributes and will *not* remove any attributes from it. + + If *these* is an ordered dict (`dict` on Python 3.6+, + `collections.OrderedDict` otherwise), the order is deduced from + the order of the attributes inside *these*. Otherwise the order + of the definition of the attributes is used. + + :type these: `dict` of `str` to `attr.ib` + + :param str repr_ns: When using nested classes, there's no way in Python 2 + to automatically detect that. Therefore it's possible to set the + namespace explicitly for a more meaningful ``repr`` output. + :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*, + *order*, and *hash* arguments explicitly, assume they are set to + ``True`` **unless any** of the involved methods for one of the + arguments is implemented in the *current* class (i.e. it is *not* + inherited from some base class). + + So for example by implementing ``__eq__`` on a class yourself, + ``attrs`` will deduce ``eq=False`` and will create *neither* + ``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible + ``__ne__`` by default, so it *should* be enough to only implement + ``__eq__`` in most cases). + + .. warning:: + + If you prevent ``attrs`` from creating the ordering methods for you + (``order=False``, e.g. by implementing ``__le__``), it becomes + *your* responsibility to make sure its ordering is sound. The best + way is to use the `functools.total_ordering` decorator. + + + Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*, + *cmp*, or *hash* overrides whatever *auto_detect* would determine. + + *auto_detect* requires Python 3. Setting it ``True`` on Python 2 raises + an `attrs.exceptions.PythonTooOldError`. + + :param bool repr: Create a ``__repr__`` method with a human readable + representation of ``attrs`` attributes.. + :param bool str: Create a ``__str__`` method that is identical to + ``__repr__``. This is usually not necessary except for + `Exception`\ s. + :param Optional[bool] eq: If ``True`` or ``None`` (default), add ``__eq__`` + and ``__ne__`` methods that check two instances for equality. + + They compare the instances as if they were tuples of their ``attrs`` + attributes if and only if the types of both classes are *identical*! + :param Optional[bool] order: If ``True``, add ``__lt__``, ``__le__``, + ``__gt__``, and ``__ge__`` methods that behave like *eq* above and + allow instances to be ordered. If ``None`` (default) mirror value of + *eq*. + :param Optional[bool] cmp: Setting *cmp* is equivalent to setting *eq* + and *order* to the same value. Must not be mixed with *eq* or *order*. + :param Optional[bool] hash: If ``None`` (default), the ``__hash__`` method + is generated according how *eq* and *frozen* are set. + + 1. If *both* are True, ``attrs`` will generate a ``__hash__`` for you. + 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to + None, marking it unhashable (which it is). + 3. If *eq* is False, ``__hash__`` will be left untouched meaning the + ``__hash__`` method of the base class will be used (if base class is + ``object``, this means it will fall back to id-based hashing.). + + Although not recommended, you can decide for yourself and force + ``attrs`` to create one (e.g. if the class is immutable even though you + didn't freeze it programmatically) by passing ``True`` or not. Both of + these cases are rather special and should be used carefully. + + See our documentation on `hashing`, Python's documentation on + `object.__hash__`, and the `GitHub issue that led to the default \ + behavior `_ for more + details. + :param bool init: Create a ``__init__`` method that initializes the + ``attrs`` attributes. Leading underscores are stripped for the argument + name. If a ``__attrs_pre_init__`` method exists on the class, it will + be called before the class is initialized. If a ``__attrs_post_init__`` + method exists on the class, it will be called after the class is fully + initialized. + + If ``init`` is ``False``, an ``__attrs_init__`` method will be + injected instead. This allows you to define a custom ``__init__`` + method that can do pre-init work such as ``super().__init__()``, + and then call ``__attrs_init__()`` and ``__attrs_post_init__()``. + :param bool slots: Create a `slotted class ` that's more + memory-efficient. Slotted classes are generally superior to the default + dict classes, but have some gotchas you should know about, so we + encourage you to read the `glossary entry `. + :param bool frozen: Make instances immutable after initialization. If + someone attempts to modify a frozen instance, + `attr.exceptions.FrozenInstanceError` is raised. + + .. note:: + + 1. This is achieved by installing a custom ``__setattr__`` method + on your class, so you can't implement your own. + + 2. True immutability is impossible in Python. + + 3. This *does* have a minor a runtime performance `impact + ` when initializing new instances. In other words: + ``__init__`` is slightly slower with ``frozen=True``. + + 4. If a class is frozen, you cannot modify ``self`` in + ``__attrs_post_init__`` or a self-written ``__init__``. You can + circumvent that limitation by using + ``object.__setattr__(self, "attribute_name", value)``. + + 5. Subclasses of a frozen class are frozen too. + + :param bool weakref_slot: Make instances weak-referenceable. This has no + effect unless ``slots`` is also enabled. + :param bool auto_attribs: If ``True``, collect `PEP 526`_-annotated + attributes (Python 3.6 and later only) from the class body. + + In this case, you **must** annotate every field. If ``attrs`` + encounters a field that is set to an `attr.ib` but lacks a type + annotation, an `attr.exceptions.UnannotatedAttributeError` is + raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't + want to set a type. + + If you assign a value to those attributes (e.g. ``x: int = 42``), that + value becomes the default value like if it were passed using + ``attr.ib(default=42)``. Passing an instance of `attrs.Factory` also + works as expected in most cases (see warning below). + + Attributes annotated as `typing.ClassVar`, and attributes that are + neither annotated nor set to an `attr.ib` are **ignored**. + + .. warning:: + For features that use the attribute name to create decorators (e.g. + `validators `), you still *must* assign `attr.ib` to + them. Otherwise Python will either not find the name or try to use + the default value to call e.g. ``validator`` on it. + + These errors can be quite confusing and probably the most common bug + report on our bug tracker. + + .. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/ + :param bool kw_only: Make all attributes keyword-only (Python 3+) + in the generated ``__init__`` (if ``init`` is ``False``, this + parameter is ignored). + :param bool cache_hash: Ensure that the object's hash code is computed + only once and stored on the object. If this is set to ``True``, + hashing must be either explicitly or implicitly enabled for this + class. If the hash code is cached, avoid any reassignments of + fields involved in hash code computation or mutations of the objects + those fields point to after object creation. If such changes occur, + the behavior of the object's hash code is undefined. + :param bool auto_exc: If the class subclasses `BaseException` + (which implicitly includes any subclass of any exception), the + following happens to behave like a well-behaved Python exceptions + class: + + - the values for *eq*, *order*, and *hash* are ignored and the + instances compare and hash by the instance's ids (N.B. ``attrs`` will + *not* remove existing implementations of ``__hash__`` or the equality + methods. It just won't add own ones.), + - all attributes that are either passed into ``__init__`` or have a + default value are additionally available as a tuple in the ``args`` + attribute, + - the value of *str* is ignored leaving ``__str__`` to base classes. + :param bool collect_by_mro: Setting this to `True` fixes the way ``attrs`` + collects attributes from base classes. The default behavior is + incorrect in certain cases of multiple inheritance. It should be on by + default but is kept off for backward-compatibility. + + See issue `#428 `_ for + more details. + + :param Optional[bool] getstate_setstate: + .. note:: + This is usually only interesting for slotted classes and you should + probably just set *auto_detect* to `True`. + + If `True`, ``__getstate__`` and + ``__setstate__`` are generated and attached to the class. This is + necessary for slotted classes to be pickleable. If left `None`, it's + `True` by default for slotted classes and ``False`` for dict classes. + + If *auto_detect* is `True`, and *getstate_setstate* is left `None`, + and **either** ``__getstate__`` or ``__setstate__`` is detected directly + on the class (i.e. not inherited), it is set to `False` (this is usually + what you want). + + :param on_setattr: A callable that is run whenever the user attempts to set + an attribute (either by assignment like ``i.x = 42`` or by using + `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments + as validators: the instance, the attribute that is being modified, and + the new value. + + If no exception is raised, the attribute is set to the return value of + the callable. + + If a list of callables is passed, they're automatically wrapped in an + `attrs.setters.pipe`. + + :param Optional[callable] field_transformer: + A function that is called with the original class object and all + fields right before ``attrs`` finalizes the class. You can use + this, e.g., to automatically add converters or validators to + fields based on their types. See `transform-fields` for more details. + + :param bool match_args: + If `True` (default), set ``__match_args__`` on the class to support + `PEP 634 `_ (Structural + Pattern Matching). It is a tuple of all positional-only ``__init__`` + parameter names on Python 3.10 and later. Ignored on older Python + versions. + + .. versionadded:: 16.0.0 *slots* + .. versionadded:: 16.1.0 *frozen* + .. versionadded:: 16.3.0 *str* + .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. + .. versionchanged:: 17.1.0 + *hash* supports ``None`` as value which is also the default now. + .. versionadded:: 17.3.0 *auto_attribs* + .. versionchanged:: 18.1.0 + If *these* is passed, no attributes are deleted from the class body. + .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. + .. versionadded:: 18.2.0 *weakref_slot* + .. deprecated:: 18.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a + `DeprecationWarning` if the classes compared are subclasses of + each other. ``__eq`` and ``__ne__`` never tried to compared subclasses + to each other. + .. versionchanged:: 19.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider + subclasses comparable anymore. + .. versionadded:: 18.2.0 *kw_only* + .. versionadded:: 18.2.0 *cache_hash* + .. versionadded:: 19.1.0 *auto_exc* + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *auto_detect* + .. versionadded:: 20.1.0 *collect_by_mro* + .. versionadded:: 20.1.0 *getstate_setstate* + .. versionadded:: 20.1.0 *on_setattr* + .. versionadded:: 20.3.0 *field_transformer* + .. versionchanged:: 21.1.0 + ``init=False`` injects ``__attrs_init__`` + .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 21.3.0 *match_args* + """ + if auto_detect and PY2: + raise PythonTooOldError( + "auto_detect only works on Python 3 and later." + ) + + eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) + hash_ = hash # work around the lack of nonlocal + + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + def wrap(cls): + + if getattr(cls, "__class__", None) is None: + raise TypeError("attrs only works with new-style classes.") + + is_frozen = frozen or _has_frozen_base_class(cls) + is_exc = auto_exc is True and issubclass(cls, BaseException) + has_own_setattr = auto_detect and _has_own_attribute( + cls, "__setattr__" + ) + + if has_own_setattr and is_frozen: + raise ValueError("Can't freeze a class with a custom __setattr__.") + + builder = _ClassBuilder( + cls, + these, + slots, + is_frozen, + weakref_slot, + _determine_whether_to_implement( + cls, + getstate_setstate, + auto_detect, + ("__getstate__", "__setstate__"), + default=slots, + ), + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_own_setattr, + field_transformer, + ) + if _determine_whether_to_implement( + cls, repr, auto_detect, ("__repr__",) + ): + builder.add_repr(repr_ns) + if str is True: + builder.add_str() + + eq = _determine_whether_to_implement( + cls, eq_, auto_detect, ("__eq__", "__ne__") + ) + if not is_exc and eq is True: + builder.add_eq() + if not is_exc and _determine_whether_to_implement( + cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") + ): + builder.add_order() + + builder.add_setattr() + + if ( + hash_ is None + and auto_detect is True + and _has_own_attribute(cls, "__hash__") + ): + hash = False + else: + hash = hash_ + if hash is not True and hash is not False and hash is not None: + # Can't use `hash in` because 1 == True for example. + raise TypeError( + "Invalid value for hash. Must be True, False, or None." + ) + elif hash is False or (hash is None and eq is False) or is_exc: + # Don't do anything. Should fall back to __object__'s __hash__ + # which is by id. + if cache_hash: + raise TypeError( + "Invalid value for cache_hash. To use hash caching," + " hashing must be either explicitly or implicitly " + "enabled." + ) + elif hash is True or ( + hash is None and eq is True and is_frozen is True + ): + # Build a __hash__ if told so, or if it's safe. + builder.add_hash() + else: + # Raise TypeError on attempts to hash. + if cache_hash: + raise TypeError( + "Invalid value for cache_hash. To use hash caching," + " hashing must be either explicitly or implicitly " + "enabled." + ) + builder.make_unhashable() + + if _determine_whether_to_implement( + cls, init, auto_detect, ("__init__",) + ): + builder.add_init() + else: + builder.add_attrs_init() + if cache_hash: + raise TypeError( + "Invalid value for cache_hash. To use hash caching," + " init must be True." + ) + + if ( + PY310 + and match_args + and not _has_own_attribute(cls, "__match_args__") + ): + builder.add_match_args() + + return builder.build_class() + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + else: + return wrap(maybe_cls) + + +_attrs = attrs +""" +Internal alias so we can use it in functions that take an argument called +*attrs*. +""" + + +if PY2: + + def _has_frozen_base_class(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return ( + getattr(cls.__setattr__, "__module__", None) + == _frozen_setattrs.__module__ + and cls.__setattr__.__name__ == _frozen_setattrs.__name__ + ) + +else: + + def _has_frozen_base_class(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return cls.__setattr__ == _frozen_setattrs + + +def _generate_unique_filename(cls, func_name): + """ + Create a "filename" suitable for a function being generated. + """ + unique_filename = "".format( + func_name, + cls.__module__, + getattr(cls, "__qualname__", cls.__name__), + ) + return unique_filename + + +def _make_hash(cls, attrs, frozen, cache_hash): + attrs = tuple( + a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) + ) + + tab = " " + + unique_filename = _generate_unique_filename(cls, "hash") + type_hash = hash(unique_filename) + + hash_def = "def __hash__(self" + hash_func = "hash((" + closing_braces = "))" + if not cache_hash: + hash_def += "):" + else: + if not PY2: + hash_def += ", *" + + hash_def += ( + ", _cache_wrapper=" + + "__import__('attr._make')._make._CacheHashWrapper):" + ) + hash_func = "_cache_wrapper(" + hash_func + closing_braces += ")" + + method_lines = [hash_def] + + def append_hash_computation_lines(prefix, indent): + """ + Generate the code for actually computing the hash code. + Below this will either be returned directly or used to compute + a value which is then cached, depending on the value of cache_hash + """ + + method_lines.extend( + [ + indent + prefix + hash_func, + indent + " %d," % (type_hash,), + ] + ) + + for a in attrs: + method_lines.append(indent + " self.%s," % a.name) + + method_lines.append(indent + " " + closing_braces) + + if cache_hash: + method_lines.append(tab + "if self.%s is None:" % _hash_cache_field) + if frozen: + append_hash_computation_lines( + "object.__setattr__(self, '%s', " % _hash_cache_field, tab * 2 + ) + method_lines.append(tab * 2 + ")") # close __setattr__ + else: + append_hash_computation_lines( + "self.%s = " % _hash_cache_field, tab * 2 + ) + method_lines.append(tab + "return self.%s" % _hash_cache_field) + else: + append_hash_computation_lines("return ", tab) + + script = "\n".join(method_lines) + return _make_method("__hash__", script, unique_filename) + + +def _add_hash(cls, attrs): + """ + Add a hash method to *cls*. + """ + cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False) + return cls + + +def _make_ne(): + """ + Create __ne__ method. + """ + + def __ne__(self, other): + """ + Check equality and either forward a NotImplemented or + return the result negated. + """ + result = self.__eq__(other) + if result is NotImplemented: + return NotImplemented + + return not result + + return __ne__ + + +def _make_eq(cls, attrs): + """ + Create __eq__ method for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.eq] + + unique_filename = _generate_unique_filename(cls, "eq") + lines = [ + "def __eq__(self, other):", + " if other.__class__ is not self.__class__:", + " return NotImplemented", + ] + + # We can't just do a big self.x = other.x and... clause due to + # irregularities like nan == nan is false but (nan,) == (nan,) is true. + globs = {} + if attrs: + lines.append(" return (") + others = [" ) == ("] + for a in attrs: + if a.eq_key: + cmp_name = "_%s_key" % (a.name,) + # Add the key function to the global namespace + # of the evaluated function. + globs[cmp_name] = a.eq_key + lines.append( + " %s(self.%s)," + % ( + cmp_name, + a.name, + ) + ) + others.append( + " %s(other.%s)," + % ( + cmp_name, + a.name, + ) + ) + else: + lines.append(" self.%s," % (a.name,)) + others.append(" other.%s," % (a.name,)) + + lines += others + [" )"] + else: + lines.append(" return True") + + script = "\n".join(lines) + + return _make_method("__eq__", script, unique_filename, globs) + + +def _make_order(cls, attrs): + """ + Create ordering methods for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.order] + + def attrs_to_tuple(obj): + """ + Save us some typing. + """ + return tuple( + key(value) if key else value + for value, key in ( + (getattr(obj, a.name), a.order_key) for a in attrs + ) + ) + + def __lt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) < attrs_to_tuple(other) + + return NotImplemented + + def __le__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) <= attrs_to_tuple(other) + + return NotImplemented + + def __gt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) > attrs_to_tuple(other) + + return NotImplemented + + def __ge__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) >= attrs_to_tuple(other) + + return NotImplemented + + return __lt__, __le__, __gt__, __ge__ + + +def _add_eq(cls, attrs=None): + """ + Add equality methods to *cls* with *attrs*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__eq__ = _make_eq(cls, attrs) + cls.__ne__ = _make_ne() + + return cls + + +if HAS_F_STRINGS: + + def _make_repr(attrs, ns, cls): + unique_filename = _generate_unique_filename(cls, "repr") + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, (repr if a.repr is True else a.repr), a.init) + for a in attrs + if a.repr is not False + ) + globs = { + name + "_repr": r + for name, r, _ in attr_names_with_reprs + if r != repr + } + globs["_compat"] = _compat + globs["AttributeError"] = AttributeError + globs["NOTHING"] = NOTHING + attribute_fragments = [] + for name, r, i in attr_names_with_reprs: + accessor = ( + "self." + name + if i + else 'getattr(self, "' + name + '", NOTHING)' + ) + fragment = ( + "%s={%s!r}" % (name, accessor) + if r == repr + else "%s={%s_repr(%s)}" % (name, name, accessor) + ) + attribute_fragments.append(fragment) + repr_fragment = ", ".join(attribute_fragments) + + if ns is None: + cls_name_fragment = ( + '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' + ) + else: + cls_name_fragment = ns + ".{self.__class__.__name__}" + + lines = [ + "def __repr__(self):", + " try:", + " already_repring = _compat.repr_context.already_repring", + " except AttributeError:", + " already_repring = {id(self),}", + " _compat.repr_context.already_repring = already_repring", + " else:", + " if id(self) in already_repring:", + " return '...'", + " else:", + " already_repring.add(id(self))", + " try:", + " return f'%s(%s)'" % (cls_name_fragment, repr_fragment), + " finally:", + " already_repring.remove(id(self))", + ] + + return _make_method( + "__repr__", "\n".join(lines), unique_filename, globs=globs + ) + +else: + + def _make_repr(attrs, ns, _): + """ + Make a repr method that includes relevant *attrs*, adding *ns* to the + full name. + """ + + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, repr if a.repr is True else a.repr) + for a in attrs + if a.repr is not False + ) + + def __repr__(self): + """ + Automatically created by attrs. + """ + try: + already_repring = _compat.repr_context.already_repring + except AttributeError: + already_repring = set() + _compat.repr_context.already_repring = already_repring + + if id(self) in already_repring: + return "..." + real_cls = self.__class__ + if ns is None: + qualname = getattr(real_cls, "__qualname__", None) + if qualname is not None: # pragma: no cover + # This case only happens on Python 3.5 and 3.6. We exclude + # it from coverage, because we don't want to slow down our + # test suite by running them under coverage too for this + # one line. + class_name = qualname.rsplit(">.", 1)[-1] + else: + class_name = real_cls.__name__ + else: + class_name = ns + "." + real_cls.__name__ + + # Since 'self' remains on the stack (i.e.: strongly referenced) + # for the duration of this call, it's safe to depend on id(...) + # stability, and not need to track the instance and therefore + # worry about properties like weakref- or hash-ability. + already_repring.add(id(self)) + try: + result = [class_name, "("] + first = True + for name, attr_repr in attr_names_with_reprs: + if first: + first = False + else: + result.append(", ") + result.extend( + (name, "=", attr_repr(getattr(self, name, NOTHING))) + ) + return "".join(result) + ")" + finally: + already_repring.remove(id(self)) + + return __repr__ + + +def _add_repr(cls, ns=None, attrs=None): + """ + Add a repr method to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__repr__ = _make_repr(attrs, ns, cls) + return cls + + +def fields(cls): + """ + Return the tuple of ``attrs`` attributes for a class. + + The tuple also allows accessing the fields by their names (see below for + examples). + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + :rtype: tuple (with name accessors) of `attrs.Attribute` + + .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields + by name. + """ + if not isclass(cls): + raise TypeError("Passed object must be a class.") + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + raise NotAnAttrsClassError( + "{cls!r} is not an attrs-decorated class.".format(cls=cls) + ) + return attrs + + +def fields_dict(cls): + """ + Return an ordered dictionary of ``attrs`` attributes for a class, whose + keys are the attribute names. + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs`` + class. + + :rtype: an ordered dict where keys are attribute names and values are + `attrs.Attribute`\\ s. This will be a `dict` if it's + naturally ordered like on Python 3.6+ or an + :class:`~collections.OrderedDict` otherwise. + + .. versionadded:: 18.1.0 + """ + if not isclass(cls): + raise TypeError("Passed object must be a class.") + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + raise NotAnAttrsClassError( + "{cls!r} is not an attrs-decorated class.".format(cls=cls) + ) + return ordered_dict(((a.name, a) for a in attrs)) + + +def validate(inst): + """ + Validate all attributes on *inst* that have a validator. + + Leaves all exceptions through. + + :param inst: Instance of a class with ``attrs`` attributes. + """ + if _config._run_validators is False: + return + + for a in fields(inst.__class__): + v = a.validator + if v is not None: + v(inst, a, getattr(inst, a.name)) + + +def _is_slot_cls(cls): + return "__slots__" in cls.__dict__ + + +def _is_slot_attr(a_name, base_attr_map): + """ + Check if the attribute name comes from a slot class. + """ + return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name]) + + +def _make_init( + cls, + attrs, + pre_init, + post_init, + frozen, + slots, + cache_hash, + base_attr_map, + is_exc, + cls_on_setattr, + attrs_init, +): + has_cls_on_setattr = ( + cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP + ) + + if frozen and has_cls_on_setattr: + raise ValueError("Frozen classes can't use on_setattr.") + + needs_cached_setattr = cache_hash or frozen + filtered_attrs = [] + attr_dict = {} + for a in attrs: + if not a.init and a.default is NOTHING: + continue + + filtered_attrs.append(a) + attr_dict[a.name] = a + + if a.on_setattr is not None: + if frozen is True: + raise ValueError("Frozen classes can't use on_setattr.") + + needs_cached_setattr = True + elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: + needs_cached_setattr = True + + unique_filename = _generate_unique_filename(cls, "init") + + script, globs, annotations = _attrs_to_init_script( + filtered_attrs, + frozen, + slots, + pre_init, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + attrs_init, + ) + if cls.__module__ in sys.modules: + # This makes typing.get_type_hints(CLS.__init__) resolve string types. + globs.update(sys.modules[cls.__module__].__dict__) + + globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) + + if needs_cached_setattr: + # Save the lookup overhead in __init__ if we need to circumvent + # setattr hooks. + globs["_cached_setattr"] = _obj_setattr + + init = _make_method( + "__attrs_init__" if attrs_init else "__init__", + script, + unique_filename, + globs, + ) + init.__annotations__ = annotations + + return init + + +def _setattr(attr_name, value_var, has_on_setattr): + """ + Use the cached object.setattr to set *attr_name* to *value_var*. + """ + return "_setattr('%s', %s)" % (attr_name, value_var) + + +def _setattr_with_converter(attr_name, value_var, has_on_setattr): + """ + Use the cached object.setattr to set *attr_name* to *value_var*, but run + its converter first. + """ + return "_setattr('%s', %s(%s))" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + +def _assign(attr_name, value, has_on_setattr): + """ + Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise + relegate to _setattr. + """ + if has_on_setattr: + return _setattr(attr_name, value, True) + + return "self.%s = %s" % (attr_name, value) + + +def _assign_with_converter(attr_name, value_var, has_on_setattr): + """ + Unless *attr_name* has an on_setattr hook, use normal assignment after + conversion. Otherwise relegate to _setattr_with_converter. + """ + if has_on_setattr: + return _setattr_with_converter(attr_name, value_var, True) + + return "self.%s = %s(%s)" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + +if PY2: + + def _unpack_kw_only_py2(attr_name, default=None): + """ + Unpack *attr_name* from _kw_only dict. + """ + if default is not None: + arg_default = ", %s" % default + else: + arg_default = "" + return "%s = _kw_only.pop('%s'%s)" % ( + attr_name, + attr_name, + arg_default, + ) + + def _unpack_kw_only_lines_py2(kw_only_args): + """ + Unpack all *kw_only_args* from _kw_only dict and handle errors. + + Given a list of strings "{attr_name}" and "{attr_name}={default}" + generates list of lines of code that pop attrs from _kw_only dict and + raise TypeError similar to builtin if required attr is missing or + extra key is passed. + + >>> print("\n".join(_unpack_kw_only_lines_py2(["a", "b=42"]))) + try: + a = _kw_only.pop('a') + b = _kw_only.pop('b', 42) + except KeyError as _key_error: + raise TypeError( + ... + if _kw_only: + raise TypeError( + ... + """ + lines = ["try:"] + lines.extend( + " " + _unpack_kw_only_py2(*arg.split("=")) + for arg in kw_only_args + ) + lines += """\ +except KeyError as _key_error: + raise TypeError( + '__init__() missing required keyword-only argument: %s' % _key_error + ) +if _kw_only: + raise TypeError( + '__init__() got an unexpected keyword argument %r' + % next(iter(_kw_only)) + ) +""".split( + "\n" + ) + return lines + + +def _attrs_to_init_script( + attrs, + frozen, + slots, + pre_init, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + attrs_init, +): + """ + Return a script of an initializer for *attrs* and a dict of globals. + + The globals are expected by the generated script. + + If *frozen* is True, we cannot set the attributes directly so we use + a cached ``object.__setattr__``. + """ + lines = [] + if pre_init: + lines.append("self.__attrs_pre_init__()") + + if needs_cached_setattr: + lines.append( + # Circumvent the __setattr__ descriptor to save one lookup per + # assignment. + # Note _setattr will be used again below if cache_hash is True + "_setattr = _cached_setattr.__get__(self, self.__class__)" + ) + + if frozen is True: + if slots is True: + fmt_setter = _setattr + fmt_setter_with_converter = _setattr_with_converter + else: + # Dict frozen classes assign directly to __dict__. + # But only if the attribute doesn't come from an ancestor slot + # class. + # Note _inst_dict will be used again below if cache_hash is True + lines.append("_inst_dict = self.__dict__") + + def fmt_setter(attr_name, value_var, has_on_setattr): + if _is_slot_attr(attr_name, base_attr_map): + return _setattr(attr_name, value_var, has_on_setattr) + + return "_inst_dict['%s'] = %s" % (attr_name, value_var) + + def fmt_setter_with_converter( + attr_name, value_var, has_on_setattr + ): + if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): + return _setattr_with_converter( + attr_name, value_var, has_on_setattr + ) + + return "_inst_dict['%s'] = %s(%s)" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + else: + # Not frozen. + fmt_setter = _assign + fmt_setter_with_converter = _assign_with_converter + + args = [] + kw_only_args = [] + attrs_to_validate = [] + + # This is a dictionary of names to validator and converter callables. + # Injecting this into __init__ globals lets us avoid lookups. + names_for_globals = {} + annotations = {"return": None} + + for a in attrs: + if a.validator: + attrs_to_validate.append(a) + + attr_name = a.name + has_on_setattr = a.on_setattr is not None or ( + a.on_setattr is not setters.NO_OP and has_cls_on_setattr + ) + arg_name = a.name.lstrip("_") + + has_factory = isinstance(a.default, Factory) + if has_factory and a.default.takes_self: + maybe_self = "self" + else: + maybe_self = "" + + if a.init is False: + if has_factory: + init_factory_name = _init_factory_pat.format(a.name) + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + init_factory_name + "(%s)" % (maybe_self,), + has_on_setattr, + ) + ) + conv_name = _init_converter_pat % (a.name,) + names_for_globals[conv_name] = a.converter + else: + lines.append( + fmt_setter( + attr_name, + init_factory_name + "(%s)" % (maybe_self,), + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + "attr_dict['%s'].default" % (attr_name,), + has_on_setattr, + ) + ) + conv_name = _init_converter_pat % (a.name,) + names_for_globals[conv_name] = a.converter + else: + lines.append( + fmt_setter( + attr_name, + "attr_dict['%s'].default" % (attr_name,), + has_on_setattr, + ) + ) + elif a.default is not NOTHING and not has_factory: + arg = "%s=attr_dict['%s'].default" % (arg_name, attr_name) + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + elif has_factory: + arg = "%s=NOTHING" % (arg_name,) + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + lines.append("if %s is not NOTHING:" % (arg_name,)) + + init_factory_name = _init_factory_pat.format(a.name) + if a.converter is not None: + lines.append( + " " + + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter_with_converter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append( + " " + fmt_setter(attr_name, arg_name, has_on_setattr) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.kw_only: + kw_only_args.append(arg_name) + else: + args.append(arg_name) + + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + if a.init is True: + if a.type is not None and a.converter is None: + annotations[arg_name] = a.type + elif a.converter is not None and not PY2: + # Try to get the type from the converter. + sig = None + try: + sig = inspect.signature(a.converter) + except (ValueError, TypeError): # inspect failed + pass + if sig: + sig_params = list(sig.parameters.values()) + if ( + sig_params + and sig_params[0].annotation + is not inspect.Parameter.empty + ): + annotations[arg_name] = sig_params[0].annotation + + if attrs_to_validate: # we can skip this if there are no validators. + names_for_globals["_config"] = _config + lines.append("if _config._run_validators is True:") + for a in attrs_to_validate: + val_name = "__attr_validator_" + a.name + attr_name = "__attr_" + a.name + lines.append( + " %s(self, %s, self.%s)" % (val_name, attr_name, a.name) + ) + names_for_globals[val_name] = a.validator + names_for_globals[attr_name] = a + + if post_init: + lines.append("self.__attrs_post_init__()") + + # because this is set only after __attrs_post_init is called, a crash + # will result if post-init tries to access the hash code. This seemed + # preferable to setting this beforehand, in which case alteration to + # field values during post-init combined with post-init accessing the + # hash code would result in silent bugs. + if cache_hash: + if frozen: + if slots: + # if frozen and slots, then _setattr defined above + init_hash_cache = "_setattr('%s', %s)" + else: + # if frozen and not slots, then _inst_dict defined above + init_hash_cache = "_inst_dict['%s'] = %s" + else: + init_hash_cache = "self.%s = %s" + lines.append(init_hash_cache % (_hash_cache_field, "None")) + + # For exceptions we rely on BaseException.__init__ for proper + # initialization. + if is_exc: + vals = ",".join("self." + a.name for a in attrs if a.init) + + lines.append("BaseException.__init__(self, %s)" % (vals,)) + + args = ", ".join(args) + if kw_only_args: + if PY2: + lines = _unpack_kw_only_lines_py2(kw_only_args) + lines + + args += "%s**_kw_only" % (", " if args else "",) # leading comma + else: + args += "%s*, %s" % ( + ", " if args else "", # leading comma + ", ".join(kw_only_args), # kw_only args + ) + return ( + """\ +def {init_name}(self, {args}): + {lines} +""".format( + init_name=("__attrs_init__" if attrs_init else "__init__"), + args=args, + lines="\n ".join(lines) if lines else "pass", + ), + names_for_globals, + annotations, + ) + + +class Attribute(object): + """ + *Read-only* representation of an attribute. + + The class has *all* arguments of `attr.ib` (except for ``factory`` + which is only syntactic sugar for ``default=Factory(...)`` plus the + following: + + - ``name`` (`str`): The name of the attribute. + - ``inherited`` (`bool`): Whether or not that attribute has been inherited + from a base class. + - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The callables + that are used for comparing and ordering objects by this attribute, + respectively. These are set by passing a callable to `attr.ib`'s ``eq``, + ``order``, or ``cmp`` arguments. See also :ref:`comparison customization + `. + + Instances of this class are frequently used for introspection purposes + like: + + - `fields` returns a tuple of them. + - Validators get them passed as the first argument. + - The :ref:`field transformer ` hook receives a list of + them. + + .. versionadded:: 20.1.0 *inherited* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.2.0 *inherited* is not taken into account for + equality checks and hashing anymore. + .. versionadded:: 21.1.0 *eq_key* and *order_key* + + For the full version history of the fields, see `attr.ib`. + """ + + __slots__ = ( + "name", + "default", + "validator", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "type", + "converter", + "kw_only", + "inherited", + "on_setattr", + ) + + def __init__( + self, + name, + default, + validator, + repr, + cmp, # XXX: unused, remove along with other cmp code. + hash, + init, + inherited, + metadata=None, + type=None, + converter=None, + kw_only=False, + eq=None, + eq_key=None, + order=None, + order_key=None, + on_setattr=None, + ): + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq_key or eq, order_key or order, True + ) + + # Cache this descriptor here to speed things up later. + bound_setattr = _obj_setattr.__get__(self, Attribute) + + # Despite the big red warning, people *do* instantiate `Attribute` + # themselves. + bound_setattr("name", name) + bound_setattr("default", default) + bound_setattr("validator", validator) + bound_setattr("repr", repr) + bound_setattr("eq", eq) + bound_setattr("eq_key", eq_key) + bound_setattr("order", order) + bound_setattr("order_key", order_key) + bound_setattr("hash", hash) + bound_setattr("init", init) + bound_setattr("converter", converter) + bound_setattr( + "metadata", + ( + metadata_proxy(metadata) + if metadata + else _empty_metadata_singleton + ), + ) + bound_setattr("type", type) + bound_setattr("kw_only", kw_only) + bound_setattr("inherited", inherited) + bound_setattr("on_setattr", on_setattr) + + def __setattr__(self, name, value): + raise FrozenInstanceError() + + @classmethod + def from_counting_attr(cls, name, ca, type=None): + # type holds the annotated value. deal with conflicts: + if type is None: + type = ca.type + elif ca.type is not None: + raise ValueError( + "Type annotation and type argument cannot both be present" + ) + inst_dict = { + k: getattr(ca, k) + for k in Attribute.__slots__ + if k + not in ( + "name", + "validator", + "default", + "type", + "inherited", + ) # exclude methods and deprecated alias + } + return cls( + name=name, + validator=ca._validator, + default=ca._default, + type=type, + cmp=None, + inherited=False, + **inst_dict + ) + + @property + def cmp(self): + """ + Simulate the presence of a cmp attribute and warn. + """ + warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=2) + + return self.eq and self.order + + # Don't use attr.evolve since fields(Attribute) doesn't work + def evolve(self, **changes): + """ + Copy *self* and apply *changes*. + + This works similarly to `attr.evolve` but that function does not work + with ``Attribute``. + + It is mainly meant to be used for `transform-fields`. + + .. versionadded:: 20.3.0 + """ + new = copy.copy(self) + + new._setattrs(changes.items()) + + return new + + # Don't use _add_pickle since fields(Attribute) doesn't work + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple( + getattr(self, name) if name != "metadata" else dict(self.metadata) + for name in self.__slots__ + ) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + self._setattrs(zip(self.__slots__, state)) + + def _setattrs(self, name_values_pairs): + bound_setattr = _obj_setattr.__get__(self, Attribute) + for name, value in name_values_pairs: + if name != "metadata": + bound_setattr(name, value) + else: + bound_setattr( + name, + metadata_proxy(value) + if value + else _empty_metadata_singleton, + ) + + +_a = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=(name != "metadata"), + init=True, + inherited=False, + ) + for name in Attribute.__slots__ +] + +Attribute = _add_hash( + _add_eq( + _add_repr(Attribute, attrs=_a), + attrs=[a for a in _a if a.name != "inherited"], + ), + attrs=[a for a in _a if a.hash and a.name != "inherited"], +) + + +class _CountingAttr(object): + """ + Intermediate representation of attributes that uses a counter to preserve + the order in which the attributes have been defined. + + *Internal* data structure of the attrs library. Running into is most + likely the result of a bug like a forgotten `@attr.s` decorator. + """ + + __slots__ = ( + "counter", + "_default", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "_validator", + "converter", + "type", + "kw_only", + "on_setattr", + ) + __attrs_attrs__ = tuple( + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=True, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ) + for name in ( + "counter", + "_default", + "repr", + "eq", + "order", + "hash", + "init", + "on_setattr", + ) + ) + ( + Attribute( + name="metadata", + default=None, + validator=None, + repr=True, + cmp=None, + hash=False, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ), + ) + cls_counter = 0 + + def __init__( + self, + default, + validator, + repr, + cmp, + hash, + init, + converter, + metadata, + type, + kw_only, + eq, + eq_key, + order, + order_key, + on_setattr, + ): + _CountingAttr.cls_counter += 1 + self.counter = _CountingAttr.cls_counter + self._default = default + self._validator = validator + self.converter = converter + self.repr = repr + self.eq = eq + self.eq_key = eq_key + self.order = order + self.order_key = order_key + self.hash = hash + self.init = init + self.metadata = metadata + self.type = type + self.kw_only = kw_only + self.on_setattr = on_setattr + + def validator(self, meth): + """ + Decorator that adds *meth* to the list of validators. + + Returns *meth* unchanged. + + .. versionadded:: 17.1.0 + """ + if self._validator is None: + self._validator = meth + else: + self._validator = and_(self._validator, meth) + return meth + + def default(self, meth): + """ + Decorator that allows to set the default for an attribute. + + Returns *meth* unchanged. + + :raises DefaultAlreadySetError: If default has been set before. + + .. versionadded:: 17.1.0 + """ + if self._default is not NOTHING: + raise DefaultAlreadySetError() + + self._default = Factory(meth, takes_self=True) + + return meth + + +_CountingAttr = _add_eq(_add_repr(_CountingAttr)) + + +class Factory(object): + """ + Stores a factory callable. + + If passed as the default value to `attrs.field`, the factory is used to + generate a new value. + + :param callable factory: A callable that takes either none or exactly one + mandatory positional argument depending on *takes_self*. + :param bool takes_self: Pass the partially initialized instance that is + being initialized as a positional argument. + + .. versionadded:: 17.1.0 *takes_self* + """ + + __slots__ = ("factory", "takes_self") + + def __init__(self, factory, takes_self=False): + """ + `Factory` is part of the default machinery so if we want a default + value here, we have to implement it ourselves. + """ + self.factory = factory + self.takes_self = takes_self + + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple(getattr(self, name) for name in self.__slots__) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + for name, value in zip(self.__slots__, state): + setattr(self, name, value) + + +_f = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + ) + for name in Factory.__slots__ +] + +Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) + + +def make_class(name, attrs, bases=(object,), **attributes_arguments): + """ + A quick way to create a new class called *name* with *attrs*. + + :param str name: The name for the new class. + + :param attrs: A list of names or a dictionary of mappings of names to + attributes. + + If *attrs* is a list or an ordered dict (`dict` on Python 3.6+, + `collections.OrderedDict` otherwise), the order is deduced from + the order of the names or attributes inside *attrs*. Otherwise the + order of the definition of the attributes is used. + :type attrs: `list` or `dict` + + :param tuple bases: Classes that the new class will subclass. + + :param attributes_arguments: Passed unmodified to `attr.s`. + + :return: A new class with *attrs*. + :rtype: type + + .. versionadded:: 17.1.0 *bases* + .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. + """ + if isinstance(attrs, dict): + cls_dict = attrs + elif isinstance(attrs, (list, tuple)): + cls_dict = dict((a, attrib()) for a in attrs) + else: + raise TypeError("attrs argument must be a dict or a list.") + + pre_init = cls_dict.pop("__attrs_pre_init__", None) + post_init = cls_dict.pop("__attrs_post_init__", None) + user_init = cls_dict.pop("__init__", None) + + body = {} + if pre_init is not None: + body["__attrs_pre_init__"] = pre_init + if post_init is not None: + body["__attrs_post_init__"] = post_init + if user_init is not None: + body["__init__"] = user_init + + type_ = new_class(name, bases, {}, lambda ns: ns.update(body)) + + # For pickling to work, the __module__ variable needs to be set to the + # frame where the class is created. Bypass this step in environments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + try: + type_.__module__ = sys._getframe(1).f_globals.get( + "__name__", "__main__" + ) + except (AttributeError, ValueError): + pass + + # We do it here for proper warnings with meaningful stacklevel. + cmp = attributes_arguments.pop("cmp", None) + ( + attributes_arguments["eq"], + attributes_arguments["order"], + ) = _determine_attrs_eq_order( + cmp, + attributes_arguments.get("eq"), + attributes_arguments.get("order"), + True, + ) + + return _attrs(these=cls_dict, **attributes_arguments)(type_) + + +# These are required by within this module so we define them here and merely +# import into .validators / .converters. + + +@attrs(slots=True, hash=True) +class _AndValidator(object): + """ + Compose many validators to a single one. + """ + + _validators = attrib() + + def __call__(self, inst, attr, value): + for v in self._validators: + v(inst, attr, value) + + +def and_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators. + + :param callables validators: Arbitrary number of validators. + + .. versionadded:: 17.1.0 + """ + vals = [] + for validator in validators: + vals.extend( + validator._validators + if isinstance(validator, _AndValidator) + else [validator] + ) + + return _AndValidator(tuple(vals)) + + +def pipe(*converters): + """ + A converter that composes multiple converters into one. + + When called on a value, it runs all wrapped converters, returning the + *last* value. + + Type annotations will be inferred from the wrapped converters', if + they have any. + + :param callables converters: Arbitrary number of converters. + + .. versionadded:: 20.1.0 + """ + + def pipe_converter(val): + for converter in converters: + val = converter(val) + + return val + + if not PY2: + if not converters: + # If the converter list is empty, pipe_converter is the identity. + A = typing.TypeVar("A") + pipe_converter.__annotations__ = {"val": A, "return": A} + else: + # Get parameter type. + sig = None + try: + sig = inspect.signature(converters[0]) + except (ValueError, TypeError): # inspect failed + pass + if sig: + params = list(sig.parameters.values()) + if ( + params + and params[0].annotation is not inspect.Parameter.empty + ): + pipe_converter.__annotations__["val"] = params[ + 0 + ].annotation + # Get return type. + sig = None + try: + sig = inspect.signature(converters[-1]) + except (ValueError, TypeError): # inspect failed + pass + if sig and sig.return_annotation is not inspect.Signature().empty: + pipe_converter.__annotations__[ + "return" + ] = sig.return_annotation + + return pipe_converter diff --git a/myenv/lib/python3.9/site-packages/attr/_next_gen.py b/myenv/lib/python3.9/site-packages/attr/_next_gen.py new file mode 100644 index 0000000..0682536 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_next_gen.py @@ -0,0 +1,216 @@ +# SPDX-License-Identifier: MIT + +""" +These are Python 3.6+-only and keyword-only APIs that call `attr.s` and +`attr.ib` with different default values. +""" + + +from functools import partial + +from . import setters +from ._funcs import asdict as _asdict +from ._funcs import astuple as _astuple +from ._make import ( + NOTHING, + _frozen_setattrs, + _ng_default_on_setattr, + attrib, + attrs, +) +from .exceptions import UnannotatedAttributeError + + +def define( + maybe_cls=None, + *, + these=None, + repr=None, + hash=None, + init=None, + slots=True, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=None, + kw_only=False, + cache_hash=False, + auto_exc=True, + eq=None, + order=False, + auto_detect=True, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, +): + r""" + Define an ``attrs`` class. + + Differences to the classic `attr.s` that it uses underneath: + + - Automatically detect whether or not *auto_attribs* should be `True` + (c.f. *auto_attribs* parameter). + - If *frozen* is `False`, run converters and validators when setting an + attribute by default. + - *slots=True* (see :term:`slotted classes` for potentially surprising + behaviors) + - *auto_exc=True* + - *auto_detect=True* + - *order=False* + - *match_args=True* + - Some options that were only relevant on Python 2 or were kept around for + backwards-compatibility have been removed. + + Please note that these are all defaults and you can change them as you + wish. + + :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves + exactly like `attr.s`. If left `None`, `attr.s` will try to guess: + + 1. If any attributes are annotated and no unannotated `attrs.fields`\ s + are found, it assumes *auto_attribs=True*. + 2. Otherwise it assumes *auto_attribs=False* and tries to collect + `attrs.fields`\ s. + + For now, please refer to `attr.s` for the rest of the parameters. + + .. versionadded:: 20.1.0 + .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. + """ + + def do_it(cls, auto_attribs): + return attrs( + maybe_cls=cls, + these=these, + repr=repr, + hash=hash, + init=init, + slots=slots, + frozen=frozen, + weakref_slot=weakref_slot, + str=str, + auto_attribs=auto_attribs, + kw_only=kw_only, + cache_hash=cache_hash, + auto_exc=auto_exc, + eq=eq, + order=order, + auto_detect=auto_detect, + collect_by_mro=True, + getstate_setstate=getstate_setstate, + on_setattr=on_setattr, + field_transformer=field_transformer, + match_args=match_args, + ) + + def wrap(cls): + """ + Making this a wrapper ensures this code runs during class creation. + + We also ensure that frozen-ness of classes is inherited. + """ + nonlocal frozen, on_setattr + + had_on_setattr = on_setattr not in (None, setters.NO_OP) + + # By default, mutable classes convert & validate on setattr. + if frozen is False and on_setattr is None: + on_setattr = _ng_default_on_setattr + + # However, if we subclass a frozen class, we inherit the immutability + # and disable on_setattr. + for base_cls in cls.__bases__: + if base_cls.__setattr__ is _frozen_setattrs: + if had_on_setattr: + raise ValueError( + "Frozen classes can't use on_setattr " + "(frozen-ness was inherited)." + ) + + on_setattr = setters.NO_OP + break + + if auto_attribs is not None: + return do_it(cls, auto_attribs) + + try: + return do_it(cls, True) + except UnannotatedAttributeError: + return do_it(cls, False) + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + else: + return wrap(maybe_cls) + + +mutable = define +frozen = partial(define, frozen=True, on_setattr=None) + + +def field( + *, + default=NOTHING, + validator=None, + repr=True, + hash=None, + init=True, + metadata=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, +): + """ + Identical to `attr.ib`, except keyword-only and with some arguments + removed. + + .. versionadded:: 20.1.0 + """ + return attrib( + default=default, + validator=validator, + repr=repr, + hash=hash, + init=init, + metadata=metadata, + converter=converter, + factory=factory, + kw_only=kw_only, + eq=eq, + order=order, + on_setattr=on_setattr, + ) + + +def asdict(inst, *, recurse=True, filter=None, value_serializer=None): + """ + Same as `attr.asdict`, except that collections types are always retained + and dict is always used as *dict_factory*. + + .. versionadded:: 21.3.0 + """ + return _asdict( + inst=inst, + recurse=recurse, + filter=filter, + value_serializer=value_serializer, + retain_collection_types=True, + ) + + +def astuple(inst, *, recurse=True, filter=None): + """ + Same as `attr.astuple`, except that collections types are always retained + and `tuple` is always used as the *tuple_factory*. + + .. versionadded:: 21.3.0 + """ + return _astuple( + inst=inst, recurse=recurse, filter=filter, retain_collection_types=True + ) diff --git a/myenv/lib/python3.9/site-packages/attr/_version_info.py b/myenv/lib/python3.9/site-packages/attr/_version_info.py new file mode 100644 index 0000000..cdaeec3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_version_info.py @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + +from functools import total_ordering + +from ._funcs import astuple +from ._make import attrib, attrs + + +@total_ordering +@attrs(eq=False, order=False, slots=True, frozen=True) +class VersionInfo(object): + """ + A version object that can be compared to tuple of length 1--4: + + >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) + True + >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) + True + >>> vi = attr.VersionInfo(19, 2, 0, "final") + >>> vi < (19, 1, 1) + False + >>> vi < (19,) + False + >>> vi == (19, 2,) + True + >>> vi == (19, 2, 1) + False + + .. versionadded:: 19.2 + """ + + year = attrib(type=int) + minor = attrib(type=int) + micro = attrib(type=int) + releaselevel = attrib(type=str) + + @classmethod + def _from_version_string(cls, s): + """ + Parse *s* and return a _VersionInfo. + """ + v = s.split(".") + if len(v) == 3: + v.append("final") + + return cls( + year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] + ) + + def _ensure_tuple(self, other): + """ + Ensure *other* is a tuple of a valid length. + + Returns a possibly transformed *other* and ourselves as a tuple of + the same length as *other*. + """ + + if self.__class__ is other.__class__: + other = astuple(other) + + if not isinstance(other, tuple): + raise NotImplementedError + + if not (1 <= len(other) <= 4): + raise NotImplementedError + + return astuple(self)[: len(other)], other + + def __eq__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + return us == them + + def __lt__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't + # have to do anything special with releaselevel for now. + return us < them diff --git a/myenv/lib/python3.9/site-packages/attr/_version_info.pyi b/myenv/lib/python3.9/site-packages/attr/_version_info.pyi new file mode 100644 index 0000000..45ced08 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/_version_info.pyi @@ -0,0 +1,9 @@ +class VersionInfo: + @property + def year(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def micro(self) -> int: ... + @property + def releaselevel(self) -> str: ... diff --git a/myenv/lib/python3.9/site-packages/attr/converters.py b/myenv/lib/python3.9/site-packages/attr/converters.py new file mode 100644 index 0000000..1fb6c05 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/converters.py @@ -0,0 +1,155 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful converters. +""" + +from __future__ import absolute_import, division, print_function + +from ._compat import PY2 +from ._make import NOTHING, Factory, pipe + + +if not PY2: + import inspect + import typing + + +__all__ = [ + "default_if_none", + "optional", + "pipe", + "to_bool", +] + + +def optional(converter): + """ + A converter that allows an attribute to be optional. An optional attribute + is one which can be set to ``None``. + + Type annotations will be inferred from the wrapped converter's, if it + has any. + + :param callable converter: the converter that is used for non-``None`` + values. + + .. versionadded:: 17.1.0 + """ + + def optional_converter(val): + if val is None: + return None + return converter(val) + + if not PY2: + sig = None + try: + sig = inspect.signature(converter) + except (ValueError, TypeError): # inspect failed + pass + if sig: + params = list(sig.parameters.values()) + if params and params[0].annotation is not inspect.Parameter.empty: + optional_converter.__annotations__["val"] = typing.Optional[ + params[0].annotation + ] + if sig.return_annotation is not inspect.Signature.empty: + optional_converter.__annotations__["return"] = typing.Optional[ + sig.return_annotation + ] + + return optional_converter + + +def default_if_none(default=NOTHING, factory=None): + """ + A converter that allows to replace ``None`` values by *default* or the + result of *factory*. + + :param default: Value to be used if ``None`` is passed. Passing an instance + of `attrs.Factory` is supported, however the ``takes_self`` option + is *not*. + :param callable factory: A callable that takes no parameters whose result + is used if ``None`` is passed. + + :raises TypeError: If **neither** *default* or *factory* is passed. + :raises TypeError: If **both** *default* and *factory* are passed. + :raises ValueError: If an instance of `attrs.Factory` is passed with + ``takes_self=True``. + + .. versionadded:: 18.2.0 + """ + if default is NOTHING and factory is None: + raise TypeError("Must pass either `default` or `factory`.") + + if default is not NOTHING and factory is not None: + raise TypeError( + "Must pass either `default` or `factory` but not both." + ) + + if factory is not None: + default = Factory(factory) + + if isinstance(default, Factory): + if default.takes_self: + raise ValueError( + "`takes_self` is not supported by default_if_none." + ) + + def default_if_none_converter(val): + if val is not None: + return val + + return default.factory() + + else: + + def default_if_none_converter(val): + if val is not None: + return val + + return default + + return default_if_none_converter + + +def to_bool(val): + """ + Convert "boolean" strings (e.g., from env. vars.) to real booleans. + + Values mapping to :code:`True`: + + - :code:`True` + - :code:`"true"` / :code:`"t"` + - :code:`"yes"` / :code:`"y"` + - :code:`"on"` + - :code:`"1"` + - :code:`1` + + Values mapping to :code:`False`: + + - :code:`False` + - :code:`"false"` / :code:`"f"` + - :code:`"no"` / :code:`"n"` + - :code:`"off"` + - :code:`"0"` + - :code:`0` + + :raises ValueError: for any other value. + + .. versionadded:: 21.3.0 + """ + if isinstance(val, str): + val = val.lower() + truthy = {True, "true", "t", "yes", "y", "on", "1", 1} + falsy = {False, "false", "f", "no", "n", "off", "0", 0} + try: + if val in truthy: + return True + if val in falsy: + return False + except TypeError: + # Raised when "val" is not hashable (e.g., lists) + pass + raise ValueError("Cannot convert value to bool: {}".format(val)) diff --git a/myenv/lib/python3.9/site-packages/attr/converters.pyi b/myenv/lib/python3.9/site-packages/attr/converters.pyi new file mode 100644 index 0000000..0f58088 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/converters.pyi @@ -0,0 +1,13 @@ +from typing import Callable, Optional, TypeVar, overload + +from . import _ConverterType + +_T = TypeVar("_T") + +def pipe(*validators: _ConverterType) -> _ConverterType: ... +def optional(converter: _ConverterType) -> _ConverterType: ... +@overload +def default_if_none(default: _T) -> _ConverterType: ... +@overload +def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType: ... +def to_bool(val: str) -> bool: ... diff --git a/myenv/lib/python3.9/site-packages/attr/exceptions.py b/myenv/lib/python3.9/site-packages/attr/exceptions.py new file mode 100644 index 0000000..b2f1edc --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/exceptions.py @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: MIT + +from __future__ import absolute_import, division, print_function + + +class FrozenError(AttributeError): + """ + A frozen/immutable instance or attribute have been attempted to be + modified. + + It mirrors the behavior of ``namedtuples`` by using the same error message + and subclassing `AttributeError`. + + .. versionadded:: 20.1.0 + """ + + msg = "can't set attribute" + args = [msg] + + +class FrozenInstanceError(FrozenError): + """ + A frozen instance has been attempted to be modified. + + .. versionadded:: 16.1.0 + """ + + +class FrozenAttributeError(FrozenError): + """ + A frozen attribute has been attempted to be modified. + + .. versionadded:: 20.1.0 + """ + + +class AttrsAttributeNotFoundError(ValueError): + """ + An ``attrs`` function couldn't find an attribute that the user asked for. + + .. versionadded:: 16.2.0 + """ + + +class NotAnAttrsClassError(ValueError): + """ + A non-``attrs`` class has been passed into an ``attrs`` function. + + .. versionadded:: 16.2.0 + """ + + +class DefaultAlreadySetError(RuntimeError): + """ + A default has been set using ``attr.ib()`` and is attempted to be reset + using the decorator. + + .. versionadded:: 17.1.0 + """ + + +class UnannotatedAttributeError(RuntimeError): + """ + A class with ``auto_attribs=True`` has an ``attr.ib()`` without a type + annotation. + + .. versionadded:: 17.3.0 + """ + + +class PythonTooOldError(RuntimeError): + """ + It was attempted to use an ``attrs`` feature that requires a newer Python + version. + + .. versionadded:: 18.2.0 + """ + + +class NotCallableError(TypeError): + """ + A ``attr.ib()`` requiring a callable has been set with a value + that is not callable. + + .. versionadded:: 19.2.0 + """ + + def __init__(self, msg, value): + super(TypeError, self).__init__(msg, value) + self.msg = msg + self.value = value + + def __str__(self): + return str(self.msg) diff --git a/myenv/lib/python3.9/site-packages/attr/exceptions.pyi b/myenv/lib/python3.9/site-packages/attr/exceptions.pyi new file mode 100644 index 0000000..f268011 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/exceptions.pyi @@ -0,0 +1,17 @@ +from typing import Any + +class FrozenError(AttributeError): + msg: str = ... + +class FrozenInstanceError(FrozenError): ... +class FrozenAttributeError(FrozenError): ... +class AttrsAttributeNotFoundError(ValueError): ... +class NotAnAttrsClassError(ValueError): ... +class DefaultAlreadySetError(RuntimeError): ... +class UnannotatedAttributeError(RuntimeError): ... +class PythonTooOldError(RuntimeError): ... + +class NotCallableError(TypeError): + msg: str = ... + value: Any = ... + def __init__(self, msg: str, value: Any) -> None: ... diff --git a/myenv/lib/python3.9/site-packages/attr/filters.py b/myenv/lib/python3.9/site-packages/attr/filters.py new file mode 100644 index 0000000..a1978a8 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/filters.py @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful filters for `attr.asdict`. +""" + +from __future__ import absolute_import, division, print_function + +from ._compat import isclass +from ._make import Attribute + + +def _split_what(what): + """ + Returns a tuple of `frozenset`s of classes and attributes. + """ + return ( + frozenset(cls for cls in what if isclass(cls)), + frozenset(cls for cls in what if isinstance(cls, Attribute)), + ) + + +def include(*what): + """ + Include *what*. + + :param what: What to include. + :type what: `list` of `type` or `attrs.Attribute`\\ s + + :rtype: `callable` + """ + cls, attrs = _split_what(what) + + def include_(attribute, value): + return value.__class__ in cls or attribute in attrs + + return include_ + + +def exclude(*what): + """ + Exclude *what*. + + :param what: What to exclude. + :type what: `list` of classes or `attrs.Attribute`\\ s. + + :rtype: `callable` + """ + cls, attrs = _split_what(what) + + def exclude_(attribute, value): + return value.__class__ not in cls and attribute not in attrs + + return exclude_ diff --git a/myenv/lib/python3.9/site-packages/attr/filters.pyi b/myenv/lib/python3.9/site-packages/attr/filters.pyi new file mode 100644 index 0000000..9938668 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/filters.pyi @@ -0,0 +1,6 @@ +from typing import Any, Union + +from . import Attribute, _FilterType + +def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ... +def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ... diff --git a/myenv/lib/python3.9/site-packages/attr/py.typed b/myenv/lib/python3.9/site-packages/attr/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/attr/setters.py b/myenv/lib/python3.9/site-packages/attr/setters.py new file mode 100644 index 0000000..b1cbb5d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/setters.py @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly used hooks for on_setattr. +""" + +from __future__ import absolute_import, division, print_function + +from . import _config +from .exceptions import FrozenAttributeError + + +def pipe(*setters): + """ + Run all *setters* and return the return value of the last one. + + .. versionadded:: 20.1.0 + """ + + def wrapped_pipe(instance, attrib, new_value): + rv = new_value + + for setter in setters: + rv = setter(instance, attrib, rv) + + return rv + + return wrapped_pipe + + +def frozen(_, __, ___): + """ + Prevent an attribute to be modified. + + .. versionadded:: 20.1.0 + """ + raise FrozenAttributeError() + + +def validate(instance, attrib, new_value): + """ + Run *attrib*'s validator on *new_value* if it has one. + + .. versionadded:: 20.1.0 + """ + if _config._run_validators is False: + return new_value + + v = attrib.validator + if not v: + return new_value + + v(instance, attrib, new_value) + + return new_value + + +def convert(instance, attrib, new_value): + """ + Run *attrib*'s converter -- if it has one -- on *new_value* and return the + result. + + .. versionadded:: 20.1.0 + """ + c = attrib.converter + if c: + return c(new_value) + + return new_value + + +NO_OP = object() +""" +Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. + +Does not work in `pipe` or within lists. + +.. versionadded:: 20.1.0 +""" diff --git a/myenv/lib/python3.9/site-packages/attr/setters.pyi b/myenv/lib/python3.9/site-packages/attr/setters.pyi new file mode 100644 index 0000000..3f5603c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/setters.pyi @@ -0,0 +1,19 @@ +from typing import Any, NewType, NoReturn, TypeVar, cast + +from . import Attribute, _OnSetAttrType + +_T = TypeVar("_T") + +def frozen( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> NoReturn: ... +def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... +def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... + +# convert is allowed to return Any, because they can be chained using pipe. +def convert( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> Any: ... + +_NoOpType = NewType("_NoOpType", object) +NO_OP: _NoOpType diff --git a/myenv/lib/python3.9/site-packages/attr/validators.py b/myenv/lib/python3.9/site-packages/attr/validators.py new file mode 100644 index 0000000..0b0c834 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/validators.py @@ -0,0 +1,561 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful validators. +""" + +from __future__ import absolute_import, division, print_function + +import operator +import re + +from contextlib import contextmanager + +from ._config import get_run_validators, set_run_validators +from ._make import _AndValidator, and_, attrib, attrs +from .exceptions import NotCallableError + + +try: + Pattern = re.Pattern +except AttributeError: # Python <3.7 lacks a Pattern type. + Pattern = type(re.compile("")) + + +__all__ = [ + "and_", + "deep_iterable", + "deep_mapping", + "disabled", + "ge", + "get_disabled", + "gt", + "in_", + "instance_of", + "is_callable", + "le", + "lt", + "matches_re", + "max_len", + "optional", + "provides", + "set_disabled", +] + + +def set_disabled(disabled): + """ + Globally disable or enable running validators. + + By default, they are run. + + :param disabled: If ``True``, disable running all validators. + :type disabled: bool + + .. warning:: + + This function is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(not disabled) + + +def get_disabled(): + """ + Return a bool indicating whether validators are currently disabled or not. + + :return: ``True`` if validators are currently disabled. + :rtype: bool + + .. versionadded:: 21.3.0 + """ + return not get_run_validators() + + +@contextmanager +def disabled(): + """ + Context manager that disables running validators within its context. + + .. warning:: + + This context manager is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(False) + try: + yield + finally: + set_run_validators(True) + + +@attrs(repr=False, slots=True, hash=True) +class _InstanceOfValidator(object): + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not isinstance(value, self.type): + raise TypeError( + "'{name}' must be {type!r} (got {value!r} that is a " + "{actual!r}).".format( + name=attr.name, + type=self.type, + actual=value.__class__, + value=value, + ), + attr, + self.type, + value, + ) + + def __repr__(self): + return "".format( + type=self.type + ) + + +def instance_of(type): + """ + A validator that raises a `TypeError` if the initializer is called + with a wrong type for this particular attribute (checks are performed using + `isinstance` therefore it's also valid to pass a tuple of types). + + :param type: The type to check for. + :type type: type or tuple of types + + :raises TypeError: With a human readable error message, the attribute + (of type `attrs.Attribute`), the expected type, and the value it + got. + """ + return _InstanceOfValidator(type) + + +@attrs(repr=False, frozen=True, slots=True) +class _MatchesReValidator(object): + pattern = attrib() + match_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.match_func(value): + raise ValueError( + "'{name}' must match regex {pattern!r}" + " ({value!r} doesn't)".format( + name=attr.name, pattern=self.pattern.pattern, value=value + ), + attr, + self.pattern, + value, + ) + + def __repr__(self): + return "".format( + pattern=self.pattern + ) + + +def matches_re(regex, flags=0, func=None): + r""" + A validator that raises `ValueError` if the initializer is called + with a string that doesn't match *regex*. + + :param regex: a regex string or precompiled pattern to match against + :param int flags: flags that will be passed to the underlying re function + (default 0) + :param callable func: which underlying `re` function to call (options + are `re.fullmatch`, `re.search`, `re.match`, default + is ``None`` which means either `re.fullmatch` or an emulation of + it on Python 2). For performance reasons, they won't be used directly + but on a pre-`re.compile`\ ed pattern. + + .. versionadded:: 19.2.0 + .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. + """ + fullmatch = getattr(re, "fullmatch", None) + valid_funcs = (fullmatch, None, re.search, re.match) + if func not in valid_funcs: + raise ValueError( + "'func' must be one of {}.".format( + ", ".join( + sorted( + e and e.__name__ or "None" for e in set(valid_funcs) + ) + ) + ) + ) + + if isinstance(regex, Pattern): + if flags: + raise TypeError( + "'flags' can only be used with a string pattern; " + "pass flags to re.compile() instead" + ) + pattern = regex + else: + pattern = re.compile(regex, flags) + + if func is re.match: + match_func = pattern.match + elif func is re.search: + match_func = pattern.search + elif fullmatch: + match_func = pattern.fullmatch + else: # Python 2 fullmatch emulation (https://bugs.python.org/issue16203) + pattern = re.compile( + r"(?:{})\Z".format(pattern.pattern), pattern.flags + ) + match_func = pattern.match + + return _MatchesReValidator(pattern, match_func) + + +@attrs(repr=False, slots=True, hash=True) +class _ProvidesValidator(object): + interface = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.interface.providedBy(value): + raise TypeError( + "'{name}' must provide {interface!r} which {value!r} " + "doesn't.".format( + name=attr.name, interface=self.interface, value=value + ), + attr, + self.interface, + value, + ) + + def __repr__(self): + return "".format( + interface=self.interface + ) + + +def provides(interface): + """ + A validator that raises a `TypeError` if the initializer is called + with an object that does not provide the requested *interface* (checks are + performed using ``interface.providedBy(value)`` (see `zope.interface + `_). + + :param interface: The interface to check for. + :type interface: ``zope.interface.Interface`` + + :raises TypeError: With a human readable error message, the attribute + (of type `attrs.Attribute`), the expected interface, and the + value it got. + """ + return _ProvidesValidator(interface) + + +@attrs(repr=False, slots=True, hash=True) +class _OptionalValidator(object): + validator = attrib() + + def __call__(self, inst, attr, value): + if value is None: + return + + self.validator(inst, attr, value) + + def __repr__(self): + return "".format( + what=repr(self.validator) + ) + + +def optional(validator): + """ + A validator that makes an attribute optional. An optional attribute is one + which can be set to ``None`` in addition to satisfying the requirements of + the sub-validator. + + :param validator: A validator (or a list of validators) that is used for + non-``None`` values. + :type validator: callable or `list` of callables. + + .. versionadded:: 15.1.0 + .. versionchanged:: 17.1.0 *validator* can be a list of validators. + """ + if isinstance(validator, list): + return _OptionalValidator(_AndValidator(validator)) + return _OptionalValidator(validator) + + +@attrs(repr=False, slots=True, hash=True) +class _InValidator(object): + options = attrib() + + def __call__(self, inst, attr, value): + try: + in_options = value in self.options + except TypeError: # e.g. `1 in "abc"` + in_options = False + + if not in_options: + raise ValueError( + "'{name}' must be in {options!r} (got {value!r})".format( + name=attr.name, options=self.options, value=value + ) + ) + + def __repr__(self): + return "".format( + options=self.options + ) + + +def in_(options): + """ + A validator that raises a `ValueError` if the initializer is called + with a value that does not belong in the options provided. The check is + performed using ``value in options``. + + :param options: Allowed options. + :type options: list, tuple, `enum.Enum`, ... + + :raises ValueError: With a human readable error message, the attribute (of + type `attrs.Attribute`), the expected options, and the value it + got. + + .. versionadded:: 17.1.0 + """ + return _InValidator(options) + + +@attrs(repr=False, slots=False, hash=True) +class _IsCallableValidator(object): + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not callable(value): + message = ( + "'{name}' must be callable " + "(got {value!r} that is a {actual!r})." + ) + raise NotCallableError( + msg=message.format( + name=attr.name, value=value, actual=value.__class__ + ), + value=value, + ) + + def __repr__(self): + return "" + + +def is_callable(): + """ + A validator that raises a `attr.exceptions.NotCallableError` if the + initializer is called with a value for this particular attribute + that is not callable. + + .. versionadded:: 19.1.0 + + :raises `attr.exceptions.NotCallableError`: With a human readable error + message containing the attribute (`attrs.Attribute`) name, + and the value it got. + """ + return _IsCallableValidator() + + +@attrs(repr=False, slots=True, hash=True) +class _DeepIterable(object): + member_validator = attrib(validator=is_callable()) + iterable_validator = attrib( + default=None, validator=optional(is_callable()) + ) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.iterable_validator is not None: + self.iterable_validator(inst, attr, value) + + for member in value: + self.member_validator(inst, attr, member) + + def __repr__(self): + iterable_identifier = ( + "" + if self.iterable_validator is None + else " {iterable!r}".format(iterable=self.iterable_validator) + ) + return ( + "" + ).format( + iterable_identifier=iterable_identifier, + member=self.member_validator, + ) + + +def deep_iterable(member_validator, iterable_validator=None): + """ + A validator that performs deep validation of an iterable. + + :param member_validator: Validator to apply to iterable members + :param iterable_validator: Validator to apply to iterable itself + (optional) + + .. versionadded:: 19.1.0 + + :raises TypeError: if any sub-validators fail + """ + return _DeepIterable(member_validator, iterable_validator) + + +@attrs(repr=False, slots=True, hash=True) +class _DeepMapping(object): + key_validator = attrib(validator=is_callable()) + value_validator = attrib(validator=is_callable()) + mapping_validator = attrib(default=None, validator=optional(is_callable())) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.mapping_validator is not None: + self.mapping_validator(inst, attr, value) + + for key in value: + self.key_validator(inst, attr, key) + self.value_validator(inst, attr, value[key]) + + def __repr__(self): + return ( + "" + ).format(key=self.key_validator, value=self.value_validator) + + +def deep_mapping(key_validator, value_validator, mapping_validator=None): + """ + A validator that performs deep validation of a dictionary. + + :param key_validator: Validator to apply to dictionary keys + :param value_validator: Validator to apply to dictionary values + :param mapping_validator: Validator to apply to top-level mapping + attribute (optional) + + .. versionadded:: 19.1.0 + + :raises TypeError: if any sub-validators fail + """ + return _DeepMapping(key_validator, value_validator, mapping_validator) + + +@attrs(repr=False, frozen=True, slots=True) +class _NumberValidator(object): + bound = attrib() + compare_op = attrib() + compare_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.compare_func(value, self.bound): + raise ValueError( + "'{name}' must be {op} {bound}: {value}".format( + name=attr.name, + op=self.compare_op, + bound=self.bound, + value=value, + ) + ) + + def __repr__(self): + return "".format( + op=self.compare_op, bound=self.bound + ) + + +def lt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number larger or equal to *val*. + + :param val: Exclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<", operator.lt) + + +def le(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number greater than *val*. + + :param val: Inclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<=", operator.le) + + +def ge(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller than *val*. + + :param val: Inclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">=", operator.ge) + + +def gt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller or equal to *val*. + + :param val: Exclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">", operator.gt) + + +@attrs(repr=False, frozen=True, slots=True) +class _MaxLengthValidator(object): + max_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) > self.max_length: + raise ValueError( + "Length of '{name}' must be <= {max}: {len}".format( + name=attr.name, max=self.max_length, len=len(value) + ) + ) + + def __repr__(self): + return "".format(max=self.max_length) + + +def max_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is longer than *length*. + + :param int length: Maximum length of the string or iterable + + .. versionadded:: 21.3.0 + """ + return _MaxLengthValidator(length) diff --git a/myenv/lib/python3.9/site-packages/attr/validators.pyi b/myenv/lib/python3.9/site-packages/attr/validators.pyi new file mode 100644 index 0000000..5e00b85 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attr/validators.pyi @@ -0,0 +1,78 @@ +from typing import ( + Any, + AnyStr, + Callable, + Container, + ContextManager, + Iterable, + List, + Mapping, + Match, + Optional, + Pattern, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +from . import _ValidatorType + +_T = TypeVar("_T") +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") +_T3 = TypeVar("_T3") +_I = TypeVar("_I", bound=Iterable) +_K = TypeVar("_K") +_V = TypeVar("_V") +_M = TypeVar("_M", bound=Mapping) + +def set_disabled(run: bool) -> None: ... +def get_disabled() -> bool: ... +def disabled() -> ContextManager[None]: ... + +# To be more precise on instance_of use some overloads. +# If there are more than 3 items in the tuple then we fall back to Any +@overload +def instance_of(type: Type[_T]) -> _ValidatorType[_T]: ... +@overload +def instance_of(type: Tuple[Type[_T]]) -> _ValidatorType[_T]: ... +@overload +def instance_of( + type: Tuple[Type[_T1], Type[_T2]] +) -> _ValidatorType[Union[_T1, _T2]]: ... +@overload +def instance_of( + type: Tuple[Type[_T1], Type[_T2], Type[_T3]] +) -> _ValidatorType[Union[_T1, _T2, _T3]]: ... +@overload +def instance_of(type: Tuple[type, ...]) -> _ValidatorType[Any]: ... +def provides(interface: Any) -> _ValidatorType[Any]: ... +def optional( + validator: Union[_ValidatorType[_T], List[_ValidatorType[_T]]] +) -> _ValidatorType[Optional[_T]]: ... +def in_(options: Container[_T]) -> _ValidatorType[_T]: ... +def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... +def matches_re( + regex: Union[Pattern[AnyStr], AnyStr], + flags: int = ..., + func: Optional[ + Callable[[AnyStr, AnyStr, int], Optional[Match[AnyStr]]] + ] = ..., +) -> _ValidatorType[AnyStr]: ... +def deep_iterable( + member_validator: _ValidatorType[_T], + iterable_validator: Optional[_ValidatorType[_I]] = ..., +) -> _ValidatorType[_I]: ... +def deep_mapping( + key_validator: _ValidatorType[_K], + value_validator: _ValidatorType[_V], + mapping_validator: Optional[_ValidatorType[_M]] = ..., +) -> _ValidatorType[_M]: ... +def is_callable() -> _ValidatorType[_T]: ... +def lt(val: _T) -> _ValidatorType[_T]: ... +def le(val: _T) -> _ValidatorType[_T]: ... +def ge(val: _T) -> _ValidatorType[_T]: ... +def gt(val: _T) -> _ValidatorType[_T]: ... +def max_len(length: int) -> _ValidatorType[_T]: ... diff --git a/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/AUTHORS.rst b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/AUTHORS.rst new file mode 100644 index 0000000..f14ef6c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/AUTHORS.rst @@ -0,0 +1,11 @@ +Credits +======= + +``attrs`` is written and maintained by `Hynek Schlawack `_. + +The development is kindly supported by `Variomedia AG `_. + +A full list of contributors can be found in `GitHub's overview `_. + +It’s the spiritual successor of `characteristic `_ and aspires to fix some of it clunkiness and unfortunate decisions. +Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay? diff --git a/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/LICENSE new file mode 100644 index 0000000..7ae3df9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Hynek Schlawack + +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. diff --git a/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/METADATA b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/METADATA new file mode 100644 index 0000000..aa327d5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/METADATA @@ -0,0 +1,232 @@ +Metadata-Version: 2.1 +Name: attrs +Version: 21.4.0 +Summary: Classes Without Boilerplate +Home-page: https://www.attrs.org/ +Author: Hynek Schlawack +Author-email: hs@ox.cx +Maintainer: Hynek Schlawack +Maintainer-email: hs@ox.cx +License: MIT +Project-URL: Documentation, https://www.attrs.org/ +Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html +Project-URL: Bug Tracker, https://github.com/python-attrs/attrs/issues +Project-URL: Source Code, https://github.com/python-attrs/attrs +Project-URL: Funding, https://github.com/sponsors/hynek +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi +Project-URL: Ko-fi, https://ko-fi.com/the_hynek +Keywords: class,attribute,boilerplate +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: AUTHORS.rst +Provides-Extra: dev +Requires-Dist: coverage[toml] (>=5.0.2) ; extra == 'dev' +Requires-Dist: hypothesis ; extra == 'dev' +Requires-Dist: pympler ; extra == 'dev' +Requires-Dist: pytest (>=4.3.0) ; extra == 'dev' +Requires-Dist: six ; extra == 'dev' +Requires-Dist: mypy ; extra == 'dev' +Requires-Dist: pytest-mypy-plugins ; extra == 'dev' +Requires-Dist: zope.interface ; extra == 'dev' +Requires-Dist: furo ; extra == 'dev' +Requires-Dist: sphinx ; extra == 'dev' +Requires-Dist: sphinx-notfound-page ; extra == 'dev' +Requires-Dist: pre-commit ; extra == 'dev' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'dev' +Provides-Extra: docs +Requires-Dist: furo ; extra == 'docs' +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: zope.interface ; extra == 'docs' +Requires-Dist: sphinx-notfound-page ; extra == 'docs' +Provides-Extra: tests +Requires-Dist: coverage[toml] (>=5.0.2) ; extra == 'tests' +Requires-Dist: hypothesis ; extra == 'tests' +Requires-Dist: pympler ; extra == 'tests' +Requires-Dist: pytest (>=4.3.0) ; extra == 'tests' +Requires-Dist: six ; extra == 'tests' +Requires-Dist: mypy ; extra == 'tests' +Requires-Dist: pytest-mypy-plugins ; extra == 'tests' +Requires-Dist: zope.interface ; extra == 'tests' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'tests' +Provides-Extra: tests_no_zope +Requires-Dist: coverage[toml] (>=5.0.2) ; extra == 'tests_no_zope' +Requires-Dist: hypothesis ; extra == 'tests_no_zope' +Requires-Dist: pympler ; extra == 'tests_no_zope' +Requires-Dist: pytest (>=4.3.0) ; extra == 'tests_no_zope' +Requires-Dist: six ; extra == 'tests_no_zope' +Requires-Dist: mypy ; extra == 'tests_no_zope' +Requires-Dist: pytest-mypy-plugins ; extra == 'tests_no_zope' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'tests_no_zope' + + +.. image:: https://www.attrs.org/en/stable/_static/attrs_logo.png + :alt: attrs logo + :align: center + + +``attrs`` is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka `dunder methods `_). +`Trusted by NASA `_ for Mars missions since 2020! + +Its main goal is to help you to write **concise** and **correct** software without slowing down your code. + +.. teaser-end + +For that, it gives you a class decorator and a way to declaratively define the attributes on that class: + +.. -code-begin- + +.. code-block:: pycon + + >>> from attrs import asdict, define, make_class, Factory + + >>> @define + ... class SomeClass: + ... a_number: int = 42 + ... list_of_numbers: list[int] = Factory(list) + ... + ... def hard_math(self, another_number): + ... return self.a_number + sum(self.list_of_numbers) * another_number + + + >>> sc = SomeClass(1, [1, 2, 3]) + >>> sc + SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + + >>> sc.hard_math(3) + 19 + >>> sc == SomeClass(1, [1, 2, 3]) + True + >>> sc != SomeClass(2, [3, 2, 1]) + True + + >>> asdict(sc) + {'a_number': 1, 'list_of_numbers': [1, 2, 3]} + + >>> SomeClass() + SomeClass(a_number=42, list_of_numbers=[]) + + >>> C = make_class("C", ["a", "b"]) + >>> C("foo", "bar") + C(a='foo', b='bar') + + +After *declaring* your attributes ``attrs`` gives you: + +- a concise and explicit overview of the class's attributes, +- a nice human-readable ``__repr__``, +- a equality-checking methods, +- an initializer, +- and much more, + +*without* writing dull boilerplate code again and again and *without* runtime performance penalties. + +**Hate type annotations**!? +No problem! +Types are entirely **optional** with ``attrs``. +Simply assign ``attrs.field()`` to the attributes instead of annotating them with types. + +---- + +This example uses ``attrs``'s modern APIs that have been introduced in version 20.1.0, and the ``attrs`` package import name that has been added in version 21.3.0. +The classic APIs (``@attr.s``, ``attr.ib``, plus their serious business aliases) and the ``attr`` package import name will remain **indefinitely**. + +Please check out `On The Core API Names `_ for a more in-depth explanation. + + +Data Classes +============ + +On the tin, ``attrs`` might remind you of ``dataclasses`` (and indeed, ``dataclasses`` are a descendant of ``attrs``). +In practice it does a lot more and is more flexible. +For instance it allows you to define `special handling of NumPy arrays for equality checks `_, or allows more ways to `plug into the initialization process `_. + +For more details, please refer to our `comparison page `_. + + +.. -getting-help- + +Getting Help +============ + +Please use the ``python-attrs`` tag on `Stack Overflow `_ to get help. + +Answering questions of your fellow developers is also a great way to help the project! + + +.. -project-information- + +Project Information +=================== + +``attrs`` is released under the `MIT `_ license, +its documentation lives at `Read the Docs `_, +the code on `GitHub `_, +and the latest release on `PyPI `_. +It’s rigorously tested on Python 2.7, 3.5+, and PyPy. + +We collect information on **third-party extensions** in our `wiki `_. +Feel free to browse and add your own! + +If you'd like to contribute to ``attrs`` you're most welcome and we've written `a little guide `_ to get you started! + + +``attrs`` for Enterprise +------------------------ + +Available as part of the Tidelift Subscription. + +The maintainers of ``attrs`` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +`Learn more. `_ + + +Release Information +=================== + +21.4.0 (2021-12-29) +------------------- + +Changes +^^^^^^^ + +- Fixed the test suite on PyPy3.8 where ``cloudpickle`` does not work. + `#892 `_ +- Fixed ``coverage report`` for projects that use ``attrs`` and don't set a ``--source``. + `#895 `_, + `#896 `_ + +`Full changelog `_. + +Credits +======= + +``attrs`` is written and maintained by `Hynek Schlawack `_. + +The development is kindly supported by `Variomedia AG `_. + +A full list of contributors can be found in `GitHub's overview `_. + +It’s the spiritual successor of `characteristic `_ and aspires to fix some of it clunkiness and unfortunate decisions. +Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay? + + diff --git a/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/RECORD b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/RECORD new file mode 100644 index 0000000..896e259 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/RECORD @@ -0,0 +1,37 @@ +attr/__init__.py,sha256=_zhJ4O8Q5KR5gaIrjX73vkR5nA6NjfpMGXQChEdNljI,1667 +attr/__init__.pyi,sha256=ubRkstoRHPpQN17iA0OCh8waIwZ5NeJgbz0lwI8XUjY,15100 +attr/_cmp.py,sha256=JP0N7OIyTqIR3prUDfMZOR4DV4tlV_xXf39-bQg7xOo,4165 +attr/_cmp.pyi,sha256=oyjJVytrwwkUJOoe332IiYzp6pCVZEKKcKveH-ev604,317 +attr/_compat.py,sha256=i8u27AAK_4SzQnmTf3aliGV27UdYbJxdZ-O0tOHbLU8,8396 +attr/_config.py,sha256=aj1Lh8t2CuVa5nSxgCrLQtg_ZSdO8ZKeNJQd6RvpIp8,892 +attr/_funcs.py,sha256=sm_D12y2IyRW_bCnR7M-O7U5qHaieXr0BzINwJ7_K38,14753 +attr/_make.py,sha256=D05j0_ckcVIRFn2xHch5SPUCwh3t7WpeFj-3Ku9SocQ,102736 +attr/_next_gen.py,sha256=s5jCsVEQ4IhOjAykP4N0ETaWpg0RsgQttMvEZErUrhQ,5752 +attr/_version_info.py,sha256=sxD9yNai0jGbur_-RGEQHbgV2YX5_5G9PhrhBA5pA54,2194 +attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 +attr/converters.py,sha256=uiiWTz8GLJe8I1Ty7UICK1DegVUnqHTXbOSnar7g7Nk,4078 +attr/converters.pyi,sha256=MQo7iEzPNVoFpKqD30sVwgVpdNoIeSCF2nsXvoxLZ-Y,416 +attr/exceptions.py,sha256=BMg7AljkJnvG-irMwL2TBHYlaLBXhSKnzoEWo4e42Zw,1981 +attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 +attr/filters.py,sha256=JGZgvPGkdOfttkoL6XhXS6ZCoaVV5nZ8GCYeZNUN_mE,1124 +attr/filters.pyi,sha256=_Sm80jGySETX_Clzdkon5NHVjQWRl3Y3liQKZX1czXc,215 +attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attr/setters.py,sha256=rH_UtQuHgQEC7hfZyMO_SJW0R1Gus7-a83U8igZfqs8,1466 +attr/setters.pyi,sha256=7dM10rqpQVDW0y-iJUnq8rabdO5Wx2Sbo5LwNa0IXl0,573 +attr/validators.py,sha256=jVE9roaSOmTf0dJNSLHNaQNilkrlzc3pNNBKmv0g7pk,15966 +attr/validators.pyi,sha256=adn6rNbIXmRXlg_FKrTmWj0dOX0vKTsGG82Jd3YcJbQ,2268 +attrs/__init__.py,sha256=CeyxLGVViAEKKsLOLaif8vF3vs1a28vsrRVLv7eMEgM,1109 +attrs/__init__.pyi,sha256=57aCxUJukK9lZlrUgk9RuWiBiPY5DzDKJAJkhbrStYw,1982 +attrs/converters.py,sha256=fCBEdlYWcmI3sCnpUk2pz22GYtXzqTkp6NeOpdI64PY,70 +attrs/exceptions.py,sha256=SlDli6AY77f6ny-H7oy98OkQjsrw-D_supEuErIVYkE,70 +attrs/filters.py,sha256=dc_dNey29kH6KLU1mT2Dakq7tZ3kBfzEGwzOmDzw1F8,67 +attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attrs/setters.py,sha256=oKw51C72Hh45wTwYvDHJP9kbicxiMhMR4Y5GvdpKdHQ,67 +attrs/validators.py,sha256=4ag1SyVD2Hm3PYKiNG_NOtR_e7f81Hr6GiNl4YvXo4Q,70 +attrs-21.4.0.dist-info/AUTHORS.rst,sha256=wsqCNbGz_mklcJrt54APIZHZpoTIJLkXqEhhn4Nd8hc,752 +attrs-21.4.0.dist-info/LICENSE,sha256=v2WaKLSSQGAvVrvfSQy-LsUJsVuY-Z17GaUsdA4yeGM,1082 +attrs-21.4.0.dist-info/METADATA,sha256=WwgR4MfxE55PpGGv21UOEOEtXZGCqwekfXYg-JgA5HY,9810 +attrs-21.4.0.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110 +attrs-21.4.0.dist-info/top_level.txt,sha256=AGbmKnOtYpdkLRsDRQVSBIwfL32pAQ6BSo1mt-BxI7M,11 +attrs-21.4.0.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +attrs-21.4.0.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/WHEEL new file mode 100644 index 0000000..0b18a28 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/top_level.txt new file mode 100644 index 0000000..eca8ba9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs-21.4.0.dist-info/top_level.txt @@ -0,0 +1,2 @@ +attr +attrs diff --git a/myenv/lib/python3.9/site-packages/attrs/__init__.py b/myenv/lib/python3.9/site-packages/attrs/__init__.py new file mode 100644 index 0000000..a704b8b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs/__init__.py @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: MIT + +from attr import ( + NOTHING, + Attribute, + Factory, + __author__, + __copyright__, + __description__, + __doc__, + __email__, + __license__, + __title__, + __url__, + __version__, + __version_info__, + assoc, + cmp_using, + define, + evolve, + field, + fields, + fields_dict, + frozen, + has, + make_class, + mutable, + resolve_types, + validate, +) +from attr._next_gen import asdict, astuple + +from . import converters, exceptions, filters, setters, validators + + +__all__ = [ + "__author__", + "__copyright__", + "__description__", + "__doc__", + "__email__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "asdict", + "assoc", + "astuple", + "Attribute", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "Factory", + "field", + "fields_dict", + "fields", + "filters", + "frozen", + "has", + "make_class", + "mutable", + "NOTHING", + "resolve_types", + "setters", + "validate", + "validators", +] diff --git a/myenv/lib/python3.9/site-packages/attrs/__init__.pyi b/myenv/lib/python3.9/site-packages/attrs/__init__.pyi new file mode 100644 index 0000000..7426fa5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs/__init__.pyi @@ -0,0 +1,63 @@ +from typing import ( + Any, + Callable, + Dict, + Mapping, + Optional, + Sequence, + Tuple, + Type, +) + +# Because we need to type our own stuff, we have to make everything from +# attr explicitly public too. +from attr import __author__ as __author__ +from attr import __copyright__ as __copyright__ +from attr import __description__ as __description__ +from attr import __email__ as __email__ +from attr import __license__ as __license__ +from attr import __title__ as __title__ +from attr import __url__ as __url__ +from attr import __version__ as __version__ +from attr import __version_info__ as __version_info__ +from attr import _FilterType +from attr import assoc as assoc +from attr import Attribute as Attribute +from attr import define as define +from attr import evolve as evolve +from attr import Factory as Factory +from attr import exceptions as exceptions +from attr import field as field +from attr import fields as fields +from attr import fields_dict as fields_dict +from attr import frozen as frozen +from attr import has as has +from attr import make_class as make_class +from attr import mutable as mutable +from attr import NOTHING as NOTHING +from attr import resolve_types as resolve_types +from attr import setters as setters +from attr import validate as validate +from attr import validators as validators + +# TODO: see definition of attr.asdict/astuple +def asdict( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + dict_factory: Type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: bool = ..., +) -> Dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: Any, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + tuple_factory: Type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> Tuple[Any, ...]: ... diff --git a/myenv/lib/python3.9/site-packages/attrs/converters.py b/myenv/lib/python3.9/site-packages/attrs/converters.py new file mode 100644 index 0000000..edfa8d3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs/converters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.converters import * # noqa diff --git a/myenv/lib/python3.9/site-packages/attrs/exceptions.py b/myenv/lib/python3.9/site-packages/attrs/exceptions.py new file mode 100644 index 0000000..bd9efed --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs/exceptions.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.exceptions import * # noqa diff --git a/myenv/lib/python3.9/site-packages/attrs/filters.py b/myenv/lib/python3.9/site-packages/attrs/filters.py new file mode 100644 index 0000000..5295900 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs/filters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.filters import * # noqa diff --git a/myenv/lib/python3.9/site-packages/attrs/py.typed b/myenv/lib/python3.9/site-packages/attrs/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/attrs/setters.py b/myenv/lib/python3.9/site-packages/attrs/setters.py new file mode 100644 index 0000000..9b50770 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs/setters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.setters import * # noqa diff --git a/myenv/lib/python3.9/site-packages/attrs/validators.py b/myenv/lib/python3.9/site-packages/attrs/validators.py new file mode 100644 index 0000000..ab2c9b3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/attrs/validators.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.validators import * # noqa diff --git a/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/LICENSE new file mode 100644 index 0000000..11069ed --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. diff --git a/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/METADATA b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/METADATA new file mode 100644 index 0000000..1322efb --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/METADATA @@ -0,0 +1,272 @@ +Metadata-Version: 2.1 +Name: bcrypt +Version: 3.2.2 +Summary: Modern password hashing for your software and your servers +Home-page: https://github.com/pyca/bcrypt/ +Author: The Python Cryptographic Authority developers +Author-email: cryptography-dev@python.org +License: Apache License, Version 2.0 +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: cffi (>=1.1) +Provides-Extra: tests +Requires-Dist: pytest (!=3.3.0,>=3.2.1) ; extra == 'tests' +Provides-Extra: typecheck +Requires-Dist: mypy ; extra == 'typecheck' + +bcrypt +====== + +.. image:: https://img.shields.io/pypi/v/bcrypt.svg + :target: https://pypi.org/project/bcrypt/ + :alt: Latest Version + +.. image:: https://github.com/pyca/bcrypt/workflows/CI/badge.svg?branch=main + :target: https://github.com/pyca/bcrypt/actions?query=workflow%3ACI+branch%3Amain + +Good password hashing for your software and your servers + + +Installation +============ + +To install bcrypt, simply: + +.. code:: bash + + $ pip install bcrypt + +Note that bcrypt should build very easily on Linux provided you have a C compiler, headers for Python (if you're not using pypy), and headers for the libffi libraries available on your system. + +For Debian and Ubuntu, the following command will ensure that the required dependencies are installed: + +.. code:: bash + + $ sudo apt-get install build-essential libffi-dev python-dev + +For Fedora and RHEL-derivatives, the following command will ensure that the required dependencies are installed: + +.. code:: bash + + $ sudo yum install gcc libffi-devel python-devel + +For Alpine, the following command will ensure that the required dependencies are installed: + +.. code:: bash + + $ apk add --update musl-dev gcc libffi-dev + + +Alternatives +============ + +While bcrypt remains a good choice for password storage depending on your specific use case you may also want to consider using scrypt (either via `standard library`_ or `cryptography`_) or argon2id via `argon2_cffi`_. + +Changelog +========= + +3.2.2 +----- + +* Fixed packaging of ``py.typed`` files in wheels so that ``mypy`` works. + +3.2.1 +----- + +* Added support for compilation on z/OS +* The next release of ``bcrypt`` with be 4.0 and it will require Rust at + compile time, for users building from source. There will be no additional + requirement for users who are installing from wheels. Users on most + platforms will be able to obtain a wheel by making sure they have an up to + date ``pip``. The minimum supported Rust version will be 1.56.0. +* This will be the final release for which we ship ``manylinux2010`` wheels. + Going forward the minimum supported manylinux ABI for our wheels will be + ``manylinux2014``. The vast majority of users will continue to receive + ``manylinux`` wheels provided they have an up to date ``pip``. + + +3.2.0 +----- + +* Added typehints for library functions. +* Dropped support for Python versions less than 3.6 (2.7, 3.4, 3.5). +* Shipped ``abi3`` Windows wheels (requires pip >= 20). + +3.1.7 +----- + +* Set a ``setuptools`` lower bound for PEP517 wheel building. +* We no longer distribute 32-bit ``manylinux1`` wheels. Continuing to produce + them was a maintenance burden. + +3.1.6 +----- + +* Added support for compilation on Haiku. + +3.1.5 +----- + +* Added support for compilation on AIX. +* Dropped Python 2.6 and 3.3 support. +* Switched to using ``abi3`` wheels for Python 3. If you are not getting a + wheel on a compatible platform please upgrade your ``pip`` version. + +3.1.4 +----- + +* Fixed compilation with mingw and on illumos. + +3.1.3 +----- +* Fixed a compilation issue on Solaris. +* Added a warning when using too few rounds with ``kdf``. + +3.1.2 +----- +* Fixed a compile issue affecting big endian platforms. +* Fixed invalid escape sequence warnings on Python 3.6. +* Fixed building in non-UTF8 environments on Python 2. + +3.1.1 +----- +* Resolved a ``UserWarning`` when used with ``cffi`` 1.8.3. + +3.1.0 +----- +* Added support for ``checkpw``, a convenience method for verifying a password. +* Ensure that you get a ``$2y$`` hash when you input a ``$2y$`` salt. +* Fixed a regression where ``$2a`` hashes were vulnerable to a wraparound bug. +* Fixed compilation under Alpine Linux. + +3.0.0 +----- +* Switched the C backend to code obtained from the OpenBSD project rather than + openwall. +* Added support for ``bcrypt_pbkdf`` via the ``kdf`` function. + +2.0.0 +----- +* Added support for an adjustible prefix when calling ``gensalt``. +* Switched to CFFI 1.0+ + +Usage +----- + +Password Hashing +~~~~~~~~~~~~~~~~ + +Hashing and then later checking that a password matches the previous hashed +password is very simple: + +.. code:: pycon + + >>> import bcrypt + >>> password = b"super secret password" + >>> # Hash a password for the first time, with a randomly-generated salt + >>> hashed = bcrypt.hashpw(password, bcrypt.gensalt()) + >>> # Check that an unhashed password matches one that has previously been + >>> # hashed + >>> if bcrypt.checkpw(password, hashed): + ... print("It Matches!") + ... else: + ... print("It Does not Match :(") + +KDF +~~~ + +As of 3.0.0 ``bcrypt`` now offers a ``kdf`` function which does ``bcrypt_pbkdf``. +This KDF is used in OpenSSH's newer encrypted private key format. + +.. code:: pycon + + >>> import bcrypt + >>> key = bcrypt.kdf( + ... password=b'password', + ... salt=b'salt', + ... desired_key_bytes=32, + ... rounds=100) + + +Adjustable Work Factor +~~~~~~~~~~~~~~~~~~~~~~ +One of bcrypt's features is an adjustable logarithmic work factor. To adjust +the work factor merely pass the desired number of rounds to +``bcrypt.gensalt(rounds=12)`` which defaults to 12): + +.. code:: pycon + + >>> import bcrypt + >>> password = b"super secret password" + >>> # Hash a password for the first time, with a certain number of rounds + >>> hashed = bcrypt.hashpw(password, bcrypt.gensalt(14)) + >>> # Check that a unhashed password matches one that has previously been + >>> # hashed + >>> if bcrypt.checkpw(password, hashed): + ... print("It Matches!") + ... else: + ... print("It Does not Match :(") + + +Adjustable Prefix +~~~~~~~~~~~~~~~~~ + +Another one of bcrypt's features is an adjustable prefix to let you define what +libraries you'll remain compatible with. To adjust this, pass either ``2a`` or +``2b`` (the default) to ``bcrypt.gensalt(prefix=b"2b")`` as a bytes object. + +As of 3.0.0 the ``$2y$`` prefix is still supported in ``hashpw`` but deprecated. + +Maximum Password Length +~~~~~~~~~~~~~~~~~~~~~~~ + +The bcrypt algorithm only handles passwords up to 72 characters, any characters +beyond that are ignored. To work around this, a common approach is to hash a +password with a cryptographic hash (such as ``sha256``) and then base64 +encode it to prevent NULL byte problems before hashing the result with +``bcrypt``: + +.. code:: pycon + + >>> password = b"an incredibly long password" * 10 + >>> hashed = bcrypt.hashpw( + ... base64.b64encode(hashlib.sha256(password).digest()), + ... bcrypt.gensalt() + ... ) + +Compatibility +------------- + +This library should be compatible with py-bcrypt and it will run on Python +3.6+, and PyPy 3. + +C Code +------ + +This library uses code from OpenBSD. + +Security +-------- + +``bcrypt`` follows the `same security policy as cryptography`_, if you +identify a vulnerability, we ask you to contact us privately. + +.. _`same security policy as cryptography`: https://cryptography.io/en/latest/security.html +.. _`standard library`: https://docs.python.org/3/library/hashlib.html#hashlib.scrypt +.. _`argon2_cffi`: https://argon2-cffi.readthedocs.io +.. _`cryptography`: https://cryptography.io/en/latest/hazmat/primitives/key-derivation-functions/#cryptography.hazmat.primitives.kdf.scrypt.Scrypt + + diff --git a/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/RECORD b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/RECORD new file mode 100644 index 0000000..eb0ddf5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/RECORD @@ -0,0 +1,11 @@ +bcrypt/__about__.py,sha256=y3-LY1hqQ1KAVagHmhL_-VDEDf4r3LWt4HnGi6OCGmk,1320 +bcrypt/__init__.py,sha256=tr7xBv0w9ajqIHf8537qirLqM_bGOGM_lIQMjFd1PfI,5587 +bcrypt/_bcrypt.abi3.so,sha256=dSpfL4RVrKuQDWuXmWOuWIJrU5kgFnBZl8l1j1_78d8,156671 +bcrypt/_bcrypt.pyi,sha256=TGNrzZD1NWdyeWGGJ2i3tj_HWg_YovqF-WdI7otmiIg,47 +bcrypt/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +bcrypt-3.2.2.dist-info/LICENSE,sha256=gXPVwptPlW1TJ4HSuG5OMPg-a3h43OGMkZRR1rpwfJA,10850 +bcrypt-3.2.2.dist-info/METADATA,sha256=cTPRtd-8x91DRNDRQwvtj4_cic98Cqx4qTgCCS29NGc,8342 +bcrypt-3.2.2.dist-info/WHEEL,sha256=4Pc_qD0VhjiuSiOgv99UcgTmp8ljuSMnWHBjm4-tsjo,114 +bcrypt-3.2.2.dist-info/top_level.txt,sha256=igJttN6fNWPEzk4lnCMzlitVT_1PlLVJzxzogMWGARU,15 +bcrypt-3.2.2.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +bcrypt-3.2.2.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/WHEEL new file mode 100644 index 0000000..b254a18 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: false +Tag: cp36-abi3-macosx_10_10_universal2 + diff --git a/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/top_level.txt new file mode 100644 index 0000000..9fd6492 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt-3.2.2.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_bcrypt +bcrypt diff --git a/myenv/lib/python3.9/site-packages/bcrypt/__about__.py b/myenv/lib/python3.9/site-packages/bcrypt/__about__.py new file mode 100644 index 0000000..8bcee8d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt/__about__.py @@ -0,0 +1,41 @@ +# Author:: Donald Stufft () +# Copyright:: Copyright (c) 2013 Donald Stufft +# License:: Apache License, Version 2.0 +# +# 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. +from __future__ import absolute_import +from __future__ import division +from __future__ import unicode_literals + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", +] + +__title__ = "bcrypt" +__summary__ = "Modern password hashing for your software and your servers" +__uri__ = "https://github.com/pyca/bcrypt/" + +__version__ = "3.2.2" + +__author__ = "The Python Cryptographic Authority developers" +__email__ = "cryptography-dev@python.org" + +__license__ = "Apache License, Version 2.0" +__copyright__ = "Copyright 2013-2022 {0}".format(__author__) diff --git a/myenv/lib/python3.9/site-packages/bcrypt/__init__.py b/myenv/lib/python3.9/site-packages/bcrypt/__init__.py new file mode 100644 index 0000000..a9aae84 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/bcrypt/__init__.py @@ -0,0 +1,171 @@ +# Author:: Donald Stufft () +# Copyright:: Copyright (c) 2013 Donald Stufft +# License:: Apache License, Version 2.0 +# +# 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. +from __future__ import absolute_import +from __future__ import division + +import hmac +import os +import re +import warnings + +from .__about__ import ( + __author__, + __copyright__, + __email__, + __license__, + __summary__, + __title__, + __uri__, + __version__, +) +from . import _bcrypt # noqa: I100 + + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", + "gensalt", + "hashpw", + "kdf", + "checkpw", +] + + +_normalize_re = re.compile(rb"^\$2y\$") + + +def gensalt(rounds: int = 12, prefix: bytes = b"2b") -> bytes: + if prefix not in (b"2a", b"2b"): + raise ValueError("Supported prefixes are b'2a' or b'2b'") + + if rounds < 4 or rounds > 31: + raise ValueError("Invalid rounds") + + salt = os.urandom(16) + output = _bcrypt.ffi.new("char[]", 30) + _bcrypt.lib.encode_base64(output, salt, len(salt)) + + return ( + b"$" + + prefix + + b"$" + + ("%2.2u" % rounds).encode("ascii") + + b"$" + + _bcrypt.ffi.string(output) + ) + + +def hashpw(password: bytes, salt: bytes) -> bytes: + if isinstance(password, str) or isinstance(salt, str): + raise TypeError("Strings must be encoded before hashing") + + if b"\x00" in password: + raise ValueError("password may not contain NUL bytes") + + # bcrypt originally suffered from a wraparound bug: + # http://www.openwall.com/lists/oss-security/2012/01/02/4 + # This bug was corrected in the OpenBSD source by truncating inputs to 72 + # bytes on the updated prefix $2b$, but leaving $2a$ unchanged for + # compatibility. However, pyca/bcrypt 2.0.0 *did* correctly truncate inputs + # on $2a$, so we do it here to preserve compatibility with 2.0.0 + password = password[:72] + + # When the original 8bit bug was found the original library we supported + # added a new prefix, $2y$, that fixes it. This prefix is exactly the same + # as the $2b$ prefix added by OpenBSD other than the name. Since the + # OpenBSD library does not support the $2y$ prefix, if the salt given to us + # is for the $2y$ prefix, we'll just mugne it so that it's a $2b$ prior to + # passing it into the C library. + original_salt, salt = salt, _normalize_re.sub(b"$2b$", salt) + + hashed = _bcrypt.ffi.new("char[]", 128) + retval = _bcrypt.lib.bcrypt_hashpass(password, salt, hashed, len(hashed)) + + if retval != 0: + raise ValueError("Invalid salt") + + # Now that we've gotten our hashed password, we want to ensure that the + # prefix we return is the one that was passed in, so we'll use the prefix + # from the original salt and concatenate that with the return value (minus + # the return value's prefix). This will ensure that if someone passed in a + # salt with a $2y$ prefix, that they get back a hash with a $2y$ prefix + # even though we munged it to $2b$. + return original_salt[:4] + _bcrypt.ffi.string(hashed)[4:] + + +def checkpw(password: bytes, hashed_password: bytes) -> bool: + if isinstance(password, str) or isinstance(hashed_password, str): + raise TypeError("Strings must be encoded before checking") + + if b"\x00" in password or b"\x00" in hashed_password: + raise ValueError( + "password and hashed_password may not contain NUL bytes" + ) + + ret = hashpw(password, hashed_password) + return hmac.compare_digest(ret, hashed_password) + + +def kdf( + password: bytes, + salt: bytes, + desired_key_bytes: int, + rounds: int, + ignore_few_rounds: bool = False, +) -> bytes: + if isinstance(password, str) or isinstance(salt, str): + raise TypeError("Strings must be encoded before hashing") + + if len(password) == 0 or len(salt) == 0: + raise ValueError("password and salt must not be empty") + + if desired_key_bytes <= 0 or desired_key_bytes > 512: + raise ValueError("desired_key_bytes must be 1-512") + + if rounds < 1: + raise ValueError("rounds must be 1 or more") + + if rounds < 50 and not ignore_few_rounds: + # They probably think bcrypt.kdf()'s rounds parameter is logarithmic, + # expecting this value to be slow enough (it probably would be if this + # were bcrypt). Emit a warning. + warnings.warn( + ( + "Warning: bcrypt.kdf() called with only {0} round(s). " + "This few is not secure: the parameter is linear, like PBKDF2." + ).format(rounds), + UserWarning, + stacklevel=2, + ) + + key = _bcrypt.ffi.new("uint8_t[]", desired_key_bytes) + res = _bcrypt.lib.bcrypt_pbkdf( + password, len(password), salt, len(salt), key, len(key), rounds + ) + _bcrypt_assert(res == 0) + + return _bcrypt.ffi.buffer(key, desired_key_bytes)[:] + + +def _bcrypt_assert(ok: bool) -> None: + if not ok: + raise SystemError("bcrypt assertion failed") diff --git a/myenv/lib/python3.9/site-packages/bcrypt/_bcrypt.abi3.so b/myenv/lib/python3.9/site-packages/bcrypt/_bcrypt.abi3.so new file mode 100755 index 0000000000000000000000000000000000000000..5712368a177b228dd415c9a780a3f483137b2579 GIT binary patch literal 156671 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.6.2 +Description-Content-Type: text/markdown +License-File: LICENSE +License-File: AUTHORS.md +Requires-Dist: click (>=7.1.2) +Requires-Dist: platformdirs (>=2) +Requires-Dist: tomli (<2.0.0,>=0.2.6) +Requires-Dist: pathspec (<1,>=0.9.0) +Requires-Dist: typing-extensions (>=3.10.0.0) +Requires-Dist: mypy-extensions (>=0.4.3) +Requires-Dist: dataclasses (>=0.6) ; python_version < "3.7" +Requires-Dist: typed-ast (>=1.4.2) ; python_version < "3.8" and implementation_name == "cpython" +Requires-Dist: typing-extensions (!=3.10.0.1) ; python_version >= "3.10" +Provides-Extra: colorama +Requires-Dist: colorama (>=0.4.3) ; extra == 'colorama' +Provides-Extra: d +Requires-Dist: aiohttp (>=3.7.4) ; extra == 'd' +Provides-Extra: jupyter +Requires-Dist: ipython (>=7.8.0) ; extra == 'jupyter' +Requires-Dist: tokenize-rt (>=3.2.0) ; extra == 'jupyter' +Provides-Extra: python2 +Requires-Dist: typed-ast (>=1.4.3) ; extra == 'python2' +Provides-Extra: uvloop +Requires-Dist: uvloop (>=0.15.2) ; extra == 'uvloop' + +![Black Logo](https://raw.githubusercontent.com/psf/black/main/docs/_static/logo2-readme.png) + +

The Uncompromising Code Formatter

+ +

+Actions Status +Actions Status +Documentation Status +Coverage Status +License: MIT +PyPI +Downloads +conda-forge +Code style: black +

+ +> “Any color you like.” + +_Black_ is the uncompromising Python code formatter. By using it, you agree to cede +control over minutiae of hand-formatting. In return, _Black_ gives you speed, +determinism, and freedom from `pycodestyle` nagging about formatting. You will save time +and mental energy for more important matters. + +Blackened code looks the same regardless of the project you're reading. Formatting +becomes transparent after a while and you can focus on the content instead. + +_Black_ makes code review faster by producing the smallest diffs possible. + +Try it out now using the [Black Playground](https://black.vercel.app). Watch the +[PyCon 2019 talk](https://youtu.be/esZLCuWs_2Y) to learn more. + +--- + +**[Read the documentation on ReadTheDocs!](https://black.readthedocs.io/en/stable)** + +--- + +## Installation and usage + +### Installation + +_Black_ can be installed by running `pip install black`. It requires Python 3.6.2+ to +run. If you want to format Python 2 code as well, install with +`pip install black[python2]`. If you want to format Jupyter Notebooks, install with +`pip install black[jupyter]`. + +If you can't wait for the latest _hotness_ and want to install from GitHub, use: + +`pip install git+git://github.com/psf/black` + +### Usage + +To get started right away with sensible defaults: + +```sh +black {source_file_or_directory} +``` + +You can run _Black_ as a package if running it as a script doesn't work: + +```sh +python -m black {source_file_or_directory} +``` + +Further information can be found in our docs: + +- [Usage and Configuration](https://black.readthedocs.io/en/stable/usage_and_configuration/index.html) + +### NOTE: This is a beta product + +_Black_ is already [successfully used](https://github.com/psf/black#used-by) by many +projects, small and big. Black has a comprehensive test suite, with efficient parallel +tests, and our own auto formatting and parallel Continuous Integration runner. However, +_Black_ is still beta. Things will probably be wonky for a while. This is made explicit +by the "Beta" trove classifier, as well as by the "b" in the version number. What this +means for you is that **until the formatter becomes stable, you should expect some +formatting to change in the future**. That being said, no drastic stylistic changes are +planned, mostly responses to bug reports. + +Also, as a safety measure which slows down processing, _Black_ will check that the +reformatted code still produces a valid AST that is effectively equivalent to the +original (see the +[Pragmatism](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#ast-before-and-after-formatting) +section for details). If you're feeling confident, use `--fast`. + +## The _Black_ code style + +_Black_ is a PEP 8 compliant opinionated formatter. _Black_ reformats entire files in +place. Style configuration options are deliberately limited and rarely added. It doesn't +take previous formatting into account (see [Pragmatism](#pragmatism) for exceptions). + +Our documentation covers the current _Black_ code style, but planned changes to it are +also documented. They're both worth taking a look: + +- [The _Black_ Code Style: Current style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html) +- [The _Black_ Code Style: Future style](https://black.readthedocs.io/en/stable/the_black_code_style/future_style.html) + +Please refer to this document before submitting an issue. What seems like a bug might be +intended behaviour. + +### Pragmatism + +Early versions of _Black_ used to be absolutist in some respects. They took after its +initial author. This was fine at the time as it made the implementation simpler and +there were not many users anyway. Not many edge cases were reported. As a mature tool, +_Black_ does make some exceptions to rules it otherwise holds. + +- [The _Black_ code style: Pragmatism](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#pragmatism) + +Please refer to this document before submitting an issue just like with the document +above. What seems like a bug might be intended behaviour. + +## Configuration + +_Black_ is able to read project-specific default values for its command line options +from a `pyproject.toml` file. This is especially useful for specifying custom +`--include` and `--exclude`/`--force-exclude`/`--extend-exclude` patterns for your +project. + +You can find more details in our documentation: + +- [The basics: Configuration via a file](https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file) + +And if you're looking for more general configuration documentation: + +- [Usage and Configuration](https://black.readthedocs.io/en/stable/usage_and_configuration/index.html) + +**Pro-tip**: If you're asking yourself "Do I need to configure anything?" the answer is +"No". _Black_ is all about sensible defaults. Applying those defaults will have your +code in compliance with many other _Black_ formatted projects. + +## Used by + +The following notable open-source projects trust _Black_ with enforcing a consistent +code style: pytest, tox, Pyramid, Django Channels, Hypothesis, attrs, SQLAlchemy, +Poetry, PyPA applications (Warehouse, Bandersnatch, Pipenv, virtualenv), pandas, Pillow, +Twisted, LocalStack, every Datadog Agent Integration, Home Assistant, Zulip, Kedro, and +many more. + +The following organizations use _Black_: Facebook, Dropbox, KeepTruckin, Mozilla, Quora, +Duolingo, QuantumBlack, Tesla. + +Are we missing anyone? Let us know. + +## Testimonials + +**Mike Bayer**, [author of `SQLAlchemy`](https://www.sqlalchemy.org/): + +> I can't think of any single tool in my entire programming career that has given me a +> bigger productivity increase by its introduction. I can now do refactorings in about +> 1% of the keystrokes that it would have taken me previously when we had no way for +> code to format itself. + +**Dusty Phillips**, +[writer](https://smile.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=dusty+phillips): + +> _Black_ is opinionated so you don't have to be. + +**Hynek Schlawack**, [creator of `attrs`](https://www.attrs.org/), core developer of +Twisted and CPython: + +> An auto-formatter that doesn't suck is all I want for Xmas! + +**Carl Meyer**, [Django](https://www.djangoproject.com/) core developer: + +> At least the name is good. + +**Kenneth Reitz**, creator of [`requests`](http://python-requests.org/) and +[`pipenv`](https://readthedocs.org/projects/pipenv/): + +> This vastly improves the formatting of our code. Thanks a ton! + +## Show your style + +Use the badge in your project's README.md: + +```md +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +``` + +Using the badge in README.rst: + +``` +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black +``` + +Looks like this: +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) + +## License + +MIT + +## Contributing + +Welcome! Happy to see you willing to make the project better. You can get started by +reading this: + +- [Contributing: The basics](https://black.readthedocs.io/en/latest/contributing/the_basics.html) + +You can also take a look at the rest of the contributing docs or talk with the +developers: + +- [Contributing documentation](https://black.readthedocs.io/en/latest/contributing/index.html) +- [Chat on Discord](https://discord.gg/RtVdv86PrH) + +## Change log + +The log has become rather long. It moved to its own file. + +See [CHANGES](https://black.readthedocs.io/en/latest/change_log.html). + +## Authors + +The author list is quite long nowadays, so it lives in its own file. + +See [AUTHORS.md](./AUTHORS.md) + +## Code of Conduct + +Everyone participating in the _Black_ project, and in particular in the issue tracker, +pull requests, and social media activity, is expected to treat other people with respect +and more generally to follow the guidelines articulated in the +[Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/). + +At the same time, humor is encouraged. In fact, basic familiarity with Monty Python's +Flying Circus is expected. We are not savages. + +And if you _really_ need to slap somebody, do it with a fish while dancing. + + +# Change Log + +## 21.12b0 + +### _Black_ + +- Fix determination of f-string expression spans (#2654) +- Fix bad formatting of error messages about EOF in multi-line statements (#2343) +- Functions and classes in blocks now have more consistent surrounding spacing (#2472) + +#### Jupyter Notebook support + +- Cell magics are now only processed if they are known Python cell magics. Earlier, all + cell magics were tokenized, leading to possible indentation errors e.g. with + `%%writefile`. (#2630) +- Fix assignment to environment variables in Jupyter Notebooks (#2642) + +#### Python 3.10 support + +- Point users to using `--target-version py310` if we detect 3.10-only syntax (#2668) +- Fix `match` statements with open sequence subjects, like `match a, b:` or + `match a, *b:` (#2639) (#2659) +- Fix `match`/`case` statements that contain `match`/`case` soft keywords multiple + times, like `match re.match()` (#2661) +- Fix `case` statements with an inline body (#2665) +- Fix styling of starred expressions inside `match` subject (#2667) +- Fix parser error location on invalid syntax in a `match` statement (#2649) +- Fix Python 3.10 support on platforms without ProcessPoolExecutor (#2631) +- Improve parsing performance on code that uses `match` under `--target-version py310` + up to ~50% (#2670) + +### Packaging + +- Remove dependency on `regex` (#2644) (#2663) + +## 21.11b1 + +### _Black_ + +- Bumped regex version minimum to 2021.4.4 to fix Pattern class usage (#2621) + +## 21.11b0 + +### _Black_ + +- Warn about Python 2 deprecation in more cases by improving Python 2 only syntax + detection (#2592) +- Add experimental PyPy support (#2559) +- Add partial support for the match statement. As it's experimental, it's only enabled + when `--target-version py310` is explicitly specified (#2586) +- Add support for parenthesized with (#2586) +- Declare support for Python 3.10 for running Black (#2562) + +### Integrations + +- Fixed vim plugin with Python 3.10 by removing deprecated distutils import (#2610) +- The vim plugin now parses `skip_magic_trailing_comma` from pyproject.toml (#2613) + +## 21.10b0 + +### _Black_ + +- Document stability policy, that will apply for non-beta releases (#2529) +- Add new `--workers` parameter (#2514) +- Fixed feature detection for positional-only arguments in lambdas (#2532) +- Bumped typed-ast version minimum to 1.4.3 for 3.10 compatibility (#2519) +- Fixed a Python 3.10 compatibility issue where the loop argument was still being passed + even though it has been removed (#2580) +- Deprecate Python 2 formatting support (#2523) + +### _Blackd_ + +- Remove dependency on aiohttp-cors (#2500) +- Bump required aiohttp version to 3.7.4 (#2509) + +### _Black-Primer_ + +- Add primer support for --projects (#2555) +- Print primer summary after individual failures (#2570) + +### Integrations + +- Allow to pass `target_version` in the vim plugin (#1319) +- Install build tools in docker file and use multi-stage build to keep the image size + down (#2582) + +## 21.9b0 + +### Packaging + +- Fix missing modules in self-contained binaries (#2466) +- Fix missing toml extra used during installation (#2475) + +## 21.8b0 + +### _Black_ + +- Add support for formatting Jupyter Notebook files (#2357) +- Move from `appdirs` dependency to `platformdirs` (#2375) +- Present a more user-friendly error if .gitignore is invalid (#2414) +- The failsafe for accidentally added backslashes in f-string expressions has been + hardened to handle more edge cases during quote normalization (#2437) +- Avoid changing a function return type annotation's type to a tuple by adding a + trailing comma (#2384) +- Parsing support has been added for unparenthesized walruses in set literals, set + comprehensions, and indices (#2447). +- Pin `setuptools-scm` build-time dependency version (#2457) +- Exclude typing-extensions version 3.10.0.1 due to it being broken on Python 3.10 + (#2460) + +### _Blackd_ + +- Replace sys.exit(-1) with raise ImportError as it plays more nicely with tools that + scan installed packages (#2440) + +### Integrations + +- The provided pre-commit hooks no longer specify `language_version` to avoid overriding + `default_language_version` (#2430) + +## 21.7b0 + +### _Black_ + +- Configuration files using TOML features higher than spec v0.5.0 are now supported + (#2301) +- Add primer support and test for code piped into black via STDIN (#2315) +- Fix internal error when `FORCE_OPTIONAL_PARENTHESES` feature is enabled (#2332) +- Accept empty stdin (#2346) +- Provide a more useful error when parsing fails during AST safety checks (#2304) + +### Docker + +- Add new `latest_release` tag automation to follow latest black release on docker + images (#2374) + +### Integrations + +- The vim plugin now searches upwards from the directory containing the current buffer + instead of the current working directory for pyproject.toml. (#1871) +- The vim plugin now reads the correct string normalization option in pyproject.toml + (#1869) +- The vim plugin no longer crashes Black when there's boolean values in pyproject.toml + (#1869) + +## 21.6b0 + +### _Black_ + +- Fix failure caused by `fmt: skip` and indentation (#2281) +- Account for += assignment when deciding whether to split string (#2312) +- Correct max string length calculation when there are string operators (#2292) +- Fixed option usage when using the `--code` flag (#2259) +- Do not call `uvloop.install()` when _Black_ is used as a library (#2303) +- Added `--required-version` option to require a specific version to be running (#2300) +- Fix incorrect custom breakpoint indices when string group contains fake f-strings + (#2311) +- Fix regression where `R` prefixes would be lowercased for docstrings (#2285) +- Fix handling of named escapes (`\N{...}`) when `--experimental-string-processing` is + used (#2319) + +### Integrations + +- The official Black action now supports choosing what version to use, and supports the + major 3 OSes. (#1940) + +## 21.5b2 + +### _Black_ + +- A space is no longer inserted into empty docstrings (#2249) +- Fix handling of .gitignore files containing non-ASCII characters on Windows (#2229) +- Respect `.gitignore` files in all levels, not only `root/.gitignore` file (apply + `.gitignore` rules like `git` does) (#2225) +- Restored compatibility with Click 8.0 on Python 3.6 when LANG=C used (#2227) +- Add extra uvloop install + import support if in python env (#2258) +- Fix --experimental-string-processing crash when matching parens are not found (#2283) +- Make sure to split lines that start with a string operator (#2286) +- Fix regular expression that black uses to identify f-expressions (#2287) + +### _Blackd_ + +- Add a lower bound for the `aiohttp-cors` dependency. Only 0.4.0 or higher is + supported. (#2231) + +### Packaging + +- Release self-contained x86_64 MacOS binaries as part of the GitHub release pipeline + (#2198) +- Always build binaries with the latest available Python (#2260) + +### Documentation + +- Add discussion of magic comments to FAQ page (#2272) +- `--experimental-string-processing` will be enabled by default in the future (#2273) +- Fix typos discovered by codespell (#2228) +- Fix Vim plugin installation instructions. (#2235) +- Add new Frequently Asked Questions page (#2247) +- Fix encoding + symlink issues preventing proper build on Windows (#2262) + +## 21.5b1 + +### _Black_ + +- Refactor `src/black/__init__.py` into many files (#2206) + +### Documentation + +- Replaced all remaining references to the + [`master`](https://github.com/psf/black/tree/main) branch with the + [`main`](https://github.com/psf/black/tree/main) branch. Some additional changes in + the source code were also made. (#2210) +- Sigificantly reorganized the documentation to make much more sense. Check them out by + heading over to [the stable docs on RTD](https://black.readthedocs.io/en/stable/). + (#2174) + +## 21.5b0 + +### _Black_ + +- Set `--pyi` mode if `--stdin-filename` ends in `.pyi` (#2169) +- Stop detecting target version as Python 3.9+ with pre-PEP-614 decorators that are + being called but with no arguments (#2182) + +### _Black-Primer_ + +- Add `--no-diff` to black-primer to suppress formatting changes (#2187) + +## 21.4b2 + +### _Black_ + +- Fix crash if the user configuration directory is inaccessible. (#2158) + +- Clarify + [circumstances](https://github.com/psf/black/blob/master/docs/the_black_code_style.md#pragmatism) + in which _Black_ may change the AST (#2159) + +- Allow `.gitignore` rules to be overridden by specifying `exclude` in `pyproject.toml` + or on the command line. (#2170) + +### _Packaging_ + +- Install `primer.json` (used by `black-primer` by default) with black. (#2154) + +## 21.4b1 + +### _Black_ + +- Fix crash on docstrings ending with "\\ ". (#2142) + +- Fix crash when atypical whitespace is cleaned out of dostrings (#2120) + +- Reflect the `--skip-magic-trailing-comma` and `--experimental-string-processing` flags + in the name of the cache file. Without this fix, changes in these flags would not take + effect if the cache had already been populated. (#2131) + +- Don't remove necessary parentheses from assignment expression containing assert / + return statements. (#2143) + +### _Packaging_ + +- Bump pathspec to >= 0.8.1 to solve invalid .gitignore exclusion handling + +## 21.4b0 + +### _Black_ + +- Fixed a rare but annoying formatting instability created by the combination of + optional trailing commas inserted by `Black` and optional parentheses looking at + pre-existing "magic" trailing commas. This fixes issue #1629 and all of its many many + duplicates. (#2126) + +- `Black` now processes one-line docstrings by stripping leading and trailing spaces, + and adding a padding space when needed to break up """". (#1740) + +- `Black` now cleans up leading non-breaking spaces in comments (#2092) + +- `Black` now respects `--skip-string-normalization` when normalizing multiline + docstring quotes (#1637) + +- `Black` no longer removes all empty lines between non-function code and decorators + when formatting typing stubs. Now `Black` enforces a single empty line. (#1646) + +- `Black` no longer adds an incorrect space after a parenthesized assignment expression + in if/while statements (#1655) + +- Added `--skip-magic-trailing-comma` / `-C` to avoid using trailing commas as a reason + to split lines (#1824) + +- fixed a crash when PWD=/ on POSIX (#1631) + +- fixed "I/O operation on closed file" when using --diff (#1664) + +- Prevent coloured diff output being interleaved with multiple files (#1673) + +- Added support for PEP 614 relaxed decorator syntax on python 3.9 (#1711) + +- Added parsing support for unparenthesized tuples and yield expressions in annotated + assignments (#1835) + +- added `--extend-exclude` argument (PR #2005) + +- speed up caching by avoiding pathlib (#1950) + +- `--diff` correctly indicates when a file doesn't end in a newline (#1662) + +- Added `--stdin-filename` argument to allow stdin to respect `--force-exclude` rules + (#1780) + +- Lines ending with `fmt: skip` will now be not formatted (#1800) + +- PR #2053: Black no longer relies on typed-ast for Python 3.8 and higher + +- PR #2053: Python 2 support is now optional, install with + `python3 -m pip install black[python2]` to maintain support. + +- Exclude `venv` directory by default (#1683) + +- Fixed "Black produced code that is not equivalent to the source" when formatting + Python 2 docstrings (#2037) + +### _Packaging_ + +- Self-contained native _Black_ binaries are now provided for releases via GitHub + Releases (#1743) + +## 20.8b1 + +### _Packaging_ + +- explicitly depend on Click 7.1.2 or newer as `Black` no longer works with versions + older than 7.0 + +## 20.8b0 + +### _Black_ + +- re-implemented support for explicit trailing commas: now it works consistently within + any bracket pair, including nested structures (#1288 and duplicates) + +- `Black` now reindents docstrings when reindenting code around it (#1053) + +- `Black` now shows colored diffs (#1266) + +- `Black` is now packaged using 'py3' tagged wheels (#1388) + +- `Black` now supports Python 3.8 code, e.g. star expressions in return statements + (#1121) + +- `Black` no longer normalizes capital R-string prefixes as those have a + community-accepted meaning (#1244) + +- `Black` now uses exit code 2 when specified configuration file doesn't exit (#1361) + +- `Black` now works on AWS Lambda (#1141) + +- added `--force-exclude` argument (#1032) + +- removed deprecated `--py36` option (#1236) + +- fixed `--diff` output when EOF is encountered (#526) + +- fixed `# fmt: off` handling around decorators (#560) + +- fixed unstable formatting with some `# type: ignore` comments (#1113) + +- fixed invalid removal on organizing brackets followed by indexing (#1575) + +- introduced `black-primer`, a CI tool that allows us to run regression tests against + existing open source users of Black (#1402) + +- introduced property-based fuzzing to our test suite based on Hypothesis and + Hypothersmith (#1566) + +- implemented experimental and disabled by default long string rewrapping (#1132), + hidden under a `--experimental-string-processing` flag while it's being worked on; + this is an undocumented and unsupported feature, you lose Internet points for + depending on it (#1609) + +### Vim plugin + +- prefer virtualenv packages over global packages (#1383) + +## 19.10b0 + +- added support for PEP 572 assignment expressions (#711) + +- added support for PEP 570 positional-only arguments (#943) + +- added support for async generators (#593) + +- added support for pre-splitting collections by putting an explicit trailing comma + inside (#826) + +- added `black -c` as a way to format code passed from the command line (#761) + +- --safe now works with Python 2 code (#840) + +- fixed grammar selection for Python 2-specific code (#765) + +- fixed feature detection for trailing commas in function definitions and call sites + (#763) + +- `# fmt: off`/`# fmt: on` comment pairs placed multiple times within the same block of + code now behave correctly (#1005) + +- _Black_ no longer crashes on Windows machines with more than 61 cores (#838) + +- _Black_ no longer crashes on standalone comments prepended with a backslash (#767) + +- _Black_ no longer crashes on `from` ... `import` blocks with comments (#829) + +- _Black_ no longer crashes on Python 3.7 on some platform configurations (#494) + +- _Black_ no longer fails on comments in from-imports (#671) + +- _Black_ no longer fails when the file starts with a backslash (#922) + +- _Black_ no longer merges regular comments with type comments (#1027) + +- _Black_ no longer splits long lines that contain type comments (#997) + +- removed unnecessary parentheses around `yield` expressions (#834) + +- added parentheses around long tuples in unpacking assignments (#832) + +- added parentheses around complex powers when they are prefixed by a unary operator + (#646) + +- fixed bug that led _Black_ format some code with a line length target of 1 (#762) + +- _Black_ no longer introduces quotes in f-string subexpressions on string boundaries + (#863) + +- if _Black_ puts parenthesis around a single expression, it moves comments to the + wrapped expression instead of after the brackets (#872) + +- `blackd` now returns the version of _Black_ in the response headers (#1013) + +- `blackd` can now output the diff of formats on source code when the `X-Diff` header is + provided (#969) + +## 19.3b0 + +- new option `--target-version` to control which Python versions _Black_-formatted code + should target (#618) + +- deprecated `--py36` (use `--target-version=py36` instead) (#724) + +- _Black_ no longer normalizes numeric literals to include `_` separators (#696) + +- long `del` statements are now split into multiple lines (#698) + +- type comments are no longer mangled in function signatures + +- improved performance of formatting deeply nested data structures (#509) + +- _Black_ now properly formats multiple files in parallel on Windows (#632) + +- _Black_ now creates cache files atomically which allows it to be used in parallel + pipelines (like `xargs -P8`) (#673) + +- _Black_ now correctly indents comments in files that were previously formatted with + tabs (#262) + +- `blackd` now supports CORS (#622) + +## 18.9b0 + +- numeric literals are now formatted by _Black_ (#452, #461, #464, #469): + + - numeric literals are normalized to include `_` separators on Python 3.6+ code + + - added `--skip-numeric-underscore-normalization` to disable the above behavior and + leave numeric underscores as they were in the input + + - code with `_` in numeric literals is recognized as Python 3.6+ + + - most letters in numeric literals are lowercased (e.g., in `1e10`, `0x01`) + + - hexadecimal digits are always uppercased (e.g. `0xBADC0DE`) + +- added `blackd`, see + [its documentation](https://github.com/psf/black/blob/18.9b0/README.md#blackd) for + more info (#349) + +- adjacent string literals are now correctly split into multiple lines (#463) + +- trailing comma is now added to single imports that don't fit on a line (#250) + +- cache is now populated when `--check` is successful for a file which speeds up + consecutive checks of properly formatted unmodified files (#448) + +- whitespace at the beginning of the file is now removed (#399) + +- fixed mangling [pweave](http://mpastell.com/pweave/) and + [Spyder IDE](https://www.spyder-ide.org/) special comments (#532) + +- fixed unstable formatting when unpacking big tuples (#267) + +- fixed parsing of `__future__` imports with renames (#389) + +- fixed scope of `# fmt: off` when directly preceding `yield` and other nodes (#385) + +- fixed formatting of lambda expressions with default arguments (#468) + +- fixed `async for` statements: _Black_ no longer breaks them into separate lines (#372) + +- note: the Vim plugin stopped registering `,=` as a default chord as it turned out to + be a bad idea (#415) + +## 18.6b4 + +- hotfix: don't freeze when multiple comments directly precede `# fmt: off` (#371) + +## 18.6b3 + +- typing stub files (`.pyi`) now have blank lines added after constants (#340) + +- `# fmt: off` and `# fmt: on` are now much more dependable: + + - they now work also within bracket pairs (#329) + + - they now correctly work across function/class boundaries (#335) + + - they now work when an indentation block starts with empty lines or misaligned + comments (#334) + +- made Click not fail on invalid environments; note that Click is right but the + likelihood we'll need to access non-ASCII file paths when dealing with Python source + code is low (#277) + +- fixed improper formatting of f-strings with quotes inside interpolated expressions + (#322) + +- fixed unnecessary slowdown when long list literals where found in a file + +- fixed unnecessary slowdown on AST nodes with very many siblings + +- fixed cannibalizing backslashes during string normalization + +- fixed a crash due to symbolic links pointing outside of the project directory (#338) + +## 18.6b2 + +- added `--config` (#65) + +- added `-h` equivalent to `--help` (#316) + +- fixed improper unmodified file caching when `-S` was used + +- fixed extra space in string unpacking (#305) + +- fixed formatting of empty triple quoted strings (#313) + +- fixed unnecessary slowdown in comment placement calculation on lines without comments + +## 18.6b1 + +- hotfix: don't output human-facing information on stdout (#299) + +- hotfix: don't output cake emoji on non-zero return code (#300) + +## 18.6b0 + +- added `--include` and `--exclude` (#270) + +- added `--skip-string-normalization` (#118) + +- added `--verbose` (#283) + +- the header output in `--diff` now actually conforms to the unified diff spec + +- fixed long trivial assignments being wrapped in unnecessary parentheses (#273) + +- fixed unnecessary parentheses when a line contained multiline strings (#232) + +- fixed stdin handling not working correctly if an old version of Click was used (#276) + +- _Black_ now preserves line endings when formatting a file in place (#258) + +## 18.5b1 + +- added `--pyi` (#249) + +- added `--py36` (#249) + +- Python grammar pickle caches are stored with the formatting caches, making _Black_ + work in environments where site-packages is not user-writable (#192) + +- _Black_ now enforces a PEP 257 empty line after a class-level docstring (and/or + fields) and the first method + +- fixed invalid code produced when standalone comments were present in a trailer that + was omitted from line splitting on a large expression (#237) + +- fixed optional parentheses being removed within `# fmt: off` sections (#224) + +- fixed invalid code produced when stars in very long imports were incorrectly wrapped + in optional parentheses (#234) + +- fixed unstable formatting when inline comments were moved around in a trailer that was + omitted from line splitting on a large expression (#238) + +- fixed extra empty line between a class declaration and the first method if no class + docstring or fields are present (#219) + +- fixed extra empty line between a function signature and an inner function or inner + class (#196) + +## 18.5b0 + +- call chains are now formatted according to the + [fluent interfaces](https://en.wikipedia.org/wiki/Fluent_interface) style (#67) + +- data structure literals (tuples, lists, dictionaries, and sets) are now also always + exploded like imports when they don't fit in a single line (#152) + +- slices are now formatted according to PEP 8 (#178) + +- parentheses are now also managed automatically on the right-hand side of assignments + and return statements (#140) + +- math operators now use their respective priorities for delimiting multiline + expressions (#148) + +- optional parentheses are now omitted on expressions that start or end with a bracket + and only contain a single operator (#177) + +- empty parentheses in a class definition are now removed (#145, #180) + +- string prefixes are now standardized to lowercase and `u` is removed on Python 3.6+ + only code and Python 2.7+ code with the `unicode_literals` future import (#188, #198, + #199) + +- typing stub files (`.pyi`) are now formatted in a style that is consistent with PEP + 484 (#207, #210) + +- progress when reformatting many files is now reported incrementally + +- fixed trailers (content with brackets) being unnecessarily exploded into their own + lines after a dedented closing bracket (#119) + +- fixed an invalid trailing comma sometimes left in imports (#185) + +- fixed non-deterministic formatting when multiple pairs of removable parentheses were + used (#183) + +- fixed multiline strings being unnecessarily wrapped in optional parentheses in long + assignments (#215) + +- fixed not splitting long from-imports with only a single name + +- fixed Python 3.6+ file discovery by also looking at function calls with unpacking. + This fixed non-deterministic formatting if trailing commas where used both in function + signatures with stars and function calls with stars but the former would be + reformatted to a single line. + +- fixed crash on dealing with optional parentheses (#193) + +- fixed "is", "is not", "in", and "not in" not considered operators for splitting + purposes + +- fixed crash when dead symlinks where encountered + +## 18.4a4 + +- don't populate the cache on `--check` (#175) + +## 18.4a3 + +- added a "cache"; files already reformatted that haven't changed on disk won't be + reformatted again (#109) + +- `--check` and `--diff` are no longer mutually exclusive (#149) + +- generalized star expression handling, including double stars; this fixes + multiplication making expressions "unsafe" for trailing commas (#132) + +- _Black_ no longer enforces putting empty lines behind control flow statements (#90) + +- _Black_ now splits imports like "Mode 3 + trailing comma" of isort (#127) + +- fixed comment indentation when a standalone comment closes a block (#16, #32) + +- fixed standalone comments receiving extra empty lines if immediately preceding a + class, def, or decorator (#56, #154) + +- fixed `--diff` not showing entire path (#130) + +- fixed parsing of complex expressions after star and double stars in function calls + (#2) + +- fixed invalid splitting on comma in lambda arguments (#133) + +- fixed missing splits of ternary expressions (#141) + +## 18.4a2 + +- fixed parsing of unaligned standalone comments (#99, #112) + +- fixed placement of dictionary unpacking inside dictionary literals (#111) + +- Vim plugin now works on Windows, too + +- fixed unstable formatting when encountering unnecessarily escaped quotes in a string + (#120) + +## 18.4a1 + +- added `--quiet` (#78) + +- added automatic parentheses management (#4) + +- added [pre-commit](https://pre-commit.com) integration (#103, #104) + +- fixed reporting on `--check` with multiple files (#101, #102) + +- fixed removing backslash escapes from raw strings (#100, #105) + +## 18.4a0 + +- added `--diff` (#87) + +- add line breaks before all delimiters, except in cases like commas, to better comply + with PEP 8 (#73) + +- standardize string literals to use double quotes (almost) everywhere (#75) + +- fixed handling of standalone comments within nested bracketed expressions; _Black_ + will no longer produce super long lines or put all standalone comments at the end of + the expression (#22) + +- fixed 18.3a4 regression: don't crash and burn on empty lines with trailing whitespace + (#80) + +- fixed 18.3a4 regression: `# yapf: disable` usage as trailing comment would cause + _Black_ to not emit the rest of the file (#95) + +- when CTRL+C is pressed while formatting many files, _Black_ no longer freaks out with + a flurry of asyncio-related exceptions + +- only allow up to two empty lines on module level and only single empty lines within + functions (#74) + +## 18.3a4 + +- `# fmt: off` and `# fmt: on` are implemented (#5) + +- automatic detection of deprecated Python 2 forms of print statements and exec + statements in the formatted file (#49) + +- use proper spaces for complex expressions in default values of typed function + arguments (#60) + +- only return exit code 1 when --check is used (#50) + +- don't remove single trailing commas from square bracket indexing (#59) + +- don't omit whitespace if the previous factor leaf wasn't a math operator (#55) + +- omit extra space in kwarg unpacking if it's the first argument (#46) + +- omit extra space in + [Sphinx auto-attribute comments](http://www.sphinx-doc.org/en/stable/ext/autodoc.html#directive-autoattribute) + (#68) + +## 18.3a3 + +- don't remove single empty lines outside of bracketed expressions (#19) + +- added ability to pipe formatting from stdin to stdin (#25) + +- restored ability to format code with legacy usage of `async` as a name (#20, #42) + +- even better handling of numpy-style array indexing (#33, again) + +## 18.3a2 + +- changed positioning of binary operators to occur at beginning of lines instead of at + the end, following + [a recent change to PEP 8](https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b) + (#21) + +- ignore empty bracket pairs while splitting. This avoids very weirdly looking + formattings (#34, #35) + +- remove a trailing comma if there is a single argument to a call + +- if top level functions were separated by a comment, don't put four empty lines after + the upper function + +- fixed unstable formatting of newlines with imports + +- fixed unintentional folding of post scriptum standalone comments into last statement + if it was a simple statement (#18, #28) + +- fixed missing space in numpy-style array indexing (#33) + +- fixed spurious space after star-based unary expressions (#31) + +## 18.3a1 + +- added `--check` + +- only put trailing commas in function signatures and calls if it's safe to do so. If + the file is Python 3.6+ it's always safe, otherwise only safe if there are no `*args` + or `**kwargs` used in the signature or call. (#8) + +- fixed invalid spacing of dots in relative imports (#6, #13) + +- fixed invalid splitting after comma on unpacked variables in for-loops (#23) + +- fixed spurious space in parenthesized set expressions (#7) + +- fixed spurious space after opening parentheses and in default arguments (#14, #17) + +- fixed spurious space after unary operators when the operand was a complex expression + (#15) + +## 18.3a0 + +- first published version, Happy 🍰 Day 2018! + +- alpha quality + +- date-versioned (see: ) + + diff --git a/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/RECORD b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/RECORD new file mode 100644 index 0000000..53b0b4f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/RECORD @@ -0,0 +1,54 @@ +../../../bin/black,sha256=OxSf28OqvHfdamdUy6uj720fnq5YrNowAKX6rxRn1zo,261 +../../../bin/black-primer,sha256=83JdAPbcZRtxyDvx62xZ8PXPONS3ARcT1QGohKYEIZc,256 +../../../bin/blackd,sha256=4Ql34teLrKgP_I07BOQpKyMdTOKTbk8sTD19Js_CEZY,262 +_black_version.py,sha256=J13gsXjkb0PeiRMcxI_ff48THu--ndPguUjbwdQKirA,20 +black/__init__.py,sha256=WfrijLeAboMaGIz1VvQoxg3K0925OS3EjtNGedtQesg,44979 +black/__main__.py,sha256=mogeA4o9zt4w-ufKvaQjSEhtSgQkcMVLK9ChvdB5wH8,47 +black/brackets.py,sha256=4YGgFwSDk2hdzHaJTPF_JWoo_hdmnTGTwN7aQMWjogo,10761 +black/cache.py,sha256=fG6R1gIB7laUKJmJGGDLbvGyXV-mVV6d8OyY7sN4YnY,2342 +black/comments.py,sha256=6ybPXvmmQ7pcbNInMuUKjiP8zZlMOis5O-uUC_hMAxI,10197 +black/concurrency.py,sha256=MDDmc2LKcbai2scV2vYIas4eBmLhoThFqo4mPQcAuew,1829 +black/const.py,sha256=5jQVHjBmOqRai7fDheI-16JruvI4Nj6_7yBa6GCHMoM,249 +black/debug.py,sha256=BblF9L88hNGbuVo-EH6SzHo5jgBbFgWHyLL14zhlO3Y,1595 +black/files.py,sha256=BphFBRqiyN_l0evZZoDqjhvRTkJWB_Z3MzGGJdomceY,8448 +black/handle_ipynb_magics.py,sha256=s40Co89epSnHVz9MfdloZqWCmUiKKU7Buma9j-E5yss,13534 +black/linegen.py,sha256=znJY9M7CUF7HPacQUcnGDW6j2CNLDgVhhVSypoHEZGQ,41093 +black/lines.py,sha256=rPVcLxYuQVNeb-VOiB13QBJP04Qno6KghQuBPnv-yVY,26879 +black/mode.py,sha256=990qXazXHjHIsX33oin5Ps7K3mVQP9yqMIuzJLhW0bs,4699 +black/nodes.py,sha256=06hQf4EX3yRhnz5wvDfZN6vRPSlNCOtlxe_IZj2IkEE,24373 +black/numerics.py,sha256=zg7l1_XOtFNfcWnEd12sTsQsilAEtI3o7Rt6osdK3m4,1843 +black/output.py,sha256=sg1AEcMQ0kcS0gyD9jPESo34wpfKAd074NfcTdvNLkc,3495 +black/parsing.py,sha256=Ixr_gXf0AEC5BENp_rU4euewJ2sqO-njhwqVrJFtP6Q,10410 +black/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +black/report.py,sha256=iq4YS8A_F5zBp-HyohzNGL0w5PEJJrAnOUvOg7ddx0s,3380 +black/rusty.py,sha256=JAZPP4tU8U_WyRMQerygQ65Zthb4dM10yvtX8vjHUK4,557 +black/strings.py,sha256=ogWmRbtiIbnSwTlfIxNg3UxWYer06Y45exBFN7S_1r0,7924 +black/trans.py,sha256=v3Yj0TNSabiUbS9C6uGq7mDeAPHC2hzmsC3mvE8MXd0,76431 +black_primer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +black_primer/cli.py,sha256=V7y_LxYRWHwMWj00bqhXVeRkv97uJcO3OU-3yxO6iys,4847 +black_primer/lib.py,sha256=1IH7o7nLKlnXxRUSQ2Y0SIlqkBd9NF-3pEZb57SHGUg,13941 +black_primer/primer.json,sha256=9DFXpSGbEQNx9lUk6vnYJR3nvzwv9ImeIWfL3WRD3as,6783 +blackd/__init__.py,sha256=S_AGDXsgGUN9ZdhDx-6pPxOimtqlb2x6gpXwADEJ3OQ,7104 +blackd/middlewares.py,sha256=FDA9ve5O1YptredJmHODWa0FPElVRSUkuI-LXlqtmqQ,1207 +blib2to3/Grammar.txt,sha256=Ek2B-mvc4uoMstW1GvYcYlqXLsVo0ianhfZ-L6121Q0,11163 +blib2to3/PatternGrammar.txt,sha256=7lul2ztnIqDi--JWDrwciD5yMo75w7TaHHxdHMZJvOM,793 +blib2to3/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +blib2to3/pygram.py,sha256=aY7mifSN3ddqJXtEHg0oQC-nf1b87gxuht9wrVbOaiI,5463 +blib2to3/pytree.py,sha256=jaHZDtPnUQMPmTagt26xuJ8BPGqg0lFslQHgXrOogFE,31964 +blib2to3/pgen2/__init__.py,sha256=hY6w9QUzvTvRb-MoFfd_q_7ZLt6IUHC2yxWCfsZupQA,143 +blib2to3/pgen2/conv.py,sha256=wGS0vapMV81PvxisAentOrXCZX1IlCFulQDW5Ha9Ueo,9607 +blib2to3/pgen2/driver.py,sha256=ysH9xh3jCM-K0UBiZoZIOz8E-wvgTHPnO_SCOH3r2wA,10774 +blib2to3/pgen2/grammar.py,sha256=ohZ3ZwaIGTfVz90fWRKazCYxJWVq-ZB-Ht3hItar31k,6791 +blib2to3/pgen2/literals.py,sha256=vbzw1RX0NvATBR971WwRNtp68fsXky4-pV4cBZ02_9E,1628 +blib2to3/pgen2/parse.py,sha256=RderMwR6uCnMI395EAgeCUW6Fw-gHrF7c3UVE-p_r88,13083 +blib2to3/pgen2/pgen.py,sha256=8gkqFARDLVp8tdpjxjJEP1YytCZvNrLl5tuK6SdM_nc,15491 +blib2to3/pgen2/token.py,sha256=eDZWhONvSUNGsWYzHhgBd1pIQ2HlVPP7aon0S1CLuKE,1919 +blib2to3/pgen2/tokenize.py,sha256=P41EcFKYe0bH-EaaQY2KzsWkbz-wIqSUvoUA5kgobBI,22842 +black-21.12b0.dist-info/AUTHORS.md,sha256=QkFLz3GyG9FOsxzCSs5dFyRO8VfNZ4MooKSQtK-tIgU,7699 +black-21.12b0.dist-info/LICENSE,sha256=nAQo8MO0d5hQz1vZbhGqqK_HLUqG1KNiI9erouWNbgA,1080 +black-21.12b0.dist-info/METADATA,sha256=sP67E_PJhjq7Fc4i-Guw9qfDJflioPMn8FFwqIhS468,39684 +black-21.12b0.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92 +black-21.12b0.dist-info/entry_points.txt,sha256=YLrV9zqlrKNpCDWkEerYGVwQlNq0Ib4g9LHgGcaqBww,116 +black-21.12b0.dist-info/top_level.txt,sha256=jGkYA_03ZBzJOsfB7YnyswRCARxXZRcCbzc3pugKwew,50 +black-21.12b0.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +black-21.12b0.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/WHEEL new file mode 100644 index 0000000..5bad85f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/entry_points.txt b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/entry_points.txt new file mode 100644 index 0000000..faa86e5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/entry_points.txt @@ -0,0 +1,5 @@ +[console_scripts] +black = black:patched_main +black-primer = black_primer.cli:main +blackd = blackd:patched_main [d] + diff --git a/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/top_level.txt new file mode 100644 index 0000000..edff6bd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black-21.12b0.dist-info/top_level.txt @@ -0,0 +1,5 @@ +_black_version +black +black_primer +blackd +blib2to3 diff --git a/myenv/lib/python3.9/site-packages/black/__init__.py b/myenv/lib/python3.9/site-packages/black/__init__.py new file mode 100644 index 0000000..1923c06 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/__init__.py @@ -0,0 +1,1377 @@ +import asyncio +from json.decoder import JSONDecodeError +import json +from concurrent.futures import Executor, ThreadPoolExecutor, ProcessPoolExecutor +from contextlib import contextmanager +from datetime import datetime +from enum import Enum +import io +from multiprocessing import Manager, freeze_support +import os +from pathlib import Path +from pathspec.patterns.gitwildmatch import GitWildMatchPatternError +import re +import signal +import sys +import tokenize +import traceback +from typing import ( + Any, + Dict, + Generator, + Iterator, + List, + MutableMapping, + Optional, + Pattern, + Set, + Sized, + Tuple, + Union, +) + +import click +from dataclasses import replace +from mypy_extensions import mypyc_attr + +from black.const import DEFAULT_LINE_LENGTH, DEFAULT_INCLUDES, DEFAULT_EXCLUDES +from black.const import STDIN_PLACEHOLDER +from black.nodes import STARS, syms, is_simple_decorator_expression +from black.lines import Line, EmptyLineTracker +from black.linegen import transform_line, LineGenerator, LN +from black.comments import normalize_fmt_off +from black.mode import Mode, TargetVersion +from black.mode import Feature, supports_feature, VERSION_TO_FEATURES +from black.cache import read_cache, write_cache, get_cache_info, filter_cached, Cache +from black.concurrency import cancel, shutdown, maybe_install_uvloop +from black.output import dump_to_file, ipynb_diff, diff, color_diff, out, err +from black.report import Report, Changed, NothingChanged +from black.files import find_project_root, find_pyproject_toml, parse_pyproject_toml +from black.files import gen_python_files, get_gitignore, normalize_path_maybe_ignore +from black.files import wrap_stream_for_windows +from black.parsing import InvalidInput # noqa F401 +from black.parsing import lib2to3_parse, parse_ast, stringify_ast +from black.handle_ipynb_magics import ( + mask_cell, + unmask_cell, + remove_trailing_semicolon, + put_trailing_semicolon_back, + TRANSFORMED_MAGICS, + PYTHON_CELL_MAGICS, + jupyter_dependencies_are_installed, +) + + +# lib2to3 fork +from blib2to3.pytree import Node, Leaf +from blib2to3.pgen2 import token + +from _black_version import version as __version__ + +COMPILED = Path(__file__).suffix in (".pyd", ".so") + +# types +FileContent = str +Encoding = str +NewLine = str + + +class WriteBack(Enum): + NO = 0 + YES = 1 + DIFF = 2 + CHECK = 3 + COLOR_DIFF = 4 + + @classmethod + def from_configuration( + cls, *, check: bool, diff: bool, color: bool = False + ) -> "WriteBack": + if check and not diff: + return cls.CHECK + + if diff and color: + return cls.COLOR_DIFF + + return cls.DIFF if diff else cls.YES + + +# Legacy name, left for integrations. +FileMode = Mode + +DEFAULT_WORKERS = os.cpu_count() + + +def read_pyproject_toml( + ctx: click.Context, param: click.Parameter, value: Optional[str] +) -> Optional[str]: + """Inject Black configuration from "pyproject.toml" into defaults in `ctx`. + + Returns the path to a successfully found and read configuration file, None + otherwise. + """ + if not value: + value = find_pyproject_toml(ctx.params.get("src", ())) + if value is None: + return None + + try: + config = parse_pyproject_toml(value) + except (OSError, ValueError) as e: + raise click.FileError( + filename=value, hint=f"Error reading configuration file: {e}" + ) from None + + if not config: + return None + else: + # Sanitize the values to be Click friendly. For more information please see: + # https://github.com/psf/black/issues/1458 + # https://github.com/pallets/click/issues/1567 + config = { + k: str(v) if not isinstance(v, (list, dict)) else v + for k, v in config.items() + } + + target_version = config.get("target_version") + if target_version is not None and not isinstance(target_version, list): + raise click.BadOptionUsage( + "target-version", "Config key target-version must be a list" + ) + + default_map: Dict[str, Any] = {} + if ctx.default_map: + default_map.update(ctx.default_map) + default_map.update(config) + + ctx.default_map = default_map + return value + + +def target_version_option_callback( + c: click.Context, p: Union[click.Option, click.Parameter], v: Tuple[str, ...] +) -> List[TargetVersion]: + """Compute the target versions from a --target-version flag. + + This is its own function because mypy couldn't infer the type correctly + when it was a lambda, causing mypyc trouble. + """ + return [TargetVersion[val.upper()] for val in v] + + +def re_compile_maybe_verbose(regex: str) -> Pattern[str]: + """Compile a regular expression string in `regex`. + + If it contains newlines, use verbose mode. + """ + if "\n" in regex: + regex = "(?x)" + regex + compiled: Pattern[str] = re.compile(regex) + return compiled + + +def validate_regex( + ctx: click.Context, + param: click.Parameter, + value: Optional[str], +) -> Optional[Pattern[str]]: + try: + return re_compile_maybe_verbose(value) if value is not None else None + except re.error: + raise click.BadParameter("Not a valid regular expression") from None + + +@click.command( + context_settings={"help_option_names": ["-h", "--help"]}, + # While Click does set this field automatically using the docstring, mypyc + # (annoyingly) strips 'em so we need to set it here too. + help="The uncompromising code formatter.", +) +@click.option("-c", "--code", type=str, help="Format the code passed in as a string.") +@click.option( + "-l", + "--line-length", + type=int, + default=DEFAULT_LINE_LENGTH, + help="How many characters per line to allow.", + show_default=True, +) +@click.option( + "-t", + "--target-version", + type=click.Choice([v.name.lower() for v in TargetVersion]), + callback=target_version_option_callback, + multiple=True, + help=( + "Python versions that should be supported by Black's output. [default: per-file" + " auto-detection]" + ), +) +@click.option( + "--pyi", + is_flag=True, + help=( + "Format all input files like typing stubs regardless of file extension (useful" + " when piping source on standard input)." + ), +) +@click.option( + "--ipynb", + is_flag=True, + help=( + "Format all input files like Jupyter Notebooks regardless of file extension " + "(useful when piping source on standard input)." + ), +) +@click.option( + "-S", + "--skip-string-normalization", + is_flag=True, + help="Don't normalize string quotes or prefixes.", +) +@click.option( + "-C", + "--skip-magic-trailing-comma", + is_flag=True, + help="Don't use trailing commas as a reason to split lines.", +) +@click.option( + "--experimental-string-processing", + is_flag=True, + hidden=True, + help=( + "Experimental option that performs more normalization on string literals." + " Currently disabled because it leads to some crashes." + ), +) +@click.option( + "--check", + is_flag=True, + help=( + "Don't write the files back, just return the status. Return code 0 means" + " nothing would change. Return code 1 means some files would be reformatted." + " Return code 123 means there was an internal error." + ), +) +@click.option( + "--diff", + is_flag=True, + help="Don't write the files back, just output a diff for each file on stdout.", +) +@click.option( + "--color/--no-color", + is_flag=True, + help="Show colored diff. Only applies when `--diff` is given.", +) +@click.option( + "--fast/--safe", + is_flag=True, + help="If --fast given, skip temporary sanity checks. [default: --safe]", +) +@click.option( + "--required-version", + type=str, + help=( + "Require a specific version of Black to be running (useful for unifying results" + " across many environments e.g. with a pyproject.toml file)." + ), +) +@click.option( + "--include", + type=str, + default=DEFAULT_INCLUDES, + callback=validate_regex, + help=( + "A regular expression that matches files and directories that should be" + " included on recursive searches. An empty value means all files are included" + " regardless of the name. Use forward slashes for directories on all platforms" + " (Windows, too). Exclusions are calculated first, inclusions later." + ), + show_default=True, +) +@click.option( + "--exclude", + type=str, + callback=validate_regex, + help=( + "A regular expression that matches files and directories that should be" + " excluded on recursive searches. An empty value means no paths are excluded." + " Use forward slashes for directories on all platforms (Windows, too)." + " Exclusions are calculated first, inclusions later. [default:" + f" {DEFAULT_EXCLUDES}]" + ), + show_default=False, +) +@click.option( + "--extend-exclude", + type=str, + callback=validate_regex, + help=( + "Like --exclude, but adds additional files and directories on top of the" + " excluded ones. (Useful if you simply want to add to the default)" + ), +) +@click.option( + "--force-exclude", + type=str, + callback=validate_regex, + help=( + "Like --exclude, but files and directories matching this regex will be " + "excluded even when they are passed explicitly as arguments." + ), +) +@click.option( + "--stdin-filename", + type=str, + help=( + "The name of the file when passing it through stdin. Useful to make " + "sure Black will respect --force-exclude option on some " + "editors that rely on using stdin." + ), +) +@click.option( + "-W", + "--workers", + type=click.IntRange(min=1), + default=DEFAULT_WORKERS, + show_default=True, + help="Number of parallel workers", +) +@click.option( + "-q", + "--quiet", + is_flag=True, + help=( + "Don't emit non-error messages to stderr. Errors are still emitted; silence" + " those with 2>/dev/null." + ), +) +@click.option( + "-v", + "--verbose", + is_flag=True, + help=( + "Also emit messages to stderr about files that were not changed or were ignored" + " due to exclusion patterns." + ), +) +@click.version_option( + version=__version__, + message=f"%(prog)s, %(version)s (compiled: {'yes' if COMPILED else 'no'})", +) +@click.argument( + "src", + nargs=-1, + type=click.Path( + exists=True, file_okay=True, dir_okay=True, readable=True, allow_dash=True + ), + is_eager=True, + metavar="SRC ...", +) +@click.option( + "--config", + type=click.Path( + exists=True, + file_okay=True, + dir_okay=False, + readable=True, + allow_dash=False, + path_type=str, + ), + is_eager=True, + callback=read_pyproject_toml, + help="Read configuration from FILE path.", +) +@click.pass_context +def main( + ctx: click.Context, + code: Optional[str], + line_length: int, + target_version: List[TargetVersion], + check: bool, + diff: bool, + color: bool, + fast: bool, + pyi: bool, + ipynb: bool, + skip_string_normalization: bool, + skip_magic_trailing_comma: bool, + experimental_string_processing: bool, + quiet: bool, + verbose: bool, + required_version: Optional[str], + include: Pattern[str], + exclude: Optional[Pattern[str]], + extend_exclude: Optional[Pattern[str]], + force_exclude: Optional[Pattern[str]], + stdin_filename: Optional[str], + workers: int, + src: Tuple[str, ...], + config: Optional[str], +) -> None: + """The uncompromising code formatter.""" + if config and verbose: + out(f"Using configuration from {config}.", bold=False, fg="blue") + + error_msg = "Oh no! 💥 💔 💥" + if required_version and required_version != __version__: + err( + f"{error_msg} The required version `{required_version}` does not match" + f" the running version `{__version__}`!" + ) + ctx.exit(1) + if ipynb and pyi: + err("Cannot pass both `pyi` and `ipynb` flags!") + ctx.exit(1) + + write_back = WriteBack.from_configuration(check=check, diff=diff, color=color) + if target_version: + versions = set(target_version) + else: + # We'll autodetect later. + versions = set() + mode = Mode( + target_versions=versions, + line_length=line_length, + is_pyi=pyi, + is_ipynb=ipynb, + string_normalization=not skip_string_normalization, + magic_trailing_comma=not skip_magic_trailing_comma, + experimental_string_processing=experimental_string_processing, + ) + + if code is not None: + # Run in quiet mode by default with -c; the extra output isn't useful. + # You can still pass -v to get verbose output. + quiet = True + + report = Report(check=check, diff=diff, quiet=quiet, verbose=verbose) + + if code is not None: + reformat_code( + content=code, fast=fast, write_back=write_back, mode=mode, report=report + ) + else: + try: + sources = get_sources( + ctx=ctx, + src=src, + quiet=quiet, + verbose=verbose, + include=include, + exclude=exclude, + extend_exclude=extend_exclude, + force_exclude=force_exclude, + report=report, + stdin_filename=stdin_filename, + ) + except GitWildMatchPatternError: + ctx.exit(1) + + path_empty( + sources, + "No Python files are present to be formatted. Nothing to do 😴", + quiet, + verbose, + ctx, + ) + + if len(sources) == 1: + reformat_one( + src=sources.pop(), + fast=fast, + write_back=write_back, + mode=mode, + report=report, + ) + else: + reformat_many( + sources=sources, + fast=fast, + write_back=write_back, + mode=mode, + report=report, + workers=workers, + ) + + if verbose or not quiet: + out(error_msg if report.return_code else "All done! ✨ 🍰 ✨") + if code is None: + click.echo(str(report), err=True) + ctx.exit(report.return_code) + + +def get_sources( + *, + ctx: click.Context, + src: Tuple[str, ...], + quiet: bool, + verbose: bool, + include: Pattern[str], + exclude: Optional[Pattern[str]], + extend_exclude: Optional[Pattern[str]], + force_exclude: Optional[Pattern[str]], + report: "Report", + stdin_filename: Optional[str], +) -> Set[Path]: + """Compute the set of files to be formatted.""" + + root = find_project_root(src) + sources: Set[Path] = set() + path_empty(src, "No Path provided. Nothing to do 😴", quiet, verbose, ctx) + + if exclude is None: + exclude = re_compile_maybe_verbose(DEFAULT_EXCLUDES) + gitignore = get_gitignore(root) + else: + gitignore = None + + for s in src: + if s == "-" and stdin_filename: + p = Path(stdin_filename) + is_stdin = True + else: + p = Path(s) + is_stdin = False + + if is_stdin or p.is_file(): + normalized_path = normalize_path_maybe_ignore(p, root, report) + if normalized_path is None: + continue + + normalized_path = "/" + normalized_path + # Hard-exclude any files that matches the `--force-exclude` regex. + if force_exclude: + force_exclude_match = force_exclude.search(normalized_path) + else: + force_exclude_match = None + if force_exclude_match and force_exclude_match.group(0): + report.path_ignored(p, "matches the --force-exclude regular expression") + continue + + if is_stdin: + p = Path(f"{STDIN_PLACEHOLDER}{str(p)}") + + if p.suffix == ".ipynb" and not jupyter_dependencies_are_installed( + verbose=verbose, quiet=quiet + ): + continue + + sources.add(p) + elif p.is_dir(): + sources.update( + gen_python_files( + p.iterdir(), + root, + include, + exclude, + extend_exclude, + force_exclude, + report, + gitignore, + verbose=verbose, + quiet=quiet, + ) + ) + elif s == "-": + sources.add(p) + else: + err(f"invalid path: {s}") + return sources + + +def path_empty( + src: Sized, msg: str, quiet: bool, verbose: bool, ctx: click.Context +) -> None: + """ + Exit if there is no `src` provided for formatting + """ + if not src: + if verbose or not quiet: + out(msg) + ctx.exit(0) + + +def reformat_code( + content: str, fast: bool, write_back: WriteBack, mode: Mode, report: Report +) -> None: + """ + Reformat and print out `content` without spawning child processes. + Similar to `reformat_one`, but for string content. + + `fast`, `write_back`, and `mode` options are passed to + :func:`format_file_in_place` or :func:`format_stdin_to_stdout`. + """ + path = Path("") + try: + changed = Changed.NO + if format_stdin_to_stdout( + content=content, fast=fast, write_back=write_back, mode=mode + ): + changed = Changed.YES + report.done(path, changed) + except Exception as exc: + if report.verbose: + traceback.print_exc() + report.failed(path, str(exc)) + + +def reformat_one( + src: Path, fast: bool, write_back: WriteBack, mode: Mode, report: "Report" +) -> None: + """Reformat a single file under `src` without spawning child processes. + + `fast`, `write_back`, and `mode` options are passed to + :func:`format_file_in_place` or :func:`format_stdin_to_stdout`. + """ + try: + changed = Changed.NO + + if str(src) == "-": + is_stdin = True + elif str(src).startswith(STDIN_PLACEHOLDER): + is_stdin = True + # Use the original name again in case we want to print something + # to the user + src = Path(str(src)[len(STDIN_PLACEHOLDER) :]) + else: + is_stdin = False + + if is_stdin: + if src.suffix == ".pyi": + mode = replace(mode, is_pyi=True) + elif src.suffix == ".ipynb": + mode = replace(mode, is_ipynb=True) + if format_stdin_to_stdout(fast=fast, write_back=write_back, mode=mode): + changed = Changed.YES + else: + cache: Cache = {} + if write_back not in (WriteBack.DIFF, WriteBack.COLOR_DIFF): + cache = read_cache(mode) + res_src = src.resolve() + res_src_s = str(res_src) + if res_src_s in cache and cache[res_src_s] == get_cache_info(res_src): + changed = Changed.CACHED + if changed is not Changed.CACHED and format_file_in_place( + src, fast=fast, write_back=write_back, mode=mode + ): + changed = Changed.YES + if (write_back is WriteBack.YES and changed is not Changed.CACHED) or ( + write_back is WriteBack.CHECK and changed is Changed.NO + ): + write_cache(cache, [src], mode) + report.done(src, changed) + except Exception as exc: + if report.verbose: + traceback.print_exc() + report.failed(src, str(exc)) + + +# diff-shades depends on being to monkeypatch this function to operate. I know it's +# not ideal, but this shouldn't cause any issues ... hopefully. ~ichard26 +@mypyc_attr(patchable=True) +def reformat_many( + sources: Set[Path], + fast: bool, + write_back: WriteBack, + mode: Mode, + report: "Report", + workers: Optional[int], +) -> None: + """Reformat multiple files using a ProcessPoolExecutor.""" + executor: Executor + loop = asyncio.get_event_loop() + worker_count = workers if workers is not None else DEFAULT_WORKERS + if sys.platform == "win32": + # Work around https://bugs.python.org/issue26903 + assert worker_count is not None + worker_count = min(worker_count, 60) + try: + executor = ProcessPoolExecutor(max_workers=worker_count) + except (ImportError, NotImplementedError, OSError): + # we arrive here if the underlying system does not support multi-processing + # like in AWS Lambda or Termux, in which case we gracefully fallback to + # a ThreadPoolExecutor with just a single worker (more workers would not do us + # any good due to the Global Interpreter Lock) + executor = ThreadPoolExecutor(max_workers=1) + + try: + loop.run_until_complete( + schedule_formatting( + sources=sources, + fast=fast, + write_back=write_back, + mode=mode, + report=report, + loop=loop, + executor=executor, + ) + ) + finally: + shutdown(loop) + if executor is not None: + executor.shutdown() + + +async def schedule_formatting( + sources: Set[Path], + fast: bool, + write_back: WriteBack, + mode: Mode, + report: "Report", + loop: asyncio.AbstractEventLoop, + executor: Executor, +) -> None: + """Run formatting of `sources` in parallel using the provided `executor`. + + (Use ProcessPoolExecutors for actual parallelism.) + + `write_back`, `fast`, and `mode` options are passed to + :func:`format_file_in_place`. + """ + cache: Cache = {} + if write_back not in (WriteBack.DIFF, WriteBack.COLOR_DIFF): + cache = read_cache(mode) + sources, cached = filter_cached(cache, sources) + for src in sorted(cached): + report.done(src, Changed.CACHED) + if not sources: + return + + cancelled = [] + sources_to_cache = [] + lock = None + if write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF): + # For diff output, we need locks to ensure we don't interleave output + # from different processes. + manager = Manager() + lock = manager.Lock() + tasks = { + asyncio.ensure_future( + loop.run_in_executor( + executor, format_file_in_place, src, fast, mode, write_back, lock + ) + ): src + for src in sorted(sources) + } + pending = tasks.keys() + try: + loop.add_signal_handler(signal.SIGINT, cancel, pending) + loop.add_signal_handler(signal.SIGTERM, cancel, pending) + except NotImplementedError: + # There are no good alternatives for these on Windows. + pass + while pending: + done, _ = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED) + for task in done: + src = tasks.pop(task) + if task.cancelled(): + cancelled.append(task) + elif task.exception(): + report.failed(src, str(task.exception())) + else: + changed = Changed.YES if task.result() else Changed.NO + # If the file was written back or was successfully checked as + # well-formatted, store this information in the cache. + if write_back is WriteBack.YES or ( + write_back is WriteBack.CHECK and changed is Changed.NO + ): + sources_to_cache.append(src) + report.done(src, changed) + if cancelled: + if sys.version_info >= (3, 7): + await asyncio.gather(*cancelled, return_exceptions=True) + else: + await asyncio.gather(*cancelled, loop=loop, return_exceptions=True) + if sources_to_cache: + write_cache(cache, sources_to_cache, mode) + + +def format_file_in_place( + src: Path, + fast: bool, + mode: Mode, + write_back: WriteBack = WriteBack.NO, + lock: Any = None, # multiprocessing.Manager().Lock() is some crazy proxy +) -> bool: + """Format file under `src` path. Return True if changed. + + If `write_back` is DIFF, write a diff to stdout. If it is YES, write reformatted + code to the file. + `mode` and `fast` options are passed to :func:`format_file_contents`. + """ + if src.suffix == ".pyi": + mode = replace(mode, is_pyi=True) + elif src.suffix == ".ipynb": + mode = replace(mode, is_ipynb=True) + + then = datetime.utcfromtimestamp(src.stat().st_mtime) + with open(src, "rb") as buf: + src_contents, encoding, newline = decode_bytes(buf.read()) + try: + dst_contents = format_file_contents(src_contents, fast=fast, mode=mode) + except NothingChanged: + return False + except JSONDecodeError: + raise ValueError( + f"File '{src}' cannot be parsed as valid Jupyter notebook." + ) from None + + if write_back == WriteBack.YES: + with open(src, "w", encoding=encoding, newline=newline) as f: + f.write(dst_contents) + elif write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF): + now = datetime.utcnow() + src_name = f"{src}\t{then} +0000" + dst_name = f"{src}\t{now} +0000" + if mode.is_ipynb: + diff_contents = ipynb_diff(src_contents, dst_contents, src_name, dst_name) + else: + diff_contents = diff(src_contents, dst_contents, src_name, dst_name) + + if write_back == WriteBack.COLOR_DIFF: + diff_contents = color_diff(diff_contents) + + with lock or nullcontext(): + f = io.TextIOWrapper( + sys.stdout.buffer, + encoding=encoding, + newline=newline, + write_through=True, + ) + f = wrap_stream_for_windows(f) + f.write(diff_contents) + f.detach() + + return True + + +def format_stdin_to_stdout( + fast: bool, + *, + content: Optional[str] = None, + write_back: WriteBack = WriteBack.NO, + mode: Mode, +) -> bool: + """Format file on stdin. Return True if changed. + + If content is None, it's read from sys.stdin. + + If `write_back` is YES, write reformatted code back to stdout. If it is DIFF, + write a diff to stdout. The `mode` argument is passed to + :func:`format_file_contents`. + """ + then = datetime.utcnow() + + if content is None: + src, encoding, newline = decode_bytes(sys.stdin.buffer.read()) + else: + src, encoding, newline = content, "utf-8", "" + + dst = src + try: + dst = format_file_contents(src, fast=fast, mode=mode) + return True + + except NothingChanged: + return False + + finally: + f = io.TextIOWrapper( + sys.stdout.buffer, encoding=encoding, newline=newline, write_through=True + ) + if write_back == WriteBack.YES: + # Make sure there's a newline after the content + if dst and dst[-1] != "\n": + dst += "\n" + f.write(dst) + elif write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF): + now = datetime.utcnow() + src_name = f"STDIN\t{then} +0000" + dst_name = f"STDOUT\t{now} +0000" + d = diff(src, dst, src_name, dst_name) + if write_back == WriteBack.COLOR_DIFF: + d = color_diff(d) + f = wrap_stream_for_windows(f) + f.write(d) + f.detach() + + +def check_stability_and_equivalence( + src_contents: str, dst_contents: str, *, mode: Mode +) -> None: + """Perform stability and equivalence checks. + + Raise AssertionError if source and destination contents are not + equivalent, or if a second pass of the formatter would format the + content differently. + """ + assert_equivalent(src_contents, dst_contents) + + # Forced second pass to work around optional trailing commas (becoming + # forced trailing commas on pass 2) interacting differently with optional + # parentheses. Admittedly ugly. + dst_contents_pass2 = format_str(dst_contents, mode=mode) + if dst_contents != dst_contents_pass2: + dst_contents = dst_contents_pass2 + assert_equivalent(src_contents, dst_contents, pass_num=2) + assert_stable(src_contents, dst_contents, mode=mode) + # Note: no need to explicitly call `assert_stable` if `dst_contents` was + # the same as `dst_contents_pass2`. + + +def format_file_contents(src_contents: str, *, fast: bool, mode: Mode) -> FileContent: + """Reformat contents of a file and return new contents. + + If `fast` is False, additionally confirm that the reformatted code is + valid by calling :func:`assert_equivalent` and :func:`assert_stable` on it. + `mode` is passed to :func:`format_str`. + """ + if not src_contents.strip(): + raise NothingChanged + + if mode.is_ipynb: + dst_contents = format_ipynb_string(src_contents, fast=fast, mode=mode) + else: + dst_contents = format_str(src_contents, mode=mode) + if src_contents == dst_contents: + raise NothingChanged + + if not fast and not mode.is_ipynb: + # Jupyter notebooks will already have been checked above. + check_stability_and_equivalence(src_contents, dst_contents, mode=mode) + return dst_contents + + +def validate_cell(src: str) -> None: + """Check that cell does not already contain TransformerManager transformations, + or non-Python cell magics, which might cause tokenizer_rt to break because of + indentations. + + If a cell contains ``!ls``, then it'll be transformed to + ``get_ipython().system('ls')``. However, if the cell originally contained + ``get_ipython().system('ls')``, then it would get transformed in the same way: + + >>> TransformerManager().transform_cell("get_ipython().system('ls')") + "get_ipython().system('ls')\n" + >>> TransformerManager().transform_cell("!ls") + "get_ipython().system('ls')\n" + + Due to the impossibility of safely roundtripping in such situations, cells + containing transformed magics will be ignored. + """ + if any(transformed_magic in src for transformed_magic in TRANSFORMED_MAGICS): + raise NothingChanged + if src[:2] == "%%" and src.split()[0][2:] not in PYTHON_CELL_MAGICS: + raise NothingChanged + + +def format_cell(src: str, *, fast: bool, mode: Mode) -> str: + """Format code in given cell of Jupyter notebook. + + General idea is: + + - if cell has trailing semicolon, remove it; + - if cell has IPython magics, mask them; + - format cell; + - reinstate IPython magics; + - reinstate trailing semicolon (if originally present); + - strip trailing newlines. + + Cells with syntax errors will not be processed, as they + could potentially be automagics or multi-line magics, which + are currently not supported. + """ + validate_cell(src) + src_without_trailing_semicolon, has_trailing_semicolon = remove_trailing_semicolon( + src + ) + try: + masked_src, replacements = mask_cell(src_without_trailing_semicolon) + except SyntaxError: + raise NothingChanged from None + masked_dst = format_str(masked_src, mode=mode) + if not fast: + check_stability_and_equivalence(masked_src, masked_dst, mode=mode) + dst_without_trailing_semicolon = unmask_cell(masked_dst, replacements) + dst = put_trailing_semicolon_back( + dst_without_trailing_semicolon, has_trailing_semicolon + ) + dst = dst.rstrip("\n") + if dst == src: + raise NothingChanged from None + return dst + + +def validate_metadata(nb: MutableMapping[str, Any]) -> None: + """If notebook is marked as non-Python, don't format it. + + All notebook metadata fields are optional, see + https://nbformat.readthedocs.io/en/latest/format_description.html. So + if a notebook has empty metadata, we will try to parse it anyway. + """ + language = nb.get("metadata", {}).get("language_info", {}).get("name", None) + if language is not None and language != "python": + raise NothingChanged from None + + +def format_ipynb_string(src_contents: str, *, fast: bool, mode: Mode) -> FileContent: + """Format Jupyter notebook. + + Operate cell-by-cell, only on code cells, only for Python notebooks. + If the ``.ipynb`` originally had a trailing newline, it'll be preserved. + """ + trailing_newline = src_contents[-1] == "\n" + modified = False + nb = json.loads(src_contents) + validate_metadata(nb) + for cell in nb["cells"]: + if cell.get("cell_type", None) == "code": + try: + src = "".join(cell["source"]) + dst = format_cell(src, fast=fast, mode=mode) + except NothingChanged: + pass + else: + cell["source"] = dst.splitlines(keepends=True) + modified = True + if modified: + dst_contents = json.dumps(nb, indent=1, ensure_ascii=False) + if trailing_newline: + dst_contents = dst_contents + "\n" + return dst_contents + else: + raise NothingChanged + + +def format_str(src_contents: str, *, mode: Mode) -> FileContent: + """Reformat a string and return new contents. + + `mode` determines formatting options, such as how many characters per line are + allowed. Example: + + >>> import black + >>> print(black.format_str("def f(arg:str='')->None:...", mode=black.Mode())) + def f(arg: str = "") -> None: + ... + + A more complex example: + + >>> print( + ... black.format_str( + ... "def f(arg:str='')->None: hey", + ... mode=black.Mode( + ... target_versions={black.TargetVersion.PY36}, + ... line_length=10, + ... string_normalization=False, + ... is_pyi=False, + ... ), + ... ), + ... ) + def f( + arg: str = '', + ) -> None: + hey + + """ + src_node = lib2to3_parse(src_contents.lstrip(), mode.target_versions) + dst_contents = [] + future_imports = get_future_imports(src_node) + if mode.target_versions: + versions = mode.target_versions + else: + versions = detect_target_versions(src_node) + + # TODO: fully drop support and this code hopefully in January 2022 :D + if TargetVersion.PY27 in mode.target_versions or versions == {TargetVersion.PY27}: + msg = ( + "DEPRECATION: Python 2 support will be removed in the first stable release " + "expected in January 2022." + ) + err(msg, fg="yellow", bold=True) + + normalize_fmt_off(src_node) + lines = LineGenerator( + mode=mode, + remove_u_prefix="unicode_literals" in future_imports + or supports_feature(versions, Feature.UNICODE_LITERALS), + ) + elt = EmptyLineTracker(is_pyi=mode.is_pyi) + empty_line = Line(mode=mode) + after = 0 + split_line_features = { + feature + for feature in {Feature.TRAILING_COMMA_IN_CALL, Feature.TRAILING_COMMA_IN_DEF} + if supports_feature(versions, feature) + } + for current_line in lines.visit(src_node): + dst_contents.append(str(empty_line) * after) + before, after = elt.maybe_empty_lines(current_line) + dst_contents.append(str(empty_line) * before) + for line in transform_line( + current_line, mode=mode, features=split_line_features + ): + dst_contents.append(str(line)) + return "".join(dst_contents) + + +def decode_bytes(src: bytes) -> Tuple[FileContent, Encoding, NewLine]: + """Return a tuple of (decoded_contents, encoding, newline). + + `newline` is either CRLF or LF but `decoded_contents` is decoded with + universal newlines (i.e. only contains LF). + """ + srcbuf = io.BytesIO(src) + encoding, lines = tokenize.detect_encoding(srcbuf.readline) + if not lines: + return "", encoding, "\n" + + newline = "\r\n" if b"\r\n" == lines[0][-2:] else "\n" + srcbuf.seek(0) + with io.TextIOWrapper(srcbuf, encoding) as tiow: + return tiow.read(), encoding, newline + + +def get_features_used(node: Node) -> Set[Feature]: # noqa: C901 + """Return a set of (relatively) new Python features used in this file. + + Currently looking for: + - f-strings; + - underscores in numeric literals; + - trailing commas after * or ** in function signatures and calls; + - positional only arguments in function signatures and lambdas; + - assignment expression; + - relaxed decorator syntax; + - print / exec statements; + """ + features: Set[Feature] = set() + for n in node.pre_order(): + if n.type == token.STRING: + value_head = n.value[:2] # type: ignore + if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}: + features.add(Feature.F_STRINGS) + + elif n.type == token.NUMBER: + assert isinstance(n, Leaf) + if "_" in n.value: + features.add(Feature.NUMERIC_UNDERSCORES) + elif n.value.endswith(("L", "l")): + # Python 2: 10L + features.add(Feature.LONG_INT_LITERAL) + elif len(n.value) >= 2 and n.value[0] == "0" and n.value[1].isdigit(): + # Python 2: 0123; 00123; ... + if not all(char == "0" for char in n.value): + # although we don't want to match 0000 or similar + features.add(Feature.OCTAL_INT_LITERAL) + + elif n.type == token.SLASH: + if n.parent and n.parent.type in { + syms.typedargslist, + syms.arglist, + syms.varargslist, + }: + features.add(Feature.POS_ONLY_ARGUMENTS) + + elif n.type == token.COLONEQUAL: + features.add(Feature.ASSIGNMENT_EXPRESSIONS) + + elif n.type == syms.decorator: + if len(n.children) > 1 and not is_simple_decorator_expression( + n.children[1] + ): + features.add(Feature.RELAXED_DECORATORS) + + elif ( + n.type in {syms.typedargslist, syms.arglist} + and n.children + and n.children[-1].type == token.COMMA + ): + if n.type == syms.typedargslist: + feature = Feature.TRAILING_COMMA_IN_DEF + else: + feature = Feature.TRAILING_COMMA_IN_CALL + + for ch in n.children: + if ch.type in STARS: + features.add(feature) + + if ch.type == syms.argument: + for argch in ch.children: + if argch.type in STARS: + features.add(feature) + + # Python 2 only features (for its deprecation) except for integers, see above + elif n.type == syms.print_stmt: + features.add(Feature.PRINT_STMT) + elif n.type == syms.exec_stmt: + features.add(Feature.EXEC_STMT) + elif n.type == syms.tfpdef: + # def set_position((x, y), value): + # ... + features.add(Feature.AUTOMATIC_PARAMETER_UNPACKING) + elif n.type == syms.except_clause: + # try: + # ... + # except Exception, err: + # ... + if len(n.children) >= 4: + if n.children[-2].type == token.COMMA: + features.add(Feature.COMMA_STYLE_EXCEPT) + elif n.type == syms.raise_stmt: + # raise Exception, "msg" + if len(n.children) >= 4: + if n.children[-2].type == token.COMMA: + features.add(Feature.COMMA_STYLE_RAISE) + elif n.type == token.BACKQUOTE: + # `i'm surprised this ever existed` + features.add(Feature.BACKQUOTE_REPR) + + return features + + +def detect_target_versions(node: Node) -> Set[TargetVersion]: + """Detect the version to target based on the nodes used.""" + features = get_features_used(node) + return { + version for version in TargetVersion if features <= VERSION_TO_FEATURES[version] + } + + +def get_future_imports(node: Node) -> Set[str]: + """Return a set of __future__ imports in the file.""" + imports: Set[str] = set() + + def get_imports_from_children(children: List[LN]) -> Generator[str, None, None]: + for child in children: + if isinstance(child, Leaf): + if child.type == token.NAME: + yield child.value + + elif child.type == syms.import_as_name: + orig_name = child.children[0] + assert isinstance(orig_name, Leaf), "Invalid syntax parsing imports" + assert orig_name.type == token.NAME, "Invalid syntax parsing imports" + yield orig_name.value + + elif child.type == syms.import_as_names: + yield from get_imports_from_children(child.children) + + else: + raise AssertionError("Invalid syntax parsing imports") + + for child in node.children: + if child.type != syms.simple_stmt: + break + + first_child = child.children[0] + if isinstance(first_child, Leaf): + # Continue looking if we see a docstring; otherwise stop. + if ( + len(child.children) == 2 + and first_child.type == token.STRING + and child.children[1].type == token.NEWLINE + ): + continue + + break + + elif first_child.type == syms.import_from: + module_name = first_child.children[1] + if not isinstance(module_name, Leaf) or module_name.value != "__future__": + break + + imports |= set(get_imports_from_children(first_child.children[3:])) + else: + break + + return imports + + +def assert_equivalent(src: str, dst: str, *, pass_num: int = 1) -> None: + """Raise AssertionError if `src` and `dst` aren't equivalent.""" + try: + src_ast = parse_ast(src) + except Exception as exc: + raise AssertionError( + "cannot use --safe with this file; failed to parse source file." + ) from exc + + try: + dst_ast = parse_ast(dst) + except Exception as exc: + log = dump_to_file("".join(traceback.format_tb(exc.__traceback__)), dst) + raise AssertionError( + f"INTERNAL ERROR: Black produced invalid code on pass {pass_num}: {exc}. " + "Please report a bug on https://github.com/psf/black/issues. " + f"This invalid output might be helpful: {log}" + ) from None + + src_ast_str = "\n".join(stringify_ast(src_ast)) + dst_ast_str = "\n".join(stringify_ast(dst_ast)) + if src_ast_str != dst_ast_str: + log = dump_to_file(diff(src_ast_str, dst_ast_str, "src", "dst")) + raise AssertionError( + "INTERNAL ERROR: Black produced code that is not equivalent to the" + f" source on pass {pass_num}. Please report a bug on " + f"https://github.com/psf/black/issues. This diff might be helpful: {log}" + ) from None + + +def assert_stable(src: str, dst: str, mode: Mode) -> None: + """Raise AssertionError if `dst` reformats differently the second time.""" + newdst = format_str(dst, mode=mode) + if dst != newdst: + log = dump_to_file( + str(mode), + diff(src, dst, "source", "first pass"), + diff(dst, newdst, "first pass", "second pass"), + ) + raise AssertionError( + "INTERNAL ERROR: Black produced different code on the second pass of the" + " formatter. Please report a bug on https://github.com/psf/black/issues." + f" This diff might be helpful: {log}" + ) from None + + +@contextmanager +def nullcontext() -> Iterator[None]: + """Return an empty context manager. + + To be used like `nullcontext` in Python 3.7. + """ + yield + + +def patch_click() -> None: + """Make Click not crash on Python 3.6 with LANG=C. + + On certain misconfigured environments, Python 3 selects the ASCII encoding as the + default which restricts paths that it can access during the lifetime of the + application. Click refuses to work in this scenario by raising a RuntimeError. + + In case of Black the likelihood that non-ASCII characters are going to be used in + file paths is minimal since it's Python source code. Moreover, this crash was + spurious on Python 3.7 thanks to PEP 538 and PEP 540. + """ + try: + from click import core + from click import _unicodefun + except ModuleNotFoundError: + return + + for module in (core, _unicodefun): + if hasattr(module, "_verify_python3_env"): + module._verify_python3_env = lambda: None # type: ignore + if hasattr(module, "_verify_python_env"): + module._verify_python_env = lambda: None # type: ignore + + +def patched_main() -> None: + maybe_install_uvloop() + freeze_support() + patch_click() + main() + + +if __name__ == "__main__": + patched_main() diff --git a/myenv/lib/python3.9/site-packages/black/__main__.py b/myenv/lib/python3.9/site-packages/black/__main__.py new file mode 100644 index 0000000..19b810b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/__main__.py @@ -0,0 +1,3 @@ +from black import patched_main + +patched_main() diff --git a/myenv/lib/python3.9/site-packages/black/brackets.py b/myenv/lib/python3.9/site-packages/black/brackets.py new file mode 100644 index 0000000..c5ed4bf --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/brackets.py @@ -0,0 +1,334 @@ +"""Builds on top of nodes.py to track brackets.""" + +from dataclasses import dataclass, field +import sys +from typing import Dict, Iterable, List, Optional, Tuple, Union + +if sys.version_info < (3, 8): + from typing_extensions import Final +else: + from typing import Final + +from blib2to3.pytree import Leaf, Node +from blib2to3.pgen2 import token + +from black.nodes import syms, is_vararg, VARARGS_PARENTS, UNPACKING_PARENTS +from black.nodes import BRACKET, OPENING_BRACKETS, CLOSING_BRACKETS +from black.nodes import MATH_OPERATORS, COMPARATORS, LOGIC_OPERATORS + +# types +LN = Union[Leaf, Node] +Depth = int +LeafID = int +NodeType = int +Priority = int + + +COMPREHENSION_PRIORITY: Final = 20 +COMMA_PRIORITY: Final = 18 +TERNARY_PRIORITY: Final = 16 +LOGIC_PRIORITY: Final = 14 +STRING_PRIORITY: Final = 12 +COMPARATOR_PRIORITY: Final = 10 +MATH_PRIORITIES: Final = { + token.VBAR: 9, + token.CIRCUMFLEX: 8, + token.AMPER: 7, + token.LEFTSHIFT: 6, + token.RIGHTSHIFT: 6, + token.PLUS: 5, + token.MINUS: 5, + token.STAR: 4, + token.SLASH: 4, + token.DOUBLESLASH: 4, + token.PERCENT: 4, + token.AT: 4, + token.TILDE: 3, + token.DOUBLESTAR: 2, +} +DOT_PRIORITY: Final = 1 + + +class BracketMatchError(Exception): + """Raised when an opening bracket is unable to be matched to a closing bracket.""" + + +@dataclass +class BracketTracker: + """Keeps track of brackets on a line.""" + + depth: int = 0 + bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = field(default_factory=dict) + delimiters: Dict[LeafID, Priority] = field(default_factory=dict) + previous: Optional[Leaf] = None + _for_loop_depths: List[int] = field(default_factory=list) + _lambda_argument_depths: List[int] = field(default_factory=list) + invisible: List[Leaf] = field(default_factory=list) + + def mark(self, leaf: Leaf) -> None: + """Mark `leaf` with bracket-related metadata. Keep track of delimiters. + + All leaves receive an int `bracket_depth` field that stores how deep + within brackets a given leaf is. 0 means there are no enclosing brackets + that started on this line. + + If a leaf is itself a closing bracket, it receives an `opening_bracket` + field that it forms a pair with. This is a one-directional link to + avoid reference cycles. + + If a leaf is a delimiter (a token on which Black can split the line if + needed) and it's on depth 0, its `id()` is stored in the tracker's + `delimiters` field. + """ + if leaf.type == token.COMMENT: + return + + self.maybe_decrement_after_for_loop_variable(leaf) + self.maybe_decrement_after_lambda_arguments(leaf) + if leaf.type in CLOSING_BRACKETS: + self.depth -= 1 + try: + opening_bracket = self.bracket_match.pop((self.depth, leaf.type)) + except KeyError as e: + raise BracketMatchError( + "Unable to match a closing bracket to the following opening" + f" bracket: {leaf}" + ) from e + leaf.opening_bracket = opening_bracket + if not leaf.value: + self.invisible.append(leaf) + leaf.bracket_depth = self.depth + if self.depth == 0: + delim = is_split_before_delimiter(leaf, self.previous) + if delim and self.previous is not None: + self.delimiters[id(self.previous)] = delim + else: + delim = is_split_after_delimiter(leaf, self.previous) + if delim: + self.delimiters[id(leaf)] = delim + if leaf.type in OPENING_BRACKETS: + self.bracket_match[self.depth, BRACKET[leaf.type]] = leaf + self.depth += 1 + if not leaf.value: + self.invisible.append(leaf) + self.previous = leaf + self.maybe_increment_lambda_arguments(leaf) + self.maybe_increment_for_loop_variable(leaf) + + def any_open_brackets(self) -> bool: + """Return True if there is an yet unmatched open bracket on the line.""" + return bool(self.bracket_match) + + def max_delimiter_priority(self, exclude: Iterable[LeafID] = ()) -> Priority: + """Return the highest priority of a delimiter found on the line. + + Values are consistent with what `is_split_*_delimiter()` return. + Raises ValueError on no delimiters. + """ + return max(v for k, v in self.delimiters.items() if k not in exclude) + + def delimiter_count_with_priority(self, priority: Priority = 0) -> int: + """Return the number of delimiters with the given `priority`. + + If no `priority` is passed, defaults to max priority on the line. + """ + if not self.delimiters: + return 0 + + priority = priority or self.max_delimiter_priority() + return sum(1 for p in self.delimiters.values() if p == priority) + + def maybe_increment_for_loop_variable(self, leaf: Leaf) -> bool: + """In a for loop, or comprehension, the variables are often unpacks. + + To avoid splitting on the comma in this situation, increase the depth of + tokens between `for` and `in`. + """ + if leaf.type == token.NAME and leaf.value == "for": + self.depth += 1 + self._for_loop_depths.append(self.depth) + return True + + return False + + def maybe_decrement_after_for_loop_variable(self, leaf: Leaf) -> bool: + """See `maybe_increment_for_loop_variable` above for explanation.""" + if ( + self._for_loop_depths + and self._for_loop_depths[-1] == self.depth + and leaf.type == token.NAME + and leaf.value == "in" + ): + self.depth -= 1 + self._for_loop_depths.pop() + return True + + return False + + def maybe_increment_lambda_arguments(self, leaf: Leaf) -> bool: + """In a lambda expression, there might be more than one argument. + + To avoid splitting on the comma in this situation, increase the depth of + tokens between `lambda` and `:`. + """ + if leaf.type == token.NAME and leaf.value == "lambda": + self.depth += 1 + self._lambda_argument_depths.append(self.depth) + return True + + return False + + def maybe_decrement_after_lambda_arguments(self, leaf: Leaf) -> bool: + """See `maybe_increment_lambda_arguments` above for explanation.""" + if ( + self._lambda_argument_depths + and self._lambda_argument_depths[-1] == self.depth + and leaf.type == token.COLON + ): + self.depth -= 1 + self._lambda_argument_depths.pop() + return True + + return False + + def get_open_lsqb(self) -> Optional[Leaf]: + """Return the most recent opening square bracket (if any).""" + return self.bracket_match.get((self.depth - 1, token.RSQB)) + + +def is_split_after_delimiter(leaf: Leaf, previous: Optional[Leaf] = None) -> Priority: + """Return the priority of the `leaf` delimiter, given a line break after it. + + The delimiter priorities returned here are from those delimiters that would + cause a line break after themselves. + + Higher numbers are higher priority. + """ + if leaf.type == token.COMMA: + return COMMA_PRIORITY + + return 0 + + +def is_split_before_delimiter(leaf: Leaf, previous: Optional[Leaf] = None) -> Priority: + """Return the priority of the `leaf` delimiter, given a line break before it. + + The delimiter priorities returned here are from those delimiters that would + cause a line break before themselves. + + Higher numbers are higher priority. + """ + if is_vararg(leaf, within=VARARGS_PARENTS | UNPACKING_PARENTS): + # * and ** might also be MATH_OPERATORS but in this case they are not. + # Don't treat them as a delimiter. + return 0 + + if ( + leaf.type == token.DOT + and leaf.parent + and leaf.parent.type not in {syms.import_from, syms.dotted_name} + and (previous is None or previous.type in CLOSING_BRACKETS) + ): + return DOT_PRIORITY + + if ( + leaf.type in MATH_OPERATORS + and leaf.parent + and leaf.parent.type not in {syms.factor, syms.star_expr} + ): + return MATH_PRIORITIES[leaf.type] + + if leaf.type in COMPARATORS: + return COMPARATOR_PRIORITY + + if ( + leaf.type == token.STRING + and previous is not None + and previous.type == token.STRING + ): + return STRING_PRIORITY + + if leaf.type not in {token.NAME, token.ASYNC}: + return 0 + + if ( + leaf.value == "for" + and leaf.parent + and leaf.parent.type in {syms.comp_for, syms.old_comp_for} + or leaf.type == token.ASYNC + ): + if ( + not isinstance(leaf.prev_sibling, Leaf) + or leaf.prev_sibling.value != "async" + ): + return COMPREHENSION_PRIORITY + + if ( + leaf.value == "if" + and leaf.parent + and leaf.parent.type in {syms.comp_if, syms.old_comp_if} + ): + return COMPREHENSION_PRIORITY + + if leaf.value in {"if", "else"} and leaf.parent and leaf.parent.type == syms.test: + return TERNARY_PRIORITY + + if leaf.value == "is": + return COMPARATOR_PRIORITY + + if ( + leaf.value == "in" + and leaf.parent + and leaf.parent.type in {syms.comp_op, syms.comparison} + and not ( + previous is not None + and previous.type == token.NAME + and previous.value == "not" + ) + ): + return COMPARATOR_PRIORITY + + if ( + leaf.value == "not" + and leaf.parent + and leaf.parent.type == syms.comp_op + and not ( + previous is not None + and previous.type == token.NAME + and previous.value == "is" + ) + ): + return COMPARATOR_PRIORITY + + if leaf.value in LOGIC_OPERATORS and leaf.parent: + return LOGIC_PRIORITY + + return 0 + + +def max_delimiter_priority_in_atom(node: LN) -> Priority: + """Return maximum delimiter priority inside `node`. + + This is specific to atoms with contents contained in a pair of parentheses. + If `node` isn't an atom or there are no enclosing parentheses, returns 0. + """ + if node.type != syms.atom: + return 0 + + first = node.children[0] + last = node.children[-1] + if not (first.type == token.LPAR and last.type == token.RPAR): + return 0 + + bt = BracketTracker() + for c in node.children[1:-1]: + if isinstance(c, Leaf): + bt.mark(c) + else: + for leaf in c.leaves(): + bt.mark(leaf) + try: + return bt.max_delimiter_priority() + + except ValueError: + return 0 diff --git a/myenv/lib/python3.9/site-packages/black/cache.py b/myenv/lib/python3.9/site-packages/black/cache.py new file mode 100644 index 0000000..bca7279 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/cache.py @@ -0,0 +1,83 @@ +"""Caching of formatted files with feature-based invalidation.""" + +import os +import pickle +from pathlib import Path +import tempfile +from typing import Dict, Iterable, Set, Tuple + +from platformdirs import user_cache_dir + +from black.mode import Mode + +from _black_version import version as __version__ + + +# types +Timestamp = float +FileSize = int +CacheInfo = Tuple[Timestamp, FileSize] +Cache = Dict[str, CacheInfo] + + +CACHE_DIR = Path(user_cache_dir("black", version=__version__)) + + +def read_cache(mode: Mode) -> Cache: + """Read the cache if it exists and is well formed. + + If it is not well formed, the call to write_cache later should resolve the issue. + """ + cache_file = get_cache_file(mode) + if not cache_file.exists(): + return {} + + with cache_file.open("rb") as fobj: + try: + cache: Cache = pickle.load(fobj) + except (pickle.UnpicklingError, ValueError, IndexError): + return {} + + return cache + + +def get_cache_file(mode: Mode) -> Path: + return CACHE_DIR / f"cache.{mode.get_cache_key()}.pickle" + + +def get_cache_info(path: Path) -> CacheInfo: + """Return the information used to check if a file is already formatted or not.""" + stat = path.stat() + return stat.st_mtime, stat.st_size + + +def filter_cached(cache: Cache, sources: Iterable[Path]) -> Tuple[Set[Path], Set[Path]]: + """Split an iterable of paths in `sources` into two sets. + + The first contains paths of files that modified on disk or are not in the + cache. The other contains paths to non-modified files. + """ + todo, done = set(), set() + for src in sources: + res_src = src.resolve() + if cache.get(str(res_src)) != get_cache_info(res_src): + todo.add(src) + else: + done.add(src) + return todo, done + + +def write_cache(cache: Cache, sources: Iterable[Path], mode: Mode) -> None: + """Update the cache file.""" + cache_file = get_cache_file(mode) + try: + CACHE_DIR.mkdir(parents=True, exist_ok=True) + new_cache = { + **cache, + **{str(src.resolve()): get_cache_info(src) for src in sources}, + } + with tempfile.NamedTemporaryFile(dir=str(cache_file.parent), delete=False) as f: + pickle.dump(new_cache, f, protocol=4) + os.replace(f.name, cache_file) + except OSError: + pass diff --git a/myenv/lib/python3.9/site-packages/black/comments.py b/myenv/lib/python3.9/site-packages/black/comments.py new file mode 100644 index 0000000..28b9117 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/comments.py @@ -0,0 +1,277 @@ +import sys +from dataclasses import dataclass +from functools import lru_cache +import re +from typing import Iterator, List, Optional, Union + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +from blib2to3.pytree import Node, Leaf +from blib2to3.pgen2 import token + +from black.nodes import first_leaf_column, preceding_leaf, container_of +from black.nodes import STANDALONE_COMMENT, WHITESPACE + +# types +LN = Union[Leaf, Node] + +FMT_OFF: Final = {"# fmt: off", "# fmt:off", "# yapf: disable"} +FMT_SKIP: Final = {"# fmt: skip", "# fmt:skip"} +FMT_PASS: Final = {*FMT_OFF, *FMT_SKIP} +FMT_ON: Final = {"# fmt: on", "# fmt:on", "# yapf: enable"} + + +@dataclass +class ProtoComment: + """Describes a piece of syntax that is a comment. + + It's not a :class:`blib2to3.pytree.Leaf` so that: + + * it can be cached (`Leaf` objects should not be reused more than once as + they store their lineno, column, prefix, and parent information); + * `newlines` and `consumed` fields are kept separate from the `value`. This + simplifies handling of special marker comments like ``# fmt: off/on``. + """ + + type: int # token.COMMENT or STANDALONE_COMMENT + value: str # content of the comment + newlines: int # how many newlines before the comment + consumed: int # how many characters of the original leaf's prefix did we consume + + +def generate_comments(leaf: LN) -> Iterator[Leaf]: + """Clean the prefix of the `leaf` and generate comments from it, if any. + + Comments in lib2to3 are shoved into the whitespace prefix. This happens + in `pgen2/driver.py:Driver.parse_tokens()`. This was a brilliant implementation + move because it does away with modifying the grammar to include all the + possible places in which comments can be placed. + + The sad consequence for us though is that comments don't "belong" anywhere. + This is why this function generates simple parentless Leaf objects for + comments. We simply don't know what the correct parent should be. + + No matter though, we can live without this. We really only need to + differentiate between inline and standalone comments. The latter don't + share the line with any code. + + Inline comments are emitted as regular token.COMMENT leaves. Standalone + are emitted with a fake STANDALONE_COMMENT token identifier. + """ + for pc in list_comments(leaf.prefix, is_endmarker=leaf.type == token.ENDMARKER): + yield Leaf(pc.type, pc.value, prefix="\n" * pc.newlines) + + +@lru_cache(maxsize=4096) +def list_comments(prefix: str, *, is_endmarker: bool) -> List[ProtoComment]: + """Return a list of :class:`ProtoComment` objects parsed from the given `prefix`.""" + result: List[ProtoComment] = [] + if not prefix or "#" not in prefix: + return result + + consumed = 0 + nlines = 0 + ignored_lines = 0 + for index, line in enumerate(re.split("\r?\n", prefix)): + consumed += len(line) + 1 # adding the length of the split '\n' + line = line.lstrip() + if not line: + nlines += 1 + if not line.startswith("#"): + # Escaped newlines outside of a comment are not really newlines at + # all. We treat a single-line comment following an escaped newline + # as a simple trailing comment. + if line.endswith("\\"): + ignored_lines += 1 + continue + + if index == ignored_lines and not is_endmarker: + comment_type = token.COMMENT # simple trailing comment + else: + comment_type = STANDALONE_COMMENT + comment = make_comment(line) + result.append( + ProtoComment( + type=comment_type, value=comment, newlines=nlines, consumed=consumed + ) + ) + nlines = 0 + return result + + +def make_comment(content: str) -> str: + """Return a consistently formatted comment from the given `content` string. + + All comments (except for "##", "#!", "#:", '#'", "#%%") should have a single + space between the hash sign and the content. + + If `content` didn't start with a hash sign, one is provided. + """ + content = content.rstrip() + if not content: + return "#" + + if content[0] == "#": + content = content[1:] + NON_BREAKING_SPACE = " " + if ( + content + and content[0] == NON_BREAKING_SPACE + and not content.lstrip().startswith("type:") + ): + content = " " + content[1:] # Replace NBSP by a simple space + if content and content[0] not in " !:#'%": + content = " " + content + return "#" + content + + +def normalize_fmt_off(node: Node) -> None: + """Convert content between `# fmt: off`/`# fmt: on` into standalone comments.""" + try_again = True + while try_again: + try_again = convert_one_fmt_off_pair(node) + + +def convert_one_fmt_off_pair(node: Node) -> bool: + """Convert content of a single `# fmt: off`/`# fmt: on` into a standalone comment. + + Returns True if a pair was converted. + """ + for leaf in node.leaves(): + previous_consumed = 0 + for comment in list_comments(leaf.prefix, is_endmarker=False): + if comment.value not in FMT_PASS: + previous_consumed = comment.consumed + continue + # We only want standalone comments. If there's no previous leaf or + # the previous leaf is indentation, it's a standalone comment in + # disguise. + if comment.value in FMT_PASS and comment.type != STANDALONE_COMMENT: + prev = preceding_leaf(leaf) + if prev: + if comment.value in FMT_OFF and prev.type not in WHITESPACE: + continue + if comment.value in FMT_SKIP and prev.type in WHITESPACE: + continue + + ignored_nodes = list(generate_ignored_nodes(leaf, comment)) + if not ignored_nodes: + continue + + first = ignored_nodes[0] # Can be a container node with the `leaf`. + parent = first.parent + prefix = first.prefix + if comment.value in FMT_OFF: + first.prefix = prefix[comment.consumed :] + if comment.value in FMT_SKIP: + first.prefix = "" + hidden_value = "".join(str(n) for n in ignored_nodes) + if comment.value in FMT_OFF: + hidden_value = comment.value + "\n" + hidden_value + if comment.value in FMT_SKIP: + hidden_value += " " + comment.value + if hidden_value.endswith("\n"): + # That happens when one of the `ignored_nodes` ended with a NEWLINE + # leaf (possibly followed by a DEDENT). + hidden_value = hidden_value[:-1] + first_idx: Optional[int] = None + for ignored in ignored_nodes: + index = ignored.remove() + if first_idx is None: + first_idx = index + assert parent is not None, "INTERNAL ERROR: fmt: on/off handling (1)" + assert first_idx is not None, "INTERNAL ERROR: fmt: on/off handling (2)" + parent.insert_child( + first_idx, + Leaf( + STANDALONE_COMMENT, + hidden_value, + prefix=prefix[:previous_consumed] + "\n" * comment.newlines, + ), + ) + return True + + return False + + +def generate_ignored_nodes(leaf: Leaf, comment: ProtoComment) -> Iterator[LN]: + """Starting from the container of `leaf`, generate all leaves until `# fmt: on`. + + If comment is skip, returns leaf only. + Stops at the end of the block. + """ + container: Optional[LN] = container_of(leaf) + if comment.value in FMT_SKIP: + prev_sibling = leaf.prev_sibling + if comment.value in leaf.prefix and prev_sibling is not None: + leaf.prefix = leaf.prefix.replace(comment.value, "") + siblings = [prev_sibling] + while ( + "\n" not in prev_sibling.prefix + and prev_sibling.prev_sibling is not None + ): + prev_sibling = prev_sibling.prev_sibling + siblings.insert(0, prev_sibling) + for sibling in siblings: + yield sibling + elif leaf.parent is not None: + yield leaf.parent + return + while container is not None and container.type != token.ENDMARKER: + if is_fmt_on(container): + return + + # fix for fmt: on in children + if contains_fmt_on_at_column(container, leaf.column): + for child in container.children: + if contains_fmt_on_at_column(child, leaf.column): + return + yield child + else: + yield container + container = container.next_sibling + + +def is_fmt_on(container: LN) -> bool: + """Determine whether formatting is switched on within a container. + Determined by whether the last `# fmt:` comment is `on` or `off`. + """ + fmt_on = False + for comment in list_comments(container.prefix, is_endmarker=False): + if comment.value in FMT_ON: + fmt_on = True + elif comment.value in FMT_OFF: + fmt_on = False + return fmt_on + + +def contains_fmt_on_at_column(container: LN, column: int) -> bool: + """Determine if children at a given column have formatting switched on.""" + for child in container.children: + if ( + isinstance(child, Node) + and first_leaf_column(child) == column + or isinstance(child, Leaf) + and child.column == column + ): + if is_fmt_on(child): + return True + + return False + + +def contains_pragma_comment(comment_list: List[Leaf]) -> bool: + """ + Returns: + True iff one of the comments in @comment_list is a pragma used by one + of the more common static analysis tools for python (e.g. mypy, flake8, + pylint). + """ + for comment in comment_list: + if comment.value.startswith(("# type:", "# noqa", "# pylint:")): + return True + + return False diff --git a/myenv/lib/python3.9/site-packages/black/concurrency.py b/myenv/lib/python3.9/site-packages/black/concurrency.py new file mode 100644 index 0000000..24f67b6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/concurrency.py @@ -0,0 +1,57 @@ +import asyncio +import logging +import sys +from typing import Any, Iterable + +from black.output import err + + +def maybe_install_uvloop() -> None: + """If our environment has uvloop installed we use it. + + This is called only from command-line entry points to avoid + interfering with the parent process if Black is used as a library. + + """ + try: + import uvloop + + uvloop.install() + except ImportError: + pass + + +def cancel(tasks: Iterable["asyncio.Task[Any]"]) -> None: + """asyncio signal handler that cancels all `tasks` and reports to stderr.""" + err("Aborted!") + for task in tasks: + task.cancel() + + +def shutdown(loop: asyncio.AbstractEventLoop) -> None: + """Cancel all pending tasks on `loop`, wait for them, and close the loop.""" + try: + if sys.version_info[:2] >= (3, 7): + all_tasks = asyncio.all_tasks + else: + all_tasks = asyncio.Task.all_tasks + # This part is borrowed from asyncio/runners.py in Python 3.7b2. + to_cancel = [task for task in all_tasks(loop) if not task.done()] + if not to_cancel: + return + + for task in to_cancel: + task.cancel() + if sys.version_info >= (3, 7): + loop.run_until_complete(asyncio.gather(*to_cancel, return_exceptions=True)) + else: + loop.run_until_complete( + asyncio.gather(*to_cancel, loop=loop, return_exceptions=True) + ) + finally: + # `concurrent.futures.Future` objects cannot be cancelled once they + # are already running. There might be some when the `shutdown()` happened. + # Silence their logger's spew about the event loop being closed. + cf_logger = logging.getLogger("concurrent.futures") + cf_logger.setLevel(logging.CRITICAL) + loop.close() diff --git a/myenv/lib/python3.9/site-packages/black/const.py b/myenv/lib/python3.9/site-packages/black/const.py new file mode 100644 index 0000000..dbb4826 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/const.py @@ -0,0 +1,4 @@ +DEFAULT_LINE_LENGTH = 88 +DEFAULT_EXCLUDES = r"/(\.direnv|\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|venv|\.svn|_build|buck-out|build|dist)/" # noqa: B950 +DEFAULT_INCLUDES = r"(\.pyi?|\.ipynb)$" +STDIN_PLACEHOLDER = "__BLACK_STDIN_FILENAME__" diff --git a/myenv/lib/python3.9/site-packages/black/debug.py b/myenv/lib/python3.9/site-packages/black/debug.py new file mode 100644 index 0000000..5143076 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/debug.py @@ -0,0 +1,48 @@ +from dataclasses import dataclass +from typing import Iterator, TypeVar, Union + +from blib2to3.pytree import Node, Leaf, type_repr +from blib2to3.pgen2 import token + +from black.nodes import Visitor +from black.output import out +from black.parsing import lib2to3_parse + +LN = Union[Leaf, Node] +T = TypeVar("T") + + +@dataclass +class DebugVisitor(Visitor[T]): + tree_depth: int = 0 + + def visit_default(self, node: LN) -> Iterator[T]: + indent = " " * (2 * self.tree_depth) + if isinstance(node, Node): + _type = type_repr(node.type) + out(f"{indent}{_type}", fg="yellow") + self.tree_depth += 1 + for child in node.children: + yield from self.visit(child) + + self.tree_depth -= 1 + out(f"{indent}/{_type}", fg="yellow", bold=False) + else: + _type = token.tok_name.get(node.type, str(node.type)) + out(f"{indent}{_type}", fg="blue", nl=False) + if node.prefix: + # We don't have to handle prefixes for `Node` objects since + # that delegates to the first child anyway. + out(f" {node.prefix!r}", fg="green", bold=False, nl=False) + out(f" {node.value!r}", fg="blue", bold=False) + + @classmethod + def show(cls, code: Union[str, Leaf, Node]) -> None: + """Pretty-print the lib2to3 AST of a given string of `code`. + + Convenience method for debugging. + """ + v: DebugVisitor[None] = DebugVisitor() + if isinstance(code, str): + code = lib2to3_parse(code) + list(v.visit(code)) diff --git a/myenv/lib/python3.9/site-packages/black/files.py b/myenv/lib/python3.9/site-packages/black/files.py new file mode 100644 index 0000000..560aa05 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/files.py @@ -0,0 +1,261 @@ +from functools import lru_cache +import io +import os +from pathlib import Path +import sys +from typing import ( + Any, + Dict, + Iterable, + Iterator, + List, + Optional, + Pattern, + Sequence, + Tuple, + Union, + TYPE_CHECKING, +) + +from mypy_extensions import mypyc_attr +from pathspec import PathSpec +from pathspec.patterns.gitwildmatch import GitWildMatchPatternError +import tomli + +from black.output import err +from black.report import Report +from black.handle_ipynb_magics import jupyter_dependencies_are_installed + +if TYPE_CHECKING: + import colorama # noqa: F401 + + +@lru_cache() +def find_project_root(srcs: Sequence[str]) -> Path: + """Return a directory containing .git, .hg, or pyproject.toml. + + That directory will be a common parent of all files and directories + passed in `srcs`. + + If no directory in the tree contains a marker that would specify it's the + project root, the root of the file system is returned. + """ + if not srcs: + srcs = [str(Path.cwd().resolve())] + + path_srcs = [Path(Path.cwd(), src).resolve() for src in srcs] + + # A list of lists of parents for each 'src'. 'src' is included as a + # "parent" of itself if it is a directory + src_parents = [ + list(path.parents) + ([path] if path.is_dir() else []) for path in path_srcs + ] + + common_base = max( + set.intersection(*(set(parents) for parents in src_parents)), + key=lambda path: path.parts, + ) + + for directory in (common_base, *common_base.parents): + if (directory / ".git").exists(): + return directory + + if (directory / ".hg").is_dir(): + return directory + + if (directory / "pyproject.toml").is_file(): + return directory + + return directory + + +def find_pyproject_toml(path_search_start: Tuple[str, ...]) -> Optional[str]: + """Find the absolute filepath to a pyproject.toml if it exists""" + path_project_root = find_project_root(path_search_start) + path_pyproject_toml = path_project_root / "pyproject.toml" + if path_pyproject_toml.is_file(): + return str(path_pyproject_toml) + + try: + path_user_pyproject_toml = find_user_pyproject_toml() + return ( + str(path_user_pyproject_toml) + if path_user_pyproject_toml.is_file() + else None + ) + except PermissionError as e: + # We do not have access to the user-level config directory, so ignore it. + err(f"Ignoring user configuration directory due to {e!r}") + return None + + +@mypyc_attr(patchable=True) +def parse_pyproject_toml(path_config: str) -> Dict[str, Any]: + """Parse a pyproject toml file, pulling out relevant parts for Black + + If parsing fails, will raise a tomli.TOMLDecodeError + """ + with open(path_config, encoding="utf8") as f: + pyproject_toml = tomli.loads(f.read()) + config = pyproject_toml.get("tool", {}).get("black", {}) + return {k.replace("--", "").replace("-", "_"): v for k, v in config.items()} + + +@lru_cache() +def find_user_pyproject_toml() -> Path: + r"""Return the path to the top-level user configuration for black. + + This looks for ~\.black on Windows and ~/.config/black on Linux and other + Unix systems. + """ + if sys.platform == "win32": + # Windows + user_config_path = Path.home() / ".black" + else: + config_root = os.environ.get("XDG_CONFIG_HOME", "~/.config") + user_config_path = Path(config_root).expanduser() / "black" + return user_config_path.resolve() + + +@lru_cache() +def get_gitignore(root: Path) -> PathSpec: + """Return a PathSpec matching gitignore content if present.""" + gitignore = root / ".gitignore" + lines: List[str] = [] + if gitignore.is_file(): + with gitignore.open(encoding="utf-8") as gf: + lines = gf.readlines() + try: + return PathSpec.from_lines("gitwildmatch", lines) + except GitWildMatchPatternError as e: + err(f"Could not parse {gitignore}: {e}") + raise + + +def normalize_path_maybe_ignore( + path: Path, root: Path, report: Report +) -> Optional[str]: + """Normalize `path`. May return `None` if `path` was ignored. + + `report` is where "path ignored" output goes. + """ + try: + abspath = path if path.is_absolute() else Path.cwd() / path + normalized_path = abspath.resolve().relative_to(root).as_posix() + except OSError as e: + report.path_ignored(path, f"cannot be read because {e}") + return None + + except ValueError: + if path.is_symlink(): + report.path_ignored(path, f"is a symbolic link that points outside {root}") + return None + + raise + + return normalized_path + + +def path_is_excluded( + normalized_path: str, + pattern: Optional[Pattern[str]], +) -> bool: + match = pattern.search(normalized_path) if pattern else None + return bool(match and match.group(0)) + + +def gen_python_files( + paths: Iterable[Path], + root: Path, + include: Pattern[str], + exclude: Pattern[str], + extend_exclude: Optional[Pattern[str]], + force_exclude: Optional[Pattern[str]], + report: Report, + gitignore: Optional[PathSpec], + *, + verbose: bool, + quiet: bool, +) -> Iterator[Path]: + """Generate all files under `path` whose paths are not excluded by the + `exclude_regex`, `extend_exclude`, or `force_exclude` regexes, + but are included by the `include` regex. + + Symbolic links pointing outside of the `root` directory are ignored. + + `report` is where output about exclusions goes. + """ + assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}" + for child in paths: + normalized_path = normalize_path_maybe_ignore(child, root, report) + if normalized_path is None: + continue + + # First ignore files matching .gitignore, if passed + if gitignore is not None and gitignore.match_file(normalized_path): + report.path_ignored(child, "matches the .gitignore file content") + continue + + # Then ignore with `--exclude` `--extend-exclude` and `--force-exclude` options. + normalized_path = "/" + normalized_path + if child.is_dir(): + normalized_path += "/" + + if path_is_excluded(normalized_path, exclude): + report.path_ignored(child, "matches the --exclude regular expression") + continue + + if path_is_excluded(normalized_path, extend_exclude): + report.path_ignored( + child, "matches the --extend-exclude regular expression" + ) + continue + + if path_is_excluded(normalized_path, force_exclude): + report.path_ignored(child, "matches the --force-exclude regular expression") + continue + + if child.is_dir(): + # If gitignore is None, gitignore usage is disabled, while a Falsey + # gitignore is when the directory doesn't have a .gitignore file. + yield from gen_python_files( + child.iterdir(), + root, + include, + exclude, + extend_exclude, + force_exclude, + report, + gitignore + get_gitignore(child) if gitignore is not None else None, + verbose=verbose, + quiet=quiet, + ) + + elif child.is_file(): + if child.suffix == ".ipynb" and not jupyter_dependencies_are_installed( + verbose=verbose, quiet=quiet + ): + continue + include_match = include.search(normalized_path) if include else True + if include_match: + yield child + + +def wrap_stream_for_windows( + f: io.TextIOWrapper, +) -> Union[io.TextIOWrapper, "colorama.AnsiToWin32"]: + """ + Wrap stream with colorama's wrap_stream so colors are shown on Windows. + + If `colorama` is unavailable, the original stream is returned unmodified. + Otherwise, the `wrap_stream()` function determines whether the stream needs + to be wrapped for a Windows environment and will accordingly either return + an `AnsiToWin32` wrapper or the original stream. + """ + try: + from colorama.initialise import wrap_stream + except ImportError: + return f + else: + # Set `strip=False` to avoid needing to modify test_express_diff_with_color. + return wrap_stream(f, convert=None, strip=False, autoreset=False, wrap=True) diff --git a/myenv/lib/python3.9/site-packages/black/handle_ipynb_magics.py b/myenv/lib/python3.9/site-packages/black/handle_ipynb_magics.py new file mode 100644 index 0000000..a0ed56b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/handle_ipynb_magics.py @@ -0,0 +1,465 @@ +"""Functions to process IPython magics with.""" + +from functools import lru_cache +import dataclasses +import ast +from typing import Dict, List, Tuple, Optional + +import secrets +import sys +import collections + +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: + from typing_extensions import TypeGuard + +from black.report import NothingChanged +from black.output import out + + +TRANSFORMED_MAGICS = frozenset( + ( + "get_ipython().run_cell_magic", + "get_ipython().system", + "get_ipython().getoutput", + "get_ipython().run_line_magic", + ) +) +TOKENS_TO_IGNORE = frozenset( + ( + "ENDMARKER", + "NL", + "NEWLINE", + "COMMENT", + "DEDENT", + "UNIMPORTANT_WS", + "ESCAPED_NL", + ) +) +PYTHON_CELL_MAGICS = frozenset( + ( + "capture", + "prun", + "pypy", + "python", + "python3", + "time", + "timeit", + ) +) +TOKEN_HEX = secrets.token_hex + + +@dataclasses.dataclass(frozen=True) +class Replacement: + mask: str + src: str + + +@lru_cache() +def jupyter_dependencies_are_installed(*, verbose: bool, quiet: bool) -> bool: + try: + import IPython # noqa:F401 + import tokenize_rt # noqa:F401 + except ModuleNotFoundError: + if verbose or not quiet: + msg = ( + "Skipping .ipynb files as Jupyter dependencies are not installed.\n" + "You can fix this by running ``pip install black[jupyter]``" + ) + out(msg) + return False + else: + return True + + +def remove_trailing_semicolon(src: str) -> Tuple[str, bool]: + """Remove trailing semicolon from Jupyter notebook cell. + + For example, + + fig, ax = plt.subplots() + ax.plot(x_data, y_data); # plot data + + would become + + fig, ax = plt.subplots() + ax.plot(x_data, y_data) # plot data + + Mirrors the logic in `quiet` from `IPython.core.displayhook`, but uses + ``tokenize_rt`` so that round-tripping works fine. + """ + from tokenize_rt import ( + src_to_tokens, + tokens_to_src, + reversed_enumerate, + ) + + tokens = src_to_tokens(src) + trailing_semicolon = False + for idx, token in reversed_enumerate(tokens): + if token.name in TOKENS_TO_IGNORE: + continue + if token.name == "OP" and token.src == ";": + del tokens[idx] + trailing_semicolon = True + break + if not trailing_semicolon: + return src, False + return tokens_to_src(tokens), True + + +def put_trailing_semicolon_back(src: str, has_trailing_semicolon: bool) -> str: + """Put trailing semicolon back if cell originally had it. + + Mirrors the logic in `quiet` from `IPython.core.displayhook`, but uses + ``tokenize_rt`` so that round-tripping works fine. + """ + if not has_trailing_semicolon: + return src + from tokenize_rt import src_to_tokens, tokens_to_src, reversed_enumerate + + tokens = src_to_tokens(src) + for idx, token in reversed_enumerate(tokens): + if token.name in TOKENS_TO_IGNORE: + continue + tokens[idx] = token._replace(src=token.src + ";") + break + else: # pragma: nocover + raise AssertionError( + "INTERNAL ERROR: Was not able to reinstate trailing semicolon. " + "Please report a bug on https://github.com/psf/black/issues. " + ) from None + return str(tokens_to_src(tokens)) + + +def mask_cell(src: str) -> Tuple[str, List[Replacement]]: + """Mask IPython magics so content becomes parseable Python code. + + For example, + + %matplotlib inline + 'foo' + + becomes + + "25716f358c32750e" + 'foo' + + The replacements are returned, along with the transformed code. + """ + replacements: List[Replacement] = [] + try: + ast.parse(src) + except SyntaxError: + # Might have IPython magics, will process below. + pass + else: + # Syntax is fine, nothing to mask, early return. + return src, replacements + + from IPython.core.inputtransformer2 import TransformerManager + + transformer_manager = TransformerManager() + transformed = transformer_manager.transform_cell(src) + transformed, cell_magic_replacements = replace_cell_magics(transformed) + replacements += cell_magic_replacements + transformed = transformer_manager.transform_cell(transformed) + transformed, magic_replacements = replace_magics(transformed) + if len(transformed.splitlines()) != len(src.splitlines()): + # Multi-line magic, not supported. + raise NothingChanged + replacements += magic_replacements + return transformed, replacements + + +def get_token(src: str, magic: str) -> str: + """Return randomly generated token to mask IPython magic with. + + For example, if 'magic' was `%matplotlib inline`, then a possible + token to mask it with would be `"43fdd17f7e5ddc83"`. The token + will be the same length as the magic, and we make sure that it was + not already present anywhere else in the cell. + """ + assert magic + nbytes = max(len(magic) // 2 - 1, 1) + token = TOKEN_HEX(nbytes) + counter = 0 + while token in src: + token = TOKEN_HEX(nbytes) + counter += 1 + if counter > 100: + raise AssertionError( + "INTERNAL ERROR: Black was not able to replace IPython magic. " + "Please report a bug on https://github.com/psf/black/issues. " + f"The magic might be helpful: {magic}" + ) from None + if len(token) + 2 < len(magic): + token = f"{token}." + return f'"{token}"' + + +def replace_cell_magics(src: str) -> Tuple[str, List[Replacement]]: + """Replace cell magic with token. + + Note that 'src' will already have been processed by IPython's + TransformerManager().transform_cell. + + Example, + + get_ipython().run_cell_magic('t', '-n1', 'ls =!ls\\n') + + becomes + + "a794." + ls =!ls + + The replacement, along with the transformed code, is returned. + """ + replacements: List[Replacement] = [] + + tree = ast.parse(src) + + cell_magic_finder = CellMagicFinder() + cell_magic_finder.visit(tree) + if cell_magic_finder.cell_magic is None: + return src, replacements + header = cell_magic_finder.cell_magic.header + mask = get_token(src, header) + replacements.append(Replacement(mask=mask, src=header)) + return f"{mask}\n{cell_magic_finder.cell_magic.body}", replacements + + +def replace_magics(src: str) -> Tuple[str, List[Replacement]]: + """Replace magics within body of cell. + + Note that 'src' will already have been processed by IPython's + TransformerManager().transform_cell. + + Example, this + + get_ipython().run_line_magic('matplotlib', 'inline') + 'foo' + + becomes + + "5e67db56d490fd39" + 'foo' + + The replacement, along with the transformed code, are returned. + """ + replacements = [] + magic_finder = MagicFinder() + magic_finder.visit(ast.parse(src)) + new_srcs = [] + for i, line in enumerate(src.splitlines(), start=1): + if i in magic_finder.magics: + offsets_and_magics = magic_finder.magics[i] + if len(offsets_and_magics) != 1: # pragma: nocover + raise AssertionError( + f"Expecting one magic per line, got: {offsets_and_magics}\n" + "Please report a bug on https://github.com/psf/black/issues." + ) + col_offset, magic = ( + offsets_and_magics[0].col_offset, + offsets_and_magics[0].magic, + ) + mask = get_token(src, magic) + replacements.append(Replacement(mask=mask, src=magic)) + line = line[:col_offset] + mask + new_srcs.append(line) + return "\n".join(new_srcs), replacements + + +def unmask_cell(src: str, replacements: List[Replacement]) -> str: + """Remove replacements from cell. + + For example + + "9b20" + foo = bar + + becomes + + %%time + foo = bar + """ + for replacement in replacements: + src = src.replace(replacement.mask, replacement.src) + return src + + +def _is_ipython_magic(node: ast.expr) -> TypeGuard[ast.Attribute]: + """Check if attribute is IPython magic. + + Note that the source of the abstract syntax tree + will already have been processed by IPython's + TransformerManager().transform_cell. + """ + return ( + isinstance(node, ast.Attribute) + and isinstance(node.value, ast.Call) + and isinstance(node.value.func, ast.Name) + and node.value.func.id == "get_ipython" + ) + + +def _get_str_args(args: List[ast.expr]) -> List[str]: + str_args = [] + for arg in args: + assert isinstance(arg, ast.Str) + str_args.append(arg.s) + return str_args + + +@dataclasses.dataclass(frozen=True) +class CellMagic: + name: str + params: Optional[str] + body: str + + @property + def header(self) -> str: + if self.params: + return f"%%{self.name} {self.params}" + return f"%%{self.name}" + + +# ast.NodeVisitor + dataclass = breakage under mypyc. +class CellMagicFinder(ast.NodeVisitor): + """Find cell magics. + + Note that the source of the abstract syntax tree + will already have been processed by IPython's + TransformerManager().transform_cell. + + For example, + + %%time\nfoo() + + would have been transformed to + + get_ipython().run_cell_magic('time', '', 'foo()\\n') + + and we look for instances of the latter. + """ + + def __init__(self, cell_magic: Optional[CellMagic] = None) -> None: + self.cell_magic = cell_magic + + def visit_Expr(self, node: ast.Expr) -> None: + """Find cell magic, extract header and body.""" + if ( + isinstance(node.value, ast.Call) + and _is_ipython_magic(node.value.func) + and node.value.func.attr == "run_cell_magic" + ): + args = _get_str_args(node.value.args) + self.cell_magic = CellMagic(name=args[0], params=args[1], body=args[2]) + self.generic_visit(node) + + +@dataclasses.dataclass(frozen=True) +class OffsetAndMagic: + col_offset: int + magic: str + + +# Unsurprisingly, subclassing ast.NodeVisitor means we can't use dataclasses here +# as mypyc will generate broken code. +class MagicFinder(ast.NodeVisitor): + """Visit cell to look for get_ipython calls. + + Note that the source of the abstract syntax tree + will already have been processed by IPython's + TransformerManager().transform_cell. + + For example, + + %matplotlib inline + + would have been transformed to + + get_ipython().run_line_magic('matplotlib', 'inline') + + and we look for instances of the latter (and likewise for other + types of magics). + """ + + def __init__(self) -> None: + self.magics: Dict[int, List[OffsetAndMagic]] = collections.defaultdict(list) + + def visit_Assign(self, node: ast.Assign) -> None: + """Look for system assign magics. + + For example, + + black_version = !black --version + env = %env var + + would have been (respectively) transformed to + + black_version = get_ipython().getoutput('black --version') + env = get_ipython().run_line_magic('env', 'var') + + and we look for instances of any of the latter. + """ + if isinstance(node.value, ast.Call) and _is_ipython_magic(node.value.func): + args = _get_str_args(node.value.args) + if node.value.func.attr == "getoutput": + src = f"!{args[0]}" + elif node.value.func.attr == "run_line_magic": + src = f"%{args[0]}" + if args[1]: + src += f" {args[1]}" + else: + raise AssertionError( + f"Unexpected IPython magic {node.value.func.attr!r} found. " + "Please report a bug on https://github.com/psf/black/issues." + ) from None + self.magics[node.value.lineno].append( + OffsetAndMagic(node.value.col_offset, src) + ) + self.generic_visit(node) + + def visit_Expr(self, node: ast.Expr) -> None: + """Look for magics in body of cell. + + For examples, + + !ls + !!ls + ?ls + ??ls + + would (respectively) get transformed to + + get_ipython().system('ls') + get_ipython().getoutput('ls') + get_ipython().run_line_magic('pinfo', 'ls') + get_ipython().run_line_magic('pinfo2', 'ls') + + and we look for instances of any of the latter. + """ + if isinstance(node.value, ast.Call) and _is_ipython_magic(node.value.func): + args = _get_str_args(node.value.args) + if node.value.func.attr == "run_line_magic": + if args[0] == "pinfo": + src = f"?{args[1]}" + elif args[0] == "pinfo2": + src = f"??{args[1]}" + else: + src = f"%{args[0]}" + if args[1]: + src += f" {args[1]}" + elif node.value.func.attr == "system": + src = f"!{args[0]}" + elif node.value.func.attr == "getoutput": + src = f"!!{args[0]}" + else: + raise NothingChanged # unsupported magic. + self.magics[node.value.lineno].append( + OffsetAndMagic(node.value.col_offset, src) + ) + self.generic_visit(node) diff --git a/myenv/lib/python3.9/site-packages/black/linegen.py b/myenv/lib/python3.9/site-packages/black/linegen.py new file mode 100644 index 0000000..f234913 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/linegen.py @@ -0,0 +1,1025 @@ +""" +Generating lines of code. +""" +from functools import partial, wraps +import sys +from typing import Collection, Iterator, List, Optional, Set, Union + +from black.nodes import WHITESPACE, RARROW, STATEMENT, STANDALONE_COMMENT +from black.nodes import ASSIGNMENTS, OPENING_BRACKETS, CLOSING_BRACKETS +from black.nodes import Visitor, syms, first_child_is_arith, ensure_visible +from black.nodes import is_docstring, is_empty_tuple, is_one_tuple, is_one_tuple_between +from black.nodes import is_walrus_assignment, is_yield, is_vararg, is_multiline_string +from black.nodes import is_stub_suite, is_stub_body, is_atom_with_invisible_parens +from black.nodes import wrap_in_parentheses +from black.brackets import max_delimiter_priority_in_atom +from black.brackets import DOT_PRIORITY, COMMA_PRIORITY +from black.lines import Line, line_to_string, is_line_short_enough +from black.lines import can_omit_invisible_parens, can_be_split, append_leaves +from black.comments import generate_comments, list_comments, FMT_OFF +from black.numerics import normalize_numeric_literal +from black.strings import get_string_prefix, fix_docstring +from black.strings import normalize_string_prefix, normalize_string_quotes +from black.trans import Transformer, CannotTransform, StringMerger +from black.trans import StringSplitter, StringParenWrapper, StringParenStripper +from black.mode import Mode +from black.mode import Feature + +from blib2to3.pytree import Node, Leaf +from blib2to3.pgen2 import token + + +# types +LeafID = int +LN = Union[Leaf, Node] + + +class CannotSplit(CannotTransform): + """A readable split that fits the allotted line length is impossible.""" + + +# This isn't a dataclass because @dataclass + Generic breaks mypyc. +# See also https://github.com/mypyc/mypyc/issues/827. +class LineGenerator(Visitor[Line]): + """Generates reformatted Line objects. Empty lines are not emitted. + + Note: destroys the tree it's visiting by mutating prefixes of its leaves + in ways that will no longer stringify to valid Python code on the tree. + """ + + def __init__(self, mode: Mode, remove_u_prefix: bool = False) -> None: + self.mode = mode + self.remove_u_prefix = remove_u_prefix + self.current_line: Line + self.__post_init__() + + def line(self, indent: int = 0) -> Iterator[Line]: + """Generate a line. + + If the line is empty, only emit if it makes sense. + If the line is too long, split it first and then generate. + + If any lines were generated, set up a new current_line. + """ + if not self.current_line: + self.current_line.depth += indent + return # Line is empty, don't emit. Creating a new one unnecessary. + + complete_line = self.current_line + self.current_line = Line(mode=self.mode, depth=complete_line.depth + indent) + yield complete_line + + def visit_default(self, node: LN) -> Iterator[Line]: + """Default `visit_*()` implementation. Recurses to children of `node`.""" + if isinstance(node, Leaf): + any_open_brackets = self.current_line.bracket_tracker.any_open_brackets() + for comment in generate_comments(node): + if any_open_brackets: + # any comment within brackets is subject to splitting + self.current_line.append(comment) + elif comment.type == token.COMMENT: + # regular trailing comment + self.current_line.append(comment) + yield from self.line() + + else: + # regular standalone comment + yield from self.line() + + self.current_line.append(comment) + yield from self.line() + + normalize_prefix(node, inside_brackets=any_open_brackets) + if self.mode.string_normalization and node.type == token.STRING: + node.value = normalize_string_prefix( + node.value, remove_u_prefix=self.remove_u_prefix + ) + node.value = normalize_string_quotes(node.value) + if node.type == token.NUMBER: + normalize_numeric_literal(node) + if node.type not in WHITESPACE: + self.current_line.append(node) + yield from super().visit_default(node) + + def visit_INDENT(self, node: Leaf) -> Iterator[Line]: + """Increase indentation level, maybe yield a line.""" + # In blib2to3 INDENT never holds comments. + yield from self.line(+1) + yield from self.visit_default(node) + + def visit_DEDENT(self, node: Leaf) -> Iterator[Line]: + """Decrease indentation level, maybe yield a line.""" + # The current line might still wait for trailing comments. At DEDENT time + # there won't be any (they would be prefixes on the preceding NEWLINE). + # Emit the line then. + yield from self.line() + + # While DEDENT has no value, its prefix may contain standalone comments + # that belong to the current indentation level. Get 'em. + yield from self.visit_default(node) + + # Finally, emit the dedent. + yield from self.line(-1) + + def visit_stmt( + self, node: Node, keywords: Set[str], parens: Set[str] + ) -> Iterator[Line]: + """Visit a statement. + + This implementation is shared for `if`, `while`, `for`, `try`, `except`, + `def`, `with`, `class`, `assert`, and assignments. + + The relevant Python language `keywords` for a given statement will be + NAME leaves within it. This methods puts those on a separate line. + + `parens` holds a set of string leaf values immediately after which + invisible parens should be put. + """ + normalize_invisible_parens(node, parens_after=parens) + for child in node.children: + if child.type == token.NAME and child.value in keywords: # type: ignore + yield from self.line() + + yield from self.visit(child) + + def visit_match_case(self, node: Node) -> Iterator[Line]: + """Visit either a match or case statement.""" + normalize_invisible_parens(node, parens_after=set()) + + yield from self.line() + for child in node.children: + yield from self.visit(child) + + def visit_suite(self, node: Node) -> Iterator[Line]: + """Visit a suite.""" + if self.mode.is_pyi and is_stub_suite(node): + yield from self.visit(node.children[2]) + else: + yield from self.visit_default(node) + + def visit_simple_stmt(self, node: Node) -> Iterator[Line]: + """Visit a statement without nested statements.""" + if first_child_is_arith(node): + wrap_in_parentheses(node, node.children[0], visible=False) + is_suite_like = node.parent and node.parent.type in STATEMENT + if is_suite_like: + if self.mode.is_pyi and is_stub_body(node): + yield from self.visit_default(node) + else: + yield from self.line(+1) + yield from self.visit_default(node) + yield from self.line(-1) + + else: + if ( + not self.mode.is_pyi + or not node.parent + or not is_stub_suite(node.parent) + ): + yield from self.line() + yield from self.visit_default(node) + + def visit_async_stmt(self, node: Node) -> Iterator[Line]: + """Visit `async def`, `async for`, `async with`.""" + yield from self.line() + + children = iter(node.children) + for child in children: + yield from self.visit(child) + + if child.type == token.ASYNC: + break + + internal_stmt = next(children) + for child in internal_stmt.children: + yield from self.visit(child) + + def visit_decorators(self, node: Node) -> Iterator[Line]: + """Visit decorators.""" + for child in node.children: + yield from self.line() + yield from self.visit(child) + + def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]: + """Remove a semicolon and put the other statement on a separate line.""" + yield from self.line() + + def visit_ENDMARKER(self, leaf: Leaf) -> Iterator[Line]: + """End of file. Process outstanding comments and end with a newline.""" + yield from self.visit_default(leaf) + yield from self.line() + + def visit_STANDALONE_COMMENT(self, leaf: Leaf) -> Iterator[Line]: + if not self.current_line.bracket_tracker.any_open_brackets(): + yield from self.line() + yield from self.visit_default(leaf) + + def visit_factor(self, node: Node) -> Iterator[Line]: + """Force parentheses between a unary op and a binary power: + + -2 ** 8 -> -(2 ** 8) + """ + _operator, operand = node.children + if ( + operand.type == syms.power + and len(operand.children) == 3 + and operand.children[1].type == token.DOUBLESTAR + ): + lpar = Leaf(token.LPAR, "(") + rpar = Leaf(token.RPAR, ")") + index = operand.remove() or 0 + node.insert_child(index, Node(syms.atom, [lpar, operand, rpar])) + yield from self.visit_default(node) + + def visit_STRING(self, leaf: Leaf) -> Iterator[Line]: + if is_docstring(leaf) and "\\\n" not in leaf.value: + # We're ignoring docstrings with backslash newline escapes because changing + # indentation of those changes the AST representation of the code. + docstring = normalize_string_prefix(leaf.value, self.remove_u_prefix) + prefix = get_string_prefix(docstring) + docstring = docstring[len(prefix) :] # Remove the prefix + quote_char = docstring[0] + # A natural way to remove the outer quotes is to do: + # docstring = docstring.strip(quote_char) + # but that breaks on """""x""" (which is '""x'). + # So we actually need to remove the first character and the next two + # characters but only if they are the same as the first. + quote_len = 1 if docstring[1] != quote_char else 3 + docstring = docstring[quote_len:-quote_len] + docstring_started_empty = not docstring + + if is_multiline_string(leaf): + indent = " " * 4 * self.current_line.depth + docstring = fix_docstring(docstring, indent) + else: + docstring = docstring.strip() + + if docstring: + # Add some padding if the docstring starts / ends with a quote mark. + if docstring[0] == quote_char: + docstring = " " + docstring + if docstring[-1] == quote_char: + docstring += " " + if docstring[-1] == "\\": + backslash_count = len(docstring) - len(docstring.rstrip("\\")) + if backslash_count % 2: + # Odd number of tailing backslashes, add some padding to + # avoid escaping the closing string quote. + docstring += " " + elif not docstring_started_empty: + docstring = " " + + # We could enforce triple quotes at this point. + quote = quote_char * quote_len + leaf.value = prefix + quote + docstring + quote + + yield from self.visit_default(leaf) + + def __post_init__(self) -> None: + """You are in a twisty little maze of passages.""" + self.current_line = Line(mode=self.mode) + + v = self.visit_stmt + Ø: Set[str] = set() + self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","}) + self.visit_if_stmt = partial( + v, keywords={"if", "else", "elif"}, parens={"if", "elif"} + ) + self.visit_while_stmt = partial(v, keywords={"while", "else"}, parens={"while"}) + self.visit_for_stmt = partial(v, keywords={"for", "else"}, parens={"for", "in"}) + self.visit_try_stmt = partial( + v, keywords={"try", "except", "else", "finally"}, parens=Ø + ) + self.visit_except_clause = partial(v, keywords={"except"}, parens=Ø) + self.visit_with_stmt = partial(v, keywords={"with"}, parens=Ø) + self.visit_funcdef = partial(v, keywords={"def"}, parens=Ø) + self.visit_classdef = partial(v, keywords={"class"}, parens=Ø) + self.visit_expr_stmt = partial(v, keywords=Ø, parens=ASSIGNMENTS) + self.visit_return_stmt = partial(v, keywords={"return"}, parens={"return"}) + self.visit_import_from = partial(v, keywords=Ø, parens={"import"}) + self.visit_del_stmt = partial(v, keywords=Ø, parens={"del"}) + self.visit_async_funcdef = self.visit_async_stmt + self.visit_decorated = self.visit_decorators + + # PEP 634 + self.visit_match_stmt = self.visit_match_case + self.visit_case_block = self.visit_match_case + + +def transform_line( + line: Line, mode: Mode, features: Collection[Feature] = () +) -> Iterator[Line]: + """Transform a `line`, potentially splitting it into many lines. + + They should fit in the allotted `line_length` but might not be able to. + + `features` are syntactical features that may be used in the output. + """ + if line.is_comment: + yield line + return + + line_str = line_to_string(line) + + ll = mode.line_length + sn = mode.string_normalization + string_merge = StringMerger(ll, sn) + string_paren_strip = StringParenStripper(ll, sn) + string_split = StringSplitter(ll, sn) + string_paren_wrap = StringParenWrapper(ll, sn) + + transformers: List[Transformer] + if ( + not line.contains_uncollapsable_type_comments() + and not line.should_split_rhs + and not line.magic_trailing_comma + and ( + is_line_short_enough(line, line_length=mode.line_length, line_str=line_str) + or line.contains_unsplittable_type_ignore() + ) + and not (line.inside_brackets and line.contains_standalone_comments()) + ): + # Only apply basic string preprocessing, since lines shouldn't be split here. + if mode.experimental_string_processing: + transformers = [string_merge, string_paren_strip] + else: + transformers = [] + elif line.is_def: + transformers = [left_hand_split] + else: + + def _rhs( + self: object, line: Line, features: Collection[Feature] + ) -> Iterator[Line]: + """Wraps calls to `right_hand_split`. + + The calls increasingly `omit` right-hand trailers (bracket pairs with + content), meaning the trailers get glued together to split on another + bracket pair instead. + """ + for omit in generate_trailers_to_omit(line, mode.line_length): + lines = list( + right_hand_split(line, mode.line_length, features, omit=omit) + ) + # Note: this check is only able to figure out if the first line of the + # *current* transformation fits in the line length. This is true only + # for simple cases. All others require running more transforms via + # `transform_line()`. This check doesn't know if those would succeed. + if is_line_short_enough(lines[0], line_length=mode.line_length): + yield from lines + return + + # All splits failed, best effort split with no omits. + # This mostly happens to multiline strings that are by definition + # reported as not fitting a single line, as well as lines that contain + # trailing commas (those have to be exploded). + yield from right_hand_split( + line, line_length=mode.line_length, features=features + ) + + # HACK: nested functions (like _rhs) compiled by mypyc don't retain their + # __name__ attribute which is needed in `run_transformer` further down. + # Unfortunately a nested class breaks mypyc too. So a class must be created + # via type ... https://github.com/mypyc/mypyc/issues/884 + rhs = type("rhs", (), {"__call__": _rhs})() + + if mode.experimental_string_processing: + if line.inside_brackets: + transformers = [ + string_merge, + string_paren_strip, + string_split, + delimiter_split, + standalone_comment_split, + string_paren_wrap, + rhs, + ] + else: + transformers = [ + string_merge, + string_paren_strip, + string_split, + string_paren_wrap, + rhs, + ] + else: + if line.inside_brackets: + transformers = [delimiter_split, standalone_comment_split, rhs] + else: + transformers = [rhs] + + for transform in transformers: + # We are accumulating lines in `result` because we might want to abort + # mission and return the original line in the end, or attempt a different + # split altogether. + try: + result = run_transformer(line, transform, mode, features, line_str=line_str) + except CannotTransform: + continue + else: + yield from result + break + + else: + yield line + + +def left_hand_split(line: Line, _features: Collection[Feature] = ()) -> Iterator[Line]: + """Split line into many lines, starting with the first matching bracket pair. + + Note: this usually looks weird, only use this for function definitions. + Prefer RHS otherwise. This is why this function is not symmetrical with + :func:`right_hand_split` which also handles optional parentheses. + """ + tail_leaves: List[Leaf] = [] + body_leaves: List[Leaf] = [] + head_leaves: List[Leaf] = [] + current_leaves = head_leaves + matching_bracket: Optional[Leaf] = None + for leaf in line.leaves: + if ( + current_leaves is body_leaves + and leaf.type in CLOSING_BRACKETS + and leaf.opening_bracket is matching_bracket + ): + current_leaves = tail_leaves if body_leaves else head_leaves + current_leaves.append(leaf) + if current_leaves is head_leaves: + if leaf.type in OPENING_BRACKETS: + matching_bracket = leaf + current_leaves = body_leaves + if not matching_bracket: + raise CannotSplit("No brackets found") + + head = bracket_split_build_line(head_leaves, line, matching_bracket) + body = bracket_split_build_line(body_leaves, line, matching_bracket, is_body=True) + tail = bracket_split_build_line(tail_leaves, line, matching_bracket) + bracket_split_succeeded_or_raise(head, body, tail) + for result in (head, body, tail): + if result: + yield result + + +def right_hand_split( + line: Line, + line_length: int, + features: Collection[Feature] = (), + omit: Collection[LeafID] = (), +) -> Iterator[Line]: + """Split line into many lines, starting with the last matching bracket pair. + + If the split was by optional parentheses, attempt splitting without them, too. + `omit` is a collection of closing bracket IDs that shouldn't be considered for + this split. + + Note: running this function modifies `bracket_depth` on the leaves of `line`. + """ + tail_leaves: List[Leaf] = [] + body_leaves: List[Leaf] = [] + head_leaves: List[Leaf] = [] + current_leaves = tail_leaves + opening_bracket: Optional[Leaf] = None + closing_bracket: Optional[Leaf] = None + for leaf in reversed(line.leaves): + if current_leaves is body_leaves: + if leaf is opening_bracket: + current_leaves = head_leaves if body_leaves else tail_leaves + current_leaves.append(leaf) + if current_leaves is tail_leaves: + if leaf.type in CLOSING_BRACKETS and id(leaf) not in omit: + opening_bracket = leaf.opening_bracket + closing_bracket = leaf + current_leaves = body_leaves + if not (opening_bracket and closing_bracket and head_leaves): + # If there is no opening or closing_bracket that means the split failed and + # all content is in the tail. Otherwise, if `head_leaves` are empty, it means + # the matching `opening_bracket` wasn't available on `line` anymore. + raise CannotSplit("No brackets found") + + tail_leaves.reverse() + body_leaves.reverse() + head_leaves.reverse() + head = bracket_split_build_line(head_leaves, line, opening_bracket) + body = bracket_split_build_line(body_leaves, line, opening_bracket, is_body=True) + tail = bracket_split_build_line(tail_leaves, line, opening_bracket) + bracket_split_succeeded_or_raise(head, body, tail) + if ( + Feature.FORCE_OPTIONAL_PARENTHESES not in features + # the opening bracket is an optional paren + and opening_bracket.type == token.LPAR + and not opening_bracket.value + # the closing bracket is an optional paren + and closing_bracket.type == token.RPAR + and not closing_bracket.value + # it's not an import (optional parens are the only thing we can split on + # in this case; attempting a split without them is a waste of time) + and not line.is_import + # there are no standalone comments in the body + and not body.contains_standalone_comments(0) + # and we can actually remove the parens + and can_omit_invisible_parens(body, line_length, omit_on_explode=omit) + ): + omit = {id(closing_bracket), *omit} + try: + yield from right_hand_split(line, line_length, features=features, omit=omit) + return + + except CannotSplit as e: + if not ( + can_be_split(body) + or is_line_short_enough(body, line_length=line_length) + ): + raise CannotSplit( + "Splitting failed, body is still too long and can't be split." + ) from e + + elif head.contains_multiline_strings() or tail.contains_multiline_strings(): + raise CannotSplit( + "The current optional pair of parentheses is bound to fail to" + " satisfy the splitting algorithm because the head or the tail" + " contains multiline strings which by definition never fit one" + " line." + ) from e + + ensure_visible(opening_bracket) + ensure_visible(closing_bracket) + for result in (head, body, tail): + if result: + yield result + + +def bracket_split_succeeded_or_raise(head: Line, body: Line, tail: Line) -> None: + """Raise :exc:`CannotSplit` if the last left- or right-hand split failed. + + Do nothing otherwise. + + A left- or right-hand split is based on a pair of brackets. Content before + (and including) the opening bracket is left on one line, content inside the + brackets is put on a separate line, and finally content starting with and + following the closing bracket is put on a separate line. + + Those are called `head`, `body`, and `tail`, respectively. If the split + produced the same line (all content in `head`) or ended up with an empty `body` + and the `tail` is just the closing bracket, then it's considered failed. + """ + tail_len = len(str(tail).strip()) + if not body: + if tail_len == 0: + raise CannotSplit("Splitting brackets produced the same line") + + elif tail_len < 3: + raise CannotSplit( + f"Splitting brackets on an empty body to save {tail_len} characters is" + " not worth it" + ) + + +def bracket_split_build_line( + leaves: List[Leaf], original: Line, opening_bracket: Leaf, *, is_body: bool = False +) -> Line: + """Return a new line with given `leaves` and respective comments from `original`. + + If `is_body` is True, the result line is one-indented inside brackets and as such + has its first leaf's prefix normalized and a trailing comma added when expected. + """ + result = Line(mode=original.mode, depth=original.depth) + if is_body: + result.inside_brackets = True + result.depth += 1 + if leaves: + # Since body is a new indent level, remove spurious leading whitespace. + normalize_prefix(leaves[0], inside_brackets=True) + # Ensure a trailing comma for imports and standalone function arguments, but + # be careful not to add one after any comments or within type annotations. + no_commas = ( + original.is_def + and opening_bracket.value == "(" + and not any(leaf.type == token.COMMA for leaf in leaves) + # In particular, don't add one within a parenthesized return annotation. + # Unfortunately the indicator we're in a return annotation (RARROW) may + # be defined directly in the parent node, the parent of the parent ... + # and so on depending on how complex the return annotation is. + # This isn't perfect and there's some false negatives but they are in + # contexts were a comma is actually fine. + and not any( + node.prev_sibling.type == RARROW + for node in ( + leaves[0].parent, + getattr(leaves[0].parent, "parent", None), + ) + if isinstance(node, Node) and isinstance(node.prev_sibling, Leaf) + ) + ) + + if original.is_import or no_commas: + for i in range(len(leaves) - 1, -1, -1): + if leaves[i].type == STANDALONE_COMMENT: + continue + + if leaves[i].type != token.COMMA: + new_comma = Leaf(token.COMMA, ",") + leaves.insert(i + 1, new_comma) + break + + # Populate the line + for leaf in leaves: + result.append(leaf, preformatted=True) + for comment_after in original.comments_after(leaf): + result.append(comment_after, preformatted=True) + if is_body and should_split_line(result, opening_bracket): + result.should_split_rhs = True + return result + + +def dont_increase_indentation(split_func: Transformer) -> Transformer: + """Normalize prefix of the first leaf in every line returned by `split_func`. + + This is a decorator over relevant split functions. + """ + + @wraps(split_func) + def split_wrapper(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]: + for line in split_func(line, features): + normalize_prefix(line.leaves[0], inside_brackets=True) + yield line + + return split_wrapper + + +@dont_increase_indentation +def delimiter_split(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]: + """Split according to delimiters of the highest priority. + + If the appropriate Features are given, the split will add trailing commas + also in function signatures and calls that contain `*` and `**`. + """ + try: + last_leaf = line.leaves[-1] + except IndexError: + raise CannotSplit("Line empty") from None + + bt = line.bracket_tracker + try: + delimiter_priority = bt.max_delimiter_priority(exclude={id(last_leaf)}) + except ValueError: + raise CannotSplit("No delimiters found") from None + + if delimiter_priority == DOT_PRIORITY: + if bt.delimiter_count_with_priority(delimiter_priority) == 1: + raise CannotSplit("Splitting a single attribute from its owner looks wrong") + + current_line = Line( + mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets + ) + lowest_depth = sys.maxsize + trailing_comma_safe = True + + def append_to_line(leaf: Leaf) -> Iterator[Line]: + """Append `leaf` to current line or to new line if appending impossible.""" + nonlocal current_line + try: + current_line.append_safe(leaf, preformatted=True) + except ValueError: + yield current_line + + current_line = Line( + mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets + ) + current_line.append(leaf) + + for leaf in line.leaves: + yield from append_to_line(leaf) + + for comment_after in line.comments_after(leaf): + yield from append_to_line(comment_after) + + lowest_depth = min(lowest_depth, leaf.bracket_depth) + if leaf.bracket_depth == lowest_depth: + if is_vararg(leaf, within={syms.typedargslist}): + trailing_comma_safe = ( + trailing_comma_safe and Feature.TRAILING_COMMA_IN_DEF in features + ) + elif is_vararg(leaf, within={syms.arglist, syms.argument}): + trailing_comma_safe = ( + trailing_comma_safe and Feature.TRAILING_COMMA_IN_CALL in features + ) + + leaf_priority = bt.delimiters.get(id(leaf)) + if leaf_priority == delimiter_priority: + yield current_line + + current_line = Line( + mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets + ) + if current_line: + if ( + trailing_comma_safe + and delimiter_priority == COMMA_PRIORITY + and current_line.leaves[-1].type != token.COMMA + and current_line.leaves[-1].type != STANDALONE_COMMENT + ): + new_comma = Leaf(token.COMMA, ",") + current_line.append(new_comma) + yield current_line + + +@dont_increase_indentation +def standalone_comment_split( + line: Line, features: Collection[Feature] = () +) -> Iterator[Line]: + """Split standalone comments from the rest of the line.""" + if not line.contains_standalone_comments(0): + raise CannotSplit("Line does not have any standalone comments") + + current_line = Line( + mode=line.mode, depth=line.depth, inside_brackets=line.inside_brackets + ) + + def append_to_line(leaf: Leaf) -> Iterator[Line]: + """Append `leaf` to current line or to new line if appending impossible.""" + nonlocal current_line + try: + current_line.append_safe(leaf, preformatted=True) + except ValueError: + yield current_line + + current_line = Line( + line.mode, depth=line.depth, inside_brackets=line.inside_brackets + ) + current_line.append(leaf) + + for leaf in line.leaves: + yield from append_to_line(leaf) + + for comment_after in line.comments_after(leaf): + yield from append_to_line(comment_after) + + if current_line: + yield current_line + + +def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None: + """Leave existing extra newlines if not `inside_brackets`. Remove everything + else. + + Note: don't use backslashes for formatting or you'll lose your voting rights. + """ + if not inside_brackets: + spl = leaf.prefix.split("#") + if "\\" not in spl[0]: + nl_count = spl[-1].count("\n") + if len(spl) > 1: + nl_count -= 1 + leaf.prefix = "\n" * nl_count + return + + leaf.prefix = "" + + +def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None: + """Make existing optional parentheses invisible or create new ones. + + `parens_after` is a set of string leaf values immediately after which parens + should be put. + + Standardizes on visible parentheses for single-element tuples, and keeps + existing visible parentheses for other tuples and generator expressions. + """ + for pc in list_comments(node.prefix, is_endmarker=False): + if pc.value in FMT_OFF: + # This `node` has a prefix with `# fmt: off`, don't mess with parens. + return + check_lpar = False + for index, child in enumerate(list(node.children)): + # Fixes a bug where invisible parens are not properly stripped from + # assignment statements that contain type annotations. + if isinstance(child, Node) and child.type == syms.annassign: + normalize_invisible_parens(child, parens_after=parens_after) + + # Add parentheses around long tuple unpacking in assignments. + if ( + index == 0 + and isinstance(child, Node) + and child.type == syms.testlist_star_expr + ): + check_lpar = True + + if check_lpar: + if child.type == syms.atom: + if maybe_make_parens_invisible_in_atom(child, parent=node): + wrap_in_parentheses(node, child, visible=False) + elif is_one_tuple(child): + wrap_in_parentheses(node, child, visible=True) + elif node.type == syms.import_from: + # "import from" nodes store parentheses directly as part of + # the statement + if child.type == token.LPAR: + # make parentheses invisible + child.value = "" # type: ignore + node.children[-1].value = "" # type: ignore + elif child.type != token.STAR: + # insert invisible parentheses + node.insert_child(index, Leaf(token.LPAR, "")) + node.append_child(Leaf(token.RPAR, "")) + break + + elif not (isinstance(child, Leaf) and is_multiline_string(child)): + wrap_in_parentheses(node, child, visible=False) + + check_lpar = isinstance(child, Leaf) and child.value in parens_after + + +def maybe_make_parens_invisible_in_atom(node: LN, parent: LN) -> bool: + """If it's safe, make the parens in the atom `node` invisible, recursively. + Additionally, remove repeated, adjacent invisible parens from the atom `node` + as they are redundant. + + Returns whether the node should itself be wrapped in invisible parentheses. + + """ + + if ( + node.type != syms.atom + or is_empty_tuple(node) + or is_one_tuple(node) + or (is_yield(node) and parent.type != syms.expr_stmt) + or max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY + ): + return False + + if is_walrus_assignment(node): + if parent.type in [ + syms.annassign, + syms.expr_stmt, + syms.assert_stmt, + syms.return_stmt, + # these ones aren't useful to end users, but they do please fuzzers + syms.for_stmt, + syms.del_stmt, + ]: + return False + + first = node.children[0] + last = node.children[-1] + if first.type == token.LPAR and last.type == token.RPAR: + middle = node.children[1] + # make parentheses invisible + first.value = "" # type: ignore + last.value = "" # type: ignore + maybe_make_parens_invisible_in_atom(middle, parent=parent) + + if is_atom_with_invisible_parens(middle): + # Strip the invisible parens from `middle` by replacing + # it with the child in-between the invisible parens + middle.replace(middle.children[1]) + + return False + + return True + + +def should_split_line(line: Line, opening_bracket: Leaf) -> bool: + """Should `line` be immediately split with `delimiter_split()` after RHS?""" + + if not (opening_bracket.parent and opening_bracket.value in "[{("): + return False + + # We're essentially checking if the body is delimited by commas and there's more + # than one of them (we're excluding the trailing comma and if the delimiter priority + # is still commas, that means there's more). + exclude = set() + trailing_comma = False + try: + last_leaf = line.leaves[-1] + if last_leaf.type == token.COMMA: + trailing_comma = True + exclude.add(id(last_leaf)) + max_priority = line.bracket_tracker.max_delimiter_priority(exclude=exclude) + except (IndexError, ValueError): + return False + + return max_priority == COMMA_PRIORITY and ( + (line.mode.magic_trailing_comma and trailing_comma) + # always explode imports + or opening_bracket.parent.type in {syms.atom, syms.import_from} + ) + + +def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[LeafID]]: + """Generate sets of closing bracket IDs that should be omitted in a RHS. + + Brackets can be omitted if the entire trailer up to and including + a preceding closing bracket fits in one line. + + Yielded sets are cumulative (contain results of previous yields, too). First + set is empty, unless the line should explode, in which case bracket pairs until + the one that needs to explode are omitted. + """ + + omit: Set[LeafID] = set() + if not line.magic_trailing_comma: + yield omit + + length = 4 * line.depth + opening_bracket: Optional[Leaf] = None + closing_bracket: Optional[Leaf] = None + inner_brackets: Set[LeafID] = set() + for index, leaf, leaf_length in line.enumerate_with_length(reversed=True): + length += leaf_length + if length > line_length: + break + + has_inline_comment = leaf_length > len(leaf.value) + len(leaf.prefix) + if leaf.type == STANDALONE_COMMENT or has_inline_comment: + break + + if opening_bracket: + if leaf is opening_bracket: + opening_bracket = None + elif leaf.type in CLOSING_BRACKETS: + prev = line.leaves[index - 1] if index > 0 else None + if ( + prev + and prev.type == token.COMMA + and not is_one_tuple_between( + leaf.opening_bracket, leaf, line.leaves + ) + ): + # Never omit bracket pairs with trailing commas. + # We need to explode on those. + break + + inner_brackets.add(id(leaf)) + elif leaf.type in CLOSING_BRACKETS: + prev = line.leaves[index - 1] if index > 0 else None + if prev and prev.type in OPENING_BRACKETS: + # Empty brackets would fail a split so treat them as "inner" + # brackets (e.g. only add them to the `omit` set if another + # pair of brackets was good enough. + inner_brackets.add(id(leaf)) + continue + + if closing_bracket: + omit.add(id(closing_bracket)) + omit.update(inner_brackets) + inner_brackets.clear() + yield omit + + if ( + prev + and prev.type == token.COMMA + and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves) + ): + # Never omit bracket pairs with trailing commas. + # We need to explode on those. + break + + if leaf.value: + opening_bracket = leaf.opening_bracket + closing_bracket = leaf + + +def run_transformer( + line: Line, + transform: Transformer, + mode: Mode, + features: Collection[Feature], + *, + line_str: str = "", +) -> List[Line]: + if not line_str: + line_str = line_to_string(line) + result: List[Line] = [] + for transformed_line in transform(line, features): + if str(transformed_line).strip("\n") == line_str: + raise CannotTransform("Line transformer returned an unchanged result") + + result.extend(transform_line(transformed_line, mode=mode, features=features)) + + if ( + transform.__class__.__name__ != "rhs" + or not line.bracket_tracker.invisible + or any(bracket.value for bracket in line.bracket_tracker.invisible) + or line.contains_multiline_strings() + or result[0].contains_uncollapsable_type_comments() + or result[0].contains_unsplittable_type_ignore() + or is_line_short_enough(result[0], line_length=mode.line_length) + # If any leaves have no parents (which _can_ occur since + # `transform(line)` potentially destroys the line's underlying node + # structure), then we can't proceed. Doing so would cause the below + # call to `append_leaves()` to fail. + or any(leaf.parent is None for leaf in line.leaves) + ): + return result + + line_copy = line.clone() + append_leaves(line_copy, line, line.leaves) + features_fop = set(features) | {Feature.FORCE_OPTIONAL_PARENTHESES} + second_opinion = run_transformer( + line_copy, transform, mode, features_fop, line_str=line_str + ) + if all( + is_line_short_enough(ln, line_length=mode.line_length) for ln in second_opinion + ): + result = second_opinion + return result diff --git a/myenv/lib/python3.9/site-packages/black/lines.py b/myenv/lib/python3.9/site-packages/black/lines.py new file mode 100644 index 0000000..f2bdada --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/lines.py @@ -0,0 +1,754 @@ +from dataclasses import dataclass, field +import itertools +import sys +from typing import ( + Callable, + Collection, + Dict, + Iterator, + List, + Optional, + Sequence, + Tuple, + TypeVar, + cast, +) + +from blib2to3.pytree import Node, Leaf +from blib2to3.pgen2 import token + +from black.brackets import BracketTracker, DOT_PRIORITY +from black.mode import Mode +from black.nodes import STANDALONE_COMMENT, TEST_DESCENDANTS +from black.nodes import BRACKETS, OPENING_BRACKETS, CLOSING_BRACKETS +from black.nodes import syms, whitespace, replace_child, child_towards +from black.nodes import is_multiline_string, is_import, is_type_comment, last_two_except +from black.nodes import is_one_tuple_between + +# types +T = TypeVar("T") +Index = int +LeafID = int + + +@dataclass +class Line: + """Holds leaves and comments. Can be printed with `str(line)`.""" + + mode: Mode + depth: int = 0 + leaves: List[Leaf] = field(default_factory=list) + # keys ordered like `leaves` + comments: Dict[LeafID, List[Leaf]] = field(default_factory=dict) + bracket_tracker: BracketTracker = field(default_factory=BracketTracker) + inside_brackets: bool = False + should_split_rhs: bool = False + magic_trailing_comma: Optional[Leaf] = None + + def append(self, leaf: Leaf, preformatted: bool = False) -> None: + """Add a new `leaf` to the end of the line. + + Unless `preformatted` is True, the `leaf` will receive a new consistent + whitespace prefix and metadata applied by :class:`BracketTracker`. + Trailing commas are maybe removed, unpacked for loop variables are + demoted from being delimiters. + + Inline comments are put aside. + """ + has_value = leaf.type in BRACKETS or bool(leaf.value.strip()) + if not has_value: + return + + if token.COLON == leaf.type and self.is_class_paren_empty: + del self.leaves[-2:] + if self.leaves and not preformatted: + # Note: at this point leaf.prefix should be empty except for + # imports, for which we only preserve newlines. + leaf.prefix += whitespace( + leaf, complex_subscript=self.is_complex_subscript(leaf) + ) + if self.inside_brackets or not preformatted: + self.bracket_tracker.mark(leaf) + if self.mode.magic_trailing_comma: + if self.has_magic_trailing_comma(leaf): + self.magic_trailing_comma = leaf + elif self.has_magic_trailing_comma(leaf, ensure_removable=True): + self.remove_trailing_comma() + if not self.append_comment(leaf): + self.leaves.append(leaf) + + def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None: + """Like :func:`append()` but disallow invalid standalone comment structure. + + Raises ValueError when any `leaf` is appended after a standalone comment + or when a standalone comment is not the first leaf on the line. + """ + if self.bracket_tracker.depth == 0: + if self.is_comment: + raise ValueError("cannot append to standalone comments") + + if self.leaves and leaf.type == STANDALONE_COMMENT: + raise ValueError( + "cannot append standalone comments to a populated line" + ) + + self.append(leaf, preformatted=preformatted) + + @property + def is_comment(self) -> bool: + """Is this line a standalone comment?""" + return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT + + @property + def is_decorator(self) -> bool: + """Is this line a decorator?""" + return bool(self) and self.leaves[0].type == token.AT + + @property + def is_import(self) -> bool: + """Is this an import line?""" + return bool(self) and is_import(self.leaves[0]) + + @property + def is_class(self) -> bool: + """Is this line a class definition?""" + return ( + bool(self) + and self.leaves[0].type == token.NAME + and self.leaves[0].value == "class" + ) + + @property + def is_stub_class(self) -> bool: + """Is this line a class definition with a body consisting only of "..."?""" + return self.is_class and self.leaves[-3:] == [ + Leaf(token.DOT, ".") for _ in range(3) + ] + + @property + def is_def(self) -> bool: + """Is this a function definition? (Also returns True for async defs.)""" + try: + first_leaf = self.leaves[0] + except IndexError: + return False + + try: + second_leaf: Optional[Leaf] = self.leaves[1] + except IndexError: + second_leaf = None + return (first_leaf.type == token.NAME and first_leaf.value == "def") or ( + first_leaf.type == token.ASYNC + and second_leaf is not None + and second_leaf.type == token.NAME + and second_leaf.value == "def" + ) + + @property + def is_class_paren_empty(self) -> bool: + """Is this a class with no base classes but using parentheses? + + Those are unnecessary and should be removed. + """ + return ( + bool(self) + and len(self.leaves) == 4 + and self.is_class + and self.leaves[2].type == token.LPAR + and self.leaves[2].value == "(" + and self.leaves[3].type == token.RPAR + and self.leaves[3].value == ")" + ) + + @property + def is_triple_quoted_string(self) -> bool: + """Is the line a triple quoted string?""" + return ( + bool(self) + and self.leaves[0].type == token.STRING + and self.leaves[0].value.startswith(('"""', "'''")) + ) + + def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool: + """If so, needs to be split before emitting.""" + for leaf in self.leaves: + if leaf.type == STANDALONE_COMMENT and leaf.bracket_depth <= depth_limit: + return True + + return False + + def contains_uncollapsable_type_comments(self) -> bool: + ignored_ids = set() + try: + last_leaf = self.leaves[-1] + ignored_ids.add(id(last_leaf)) + if last_leaf.type == token.COMMA or ( + last_leaf.type == token.RPAR and not last_leaf.value + ): + # When trailing commas or optional parens are inserted by Black for + # consistency, comments after the previous last element are not moved + # (they don't have to, rendering will still be correct). So we ignore + # trailing commas and invisible. + last_leaf = self.leaves[-2] + ignored_ids.add(id(last_leaf)) + except IndexError: + return False + + # A type comment is uncollapsable if it is attached to a leaf + # that isn't at the end of the line (since that could cause it + # to get associated to a different argument) or if there are + # comments before it (since that could cause it to get hidden + # behind a comment. + comment_seen = False + for leaf_id, comments in self.comments.items(): + for comment in comments: + if is_type_comment(comment): + if comment_seen or ( + not is_type_comment(comment, " ignore") + and leaf_id not in ignored_ids + ): + return True + + comment_seen = True + + return False + + def contains_unsplittable_type_ignore(self) -> bool: + if not self.leaves: + return False + + # If a 'type: ignore' is attached to the end of a line, we + # can't split the line, because we can't know which of the + # subexpressions the ignore was meant to apply to. + # + # We only want this to apply to actual physical lines from the + # original source, though: we don't want the presence of a + # 'type: ignore' at the end of a multiline expression to + # justify pushing it all onto one line. Thus we + # (unfortunately) need to check the actual source lines and + # only report an unsplittable 'type: ignore' if this line was + # one line in the original code. + + # Grab the first and last line numbers, skipping generated leaves + first_line = next((leaf.lineno for leaf in self.leaves if leaf.lineno != 0), 0) + last_line = next( + (leaf.lineno for leaf in reversed(self.leaves) if leaf.lineno != 0), 0 + ) + + if first_line == last_line: + # We look at the last two leaves since a comma or an + # invisible paren could have been added at the end of the + # line. + for node in self.leaves[-2:]: + for comment in self.comments.get(id(node), []): + if is_type_comment(comment, " ignore"): + return True + + return False + + def contains_multiline_strings(self) -> bool: + return any(is_multiline_string(leaf) for leaf in self.leaves) + + def has_magic_trailing_comma( + self, closing: Leaf, ensure_removable: bool = False + ) -> bool: + """Return True if we have a magic trailing comma, that is when: + - there's a trailing comma here + - it's not a one-tuple + Additionally, if ensure_removable: + - it's not from square bracket indexing + """ + if not ( + closing.type in CLOSING_BRACKETS + and self.leaves + and self.leaves[-1].type == token.COMMA + ): + return False + + if closing.type == token.RBRACE: + return True + + if closing.type == token.RSQB: + if not ensure_removable: + return True + comma = self.leaves[-1] + return bool(comma.parent and comma.parent.type == syms.listmaker) + + if self.is_import: + return True + + if not is_one_tuple_between(closing.opening_bracket, closing, self.leaves): + return True + + return False + + def append_comment(self, comment: Leaf) -> bool: + """Add an inline or standalone comment to the line.""" + if ( + comment.type == STANDALONE_COMMENT + and self.bracket_tracker.any_open_brackets() + ): + comment.prefix = "" + return False + + if comment.type != token.COMMENT: + return False + + if not self.leaves: + comment.type = STANDALONE_COMMENT + comment.prefix = "" + return False + + last_leaf = self.leaves[-1] + if ( + last_leaf.type == token.RPAR + and not last_leaf.value + and last_leaf.parent + and len(list(last_leaf.parent.leaves())) <= 3 + and not is_type_comment(comment) + ): + # Comments on an optional parens wrapping a single leaf should belong to + # the wrapped node except if it's a type comment. Pinning the comment like + # this avoids unstable formatting caused by comment migration. + if len(self.leaves) < 2: + comment.type = STANDALONE_COMMENT + comment.prefix = "" + return False + + last_leaf = self.leaves[-2] + self.comments.setdefault(id(last_leaf), []).append(comment) + return True + + def comments_after(self, leaf: Leaf) -> List[Leaf]: + """Generate comments that should appear directly after `leaf`.""" + return self.comments.get(id(leaf), []) + + def remove_trailing_comma(self) -> None: + """Remove the trailing comma and moves the comments attached to it.""" + trailing_comma = self.leaves.pop() + trailing_comma_comments = self.comments.pop(id(trailing_comma), []) + self.comments.setdefault(id(self.leaves[-1]), []).extend( + trailing_comma_comments + ) + + def is_complex_subscript(self, leaf: Leaf) -> bool: + """Return True iff `leaf` is part of a slice with non-trivial exprs.""" + open_lsqb = self.bracket_tracker.get_open_lsqb() + if open_lsqb is None: + return False + + subscript_start = open_lsqb.next_sibling + + if isinstance(subscript_start, Node): + if subscript_start.type == syms.listmaker: + return False + + if subscript_start.type == syms.subscriptlist: + subscript_start = child_towards(subscript_start, leaf) + return subscript_start is not None and any( + n.type in TEST_DESCENDANTS for n in subscript_start.pre_order() + ) + + def enumerate_with_length( + self, reversed: bool = False + ) -> Iterator[Tuple[Index, Leaf, int]]: + """Return an enumeration of leaves with their length. + + Stops prematurely on multiline strings and standalone comments. + """ + op = cast( + Callable[[Sequence[Leaf]], Iterator[Tuple[Index, Leaf]]], + enumerate_reversed if reversed else enumerate, + ) + for index, leaf in op(self.leaves): + length = len(leaf.prefix) + len(leaf.value) + if "\n" in leaf.value: + return # Multiline strings, we can't continue. + + for comment in self.comments_after(leaf): + length += len(comment.value) + + yield index, leaf, length + + def clone(self) -> "Line": + return Line( + mode=self.mode, + depth=self.depth, + inside_brackets=self.inside_brackets, + should_split_rhs=self.should_split_rhs, + magic_trailing_comma=self.magic_trailing_comma, + ) + + def __str__(self) -> str: + """Render the line.""" + if not self: + return "\n" + + indent = " " * self.depth + leaves = iter(self.leaves) + first = next(leaves) + res = f"{first.prefix}{indent}{first.value}" + for leaf in leaves: + res += str(leaf) + for comment in itertools.chain.from_iterable(self.comments.values()): + res += str(comment) + + return res + "\n" + + def __bool__(self) -> bool: + """Return True if the line has leaves or comments.""" + return bool(self.leaves or self.comments) + + +@dataclass +class EmptyLineTracker: + """Provides a stateful method that returns the number of potential extra + empty lines needed before and after the currently processed line. + + Note: this tracker works on lines that haven't been split yet. It assumes + the prefix of the first leaf consists of optional newlines. Those newlines + are consumed by `maybe_empty_lines()` and included in the computation. + """ + + is_pyi: bool = False + previous_line: Optional[Line] = None + previous_after: int = 0 + previous_defs: List[int] = field(default_factory=list) + + def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: + """Return the number of extra empty lines before and after the `current_line`. + + This is for separating `def`, `async def` and `class` with extra empty + lines (two on module-level). + """ + before, after = self._maybe_empty_lines(current_line) + before = ( + # Black should not insert empty lines at the beginning + # of the file + 0 + if self.previous_line is None + else before - self.previous_after + ) + self.previous_after = after + self.previous_line = current_line + return before, after + + def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: + max_allowed = 1 + if current_line.depth == 0: + max_allowed = 1 if self.is_pyi else 2 + if current_line.leaves: + # Consume the first leaf's extra newlines. + first_leaf = current_line.leaves[0] + before = first_leaf.prefix.count("\n") + before = min(before, max_allowed) + first_leaf.prefix = "" + else: + before = 0 + depth = current_line.depth + while self.previous_defs and self.previous_defs[-1] >= depth: + if self.is_pyi: + before = 0 if depth else 1 + else: + if depth: + before = 1 + elif ( + not depth + and self.previous_defs[-1] + and current_line.leaves[-1].type == token.COLON + and ( + current_line.leaves[0].value + not in ("with", "try", "for", "while", "if", "match") + ) + ): + # We shouldn't add two newlines between an indented function and + # a dependent non-indented clause. This is to avoid issues with + # conditional function definitions that are technically top-level + # and therefore get two trailing newlines, but look weird and + # inconsistent when they're followed by elif, else, etc. This is + # worse because these functions only get *one* preceding newline + # already. + before = 1 + else: + before = 2 + self.previous_defs.pop() + if current_line.is_decorator or current_line.is_def or current_line.is_class: + return self._maybe_empty_lines_for_class_or_def(current_line, before) + + if ( + self.previous_line + and self.previous_line.is_import + and not current_line.is_import + and depth == self.previous_line.depth + ): + return (before or 1), 0 + + if ( + self.previous_line + and self.previous_line.is_class + and current_line.is_triple_quoted_string + ): + return before, 1 + + return before, 0 + + def _maybe_empty_lines_for_class_or_def( + self, current_line: Line, before: int + ) -> Tuple[int, int]: + if not current_line.is_decorator: + self.previous_defs.append(current_line.depth) + if self.previous_line is None: + # Don't insert empty lines before the first line in the file. + return 0, 0 + + if self.previous_line.is_decorator: + if self.is_pyi and current_line.is_stub_class: + # Insert an empty line after a decorated stub class + return 0, 1 + + return 0, 0 + + if self.previous_line.depth < current_line.depth and ( + self.previous_line.is_class or self.previous_line.is_def + ): + return 0, 0 + + if ( + self.previous_line.is_comment + and self.previous_line.depth == current_line.depth + and before == 0 + ): + return 0, 0 + + if self.is_pyi: + if self.previous_line.depth > current_line.depth: + newlines = 1 + elif current_line.is_class or self.previous_line.is_class: + if current_line.is_stub_class and self.previous_line.is_stub_class: + # No blank line between classes with an empty body + newlines = 0 + else: + newlines = 1 + elif ( + current_line.is_def or current_line.is_decorator + ) and not self.previous_line.is_def: + # Blank line between a block of functions (maybe with preceding + # decorators) and a block of non-functions + newlines = 1 + else: + newlines = 0 + else: + newlines = 2 + if current_line.depth and newlines: + newlines -= 1 + return newlines, 0 + + +def enumerate_reversed(sequence: Sequence[T]) -> Iterator[Tuple[Index, T]]: + """Like `reversed(enumerate(sequence))` if that were possible.""" + index = len(sequence) - 1 + for element in reversed(sequence): + yield (index, element) + index -= 1 + + +def append_leaves( + new_line: Line, old_line: Line, leaves: List[Leaf], preformatted: bool = False +) -> None: + """ + Append leaves (taken from @old_line) to @new_line, making sure to fix the + underlying Node structure where appropriate. + + All of the leaves in @leaves are duplicated. The duplicates are then + appended to @new_line and used to replace their originals in the underlying + Node structure. Any comments attached to the old leaves are reattached to + the new leaves. + + Pre-conditions: + set(@leaves) is a subset of set(@old_line.leaves). + """ + for old_leaf in leaves: + new_leaf = Leaf(old_leaf.type, old_leaf.value) + replace_child(old_leaf, new_leaf) + new_line.append(new_leaf, preformatted=preformatted) + + for comment_leaf in old_line.comments_after(old_leaf): + new_line.append(comment_leaf, preformatted=True) + + +def is_line_short_enough(line: Line, *, line_length: int, line_str: str = "") -> bool: + """Return True if `line` is no longer than `line_length`. + + Uses the provided `line_str` rendering, if any, otherwise computes a new one. + """ + if not line_str: + line_str = line_to_string(line) + return ( + len(line_str) <= line_length + and "\n" not in line_str # multiline strings + and not line.contains_standalone_comments() + ) + + +def can_be_split(line: Line) -> bool: + """Return False if the line cannot be split *for sure*. + + This is not an exhaustive search but a cheap heuristic that we can use to + avoid some unfortunate formattings (mostly around wrapping unsplittable code + in unnecessary parentheses). + """ + leaves = line.leaves + if len(leaves) < 2: + return False + + if leaves[0].type == token.STRING and leaves[1].type == token.DOT: + call_count = 0 + dot_count = 0 + next = leaves[-1] + for leaf in leaves[-2::-1]: + if leaf.type in OPENING_BRACKETS: + if next.type not in CLOSING_BRACKETS: + return False + + call_count += 1 + elif leaf.type == token.DOT: + dot_count += 1 + elif leaf.type == token.NAME: + if not (next.type == token.DOT or next.type in OPENING_BRACKETS): + return False + + elif leaf.type not in CLOSING_BRACKETS: + return False + + if dot_count > 1 and call_count > 1: + return False + + return True + + +def can_omit_invisible_parens( + line: Line, + line_length: int, + omit_on_explode: Collection[LeafID] = (), +) -> bool: + """Does `line` have a shape safe to reformat without optional parens around it? + + Returns True for only a subset of potentially nice looking formattings but + the point is to not return false positives that end up producing lines that + are too long. + """ + bt = line.bracket_tracker + if not bt.delimiters: + # Without delimiters the optional parentheses are useless. + return True + + max_priority = bt.max_delimiter_priority() + if bt.delimiter_count_with_priority(max_priority) > 1: + # With more than one delimiter of a kind the optional parentheses read better. + return False + + if max_priority == DOT_PRIORITY: + # A single stranded method call doesn't require optional parentheses. + return True + + assert len(line.leaves) >= 2, "Stranded delimiter" + + # With a single delimiter, omit if the expression starts or ends with + # a bracket. + first = line.leaves[0] + second = line.leaves[1] + if first.type in OPENING_BRACKETS and second.type not in CLOSING_BRACKETS: + if _can_omit_opening_paren(line, first=first, line_length=line_length): + return True + + # Note: we are not returning False here because a line might have *both* + # a leading opening bracket and a trailing closing bracket. If the + # opening bracket doesn't match our rule, maybe the closing will. + + penultimate = line.leaves[-2] + last = line.leaves[-1] + if line.magic_trailing_comma: + try: + penultimate, last = last_two_except(line.leaves, omit=omit_on_explode) + except LookupError: + # Turns out we'd omit everything. We cannot skip the optional parentheses. + return False + + if ( + last.type == token.RPAR + or last.type == token.RBRACE + or ( + # don't use indexing for omitting optional parentheses; + # it looks weird + last.type == token.RSQB + and last.parent + and last.parent.type != syms.trailer + ) + ): + if penultimate.type in OPENING_BRACKETS: + # Empty brackets don't help. + return False + + if is_multiline_string(first): + # Additional wrapping of a multiline string in this situation is + # unnecessary. + return True + + if line.magic_trailing_comma and penultimate.type == token.COMMA: + # The rightmost non-omitted bracket pair is the one we want to explode on. + return True + + if _can_omit_closing_paren(line, last=last, line_length=line_length): + return True + + return False + + +def _can_omit_opening_paren(line: Line, *, first: Leaf, line_length: int) -> bool: + """See `can_omit_invisible_parens`.""" + remainder = False + length = 4 * line.depth + _index = -1 + for _index, leaf, leaf_length in line.enumerate_with_length(): + if leaf.type in CLOSING_BRACKETS and leaf.opening_bracket is first: + remainder = True + if remainder: + length += leaf_length + if length > line_length: + break + + if leaf.type in OPENING_BRACKETS: + # There are brackets we can further split on. + remainder = False + + else: + # checked the entire string and line length wasn't exceeded + if len(line.leaves) == _index + 1: + return True + + return False + + +def _can_omit_closing_paren(line: Line, *, last: Leaf, line_length: int) -> bool: + """See `can_omit_invisible_parens`.""" + length = 4 * line.depth + seen_other_brackets = False + for _index, leaf, leaf_length in line.enumerate_with_length(): + length += leaf_length + if leaf is last.opening_bracket: + if seen_other_brackets or length <= line_length: + return True + + elif leaf.type in OPENING_BRACKETS: + # There are brackets we can further split on. + seen_other_brackets = True + + return False + + +def line_to_string(line: Line) -> str: + """Returns the string representation of @line. + + WARNING: This is known to be computationally expensive. + """ + return str(line).strip("\n") diff --git a/myenv/lib/python3.9/site-packages/black/mode.py b/myenv/lib/python3.9/site-packages/black/mode.py new file mode 100644 index 0000000..e241753 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/mode.py @@ -0,0 +1,160 @@ +"""Data structures configuring Black behavior. + +Mostly around Python language feature support per version and Black configuration +chosen by the user. +""" + +from dataclasses import dataclass, field +from enum import Enum +from operator import attrgetter +from typing import Dict, Set + +from black.const import DEFAULT_LINE_LENGTH + + +class TargetVersion(Enum): + PY27 = 2 + PY33 = 3 + PY34 = 4 + PY35 = 5 + PY36 = 6 + PY37 = 7 + PY38 = 8 + PY39 = 9 + PY310 = 10 + + def is_python2(self) -> bool: + return self is TargetVersion.PY27 + + +class Feature(Enum): + # All string literals are unicode + UNICODE_LITERALS = 1 + F_STRINGS = 2 + NUMERIC_UNDERSCORES = 3 + TRAILING_COMMA_IN_CALL = 4 + TRAILING_COMMA_IN_DEF = 5 + # The following two feature-flags are mutually exclusive, and exactly one should be + # set for every version of python. + ASYNC_IDENTIFIERS = 6 + ASYNC_KEYWORDS = 7 + ASSIGNMENT_EXPRESSIONS = 8 + POS_ONLY_ARGUMENTS = 9 + RELAXED_DECORATORS = 10 + PATTERN_MATCHING = 11 + FORCE_OPTIONAL_PARENTHESES = 50 + + # temporary for Python 2 deprecation + PRINT_STMT = 200 + EXEC_STMT = 201 + AUTOMATIC_PARAMETER_UNPACKING = 202 + COMMA_STYLE_EXCEPT = 203 + COMMA_STYLE_RAISE = 204 + LONG_INT_LITERAL = 205 + OCTAL_INT_LITERAL = 206 + BACKQUOTE_REPR = 207 + + +VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = { + TargetVersion.PY27: { + Feature.ASYNC_IDENTIFIERS, + Feature.PRINT_STMT, + Feature.EXEC_STMT, + Feature.AUTOMATIC_PARAMETER_UNPACKING, + Feature.COMMA_STYLE_EXCEPT, + Feature.COMMA_STYLE_RAISE, + Feature.LONG_INT_LITERAL, + Feature.OCTAL_INT_LITERAL, + Feature.BACKQUOTE_REPR, + }, + TargetVersion.PY33: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS}, + TargetVersion.PY34: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS}, + TargetVersion.PY35: { + Feature.UNICODE_LITERALS, + Feature.TRAILING_COMMA_IN_CALL, + Feature.ASYNC_IDENTIFIERS, + }, + TargetVersion.PY36: { + Feature.UNICODE_LITERALS, + Feature.F_STRINGS, + Feature.NUMERIC_UNDERSCORES, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, + Feature.ASYNC_IDENTIFIERS, + }, + TargetVersion.PY37: { + Feature.UNICODE_LITERALS, + Feature.F_STRINGS, + Feature.NUMERIC_UNDERSCORES, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, + Feature.ASYNC_KEYWORDS, + }, + TargetVersion.PY38: { + Feature.UNICODE_LITERALS, + Feature.F_STRINGS, + Feature.NUMERIC_UNDERSCORES, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, + Feature.ASYNC_KEYWORDS, + Feature.ASSIGNMENT_EXPRESSIONS, + Feature.POS_ONLY_ARGUMENTS, + }, + TargetVersion.PY39: { + Feature.UNICODE_LITERALS, + Feature.F_STRINGS, + Feature.NUMERIC_UNDERSCORES, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, + Feature.ASYNC_KEYWORDS, + Feature.ASSIGNMENT_EXPRESSIONS, + Feature.RELAXED_DECORATORS, + Feature.POS_ONLY_ARGUMENTS, + }, + TargetVersion.PY310: { + Feature.UNICODE_LITERALS, + Feature.F_STRINGS, + Feature.NUMERIC_UNDERSCORES, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, + Feature.ASYNC_KEYWORDS, + Feature.ASSIGNMENT_EXPRESSIONS, + Feature.RELAXED_DECORATORS, + Feature.POS_ONLY_ARGUMENTS, + Feature.PATTERN_MATCHING, + }, +} + + +def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> bool: + return all(feature in VERSION_TO_FEATURES[version] for version in target_versions) + + +@dataclass +class Mode: + target_versions: Set[TargetVersion] = field(default_factory=set) + line_length: int = DEFAULT_LINE_LENGTH + string_normalization: bool = True + is_pyi: bool = False + is_ipynb: bool = False + magic_trailing_comma: bool = True + experimental_string_processing: bool = False + + def get_cache_key(self) -> str: + if self.target_versions: + version_str = ",".join( + str(version.value) + for version in sorted(self.target_versions, key=attrgetter("value")) + ) + else: + version_str = "-" + parts = [ + version_str, + str(self.line_length), + str(int(self.string_normalization)), + str(int(self.is_pyi)), + str(int(self.is_ipynb)), + str(int(self.magic_trailing_comma)), + str(int(self.experimental_string_processing)), + ] + return ".".join(parts) diff --git a/myenv/lib/python3.9/site-packages/black/nodes.py b/myenv/lib/python3.9/site-packages/black/nodes.py new file mode 100644 index 0000000..8bf1934 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/nodes.py @@ -0,0 +1,856 @@ +""" +blib2to3 Node/Leaf transformation-related utility functions. +""" + +import sys +from typing import ( + Collection, + Generic, + Iterator, + List, + Optional, + Set, + Tuple, + TypeVar, + Union, +) + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +from mypy_extensions import mypyc_attr + +# lib2to3 fork +from blib2to3.pytree import Node, Leaf, type_repr +from blib2to3 import pygram +from blib2to3.pgen2 import token + +from black.cache import CACHE_DIR +from black.strings import has_triple_quotes + + +pygram.initialize(CACHE_DIR) +syms: Final = pygram.python_symbols + + +# types +T = TypeVar("T") +LN = Union[Leaf, Node] +LeafID = int +NodeType = int + + +WHITESPACE: Final = {token.DEDENT, token.INDENT, token.NEWLINE} +STATEMENT: Final = { + syms.if_stmt, + syms.while_stmt, + syms.for_stmt, + syms.try_stmt, + syms.except_clause, + syms.with_stmt, + syms.funcdef, + syms.classdef, + syms.match_stmt, + syms.case_block, +} +STANDALONE_COMMENT: Final = 153 +token.tok_name[STANDALONE_COMMENT] = "STANDALONE_COMMENT" +LOGIC_OPERATORS: Final = {"and", "or"} +COMPARATORS: Final = { + token.LESS, + token.GREATER, + token.EQEQUAL, + token.NOTEQUAL, + token.LESSEQUAL, + token.GREATEREQUAL, +} +MATH_OPERATORS: Final = { + token.VBAR, + token.CIRCUMFLEX, + token.AMPER, + token.LEFTSHIFT, + token.RIGHTSHIFT, + token.PLUS, + token.MINUS, + token.STAR, + token.SLASH, + token.DOUBLESLASH, + token.PERCENT, + token.AT, + token.TILDE, + token.DOUBLESTAR, +} +STARS: Final = {token.STAR, token.DOUBLESTAR} +VARARGS_SPECIALS: Final = STARS | {token.SLASH} +VARARGS_PARENTS: Final = { + syms.arglist, + syms.argument, # double star in arglist + syms.trailer, # single argument to call + syms.typedargslist, + syms.varargslist, # lambdas +} +UNPACKING_PARENTS: Final = { + syms.atom, # single element of a list or set literal + syms.dictsetmaker, + syms.listmaker, + syms.testlist_gexp, + syms.testlist_star_expr, + syms.subject_expr, + syms.pattern, +} +TEST_DESCENDANTS: Final = { + syms.test, + syms.lambdef, + syms.or_test, + syms.and_test, + syms.not_test, + syms.comparison, + syms.star_expr, + syms.expr, + syms.xor_expr, + syms.and_expr, + syms.shift_expr, + syms.arith_expr, + syms.trailer, + syms.term, + syms.power, +} +ASSIGNMENTS: Final = { + "=", + "+=", + "-=", + "*=", + "@=", + "/=", + "%=", + "&=", + "|=", + "^=", + "<<=", + ">>=", + "**=", + "//=", +} + +IMPLICIT_TUPLE: Final = {syms.testlist, syms.testlist_star_expr, syms.exprlist} +BRACKET: Final = { + token.LPAR: token.RPAR, + token.LSQB: token.RSQB, + token.LBRACE: token.RBRACE, +} +OPENING_BRACKETS: Final = set(BRACKET.keys()) +CLOSING_BRACKETS: Final = set(BRACKET.values()) +BRACKETS: Final = OPENING_BRACKETS | CLOSING_BRACKETS +ALWAYS_NO_SPACE: Final = CLOSING_BRACKETS | {token.COMMA, STANDALONE_COMMENT} + +RARROW = 55 + + +@mypyc_attr(allow_interpreted_subclasses=True) +class Visitor(Generic[T]): + """Basic lib2to3 visitor that yields things of type `T` on `visit()`.""" + + def visit(self, node: LN) -> Iterator[T]: + """Main method to visit `node` and its children. + + It tries to find a `visit_*()` method for the given `node.type`, like + `visit_simple_stmt` for Node objects or `visit_INDENT` for Leaf objects. + If no dedicated `visit_*()` method is found, chooses `visit_default()` + instead. + + Then yields objects of type `T` from the selected visitor. + """ + if node.type < 256: + name = token.tok_name[node.type] + else: + name = str(type_repr(node.type)) + # We explicitly branch on whether a visitor exists (instead of + # using self.visit_default as the default arg to getattr) in order + # to save needing to create a bound method object and so mypyc can + # generate a native call to visit_default. + visitf = getattr(self, f"visit_{name}", None) + if visitf: + yield from visitf(node) + else: + yield from self.visit_default(node) + + def visit_default(self, node: LN) -> Iterator[T]: + """Default `visit_*()` implementation. Recurses to children of `node`.""" + if isinstance(node, Node): + for child in node.children: + yield from self.visit(child) + + +def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa: C901 + """Return whitespace prefix if needed for the given `leaf`. + + `complex_subscript` signals whether the given leaf is part of a subscription + which has non-trivial arguments, like arithmetic expressions or function calls. + """ + NO: Final = "" + SPACE: Final = " " + DOUBLESPACE: Final = " " + t = leaf.type + p = leaf.parent + v = leaf.value + if t in ALWAYS_NO_SPACE: + return NO + + if t == token.COMMENT: + return DOUBLESPACE + + assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}" + if t == token.COLON and p.type not in { + syms.subscript, + syms.subscriptlist, + syms.sliceop, + }: + return NO + + prev = leaf.prev_sibling + if not prev: + prevp = preceding_leaf(p) + if not prevp or prevp.type in OPENING_BRACKETS: + return NO + + if t == token.COLON: + if prevp.type == token.COLON: + return NO + + elif prevp.type != token.COMMA and not complex_subscript: + return NO + + return SPACE + + if prevp.type == token.EQUAL: + if prevp.parent: + if prevp.parent.type in { + syms.arglist, + syms.argument, + syms.parameters, + syms.varargslist, + }: + return NO + + elif prevp.parent.type == syms.typedargslist: + # A bit hacky: if the equal sign has whitespace, it means we + # previously found it's a typed argument. So, we're using + # that, too. + return prevp.prefix + + elif prevp.type in VARARGS_SPECIALS: + if is_vararg(prevp, within=VARARGS_PARENTS | UNPACKING_PARENTS): + return NO + + elif prevp.type == token.COLON: + if prevp.parent and prevp.parent.type in {syms.subscript, syms.sliceop}: + return SPACE if complex_subscript else NO + + elif ( + prevp.parent + and prevp.parent.type == syms.factor + and prevp.type in MATH_OPERATORS + ): + return NO + + elif ( + prevp.type == token.RIGHTSHIFT + and prevp.parent + and prevp.parent.type == syms.shift_expr + and prevp.prev_sibling + and prevp.prev_sibling.type == token.NAME + and prevp.prev_sibling.value == "print" # type: ignore + ): + # Python 2 print chevron + return NO + elif prevp.type == token.AT and p.parent and p.parent.type == syms.decorator: + # no space in decorators + return NO + + elif prev.type in OPENING_BRACKETS: + return NO + + if p.type in {syms.parameters, syms.arglist}: + # untyped function signatures or calls + if not prev or prev.type != token.COMMA: + return NO + + elif p.type == syms.varargslist: + # lambdas + if prev and prev.type != token.COMMA: + return NO + + elif p.type == syms.typedargslist: + # typed function signatures + if not prev: + return NO + + if t == token.EQUAL: + if prev.type != syms.tname: + return NO + + elif prev.type == token.EQUAL: + # A bit hacky: if the equal sign has whitespace, it means we + # previously found it's a typed argument. So, we're using that, too. + return prev.prefix + + elif prev.type != token.COMMA: + return NO + + elif p.type == syms.tname: + # type names + if not prev: + prevp = preceding_leaf(p) + if not prevp or prevp.type != token.COMMA: + return NO + + elif p.type == syms.trailer: + # attributes and calls + if t == token.LPAR or t == token.RPAR: + return NO + + if not prev: + if t == token.DOT: + prevp = preceding_leaf(p) + if not prevp or prevp.type != token.NUMBER: + return NO + + elif t == token.LSQB: + return NO + + elif prev.type != token.COMMA: + return NO + + elif p.type == syms.argument: + # single argument + if t == token.EQUAL: + return NO + + if not prev: + prevp = preceding_leaf(p) + if not prevp or prevp.type == token.LPAR: + return NO + + elif prev.type in {token.EQUAL} | VARARGS_SPECIALS: + return NO + + elif p.type == syms.decorator: + # decorators + return NO + + elif p.type == syms.dotted_name: + if prev: + return NO + + prevp = preceding_leaf(p) + if not prevp or prevp.type == token.AT or prevp.type == token.DOT: + return NO + + elif p.type == syms.classdef: + if t == token.LPAR: + return NO + + if prev and prev.type == token.LPAR: + return NO + + elif p.type in {syms.subscript, syms.sliceop}: + # indexing + if not prev: + assert p.parent is not None, "subscripts are always parented" + if p.parent.type == syms.subscriptlist: + return SPACE + + return NO + + elif not complex_subscript: + return NO + + elif p.type == syms.atom: + if prev and t == token.DOT: + # dots, but not the first one. + return NO + + elif p.type == syms.dictsetmaker: + # dict unpacking + if prev and prev.type == token.DOUBLESTAR: + return NO + + elif p.type in {syms.factor, syms.star_expr}: + # unary ops + if not prev: + prevp = preceding_leaf(p) + if not prevp or prevp.type in OPENING_BRACKETS: + return NO + + prevp_parent = prevp.parent + assert prevp_parent is not None + if prevp.type == token.COLON and prevp_parent.type in { + syms.subscript, + syms.sliceop, + }: + return NO + + elif prevp.type == token.EQUAL and prevp_parent.type == syms.argument: + return NO + + elif t in {token.NAME, token.NUMBER, token.STRING}: + return NO + + elif p.type == syms.import_from: + if t == token.DOT: + if prev and prev.type == token.DOT: + return NO + + elif t == token.NAME: + if v == "import": + return SPACE + + if prev and prev.type == token.DOT: + return NO + + elif p.type == syms.sliceop: + return NO + + return SPACE + + +def preceding_leaf(node: Optional[LN]) -> Optional[Leaf]: + """Return the first leaf that precedes `node`, if any.""" + while node: + res = node.prev_sibling + if res: + if isinstance(res, Leaf): + return res + + try: + return list(res.leaves())[-1] + + except IndexError: + return None + + node = node.parent + return None + + +def prev_siblings_are(node: Optional[LN], tokens: List[Optional[NodeType]]) -> bool: + """Return if the `node` and its previous siblings match types against the provided + list of tokens; the provided `node`has its type matched against the last element in + the list. `None` can be used as the first element to declare that the start of the + list is anchored at the start of its parent's children.""" + if not tokens: + return True + if tokens[-1] is None: + return node is None + if not node: + return False + if node.type != tokens[-1]: + return False + return prev_siblings_are(node.prev_sibling, tokens[:-1]) + + +def last_two_except(leaves: List[Leaf], omit: Collection[LeafID]) -> Tuple[Leaf, Leaf]: + """Return (penultimate, last) leaves skipping brackets in `omit` and contents.""" + stop_after: Optional[Leaf] = None + last: Optional[Leaf] = None + for leaf in reversed(leaves): + if stop_after: + if leaf is stop_after: + stop_after = None + continue + + if last: + return leaf, last + + if id(leaf) in omit: + stop_after = leaf.opening_bracket + else: + last = leaf + else: + raise LookupError("Last two leaves were also skipped") + + +def parent_type(node: Optional[LN]) -> Optional[NodeType]: + """ + Returns: + @node.parent.type, if @node is not None and has a parent. + OR + None, otherwise. + """ + if node is None or node.parent is None: + return None + + return node.parent.type + + +def child_towards(ancestor: Node, descendant: LN) -> Optional[LN]: + """Return the child of `ancestor` that contains `descendant`.""" + node: Optional[LN] = descendant + while node and node.parent != ancestor: + node = node.parent + return node + + +def replace_child(old_child: LN, new_child: LN) -> None: + """ + Side Effects: + * If @old_child.parent is set, replace @old_child with @new_child in + @old_child's underlying Node structure. + OR + * Otherwise, this function does nothing. + """ + parent = old_child.parent + if not parent: + return + + child_idx = old_child.remove() + if child_idx is not None: + parent.insert_child(child_idx, new_child) + + +def container_of(leaf: Leaf) -> LN: + """Return `leaf` or one of its ancestors that is the topmost container of it. + + By "container" we mean a node where `leaf` is the very first child. + """ + same_prefix = leaf.prefix + container: LN = leaf + while container: + parent = container.parent + if parent is None: + break + + if parent.children[0].prefix != same_prefix: + break + + if parent.type == syms.file_input: + break + + if parent.prev_sibling is not None and parent.prev_sibling.type in BRACKETS: + break + + container = parent + return container + + +def first_leaf_column(node: Node) -> Optional[int]: + """Returns the column of the first leaf child of a node.""" + for child in node.children: + if isinstance(child, Leaf): + return child.column + return None + + +def first_child_is_arith(node: Node) -> bool: + """Whether first child is an arithmetic or a binary arithmetic expression""" + expr_types = { + syms.arith_expr, + syms.shift_expr, + syms.xor_expr, + syms.and_expr, + } + return bool(node.children and node.children[0].type in expr_types) + + +def is_docstring(leaf: Leaf) -> bool: + if prev_siblings_are( + leaf.parent, [None, token.NEWLINE, token.INDENT, syms.simple_stmt] + ): + return True + + # Multiline docstring on the same line as the `def`. + if prev_siblings_are(leaf.parent, [syms.parameters, token.COLON, syms.simple_stmt]): + # `syms.parameters` is only used in funcdefs and async_funcdefs in the Python + # grammar. We're safe to return True without further checks. + return True + + return False + + +def is_empty_tuple(node: LN) -> bool: + """Return True if `node` holds an empty tuple.""" + return ( + node.type == syms.atom + and len(node.children) == 2 + and node.children[0].type == token.LPAR + and node.children[1].type == token.RPAR + ) + + +def is_one_tuple(node: LN) -> bool: + """Return True if `node` holds a tuple with one element, with or without parens.""" + if node.type == syms.atom: + gexp = unwrap_singleton_parenthesis(node) + if gexp is None or gexp.type != syms.testlist_gexp: + return False + + return len(gexp.children) == 2 and gexp.children[1].type == token.COMMA + + return ( + node.type in IMPLICIT_TUPLE + and len(node.children) == 2 + and node.children[1].type == token.COMMA + ) + + +def is_one_tuple_between(opening: Leaf, closing: Leaf, leaves: List[Leaf]) -> bool: + """Return True if content between `opening` and `closing` looks like a one-tuple.""" + if opening.type != token.LPAR and closing.type != token.RPAR: + return False + + depth = closing.bracket_depth + 1 + for _opening_index, leaf in enumerate(leaves): + if leaf is opening: + break + + else: + raise LookupError("Opening paren not found in `leaves`") + + commas = 0 + _opening_index += 1 + for leaf in leaves[_opening_index:]: + if leaf is closing: + break + + bracket_depth = leaf.bracket_depth + if bracket_depth == depth and leaf.type == token.COMMA: + commas += 1 + if leaf.parent and leaf.parent.type in { + syms.arglist, + syms.typedargslist, + }: + commas += 1 + break + + return commas < 2 + + +def is_walrus_assignment(node: LN) -> bool: + """Return True iff `node` is of the shape ( test := test )""" + inner = unwrap_singleton_parenthesis(node) + return inner is not None and inner.type == syms.namedexpr_test + + +def is_simple_decorator_trailer(node: LN, last: bool = False) -> bool: + """Return True iff `node` is a trailer valid in a simple decorator""" + return node.type == syms.trailer and ( + ( + len(node.children) == 2 + and node.children[0].type == token.DOT + and node.children[1].type == token.NAME + ) + # last trailer can be an argument-less parentheses pair + or ( + last + and len(node.children) == 2 + and node.children[0].type == token.LPAR + and node.children[1].type == token.RPAR + ) + # last trailer can be arguments + or ( + last + and len(node.children) == 3 + and node.children[0].type == token.LPAR + # and node.children[1].type == syms.argument + and node.children[2].type == token.RPAR + ) + ) + + +def is_simple_decorator_expression(node: LN) -> bool: + """Return True iff `node` could be a 'dotted name' decorator + + This function takes the node of the 'namedexpr_test' of the new decorator + grammar and test if it would be valid under the old decorator grammar. + + The old grammar was: decorator: @ dotted_name [arguments] NEWLINE + The new grammar is : decorator: @ namedexpr_test NEWLINE + """ + if node.type == token.NAME: + return True + if node.type == syms.power: + if node.children: + return ( + node.children[0].type == token.NAME + and all(map(is_simple_decorator_trailer, node.children[1:-1])) + and ( + len(node.children) < 2 + or is_simple_decorator_trailer(node.children[-1], last=True) + ) + ) + return False + + +def is_yield(node: LN) -> bool: + """Return True if `node` holds a `yield` or `yield from` expression.""" + if node.type == syms.yield_expr: + return True + + if node.type == token.NAME and node.value == "yield": # type: ignore + return True + + if node.type != syms.atom: + return False + + if len(node.children) != 3: + return False + + lpar, expr, rpar = node.children + if lpar.type == token.LPAR and rpar.type == token.RPAR: + return is_yield(expr) + + return False + + +def is_vararg(leaf: Leaf, within: Set[NodeType]) -> bool: + """Return True if `leaf` is a star or double star in a vararg or kwarg. + + If `within` includes VARARGS_PARENTS, this applies to function signatures. + If `within` includes UNPACKING_PARENTS, it applies to right hand-side + extended iterable unpacking (PEP 3132) and additional unpacking + generalizations (PEP 448). + """ + if leaf.type not in VARARGS_SPECIALS or not leaf.parent: + return False + + p = leaf.parent + if p.type == syms.star_expr: + # Star expressions are also used as assignment targets in extended + # iterable unpacking (PEP 3132). See what its parent is instead. + if not p.parent: + return False + + p = p.parent + + return p.type in within + + +def is_multiline_string(leaf: Leaf) -> bool: + """Return True if `leaf` is a multiline string that actually spans many lines.""" + return has_triple_quotes(leaf.value) and "\n" in leaf.value + + +def is_stub_suite(node: Node) -> bool: + """Return True if `node` is a suite with a stub body.""" + if ( + len(node.children) != 4 + or node.children[0].type != token.NEWLINE + or node.children[1].type != token.INDENT + or node.children[3].type != token.DEDENT + ): + return False + + return is_stub_body(node.children[2]) + + +def is_stub_body(node: LN) -> bool: + """Return True if `node` is a simple statement containing an ellipsis.""" + if not isinstance(node, Node) or node.type != syms.simple_stmt: + return False + + if len(node.children) != 2: + return False + + child = node.children[0] + return ( + child.type == syms.atom + and len(child.children) == 3 + and all(leaf == Leaf(token.DOT, ".") for leaf in child.children) + ) + + +def is_atom_with_invisible_parens(node: LN) -> bool: + """Given a `LN`, determines whether it's an atom `node` with invisible + parens. Useful in dedupe-ing and normalizing parens. + """ + if isinstance(node, Leaf) or node.type != syms.atom: + return False + + first, last = node.children[0], node.children[-1] + return ( + isinstance(first, Leaf) + and first.type == token.LPAR + and first.value == "" + and isinstance(last, Leaf) + and last.type == token.RPAR + and last.value == "" + ) + + +def is_empty_par(leaf: Leaf) -> bool: + return is_empty_lpar(leaf) or is_empty_rpar(leaf) + + +def is_empty_lpar(leaf: Leaf) -> bool: + return leaf.type == token.LPAR and leaf.value == "" + + +def is_empty_rpar(leaf: Leaf) -> bool: + return leaf.type == token.RPAR and leaf.value == "" + + +def is_import(leaf: Leaf) -> bool: + """Return True if the given leaf starts an import statement.""" + p = leaf.parent + t = leaf.type + v = leaf.value + return bool( + t == token.NAME + and ( + (v == "import" and p and p.type == syms.import_name) + or (v == "from" and p and p.type == syms.import_from) + ) + ) + + +def is_type_comment(leaf: Leaf, suffix: str = "") -> bool: + """Return True if the given leaf is a special comment. + Only returns true for type comments for now.""" + t = leaf.type + v = leaf.value + return t in {token.COMMENT, STANDALONE_COMMENT} and v.startswith("# type:" + suffix) + + +def wrap_in_parentheses(parent: Node, child: LN, *, visible: bool = True) -> None: + """Wrap `child` in parentheses. + + This replaces `child` with an atom holding the parentheses and the old + child. That requires moving the prefix. + + If `visible` is False, the leaves will be valueless (and thus invisible). + """ + lpar = Leaf(token.LPAR, "(" if visible else "") + rpar = Leaf(token.RPAR, ")" if visible else "") + prefix = child.prefix + child.prefix = "" + index = child.remove() or 0 + new_child = Node(syms.atom, [lpar, child, rpar]) + new_child.prefix = prefix + parent.insert_child(index, new_child) + + +def unwrap_singleton_parenthesis(node: LN) -> Optional[LN]: + """Returns `wrapped` if `node` is of the shape ( wrapped ). + + Parenthesis can be optional. Returns None otherwise""" + if len(node.children) != 3: + return None + + lpar, wrapped, rpar = node.children + if not (lpar.type == token.LPAR and rpar.type == token.RPAR): + return None + + return wrapped + + +def ensure_visible(leaf: Leaf) -> None: + """Make sure parentheses are visible. + + They could be invisible as part of some statements (see + :func:`normalize_invisible_parens` and :func:`visit_import_from`). + """ + if leaf.type == token.LPAR: + leaf.value = "(" + elif leaf.type == token.RPAR: + leaf.value = ")" diff --git a/myenv/lib/python3.9/site-packages/black/numerics.py b/myenv/lib/python3.9/site-packages/black/numerics.py new file mode 100644 index 0000000..cb1c83e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/numerics.py @@ -0,0 +1,65 @@ +""" +Formatting numeric literals. +""" +from blib2to3.pytree import Leaf + + +def format_hex(text: str) -> str: + """ + Formats a hexadecimal string like "0x12B3" + """ + before, after = text[:2], text[2:] + return f"{before}{after.upper()}" + + +def format_scientific_notation(text: str) -> str: + """Formats a numeric string utilizing scentific notation""" + before, after = text.split("e") + sign = "" + if after.startswith("-"): + after = after[1:] + sign = "-" + elif after.startswith("+"): + after = after[1:] + before = format_float_or_int_string(before) + return f"{before}e{sign}{after}" + + +def format_long_or_complex_number(text: str) -> str: + """Formats a long or complex string like `10L` or `10j`""" + number = text[:-1] + suffix = text[-1] + # Capitalize in "2L" because "l" looks too similar to "1". + if suffix == "l": + suffix = "L" + return f"{format_float_or_int_string(number)}{suffix}" + + +def format_float_or_int_string(text: str) -> str: + """Formats a float string like "1.0".""" + if "." not in text: + return text + + before, after = text.split(".") + return f"{before or 0}.{after or 0}" + + +def normalize_numeric_literal(leaf: Leaf) -> None: + """Normalizes numeric (float, int, and complex) literals. + + All letters used in the representation are normalized to lowercase (except + in Python 2 long literals). + """ + text = leaf.value.lower() + if text.startswith(("0o", "0b")): + # Leave octal and binary literals alone. + pass + elif text.startswith("0x"): + text = format_hex(text) + elif "e" in text: + text = format_scientific_notation(text) + elif text.endswith(("j", "l")): + text = format_long_or_complex_number(text) + else: + text = format_float_or_int_string(text) + leaf.value = text diff --git a/myenv/lib/python3.9/site-packages/black/output.py b/myenv/lib/python3.9/site-packages/black/output.py new file mode 100644 index 0000000..f030d0a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/output.py @@ -0,0 +1,105 @@ +"""Nice output for Black. + +The double calls are for patching purposes in tests. +""" + +import json +from typing import Any, Optional +from mypy_extensions import mypyc_attr +import tempfile + +from click import echo, style + + +@mypyc_attr(patchable=True) +def _out(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: + if message is not None: + if "bold" not in styles: + styles["bold"] = True + message = style(message, **styles) + echo(message, nl=nl, err=True) + + +@mypyc_attr(patchable=True) +def _err(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: + if message is not None: + if "fg" not in styles: + styles["fg"] = "red" + message = style(message, **styles) + echo(message, nl=nl, err=True) + + +@mypyc_attr(patchable=True) +def out(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: + _out(message, nl=nl, **styles) + + +def err(message: Optional[str] = None, nl: bool = True, **styles: Any) -> None: + _err(message, nl=nl, **styles) + + +def ipynb_diff(a: str, b: str, a_name: str, b_name: str) -> str: + """Return a unified diff string between each cell in notebooks `a` and `b`.""" + a_nb = json.loads(a) + b_nb = json.loads(b) + diff_lines = [ + diff( + "".join(a_nb["cells"][cell_number]["source"]) + "\n", + "".join(b_nb["cells"][cell_number]["source"]) + "\n", + f"{a_name}:cell_{cell_number}", + f"{b_name}:cell_{cell_number}", + ) + for cell_number, cell in enumerate(a_nb["cells"]) + if cell["cell_type"] == "code" + ] + return "".join(diff_lines) + + +def diff(a: str, b: str, a_name: str, b_name: str) -> str: + """Return a unified diff string between strings `a` and `b`.""" + import difflib + + a_lines = a.splitlines(keepends=True) + b_lines = b.splitlines(keepends=True) + diff_lines = [] + for line in difflib.unified_diff( + a_lines, b_lines, fromfile=a_name, tofile=b_name, n=5 + ): + # Work around https://bugs.python.org/issue2142 + # See: + # https://www.gnu.org/software/diffutils/manual/html_node/Incomplete-Lines.html + if line[-1] == "\n": + diff_lines.append(line) + else: + diff_lines.append(line + "\n") + diff_lines.append("\\ No newline at end of file\n") + return "".join(diff_lines) + + +def color_diff(contents: str) -> str: + """Inject the ANSI color codes to the diff.""" + lines = contents.split("\n") + for i, line in enumerate(lines): + if line.startswith("+++") or line.startswith("---"): + line = "\033[1;37m" + line + "\033[0m" # bold white, reset + elif line.startswith("@@"): + line = "\033[36m" + line + "\033[0m" # cyan, reset + elif line.startswith("+"): + line = "\033[32m" + line + "\033[0m" # green, reset + elif line.startswith("-"): + line = "\033[31m" + line + "\033[0m" # red, reset + lines[i] = line + return "\n".join(lines) + + +@mypyc_attr(patchable=True) +def dump_to_file(*output: str, ensure_final_newline: bool = True) -> str: + """Dump `output` to a temporary file. Return path to the file.""" + with tempfile.NamedTemporaryFile( + mode="w", prefix="blk_", suffix=".log", delete=False, encoding="utf8" + ) as f: + for lines in output: + f.write(lines) + if ensure_final_newline and lines and lines[-1] != "\n": + f.write("\n") + return f.name diff --git a/myenv/lib/python3.9/site-packages/black/parsing.py b/myenv/lib/python3.9/site-packages/black/parsing.py new file mode 100644 index 0000000..c101643 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/parsing.py @@ -0,0 +1,285 @@ +""" +Parse Python code and perform AST validation. +""" +import ast +import platform +import sys +from typing import Any, Iterable, Iterator, List, Set, Tuple, Type, Union + +if sys.version_info < (3, 8): + from typing_extensions import Final +else: + from typing import Final + +# lib2to3 fork +from blib2to3.pytree import Node, Leaf +from blib2to3 import pygram +from blib2to3.pgen2 import driver +from blib2to3.pgen2.grammar import Grammar +from blib2to3.pgen2.parse import ParseError +from blib2to3.pgen2.tokenize import TokenError + +from black.mode import TargetVersion, Feature, supports_feature +from black.nodes import syms + +ast3: Any +ast27: Any + +_IS_PYPY = platform.python_implementation() == "PyPy" + +try: + from typed_ast import ast3, ast27 +except ImportError: + # Either our python version is too low, or we're on pypy + if sys.version_info < (3, 7) or (sys.version_info < (3, 8) and not _IS_PYPY): + print( + "The typed_ast package is required but not installed.\n" + "You can upgrade to Python 3.8+ or install typed_ast with\n" + "`python3 -m pip install typed-ast`.", + file=sys.stderr, + ) + sys.exit(1) + else: + ast3 = ast27 = ast + + +PY310_HINT: Final[ + str +] = "Consider using --target-version py310 to parse Python 3.10 code." + + +class InvalidInput(ValueError): + """Raised when input source code fails all parse attempts.""" + + +def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]: + if not target_versions: + # No target_version specified, so try all grammars. + return [ + # Python 3.7+ + pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords, + # Python 3.0-3.6 + pygram.python_grammar_no_print_statement_no_exec_statement, + # Python 2.7 with future print_function import + pygram.python_grammar_no_print_statement, + # Python 2.7 + pygram.python_grammar, + ] + + if all(version.is_python2() for version in target_versions): + # Python 2-only code, so try Python 2 grammars. + return [ + # Python 2.7 with future print_function import + pygram.python_grammar_no_print_statement, + # Python 2.7 + pygram.python_grammar, + ] + + # Python 3-compatible code, so only try Python 3 grammar. + grammars = [] + if supports_feature(target_versions, Feature.PATTERN_MATCHING): + # Python 3.10+ + grammars.append(pygram.python_grammar_soft_keywords) + # If we have to parse both, try to parse async as a keyword first + if not supports_feature( + target_versions, Feature.ASYNC_IDENTIFIERS + ) and not supports_feature(target_versions, Feature.PATTERN_MATCHING): + # Python 3.7-3.9 + grammars.append( + pygram.python_grammar_no_print_statement_no_exec_statement_async_keywords + ) + if not supports_feature(target_versions, Feature.ASYNC_KEYWORDS): + # Python 3.0-3.6 + grammars.append(pygram.python_grammar_no_print_statement_no_exec_statement) + # At least one of the above branches must have been taken, because every Python + # version has exactly one of the two 'ASYNC_*' flags + return grammars + + +def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node: + """Given a string with source, return the lib2to3 Node.""" + if not src_txt.endswith("\n"): + src_txt += "\n" + + grammars = get_grammars(set(target_versions)) + for grammar in grammars: + drv = driver.Driver(grammar) + try: + result = drv.parse_string(src_txt, True) + break + + except ParseError as pe: + lineno, column = pe.context[1] + lines = src_txt.splitlines() + try: + faulty_line = lines[lineno - 1] + except IndexError: + faulty_line = "" + exc = InvalidInput(f"Cannot parse: {lineno}:{column}: {faulty_line}") + + except TokenError as te: + # In edge cases these are raised; and typically don't have a "faulty_line". + lineno, column = te.args[1] + exc = InvalidInput(f"Cannot parse: {lineno}:{column}: {te.args[0]}") + + else: + if pygram.python_grammar_soft_keywords not in grammars and matches_grammar( + src_txt, pygram.python_grammar_soft_keywords + ): + original_msg = exc.args[0] + msg = f"{original_msg}\n{PY310_HINT}" + raise InvalidInput(msg) from None + raise exc from None + + if isinstance(result, Leaf): + result = Node(syms.file_input, [result]) + return result + + +def matches_grammar(src_txt: str, grammar: Grammar) -> bool: + drv = driver.Driver(grammar) + try: + drv.parse_string(src_txt, True) + except (ParseError, TokenError, IndentationError): + return False + else: + return True + + +def lib2to3_unparse(node: Node) -> str: + """Given a lib2to3 node, return its string representation.""" + code = str(node) + return code + + +def parse_single_version( + src: str, version: Tuple[int, int] +) -> Union[ast.AST, ast3.AST, ast27.AST]: + filename = "" + # typed_ast is needed because of feature version limitations in the builtin ast + if sys.version_info >= (3, 8) and version >= (3,): + return ast.parse(src, filename, feature_version=version) + elif version >= (3,): + if _IS_PYPY: + return ast3.parse(src, filename) + else: + return ast3.parse(src, filename, feature_version=version[1]) + elif version == (2, 7): + return ast27.parse(src) + raise AssertionError("INTERNAL ERROR: Tried parsing unsupported Python version!") + + +def parse_ast(src: str) -> Union[ast.AST, ast3.AST, ast27.AST]: + # TODO: support Python 4+ ;) + versions = [(3, minor) for minor in range(3, sys.version_info[1] + 1)] + + if ast27.__name__ != "ast": + versions.append((2, 7)) + + first_error = "" + for version in sorted(versions, reverse=True): + try: + return parse_single_version(src, version) + except SyntaxError as e: + if not first_error: + first_error = str(e) + + raise SyntaxError(first_error) + + +ast3_AST: Final[Type[ast3.AST]] = ast3.AST +ast27_AST: Final[Type[ast27.AST]] = ast27.AST + + +def stringify_ast( + node: Union[ast.AST, ast3.AST, ast27.AST], depth: int = 0 +) -> Iterator[str]: + """Simple visitor generating strings to compare ASTs by content.""" + + node = fixup_ast_constants(node) + + yield f"{' ' * depth}{node.__class__.__name__}(" + + type_ignore_classes: Tuple[Type[Any], ...] + for field in sorted(node._fields): # noqa: F402 + # TypeIgnore will not be present using pypy < 3.8, so need for this + if not (_IS_PYPY and sys.version_info < (3, 8)): + # TypeIgnore has only one field 'lineno' which breaks this comparison + type_ignore_classes = (ast3.TypeIgnore, ast27.TypeIgnore) + if sys.version_info >= (3, 8): + type_ignore_classes += (ast.TypeIgnore,) + if isinstance(node, type_ignore_classes): + break + + try: + value = getattr(node, field) + except AttributeError: + continue + + yield f"{' ' * (depth+1)}{field}=" + + if isinstance(value, list): + for item in value: + # Ignore nested tuples within del statements, because we may insert + # parentheses and they change the AST. + if ( + field == "targets" + and isinstance(node, (ast.Delete, ast3.Delete, ast27.Delete)) + and isinstance(item, (ast.Tuple, ast3.Tuple, ast27.Tuple)) + ): + for item in item.elts: + yield from stringify_ast(item, depth + 2) + + elif isinstance(item, (ast.AST, ast3.AST, ast27.AST)): + yield from stringify_ast(item, depth + 2) + + # Note that we are referencing the typed-ast ASTs via global variables and not + # direct module attribute accesses because that breaks mypyc. It's probably + # something to do with the ast3 / ast27 variables being marked as Any leading + # mypy to think this branch is always taken, leaving the rest of the code + # unanalyzed. Tighting up the types for the typed-ast AST types avoids the + # mypyc crash. + elif isinstance(value, (ast.AST, ast3_AST, ast27_AST)): + yield from stringify_ast(value, depth + 2) + + else: + # Constant strings may be indented across newlines, if they are + # docstrings; fold spaces after newlines when comparing. Similarly, + # trailing and leading space may be removed. + # Note that when formatting Python 2 code, at least with Windows + # line-endings, docstrings can end up here as bytes instead of + # str so make sure that we handle both cases. + if ( + isinstance(node, ast.Constant) + and field == "value" + and isinstance(value, (str, bytes)) + ): + lineend = "\n" if isinstance(value, str) else b"\n" + # To normalize, we strip any leading and trailing space from + # each line... + stripped = [line.strip() for line in value.splitlines()] + normalized = lineend.join(stripped) # type: ignore[attr-defined] + # ...and remove any blank lines at the beginning and end of + # the whole string + normalized = normalized.strip() + else: + normalized = value + yield f"{' ' * (depth+2)}{normalized!r}, # {value.__class__.__name__}" + + yield f"{' ' * depth}) # /{node.__class__.__name__}" + + +def fixup_ast_constants( + node: Union[ast.AST, ast3.AST, ast27.AST] +) -> Union[ast.AST, ast3.AST, ast27.AST]: + """Map ast nodes deprecated in 3.8 to Constant.""" + if isinstance(node, (ast.Str, ast3.Str, ast27.Str, ast.Bytes, ast3.Bytes)): + return ast.Constant(value=node.s) + + if isinstance(node, (ast.Num, ast3.Num, ast27.Num)): + return ast.Constant(value=node.n) + + if isinstance(node, (ast.NameConstant, ast3.NameConstant)): + return ast.Constant(value=node.value) + + return node diff --git a/myenv/lib/python3.9/site-packages/black/py.typed b/myenv/lib/python3.9/site-packages/black/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/black/report.py b/myenv/lib/python3.9/site-packages/black/report.py new file mode 100644 index 0000000..7e1c8b4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/report.py @@ -0,0 +1,104 @@ +""" +Summarize Black runs to users. +""" +from dataclasses import dataclass +from enum import Enum +from pathlib import Path + +from click import style + +from black.output import out, err + + +class Changed(Enum): + NO = 0 + CACHED = 1 + YES = 2 + + +class NothingChanged(UserWarning): + """Raised when reformatted code is the same as source.""" + + +@dataclass +class Report: + """Provides a reformatting counter. Can be rendered with `str(report)`.""" + + check: bool = False + diff: bool = False + quiet: bool = False + verbose: bool = False + change_count: int = 0 + same_count: int = 0 + failure_count: int = 0 + + def done(self, src: Path, changed: Changed) -> None: + """Increment the counter for successful reformatting. Write out a message.""" + if changed is Changed.YES: + reformatted = "would reformat" if self.check or self.diff else "reformatted" + if self.verbose or not self.quiet: + out(f"{reformatted} {src}") + self.change_count += 1 + else: + if self.verbose: + if changed is Changed.NO: + msg = f"{src} already well formatted, good job." + else: + msg = f"{src} wasn't modified on disk since last run." + out(msg, bold=False) + self.same_count += 1 + + def failed(self, src: Path, message: str) -> None: + """Increment the counter for failed reformatting. Write out a message.""" + err(f"error: cannot format {src}: {message}") + self.failure_count += 1 + + def path_ignored(self, path: Path, message: str) -> None: + if self.verbose: + out(f"{path} ignored: {message}", bold=False) + + @property + def return_code(self) -> int: + """Return the exit code that the app should use. + + This considers the current state of changed files and failures: + - if there were any failures, return 123; + - if any files were changed and --check is being used, return 1; + - otherwise return 0. + """ + # According to http://tldp.org/LDP/abs/html/exitcodes.html starting with + # 126 we have special return codes reserved by the shell. + if self.failure_count: + return 123 + + elif self.change_count and self.check: + return 1 + + return 0 + + def __str__(self) -> str: + """Render a color report of the current state. + + Use `click.unstyle` to remove colors. + """ + if self.check or self.diff: + reformatted = "would be reformatted" + unchanged = "would be left unchanged" + failed = "would fail to reformat" + else: + reformatted = "reformatted" + unchanged = "left unchanged" + failed = "failed to reformat" + report = [] + if self.change_count: + s = "s" if self.change_count > 1 else "" + report.append( + style(f"{self.change_count} file{s} {reformatted}", bold=True) + ) + if self.same_count: + s = "s" if self.same_count > 1 else "" + report.append(f"{self.same_count} file{s} {unchanged}") + if self.failure_count: + s = "s" if self.failure_count > 1 else "" + report.append(style(f"{self.failure_count} file{s} {failed}", fg="red")) + return ", ".join(report) + "." diff --git a/myenv/lib/python3.9/site-packages/black/rusty.py b/myenv/lib/python3.9/site-packages/black/rusty.py new file mode 100644 index 0000000..822e3d7 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/rusty.py @@ -0,0 +1,28 @@ +"""An error-handling model influenced by that used by the Rust programming language + +See https://doc.rust-lang.org/book/ch09-00-error-handling.html. +""" +from typing import Generic, TypeVar, Union + + +T = TypeVar("T") +E = TypeVar("E", bound=Exception) + + +class Ok(Generic[T]): + def __init__(self, value: T) -> None: + self._value = value + + def ok(self) -> T: + return self._value + + +class Err(Generic[E]): + def __init__(self, e: E) -> None: + self._e = e + + def err(self) -> E: + return self._e + + +Result = Union[Ok[T], Err[E]] diff --git a/myenv/lib/python3.9/site-packages/black/strings.py b/myenv/lib/python3.9/site-packages/black/strings.py new file mode 100644 index 0000000..06a5da0 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/strings.py @@ -0,0 +1,234 @@ +""" +Simple formatting on strings. Further string formatting code is in trans.py. +""" + +import re +import sys +from functools import lru_cache +from typing import List, Pattern + +if sys.version_info < (3, 8): + from typing_extensions import Final +else: + from typing import Final + + +STRING_PREFIX_CHARS: Final = "furbFURB" # All possible string prefix characters. +STRING_PREFIX_RE: Final = re.compile( + r"^([" + STRING_PREFIX_CHARS + r"]*)(.*)$", re.DOTALL +) +FIRST_NON_WHITESPACE_RE: Final = re.compile(r"\s*\t+\s*(\S)") + + +def sub_twice(regex: Pattern[str], replacement: str, original: str) -> str: + """Replace `regex` with `replacement` twice on `original`. + + This is used by string normalization to perform replaces on + overlapping matches. + """ + return regex.sub(replacement, regex.sub(replacement, original)) + + +def has_triple_quotes(string: str) -> bool: + """ + Returns: + True iff @string starts with three quotation characters. + """ + raw_string = string.lstrip(STRING_PREFIX_CHARS) + return raw_string[:3] in {'"""', "'''"} + + +def lines_with_leading_tabs_expanded(s: str) -> List[str]: + """ + Splits string into lines and expands only leading tabs (following the normal + Python rules) + """ + lines = [] + for line in s.splitlines(): + # Find the index of the first non-whitespace character after a string of + # whitespace that includes at least one tab + match = FIRST_NON_WHITESPACE_RE.match(line) + if match: + first_non_whitespace_idx = match.start(1) + + lines.append( + line[:first_non_whitespace_idx].expandtabs() + + line[first_non_whitespace_idx:] + ) + else: + lines.append(line) + return lines + + +def fix_docstring(docstring: str, prefix: str) -> str: + # https://www.python.org/dev/peps/pep-0257/#handling-docstring-indentation + if not docstring: + return "" + lines = lines_with_leading_tabs_expanded(docstring) + # Determine minimum indentation (first line doesn't count): + indent = sys.maxsize + for line in lines[1:]: + stripped = line.lstrip() + if stripped: + indent = min(indent, len(line) - len(stripped)) + # Remove indentation (first line is special): + trimmed = [lines[0].strip()] + if indent < sys.maxsize: + last_line_idx = len(lines) - 2 + for i, line in enumerate(lines[1:]): + stripped_line = line[indent:].rstrip() + if stripped_line or i == last_line_idx: + trimmed.append(prefix + stripped_line) + else: + trimmed.append("") + return "\n".join(trimmed) + + +def get_string_prefix(string: str) -> str: + """ + Pre-conditions: + * assert_is_leaf_string(@string) + + Returns: + @string's prefix (e.g. '', 'r', 'f', or 'rf'). + """ + assert_is_leaf_string(string) + + prefix = "" + prefix_idx = 0 + while string[prefix_idx] in STRING_PREFIX_CHARS: + prefix += string[prefix_idx] + prefix_idx += 1 + + return prefix + + +def assert_is_leaf_string(string: str) -> None: + """ + Checks the pre-condition that @string has the format that you would expect + of `leaf.value` where `leaf` is some Leaf such that `leaf.type == + token.STRING`. A more precise description of the pre-conditions that are + checked are listed below. + + Pre-conditions: + * @string starts with either ', ", ', or " where + `set()` is some subset of `set(STRING_PREFIX_CHARS)`. + * @string ends with a quote character (' or "). + + Raises: + AssertionError(...) if the pre-conditions listed above are not + satisfied. + """ + dquote_idx = string.find('"') + squote_idx = string.find("'") + if -1 in [dquote_idx, squote_idx]: + quote_idx = max(dquote_idx, squote_idx) + else: + quote_idx = min(squote_idx, dquote_idx) + + assert ( + 0 <= quote_idx < len(string) - 1 + ), f"{string!r} is missing a starting quote character (' or \")." + assert string[-1] in ( + "'", + '"', + ), f"{string!r} is missing an ending quote character (' or \")." + assert set(string[:quote_idx]).issubset( + set(STRING_PREFIX_CHARS) + ), f"{set(string[:quote_idx])} is NOT a subset of {set(STRING_PREFIX_CHARS)}." + + +def normalize_string_prefix(s: str, remove_u_prefix: bool = False) -> str: + """Make all string prefixes lowercase. + + If remove_u_prefix is given, also removes any u prefix from the string. + """ + match = STRING_PREFIX_RE.match(s) + assert match is not None, f"failed to match string {s!r}" + orig_prefix = match.group(1) + new_prefix = orig_prefix.replace("F", "f").replace("B", "b").replace("U", "u") + if remove_u_prefix: + new_prefix = new_prefix.replace("u", "") + return f"{new_prefix}{match.group(2)}" + + +# Re(gex) does actually cache patterns internally but this still improves +# performance on a long list literal of strings by 5-9% since lru_cache's +# caching overhead is much lower. +@lru_cache(maxsize=64) +def _cached_compile(pattern: str) -> Pattern[str]: + return re.compile(pattern) + + +def normalize_string_quotes(s: str) -> str: + """Prefer double quotes but only if it doesn't cause more escaping. + + Adds or removes backslashes as appropriate. Doesn't parse and fix + strings nested in f-strings. + """ + value = s.lstrip(STRING_PREFIX_CHARS) + if value[:3] == '"""': + return s + + elif value[:3] == "'''": + orig_quote = "'''" + new_quote = '"""' + elif value[0] == '"': + orig_quote = '"' + new_quote = "'" + else: + orig_quote = "'" + new_quote = '"' + first_quote_pos = s.find(orig_quote) + if first_quote_pos == -1: + return s # There's an internal error + + prefix = s[:first_quote_pos] + unescaped_new_quote = _cached_compile(rf"(([^\\]|^)(\\\\)*){new_quote}") + escaped_new_quote = _cached_compile(rf"([^\\]|^)\\((?:\\\\)*){new_quote}") + escaped_orig_quote = _cached_compile(rf"([^\\]|^)\\((?:\\\\)*){orig_quote}") + body = s[first_quote_pos + len(orig_quote) : -len(orig_quote)] + if "r" in prefix.casefold(): + if unescaped_new_quote.search(body): + # There's at least one unescaped new_quote in this raw string + # so converting is impossible + return s + + # Do not introduce or remove backslashes in raw strings + new_body = body + else: + # remove unnecessary escapes + new_body = sub_twice(escaped_new_quote, rf"\1\2{new_quote}", body) + if body != new_body: + # Consider the string without unnecessary escapes as the original + body = new_body + s = f"{prefix}{orig_quote}{body}{orig_quote}" + new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body) + new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body) + if "f" in prefix.casefold(): + matches = re.findall( + r""" + (?:(? orig_escape_count: + return s # Do not introduce more escaping + + if new_escape_count == orig_escape_count and orig_quote == '"': + return s # Prefer double quotes + + return f"{prefix}{new_quote}{new_body}{new_quote}" diff --git a/myenv/lib/python3.9/site-packages/black/trans.py b/myenv/lib/python3.9/site-packages/black/trans.py new file mode 100644 index 0000000..cb41c1b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black/trans.py @@ -0,0 +1,2064 @@ +""" +String transformers that can split and merge strings. +""" +from abc import ABC, abstractmethod +from collections import defaultdict +from dataclasses import dataclass +import re +from typing import ( + Any, + Callable, + ClassVar, + Collection, + Dict, + Iterable, + Iterator, + List, + Optional, + Sequence, + Set, + Tuple, + TypeVar, + Union, +) +import sys + +if sys.version_info < (3, 8): + from typing_extensions import Final +else: + from typing import Final + +from mypy_extensions import trait + +from black.rusty import Result, Ok, Err + +from black.mode import Feature +from black.nodes import syms, replace_child, parent_type +from black.nodes import is_empty_par, is_empty_lpar, is_empty_rpar +from black.nodes import OPENING_BRACKETS, CLOSING_BRACKETS, STANDALONE_COMMENT +from black.lines import Line, append_leaves +from black.brackets import BracketMatchError +from black.comments import contains_pragma_comment +from black.strings import has_triple_quotes, get_string_prefix, assert_is_leaf_string +from black.strings import normalize_string_quotes + +from blib2to3.pytree import Leaf, Node +from blib2to3.pgen2 import token + + +class CannotTransform(Exception): + """Base class for errors raised by Transformers.""" + + +# types +T = TypeVar("T") +LN = Union[Leaf, Node] +Transformer = Callable[[Line, Collection[Feature]], Iterator[Line]] +Index = int +NodeType = int +ParserState = int +StringID = int +TResult = Result[T, CannotTransform] # (T)ransform Result +TMatchResult = TResult[Index] + + +def TErr(err_msg: str) -> Err[CannotTransform]: + """(T)ransform Err + + Convenience function used when working with the TResult type. + """ + cant_transform = CannotTransform(err_msg) + return Err(cant_transform) + + +class StringTransformer(ABC): + """ + An implementation of the Transformer protocol that relies on its + subclasses overriding the template methods `do_match(...)` and + `do_transform(...)`. + + This Transformer works exclusively on strings (for example, by merging + or splitting them). + + The following sections can be found among the docstrings of each concrete + StringTransformer subclass. + + Requirements: + Which requirements must be met of the given Line for this + StringTransformer to be applied? + + Transformations: + If the given Line meets all of the above requirements, which string + transformations can you expect to be applied to it by this + StringTransformer? + + Collaborations: + What contractual agreements does this StringTransformer have with other + StringTransfomers? Such collaborations should be eliminated/minimized + as much as possible. + """ + + __name__: Final = "StringTransformer" + + # Ideally this would be a dataclass, but unfortunately mypyc breaks when used with + # `abc.ABC`. + def __init__(self, line_length: int, normalize_strings: bool) -> None: + self.line_length = line_length + self.normalize_strings = normalize_strings + + @abstractmethod + def do_match(self, line: Line) -> TMatchResult: + """ + Returns: + * Ok(string_idx) such that `line.leaves[string_idx]` is our target + string, if a match was able to be made. + OR + * Err(CannotTransform), if a match was not able to be made. + """ + + @abstractmethod + def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: + """ + Yields: + * Ok(new_line) where new_line is the new transformed line. + OR + * Err(CannotTransform) if the transformation failed for some reason. The + `do_match(...)` template method should usually be used to reject + the form of the given Line, but in some cases it is difficult to + know whether or not a Line meets the StringTransformer's + requirements until the transformation is already midway. + + Side Effects: + This method should NOT mutate @line directly, but it MAY mutate the + Line's underlying Node structure. (WARNING: If the underlying Node + structure IS altered, then this method should NOT be allowed to + yield an CannotTransform after that point.) + """ + + def __call__(self, line: Line, _features: Collection[Feature]) -> Iterator[Line]: + """ + StringTransformer instances have a call signature that mirrors that of + the Transformer type. + + Raises: + CannotTransform(...) if the concrete StringTransformer class is unable + to transform @line. + """ + # Optimization to avoid calling `self.do_match(...)` when the line does + # not contain any string. + if not any(leaf.type == token.STRING for leaf in line.leaves): + raise CannotTransform("There are no strings in this line.") + + match_result = self.do_match(line) + + if isinstance(match_result, Err): + cant_transform = match_result.err() + raise CannotTransform( + f"The string transformer {self.__class__.__name__} does not recognize" + " this line as one that it can transform." + ) from cant_transform + + string_idx = match_result.ok() + + for line_result in self.do_transform(line, string_idx): + if isinstance(line_result, Err): + cant_transform = line_result.err() + raise CannotTransform( + "StringTransformer failed while attempting to transform string." + ) from cant_transform + line = line_result.ok() + yield line + + +@dataclass +class CustomSplit: + """A custom (i.e. manual) string split. + + A single CustomSplit instance represents a single substring. + + Examples: + Consider the following string: + ``` + "Hi there friend." + " This is a custom" + f" string {split}." + ``` + + This string will correspond to the following three CustomSplit instances: + ``` + CustomSplit(False, 16) + CustomSplit(False, 17) + CustomSplit(True, 16) + ``` + """ + + has_prefix: bool + break_idx: int + + +@trait +class CustomSplitMapMixin: + """ + This mixin class is used to map merged strings to a sequence of + CustomSplits, which will then be used to re-split the strings iff none of + the resultant substrings go over the configured max line length. + """ + + _Key: ClassVar = Tuple[StringID, str] + _CUSTOM_SPLIT_MAP: ClassVar[Dict[_Key, Tuple[CustomSplit, ...]]] = defaultdict( + tuple + ) + + @staticmethod + def _get_key(string: str) -> "CustomSplitMapMixin._Key": + """ + Returns: + A unique identifier that is used internally to map @string to a + group of custom splits. + """ + return (id(string), string) + + def add_custom_splits( + self, string: str, custom_splits: Iterable[CustomSplit] + ) -> None: + """Custom Split Map Setter Method + + Side Effects: + Adds a mapping from @string to the custom splits @custom_splits. + """ + key = self._get_key(string) + self._CUSTOM_SPLIT_MAP[key] = tuple(custom_splits) + + def pop_custom_splits(self, string: str) -> List[CustomSplit]: + """Custom Split Map Getter Method + + Returns: + * A list of the custom splits that are mapped to @string, if any + exist. + OR + * [], otherwise. + + Side Effects: + Deletes the mapping between @string and its associated custom + splits (which are returned to the caller). + """ + key = self._get_key(string) + + custom_splits = self._CUSTOM_SPLIT_MAP[key] + del self._CUSTOM_SPLIT_MAP[key] + + return list(custom_splits) + + def has_custom_splits(self, string: str) -> bool: + """ + Returns: + True iff @string is associated with a set of custom splits. + """ + key = self._get_key(string) + return key in self._CUSTOM_SPLIT_MAP + + +class StringMerger(StringTransformer, CustomSplitMapMixin): + """StringTransformer that merges strings together. + + Requirements: + (A) The line contains adjacent strings such that ALL of the validation checks + listed in StringMerger.__validate_msg(...)'s docstring pass. + OR + (B) The line contains a string which uses line continuation backslashes. + + Transformations: + Depending on which of the two requirements above where met, either: + + (A) The string group associated with the target string is merged. + OR + (B) All line-continuation backslashes are removed from the target string. + + Collaborations: + StringMerger provides custom split information to StringSplitter. + """ + + def do_match(self, line: Line) -> TMatchResult: + LL = line.leaves + + is_valid_index = is_valid_index_factory(LL) + + for (i, leaf) in enumerate(LL): + if ( + leaf.type == token.STRING + and is_valid_index(i + 1) + and LL[i + 1].type == token.STRING + ): + return Ok(i) + + if leaf.type == token.STRING and "\\\n" in leaf.value: + return Ok(i) + + return TErr("This line has no strings that need merging.") + + def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: + new_line = line + rblc_result = self._remove_backslash_line_continuation_chars( + new_line, string_idx + ) + if isinstance(rblc_result, Ok): + new_line = rblc_result.ok() + + msg_result = self._merge_string_group(new_line, string_idx) + if isinstance(msg_result, Ok): + new_line = msg_result.ok() + + if isinstance(rblc_result, Err) and isinstance(msg_result, Err): + msg_cant_transform = msg_result.err() + rblc_cant_transform = rblc_result.err() + cant_transform = CannotTransform( + "StringMerger failed to merge any strings in this line." + ) + + # Chain the errors together using `__cause__`. + msg_cant_transform.__cause__ = rblc_cant_transform + cant_transform.__cause__ = msg_cant_transform + + yield Err(cant_transform) + else: + yield Ok(new_line) + + @staticmethod + def _remove_backslash_line_continuation_chars( + line: Line, string_idx: int + ) -> TResult[Line]: + """ + Merge strings that were split across multiple lines using + line-continuation backslashes. + + Returns: + Ok(new_line), if @line contains backslash line-continuation + characters. + OR + Err(CannotTransform), otherwise. + """ + LL = line.leaves + + string_leaf = LL[string_idx] + if not ( + string_leaf.type == token.STRING + and "\\\n" in string_leaf.value + and not has_triple_quotes(string_leaf.value) + ): + return TErr( + f"String leaf {string_leaf} does not contain any backslash line" + " continuation characters." + ) + + new_line = line.clone() + new_line.comments = line.comments.copy() + append_leaves(new_line, line, LL) + + new_string_leaf = new_line.leaves[string_idx] + new_string_leaf.value = new_string_leaf.value.replace("\\\n", "") + + return Ok(new_line) + + def _merge_string_group(self, line: Line, string_idx: int) -> TResult[Line]: + """ + Merges string group (i.e. set of adjacent strings) where the first + string in the group is `line.leaves[string_idx]`. + + Returns: + Ok(new_line), if ALL of the validation checks found in + __validate_msg(...) pass. + OR + Err(CannotTransform), otherwise. + """ + LL = line.leaves + + is_valid_index = is_valid_index_factory(LL) + + vresult = self._validate_msg(line, string_idx) + if isinstance(vresult, Err): + return vresult + + # If the string group is wrapped inside an Atom node, we must make sure + # to later replace that Atom with our new (merged) string leaf. + atom_node = LL[string_idx].parent + + # We will place BREAK_MARK in between every two substrings that we + # merge. We will then later go through our final result and use the + # various instances of BREAK_MARK we find to add the right values to + # the custom split map. + BREAK_MARK = "@@@@@ BLACK BREAKPOINT MARKER @@@@@" + + QUOTE = LL[string_idx].value[-1] + + def make_naked(string: str, string_prefix: str) -> str: + """Strip @string (i.e. make it a "naked" string) + + Pre-conditions: + * assert_is_leaf_string(@string) + + Returns: + A string that is identical to @string except that + @string_prefix has been stripped, the surrounding QUOTE + characters have been removed, and any remaining QUOTE + characters have been escaped. + """ + assert_is_leaf_string(string) + + RE_EVEN_BACKSLASHES = r"(?:(?= 0 + ), "Logic error while filling the custom string breakpoint cache." + + temp_string = temp_string[mark_idx + len(BREAK_MARK) :] + breakpoint_idx = mark_idx + (len(prefix) if has_prefix else 0) + 1 + custom_splits.append(CustomSplit(has_prefix, breakpoint_idx)) + + string_leaf = Leaf(token.STRING, S_leaf.value.replace(BREAK_MARK, "")) + + if atom_node is not None: + replace_child(atom_node, string_leaf) + + # Build the final line ('new_line') that this method will later return. + new_line = line.clone() + for (i, leaf) in enumerate(LL): + if i == string_idx: + new_line.append(string_leaf) + + if string_idx <= i < string_idx + num_of_strings: + for comment_leaf in line.comments_after(LL[i]): + new_line.append(comment_leaf, preformatted=True) + continue + + append_leaves(new_line, line, [leaf]) + + self.add_custom_splits(string_leaf.value, custom_splits) + return Ok(new_line) + + @staticmethod + def _validate_msg(line: Line, string_idx: int) -> TResult[None]: + """Validate (M)erge (S)tring (G)roup + + Transform-time string validation logic for __merge_string_group(...). + + Returns: + * Ok(None), if ALL validation checks (listed below) pass. + OR + * Err(CannotTransform), if any of the following are true: + - The target string group does not contain ANY stand-alone comments. + - The target string is not in a string group (i.e. it has no + adjacent strings). + - The string group has more than one inline comment. + - The string group has an inline comment that appears to be a pragma. + - The set of all string prefixes in the string group is of + length greater than one and is not equal to {"", "f"}. + - The string group consists of raw strings. + """ + # We first check for "inner" stand-alone comments (i.e. stand-alone + # comments that have a string leaf before them AND after them). + for inc in [1, -1]: + i = string_idx + found_sa_comment = False + is_valid_index = is_valid_index_factory(line.leaves) + while is_valid_index(i) and line.leaves[i].type in [ + token.STRING, + STANDALONE_COMMENT, + ]: + if line.leaves[i].type == STANDALONE_COMMENT: + found_sa_comment = True + elif found_sa_comment: + return TErr( + "StringMerger does NOT merge string groups which contain " + "stand-alone comments." + ) + + i += inc + + num_of_inline_string_comments = 0 + set_of_prefixes = set() + num_of_strings = 0 + for leaf in line.leaves[string_idx:]: + if leaf.type != token.STRING: + # If the string group is trailed by a comma, we count the + # comments trailing the comma to be one of the string group's + # comments. + if leaf.type == token.COMMA and id(leaf) in line.comments: + num_of_inline_string_comments += 1 + break + + if has_triple_quotes(leaf.value): + return TErr("StringMerger does NOT merge multiline strings.") + + num_of_strings += 1 + prefix = get_string_prefix(leaf.value).lower() + if "r" in prefix: + return TErr("StringMerger does NOT merge raw strings.") + + set_of_prefixes.add(prefix) + + if id(leaf) in line.comments: + num_of_inline_string_comments += 1 + if contains_pragma_comment(line.comments[id(leaf)]): + return TErr("Cannot merge strings which have pragma comments.") + + if num_of_strings < 2: + return TErr( + f"Not enough strings to merge (num_of_strings={num_of_strings})." + ) + + if num_of_inline_string_comments > 1: + return TErr( + f"Too many inline string comments ({num_of_inline_string_comments})." + ) + + if len(set_of_prefixes) > 1 and set_of_prefixes != {"", "f"}: + return TErr(f"Too many different prefixes ({set_of_prefixes}).") + + return Ok(None) + + +class StringParenStripper(StringTransformer): + """StringTransformer that strips surrounding parentheses from strings. + + Requirements: + The line contains a string which is surrounded by parentheses and: + - The target string is NOT the only argument to a function call. + - The target string is NOT a "pointless" string. + - If the target string contains a PERCENT, the brackets are not + preceded or followed by an operator with higher precedence than + PERCENT. + + Transformations: + The parentheses mentioned in the 'Requirements' section are stripped. + + Collaborations: + StringParenStripper has its own inherent usefulness, but it is also + relied on to clean up the parentheses created by StringParenWrapper (in + the event that they are no longer needed). + """ + + def do_match(self, line: Line) -> TMatchResult: + LL = line.leaves + + is_valid_index = is_valid_index_factory(LL) + + for (idx, leaf) in enumerate(LL): + # Should be a string... + if leaf.type != token.STRING: + continue + + # If this is a "pointless" string... + if ( + leaf.parent + and leaf.parent.parent + and leaf.parent.parent.type == syms.simple_stmt + ): + continue + + # Should be preceded by a non-empty LPAR... + if ( + not is_valid_index(idx - 1) + or LL[idx - 1].type != token.LPAR + or is_empty_lpar(LL[idx - 1]) + ): + continue + + # That LPAR should NOT be preceded by a function name or a closing + # bracket (which could be a function which returns a function or a + # list/dictionary that contains a function)... + if is_valid_index(idx - 2) and ( + LL[idx - 2].type == token.NAME or LL[idx - 2].type in CLOSING_BRACKETS + ): + continue + + string_idx = idx + + # Skip the string trailer, if one exists. + string_parser = StringParser() + next_idx = string_parser.parse(LL, string_idx) + + # if the leaves in the parsed string include a PERCENT, we need to + # make sure the initial LPAR is NOT preceded by an operator with + # higher or equal precedence to PERCENT + if is_valid_index(idx - 2): + # mypy can't quite follow unless we name this + before_lpar = LL[idx - 2] + if token.PERCENT in {leaf.type for leaf in LL[idx - 1 : next_idx]} and ( + ( + before_lpar.type + in { + token.STAR, + token.AT, + token.SLASH, + token.DOUBLESLASH, + token.PERCENT, + token.TILDE, + token.DOUBLESTAR, + token.AWAIT, + token.LSQB, + token.LPAR, + } + ) + or ( + # only unary PLUS/MINUS + before_lpar.parent + and before_lpar.parent.type == syms.factor + and (before_lpar.type in {token.PLUS, token.MINUS}) + ) + ): + continue + + # Should be followed by a non-empty RPAR... + if ( + is_valid_index(next_idx) + and LL[next_idx].type == token.RPAR + and not is_empty_rpar(LL[next_idx]) + ): + # That RPAR should NOT be followed by anything with higher + # precedence than PERCENT + if is_valid_index(next_idx + 1) and LL[next_idx + 1].type in { + token.DOUBLESTAR, + token.LSQB, + token.LPAR, + token.DOT, + }: + continue + + return Ok(string_idx) + + return TErr("This line has no strings wrapped in parens.") + + def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: + LL = line.leaves + + string_parser = StringParser() + rpar_idx = string_parser.parse(LL, string_idx) + + for leaf in (LL[string_idx - 1], LL[rpar_idx]): + if line.comments_after(leaf): + yield TErr( + "Will not strip parentheses which have comments attached to them." + ) + return + + new_line = line.clone() + new_line.comments = line.comments.copy() + try: + append_leaves(new_line, line, LL[: string_idx - 1]) + except BracketMatchError: + # HACK: I believe there is currently a bug somewhere in + # right_hand_split() that is causing brackets to not be tracked + # properly by a shared BracketTracker. + append_leaves(new_line, line, LL[: string_idx - 1], preformatted=True) + + string_leaf = Leaf(token.STRING, LL[string_idx].value) + LL[string_idx - 1].remove() + replace_child(LL[string_idx], string_leaf) + new_line.append(string_leaf) + + append_leaves( + new_line, line, LL[string_idx + 1 : rpar_idx] + LL[rpar_idx + 1 :] + ) + + LL[rpar_idx].remove() + + yield Ok(new_line) + + +class BaseStringSplitter(StringTransformer): + """ + Abstract class for StringTransformers which transform a Line's strings by splitting + them or placing them on their own lines where necessary to avoid going over + the configured line length. + + Requirements: + * The target string value is responsible for the line going over the + line length limit. It follows that after all of black's other line + split methods have been exhausted, this line (or one of the resulting + lines after all line splits are performed) would still be over the + line_length limit unless we split this string. + AND + * The target string is NOT a "pointless" string (i.e. a string that has + no parent or siblings). + AND + * The target string is not followed by an inline comment that appears + to be a pragma. + AND + * The target string is not a multiline (i.e. triple-quote) string. + """ + + STRING_OPERATORS: Final = [ + token.EQEQUAL, + token.GREATER, + token.GREATEREQUAL, + token.LESS, + token.LESSEQUAL, + token.NOTEQUAL, + token.PERCENT, + token.PLUS, + token.STAR, + ] + + @abstractmethod + def do_splitter_match(self, line: Line) -> TMatchResult: + """ + BaseStringSplitter asks its clients to override this method instead of + `StringTransformer.do_match(...)`. + + Follows the same protocol as `StringTransformer.do_match(...)`. + + Refer to `help(StringTransformer.do_match)` for more information. + """ + + def do_match(self, line: Line) -> TMatchResult: + match_result = self.do_splitter_match(line) + if isinstance(match_result, Err): + return match_result + + string_idx = match_result.ok() + vresult = self._validate(line, string_idx) + if isinstance(vresult, Err): + return vresult + + return match_result + + def _validate(self, line: Line, string_idx: int) -> TResult[None]: + """ + Checks that @line meets all of the requirements listed in this classes' + docstring. Refer to `help(BaseStringSplitter)` for a detailed + description of those requirements. + + Returns: + * Ok(None), if ALL of the requirements are met. + OR + * Err(CannotTransform), if ANY of the requirements are NOT met. + """ + LL = line.leaves + + string_leaf = LL[string_idx] + + max_string_length = self._get_max_string_length(line, string_idx) + if len(string_leaf.value) <= max_string_length: + return TErr( + "The string itself is not what is causing this line to be too long." + ) + + if not string_leaf.parent or [L.type for L in string_leaf.parent.children] == [ + token.STRING, + token.NEWLINE, + ]: + return TErr( + f"This string ({string_leaf.value}) appears to be pointless (i.e. has" + " no parent)." + ) + + if id(line.leaves[string_idx]) in line.comments and contains_pragma_comment( + line.comments[id(line.leaves[string_idx])] + ): + return TErr( + "Line appears to end with an inline pragma comment. Splitting the line" + " could modify the pragma's behavior." + ) + + if has_triple_quotes(string_leaf.value): + return TErr("We cannot split multiline strings.") + + return Ok(None) + + def _get_max_string_length(self, line: Line, string_idx: int) -> int: + """ + Calculates the max string length used when attempting to determine + whether or not the target string is responsible for causing the line to + go over the line length limit. + + WARNING: This method is tightly coupled to both StringSplitter and + (especially) StringParenWrapper. There is probably a better way to + accomplish what is being done here. + + Returns: + max_string_length: such that `line.leaves[string_idx].value > + max_string_length` implies that the target string IS responsible + for causing this line to exceed the line length limit. + """ + LL = line.leaves + + is_valid_index = is_valid_index_factory(LL) + + # We use the shorthand "WMA4" in comments to abbreviate "We must + # account for". When giving examples, we use STRING to mean some/any + # valid string. + # + # Finally, we use the following convenience variables: + # + # P: The leaf that is before the target string leaf. + # N: The leaf that is after the target string leaf. + # NN: The leaf that is after N. + + # WMA4 the whitespace at the beginning of the line. + offset = line.depth * 4 + + if is_valid_index(string_idx - 1): + p_idx = string_idx - 1 + if ( + LL[string_idx - 1].type == token.LPAR + and LL[string_idx - 1].value == "" + and string_idx >= 2 + ): + # If the previous leaf is an empty LPAR placeholder, we should skip it. + p_idx -= 1 + + P = LL[p_idx] + if P.type in self.STRING_OPERATORS: + # WMA4 a space and a string operator (e.g. `+ STRING` or `== STRING`). + offset += len(str(P)) + 1 + + if P.type == token.COMMA: + # WMA4 a space, a comma, and a closing bracket [e.g. `), STRING`]. + offset += 3 + + if P.type in [token.COLON, token.EQUAL, token.PLUSEQUAL, token.NAME]: + # This conditional branch is meant to handle dictionary keys, + # variable assignments, 'return STRING' statement lines, and + # 'else STRING' ternary expression lines. + + # WMA4 a single space. + offset += 1 + + # WMA4 the lengths of any leaves that came before that space, + # but after any closing bracket before that space. + for leaf in reversed(LL[: p_idx + 1]): + offset += len(str(leaf)) + if leaf.type in CLOSING_BRACKETS: + break + + if is_valid_index(string_idx + 1): + N = LL[string_idx + 1] + if N.type == token.RPAR and N.value == "" and len(LL) > string_idx + 2: + # If the next leaf is an empty RPAR placeholder, we should skip it. + N = LL[string_idx + 2] + + if N.type == token.COMMA: + # WMA4 a single comma at the end of the string (e.g `STRING,`). + offset += 1 + + if is_valid_index(string_idx + 2): + NN = LL[string_idx + 2] + + if N.type == token.DOT and NN.type == token.NAME: + # This conditional branch is meant to handle method calls invoked + # off of a string literal up to and including the LPAR character. + + # WMA4 the '.' character. + offset += 1 + + if ( + is_valid_index(string_idx + 3) + and LL[string_idx + 3].type == token.LPAR + ): + # WMA4 the left parenthesis character. + offset += 1 + + # WMA4 the length of the method's name. + offset += len(NN.value) + + has_comments = False + for comment_leaf in line.comments_after(LL[string_idx]): + if not has_comments: + has_comments = True + # WMA4 two spaces before the '#' character. + offset += 2 + + # WMA4 the length of the inline comment. + offset += len(comment_leaf.value) + + max_string_length = self.line_length - offset + return max_string_length + + +def iter_fexpr_spans(s: str) -> Iterator[Tuple[int, int]]: + """ + Yields spans corresponding to expressions in a given f-string. + Spans are half-open ranges (left inclusive, right exclusive). + Assumes the input string is a valid f-string, but will not crash if the input + string is invalid. + """ + stack: List[int] = [] # our curly paren stack + i = 0 + while i < len(s): + if s[i] == "{": + # if we're in a string part of the f-string, ignore escaped curly braces + if not stack and i + 1 < len(s) and s[i + 1] == "{": + i += 2 + continue + stack.append(i) + i += 1 + continue + + if s[i] == "}": + if not stack: + i += 1 + continue + j = stack.pop() + # we've made it back out of the expression! yield the span + if not stack: + yield (j, i + 1) + i += 1 + continue + + # if we're in an expression part of the f-string, fast forward through strings + # note that backslashes are not legal in the expression portion of f-strings + if stack: + delim = None + if s[i : i + 3] in ("'''", '"""'): + delim = s[i : i + 3] + elif s[i] in ("'", '"'): + delim = s[i] + if delim: + i += len(delim) + while i < len(s) and s[i : i + len(delim)] != delim: + i += 1 + i += len(delim) + continue + i += 1 + + +def fstring_contains_expr(s: str) -> bool: + return any(iter_fexpr_spans(s)) + + +class StringSplitter(BaseStringSplitter, CustomSplitMapMixin): + """ + StringTransformer that splits "atom" strings (i.e. strings which exist on + lines by themselves). + + Requirements: + * The line consists ONLY of a single string (possibly prefixed by a + string operator [e.g. '+' or '==']), MAYBE a string trailer, and MAYBE + a trailing comma. + AND + * All of the requirements listed in BaseStringSplitter's docstring. + + Transformations: + The string mentioned in the 'Requirements' section is split into as + many substrings as necessary to adhere to the configured line length. + + In the final set of substrings, no substring should be smaller than + MIN_SUBSTR_SIZE characters. + + The string will ONLY be split on spaces (i.e. each new substring should + start with a space). Note that the string will NOT be split on a space + which is escaped with a backslash. + + If the string is an f-string, it will NOT be split in the middle of an + f-expression (e.g. in f"FooBar: {foo() if x else bar()}", {foo() if x + else bar()} is an f-expression). + + If the string that is being split has an associated set of custom split + records and those custom splits will NOT result in any line going over + the configured line length, those custom splits are used. Otherwise the + string is split as late as possible (from left-to-right) while still + adhering to the transformation rules listed above. + + Collaborations: + StringSplitter relies on StringMerger to construct the appropriate + CustomSplit objects and add them to the custom split map. + """ + + MIN_SUBSTR_SIZE: Final = 6 + + def do_splitter_match(self, line: Line) -> TMatchResult: + LL = line.leaves + + is_valid_index = is_valid_index_factory(LL) + + idx = 0 + + # The first two leaves MAY be the 'not in' keywords... + if ( + is_valid_index(idx) + and is_valid_index(idx + 1) + and [LL[idx].type, LL[idx + 1].type] == [token.NAME, token.NAME] + and str(LL[idx]) + str(LL[idx + 1]) == "not in" + ): + idx += 2 + # Else the first leaf MAY be a string operator symbol or the 'in' keyword... + elif is_valid_index(idx) and ( + LL[idx].type in self.STRING_OPERATORS + or LL[idx].type == token.NAME + and str(LL[idx]) == "in" + ): + idx += 1 + + # The next/first leaf MAY be an empty LPAR... + if is_valid_index(idx) and is_empty_lpar(LL[idx]): + idx += 1 + + # The next/first leaf MUST be a string... + if not is_valid_index(idx) or LL[idx].type != token.STRING: + return TErr("Line does not start with a string.") + + string_idx = idx + + # Skip the string trailer, if one exists. + string_parser = StringParser() + idx = string_parser.parse(LL, string_idx) + + # That string MAY be followed by an empty RPAR... + if is_valid_index(idx) and is_empty_rpar(LL[idx]): + idx += 1 + + # That string / empty RPAR leaf MAY be followed by a comma... + if is_valid_index(idx) and LL[idx].type == token.COMMA: + idx += 1 + + # But no more leaves are allowed... + if is_valid_index(idx): + return TErr("This line does not end with a string.") + + return Ok(string_idx) + + def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: + LL = line.leaves + + QUOTE = LL[string_idx].value[-1] + + is_valid_index = is_valid_index_factory(LL) + insert_str_child = insert_str_child_factory(LL[string_idx]) + + prefix = get_string_prefix(LL[string_idx].value).lower() + + # We MAY choose to drop the 'f' prefix from substrings that don't + # contain any f-expressions, but ONLY if the original f-string + # contains at least one f-expression. Otherwise, we will alter the AST + # of the program. + drop_pointless_f_prefix = ("f" in prefix) and fstring_contains_expr( + LL[string_idx].value + ) + + first_string_line = True + + string_op_leaves = self._get_string_operator_leaves(LL) + string_op_leaves_length = ( + sum([len(str(prefix_leaf)) for prefix_leaf in string_op_leaves]) + 1 + if string_op_leaves + else 0 + ) + + def maybe_append_string_operators(new_line: Line) -> None: + """ + Side Effects: + If @line starts with a string operator and this is the first + line we are constructing, this function appends the string + operator to @new_line and replaces the old string operator leaf + in the node structure. Otherwise this function does nothing. + """ + maybe_prefix_leaves = string_op_leaves if first_string_line else [] + for i, prefix_leaf in enumerate(maybe_prefix_leaves): + replace_child(LL[i], prefix_leaf) + new_line.append(prefix_leaf) + + ends_with_comma = ( + is_valid_index(string_idx + 1) and LL[string_idx + 1].type == token.COMMA + ) + + def max_last_string() -> int: + """ + Returns: + The max allowed length of the string value used for the last + line we will construct. + """ + result = self.line_length + result -= line.depth * 4 + result -= 1 if ends_with_comma else 0 + result -= string_op_leaves_length + return result + + # --- Calculate Max Break Index (for string value) + # We start with the line length limit + max_break_idx = self.line_length + # The last index of a string of length N is N-1. + max_break_idx -= 1 + # Leading whitespace is not present in the string value (e.g. Leaf.value). + max_break_idx -= line.depth * 4 + if max_break_idx < 0: + yield TErr( + f"Unable to split {LL[string_idx].value} at such high of a line depth:" + f" {line.depth}" + ) + return + + # Check if StringMerger registered any custom splits. + custom_splits = self.pop_custom_splits(LL[string_idx].value) + # We use them ONLY if none of them would produce lines that exceed the + # line limit. + use_custom_breakpoints = bool( + custom_splits + and all(csplit.break_idx <= max_break_idx for csplit in custom_splits) + ) + + # Temporary storage for the remaining chunk of the string line that + # can't fit onto the line currently being constructed. + rest_value = LL[string_idx].value + + def more_splits_should_be_made() -> bool: + """ + Returns: + True iff `rest_value` (the remaining string value from the last + split), should be split again. + """ + if use_custom_breakpoints: + return len(custom_splits) > 1 + else: + return len(rest_value) > max_last_string() + + string_line_results: List[Ok[Line]] = [] + while more_splits_should_be_made(): + if use_custom_breakpoints: + # Custom User Split (manual) + csplit = custom_splits.pop(0) + break_idx = csplit.break_idx + else: + # Algorithmic Split (automatic) + max_bidx = max_break_idx - string_op_leaves_length + maybe_break_idx = self._get_break_idx(rest_value, max_bidx) + if maybe_break_idx is None: + # If we are unable to algorithmically determine a good split + # and this string has custom splits registered to it, we + # fall back to using them--which means we have to start + # over from the beginning. + if custom_splits: + rest_value = LL[string_idx].value + string_line_results = [] + first_string_line = True + use_custom_breakpoints = True + continue + + # Otherwise, we stop splitting here. + break + + break_idx = maybe_break_idx + + # --- Construct `next_value` + next_value = rest_value[:break_idx] + QUOTE + + # HACK: The following 'if' statement is a hack to fix the custom + # breakpoint index in the case of either: (a) substrings that were + # f-strings but will have the 'f' prefix removed OR (b) substrings + # that were not f-strings but will now become f-strings because of + # redundant use of the 'f' prefix (i.e. none of the substrings + # contain f-expressions but one or more of them had the 'f' prefix + # anyway; in which case, we will prepend 'f' to _all_ substrings). + # + # There is probably a better way to accomplish what is being done + # here... + # + # If this substring is an f-string, we _could_ remove the 'f' + # prefix, and the current custom split did NOT originally use a + # prefix... + if ( + next_value != self._normalize_f_string(next_value, prefix) + and use_custom_breakpoints + and not csplit.has_prefix + ): + # Then `csplit.break_idx` will be off by one after removing + # the 'f' prefix. + break_idx += 1 + next_value = rest_value[:break_idx] + QUOTE + + if drop_pointless_f_prefix: + next_value = self._normalize_f_string(next_value, prefix) + + # --- Construct `next_leaf` + next_leaf = Leaf(token.STRING, next_value) + insert_str_child(next_leaf) + self._maybe_normalize_string_quotes(next_leaf) + + # --- Construct `next_line` + next_line = line.clone() + maybe_append_string_operators(next_line) + next_line.append(next_leaf) + string_line_results.append(Ok(next_line)) + + rest_value = prefix + QUOTE + rest_value[break_idx:] + first_string_line = False + + yield from string_line_results + + if drop_pointless_f_prefix: + rest_value = self._normalize_f_string(rest_value, prefix) + + rest_leaf = Leaf(token.STRING, rest_value) + insert_str_child(rest_leaf) + + # NOTE: I could not find a test case that verifies that the following + # line is actually necessary, but it seems to be. Otherwise we risk + # not normalizing the last substring, right? + self._maybe_normalize_string_quotes(rest_leaf) + + last_line = line.clone() + maybe_append_string_operators(last_line) + + # If there are any leaves to the right of the target string... + if is_valid_index(string_idx + 1): + # We use `temp_value` here to determine how long the last line + # would be if we were to append all the leaves to the right of the + # target string to the last string line. + temp_value = rest_value + for leaf in LL[string_idx + 1 :]: + temp_value += str(leaf) + if leaf.type == token.LPAR: + break + + # Try to fit them all on the same line with the last substring... + if ( + len(temp_value) <= max_last_string() + or LL[string_idx + 1].type == token.COMMA + ): + last_line.append(rest_leaf) + append_leaves(last_line, line, LL[string_idx + 1 :]) + yield Ok(last_line) + # Otherwise, place the last substring on one line and everything + # else on a line below that... + else: + last_line.append(rest_leaf) + yield Ok(last_line) + + non_string_line = line.clone() + append_leaves(non_string_line, line, LL[string_idx + 1 :]) + yield Ok(non_string_line) + # Else the target string was the last leaf... + else: + last_line.append(rest_leaf) + last_line.comments = line.comments.copy() + yield Ok(last_line) + + def _iter_nameescape_slices(self, string: str) -> Iterator[Tuple[Index, Index]]: + """ + Yields: + All ranges of @string which, if @string were to be split there, + would result in the splitting of an \\N{...} expression (which is NOT + allowed). + """ + # True - the previous backslash was unescaped + # False - the previous backslash was escaped *or* there was no backslash + previous_was_unescaped_backslash = False + it = iter(enumerate(string)) + for idx, c in it: + if c == "\\": + previous_was_unescaped_backslash = not previous_was_unescaped_backslash + continue + if not previous_was_unescaped_backslash or c != "N": + previous_was_unescaped_backslash = False + continue + previous_was_unescaped_backslash = False + + begin = idx - 1 # the position of backslash before \N{...} + for idx, c in it: + if c == "}": + end = idx + break + else: + # malformed nameescape expression? + # should have been detected by AST parsing earlier... + raise RuntimeError(f"{self.__class__.__name__} LOGIC ERROR!") + yield begin, end + + def _iter_fexpr_slices(self, string: str) -> Iterator[Tuple[Index, Index]]: + """ + Yields: + All ranges of @string which, if @string were to be split there, + would result in the splitting of an f-expression (which is NOT + allowed). + """ + if "f" not in get_string_prefix(string).lower(): + return + yield from iter_fexpr_spans(string) + + def _get_illegal_split_indices(self, string: str) -> Set[Index]: + illegal_indices: Set[Index] = set() + iterators = [ + self._iter_fexpr_slices(string), + self._iter_nameescape_slices(string), + ] + for it in iterators: + for begin, end in it: + illegal_indices.update(range(begin, end + 1)) + return illegal_indices + + def _get_break_idx(self, string: str, max_break_idx: int) -> Optional[int]: + """ + This method contains the algorithm that StringSplitter uses to + determine which character to split each string at. + + Args: + @string: The substring that we are attempting to split. + @max_break_idx: The ideal break index. We will return this value if it + meets all the necessary conditions. In the likely event that it + doesn't we will try to find the closest index BELOW @max_break_idx + that does. If that fails, we will expand our search by also + considering all valid indices ABOVE @max_break_idx. + + Pre-Conditions: + * assert_is_leaf_string(@string) + * 0 <= @max_break_idx < len(@string) + + Returns: + break_idx, if an index is able to be found that meets all of the + conditions listed in the 'Transformations' section of this classes' + docstring. + OR + None, otherwise. + """ + is_valid_index = is_valid_index_factory(string) + + assert is_valid_index(max_break_idx) + assert_is_leaf_string(string) + + _illegal_split_indices = self._get_illegal_split_indices(string) + + def breaks_unsplittable_expression(i: Index) -> bool: + """ + Returns: + True iff returning @i would result in the splitting of an + unsplittable expression (which is NOT allowed). + """ + return i in _illegal_split_indices + + def passes_all_checks(i: Index) -> bool: + """ + Returns: + True iff ALL of the conditions listed in the 'Transformations' + section of this classes' docstring would be be met by returning @i. + """ + is_space = string[i] == " " + + is_not_escaped = True + j = i - 1 + while is_valid_index(j) and string[j] == "\\": + is_not_escaped = not is_not_escaped + j -= 1 + + is_big_enough = ( + len(string[i:]) >= self.MIN_SUBSTR_SIZE + and len(string[:i]) >= self.MIN_SUBSTR_SIZE + ) + return ( + is_space + and is_not_escaped + and is_big_enough + and not breaks_unsplittable_expression(i) + ) + + # First, we check all indices BELOW @max_break_idx. + break_idx = max_break_idx + while is_valid_index(break_idx - 1) and not passes_all_checks(break_idx): + break_idx -= 1 + + if not passes_all_checks(break_idx): + # If that fails, we check all indices ABOVE @max_break_idx. + # + # If we are able to find a valid index here, the next line is going + # to be longer than the specified line length, but it's probably + # better than doing nothing at all. + break_idx = max_break_idx + 1 + while is_valid_index(break_idx + 1) and not passes_all_checks(break_idx): + break_idx += 1 + + if not is_valid_index(break_idx) or not passes_all_checks(break_idx): + return None + + return break_idx + + def _maybe_normalize_string_quotes(self, leaf: Leaf) -> None: + if self.normalize_strings: + leaf.value = normalize_string_quotes(leaf.value) + + def _normalize_f_string(self, string: str, prefix: str) -> str: + """ + Pre-Conditions: + * assert_is_leaf_string(@string) + + Returns: + * If @string is an f-string that contains no f-expressions, we + return a string identical to @string except that the 'f' prefix + has been stripped and all double braces (i.e. '{{' or '}}') have + been normalized (i.e. turned into '{' or '}'). + OR + * Otherwise, we return @string. + """ + assert_is_leaf_string(string) + + if "f" in prefix and not fstring_contains_expr(string): + new_prefix = prefix.replace("f", "") + + temp = string[len(prefix) :] + temp = re.sub(r"\{\{", "{", temp) + temp = re.sub(r"\}\}", "}", temp) + new_string = temp + + return f"{new_prefix}{new_string}" + else: + return string + + def _get_string_operator_leaves(self, leaves: Iterable[Leaf]) -> List[Leaf]: + LL = list(leaves) + + string_op_leaves = [] + i = 0 + while LL[i].type in self.STRING_OPERATORS + [token.NAME]: + prefix_leaf = Leaf(LL[i].type, str(LL[i]).strip()) + string_op_leaves.append(prefix_leaf) + i += 1 + return string_op_leaves + + +class StringParenWrapper(BaseStringSplitter, CustomSplitMapMixin): + """ + StringTransformer that splits non-"atom" strings (i.e. strings that do not + exist on lines by themselves). + + Requirements: + All of the requirements listed in BaseStringSplitter's docstring in + addition to the requirements listed below: + + * The line is a return/yield statement, which returns/yields a string. + OR + * The line is part of a ternary expression (e.g. `x = y if cond else + z`) such that the line starts with `else `, where is + some string. + OR + * The line is an assert statement, which ends with a string. + OR + * The line is an assignment statement (e.g. `x = ` or `x += + `) such that the variable is being assigned the value of some + string. + OR + * The line is a dictionary key assignment where some valid key is being + assigned the value of some string. + + Transformations: + The chosen string is wrapped in parentheses and then split at the LPAR. + + We then have one line which ends with an LPAR and another line that + starts with the chosen string. The latter line is then split again at + the RPAR. This results in the RPAR (and possibly a trailing comma) + being placed on its own line. + + NOTE: If any leaves exist to the right of the chosen string (except + for a trailing comma, which would be placed after the RPAR), those + leaves are placed inside the parentheses. In effect, the chosen + string is not necessarily being "wrapped" by parentheses. We can, + however, count on the LPAR being placed directly before the chosen + string. + + In other words, StringParenWrapper creates "atom" strings. These + can then be split again by StringSplitter, if necessary. + + Collaborations: + In the event that a string line split by StringParenWrapper is + changed such that it no longer needs to be given its own line, + StringParenWrapper relies on StringParenStripper to clean up the + parentheses it created. + """ + + def do_splitter_match(self, line: Line) -> TMatchResult: + LL = line.leaves + + if line.leaves[-1].type in OPENING_BRACKETS: + return TErr( + "Cannot wrap parens around a line that ends in an opening bracket." + ) + + string_idx = ( + self._return_match(LL) + or self._else_match(LL) + or self._assert_match(LL) + or self._assign_match(LL) + or self._dict_match(LL) + ) + + if string_idx is not None: + string_value = line.leaves[string_idx].value + # If the string has no spaces... + if " " not in string_value: + # And will still violate the line length limit when split... + max_string_length = self.line_length - ((line.depth + 1) * 4) + if len(string_value) > max_string_length: + # And has no associated custom splits... + if not self.has_custom_splits(string_value): + # Then we should NOT put this string on its own line. + return TErr( + "We do not wrap long strings in parentheses when the" + " resultant line would still be over the specified line" + " length and can't be split further by StringSplitter." + ) + return Ok(string_idx) + + return TErr("This line does not contain any non-atomic strings.") + + @staticmethod + def _return_match(LL: List[Leaf]) -> Optional[int]: + """ + Returns: + string_idx such that @LL[string_idx] is equal to our target (i.e. + matched) string, if this line matches the return/yield statement + requirements listed in the 'Requirements' section of this classes' + docstring. + OR + None, otherwise. + """ + # If this line is apart of a return/yield statement and the first leaf + # contains either the "return" or "yield" keywords... + if parent_type(LL[0]) in [syms.return_stmt, syms.yield_expr] and LL[ + 0 + ].value in ["return", "yield"]: + is_valid_index = is_valid_index_factory(LL) + + idx = 2 if is_valid_index(1) and is_empty_par(LL[1]) else 1 + # The next visible leaf MUST contain a string... + if is_valid_index(idx) and LL[idx].type == token.STRING: + return idx + + return None + + @staticmethod + def _else_match(LL: List[Leaf]) -> Optional[int]: + """ + Returns: + string_idx such that @LL[string_idx] is equal to our target (i.e. + matched) string, if this line matches the ternary expression + requirements listed in the 'Requirements' section of this classes' + docstring. + OR + None, otherwise. + """ + # If this line is apart of a ternary expression and the first leaf + # contains the "else" keyword... + if ( + parent_type(LL[0]) == syms.test + and LL[0].type == token.NAME + and LL[0].value == "else" + ): + is_valid_index = is_valid_index_factory(LL) + + idx = 2 if is_valid_index(1) and is_empty_par(LL[1]) else 1 + # The next visible leaf MUST contain a string... + if is_valid_index(idx) and LL[idx].type == token.STRING: + return idx + + return None + + @staticmethod + def _assert_match(LL: List[Leaf]) -> Optional[int]: + """ + Returns: + string_idx such that @LL[string_idx] is equal to our target (i.e. + matched) string, if this line matches the assert statement + requirements listed in the 'Requirements' section of this classes' + docstring. + OR + None, otherwise. + """ + # If this line is apart of an assert statement and the first leaf + # contains the "assert" keyword... + if parent_type(LL[0]) == syms.assert_stmt and LL[0].value == "assert": + is_valid_index = is_valid_index_factory(LL) + + for (i, leaf) in enumerate(LL): + # We MUST find a comma... + if leaf.type == token.COMMA: + idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1 + + # That comma MUST be followed by a string... + if is_valid_index(idx) and LL[idx].type == token.STRING: + string_idx = idx + + # Skip the string trailer, if one exists. + string_parser = StringParser() + idx = string_parser.parse(LL, string_idx) + + # But no more leaves are allowed... + if not is_valid_index(idx): + return string_idx + + return None + + @staticmethod + def _assign_match(LL: List[Leaf]) -> Optional[int]: + """ + Returns: + string_idx such that @LL[string_idx] is equal to our target (i.e. + matched) string, if this line matches the assignment statement + requirements listed in the 'Requirements' section of this classes' + docstring. + OR + None, otherwise. + """ + # If this line is apart of an expression statement or is a function + # argument AND the first leaf contains a variable name... + if ( + parent_type(LL[0]) in [syms.expr_stmt, syms.argument, syms.power] + and LL[0].type == token.NAME + ): + is_valid_index = is_valid_index_factory(LL) + + for (i, leaf) in enumerate(LL): + # We MUST find either an '=' or '+=' symbol... + if leaf.type in [token.EQUAL, token.PLUSEQUAL]: + idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1 + + # That symbol MUST be followed by a string... + if is_valid_index(idx) and LL[idx].type == token.STRING: + string_idx = idx + + # Skip the string trailer, if one exists. + string_parser = StringParser() + idx = string_parser.parse(LL, string_idx) + + # The next leaf MAY be a comma iff this line is apart + # of a function argument... + if ( + parent_type(LL[0]) == syms.argument + and is_valid_index(idx) + and LL[idx].type == token.COMMA + ): + idx += 1 + + # But no more leaves are allowed... + if not is_valid_index(idx): + return string_idx + + return None + + @staticmethod + def _dict_match(LL: List[Leaf]) -> Optional[int]: + """ + Returns: + string_idx such that @LL[string_idx] is equal to our target (i.e. + matched) string, if this line matches the dictionary key assignment + statement requirements listed in the 'Requirements' section of this + classes' docstring. + OR + None, otherwise. + """ + # If this line is apart of a dictionary key assignment... + if syms.dictsetmaker in [parent_type(LL[0]), parent_type(LL[0].parent)]: + is_valid_index = is_valid_index_factory(LL) + + for (i, leaf) in enumerate(LL): + # We MUST find a colon... + if leaf.type == token.COLON: + idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1 + + # That colon MUST be followed by a string... + if is_valid_index(idx) and LL[idx].type == token.STRING: + string_idx = idx + + # Skip the string trailer, if one exists. + string_parser = StringParser() + idx = string_parser.parse(LL, string_idx) + + # That string MAY be followed by a comma... + if is_valid_index(idx) and LL[idx].type == token.COMMA: + idx += 1 + + # But no more leaves are allowed... + if not is_valid_index(idx): + return string_idx + + return None + + def do_transform(self, line: Line, string_idx: int) -> Iterator[TResult[Line]]: + LL = line.leaves + + is_valid_index = is_valid_index_factory(LL) + insert_str_child = insert_str_child_factory(LL[string_idx]) + + comma_idx = -1 + ends_with_comma = False + if LL[comma_idx].type == token.COMMA: + ends_with_comma = True + + leaves_to_steal_comments_from = [LL[string_idx]] + if ends_with_comma: + leaves_to_steal_comments_from.append(LL[comma_idx]) + + # --- First Line + first_line = line.clone() + left_leaves = LL[:string_idx] + + # We have to remember to account for (possibly invisible) LPAR and RPAR + # leaves that already wrapped the target string. If these leaves do + # exist, we will replace them with our own LPAR and RPAR leaves. + old_parens_exist = False + if left_leaves and left_leaves[-1].type == token.LPAR: + old_parens_exist = True + leaves_to_steal_comments_from.append(left_leaves[-1]) + left_leaves.pop() + + append_leaves(first_line, line, left_leaves) + + lpar_leaf = Leaf(token.LPAR, "(") + if old_parens_exist: + replace_child(LL[string_idx - 1], lpar_leaf) + else: + insert_str_child(lpar_leaf) + first_line.append(lpar_leaf) + + # We throw inline comments that were originally to the right of the + # target string to the top line. They will now be shown to the right of + # the LPAR. + for leaf in leaves_to_steal_comments_from: + for comment_leaf in line.comments_after(leaf): + first_line.append(comment_leaf, preformatted=True) + + yield Ok(first_line) + + # --- Middle (String) Line + # We only need to yield one (possibly too long) string line, since the + # `StringSplitter` will break it down further if necessary. + string_value = LL[string_idx].value + string_line = Line( + mode=line.mode, + depth=line.depth + 1, + inside_brackets=True, + should_split_rhs=line.should_split_rhs, + magic_trailing_comma=line.magic_trailing_comma, + ) + string_leaf = Leaf(token.STRING, string_value) + insert_str_child(string_leaf) + string_line.append(string_leaf) + + old_rpar_leaf = None + if is_valid_index(string_idx + 1): + right_leaves = LL[string_idx + 1 :] + if ends_with_comma: + right_leaves.pop() + + if old_parens_exist: + assert right_leaves and right_leaves[-1].type == token.RPAR, ( + "Apparently, old parentheses do NOT exist?!" + f" (left_leaves={left_leaves}, right_leaves={right_leaves})" + ) + old_rpar_leaf = right_leaves.pop() + + append_leaves(string_line, line, right_leaves) + + yield Ok(string_line) + + # --- Last Line + last_line = line.clone() + last_line.bracket_tracker = first_line.bracket_tracker + + new_rpar_leaf = Leaf(token.RPAR, ")") + if old_rpar_leaf is not None: + replace_child(old_rpar_leaf, new_rpar_leaf) + else: + insert_str_child(new_rpar_leaf) + last_line.append(new_rpar_leaf) + + # If the target string ended with a comma, we place this comma to the + # right of the RPAR on the last line. + if ends_with_comma: + comma_leaf = Leaf(token.COMMA, ",") + replace_child(LL[comma_idx], comma_leaf) + last_line.append(comma_leaf) + + yield Ok(last_line) + + +class StringParser: + """ + A state machine that aids in parsing a string's "trailer", which can be + either non-existent, an old-style formatting sequence (e.g. `% varX` or `% + (varX, varY)`), or a method-call / attribute access (e.g. `.format(varX, + varY)`). + + NOTE: A new StringParser object MUST be instantiated for each string + trailer we need to parse. + + Examples: + We shall assume that `line` equals the `Line` object that corresponds + to the following line of python code: + ``` + x = "Some {}.".format("String") + some_other_string + ``` + + Furthermore, we will assume that `string_idx` is some index such that: + ``` + assert line.leaves[string_idx].value == "Some {}." + ``` + + The following code snippet then holds: + ``` + string_parser = StringParser() + idx = string_parser.parse(line.leaves, string_idx) + assert line.leaves[idx].type == token.PLUS + ``` + """ + + DEFAULT_TOKEN: Final = 20210605 + + # String Parser States + START: Final = 1 + DOT: Final = 2 + NAME: Final = 3 + PERCENT: Final = 4 + SINGLE_FMT_ARG: Final = 5 + LPAR: Final = 6 + RPAR: Final = 7 + DONE: Final = 8 + + # Lookup Table for Next State + _goto: Final[Dict[Tuple[ParserState, NodeType], ParserState]] = { + # A string trailer may start with '.' OR '%'. + (START, token.DOT): DOT, + (START, token.PERCENT): PERCENT, + (START, DEFAULT_TOKEN): DONE, + # A '.' MUST be followed by an attribute or method name. + (DOT, token.NAME): NAME, + # A method name MUST be followed by an '(', whereas an attribute name + # is the last symbol in the string trailer. + (NAME, token.LPAR): LPAR, + (NAME, DEFAULT_TOKEN): DONE, + # A '%' symbol can be followed by an '(' or a single argument (e.g. a + # string or variable name). + (PERCENT, token.LPAR): LPAR, + (PERCENT, DEFAULT_TOKEN): SINGLE_FMT_ARG, + # If a '%' symbol is followed by a single argument, that argument is + # the last leaf in the string trailer. + (SINGLE_FMT_ARG, DEFAULT_TOKEN): DONE, + # If present, a ')' symbol is the last symbol in a string trailer. + # (NOTE: LPARS and nested RPARS are not included in this lookup table, + # since they are treated as a special case by the parsing logic in this + # classes' implementation.) + (RPAR, DEFAULT_TOKEN): DONE, + } + + def __init__(self) -> None: + self._state = self.START + self._unmatched_lpars = 0 + + def parse(self, leaves: List[Leaf], string_idx: int) -> int: + """ + Pre-conditions: + * @leaves[@string_idx].type == token.STRING + + Returns: + The index directly after the last leaf which is apart of the string + trailer, if a "trailer" exists. + OR + @string_idx + 1, if no string "trailer" exists. + """ + assert leaves[string_idx].type == token.STRING + + idx = string_idx + 1 + while idx < len(leaves) and self._next_state(leaves[idx]): + idx += 1 + return idx + + def _next_state(self, leaf: Leaf) -> bool: + """ + Pre-conditions: + * On the first call to this function, @leaf MUST be the leaf that + was directly after the string leaf in question (e.g. if our target + string is `line.leaves[i]` then the first call to this method must + be `line.leaves[i + 1]`). + * On the next call to this function, the leaf parameter passed in + MUST be the leaf directly following @leaf. + + Returns: + True iff @leaf is apart of the string's trailer. + """ + # We ignore empty LPAR or RPAR leaves. + if is_empty_par(leaf): + return True + + next_token = leaf.type + if next_token == token.LPAR: + self._unmatched_lpars += 1 + + current_state = self._state + + # The LPAR parser state is a special case. We will return True until we + # find the matching RPAR token. + if current_state == self.LPAR: + if next_token == token.RPAR: + self._unmatched_lpars -= 1 + if self._unmatched_lpars == 0: + self._state = self.RPAR + # Otherwise, we use a lookup table to determine the next state. + else: + # If the lookup table matches the current state to the next + # token, we use the lookup table. + if (current_state, next_token) in self._goto: + self._state = self._goto[current_state, next_token] + else: + # Otherwise, we check if a the current state was assigned a + # default. + if (current_state, self.DEFAULT_TOKEN) in self._goto: + self._state = self._goto[current_state, self.DEFAULT_TOKEN] + # If no default has been assigned, then this parser has a logic + # error. + else: + raise RuntimeError(f"{self.__class__.__name__} LOGIC ERROR!") + + if self._state == self.DONE: + return False + + return True + + +def insert_str_child_factory(string_leaf: Leaf) -> Callable[[LN], None]: + """ + Factory for a convenience function that is used to orphan @string_leaf + and then insert multiple new leaves into the same part of the node + structure that @string_leaf had originally occupied. + + Examples: + Let `string_leaf = Leaf(token.STRING, '"foo"')` and `N = + string_leaf.parent`. Assume the node `N` has the following + original structure: + + Node( + expr_stmt, [ + Leaf(NAME, 'x'), + Leaf(EQUAL, '='), + Leaf(STRING, '"foo"'), + ] + ) + + We then run the code snippet shown below. + ``` + insert_str_child = insert_str_child_factory(string_leaf) + + lpar = Leaf(token.LPAR, '(') + insert_str_child(lpar) + + bar = Leaf(token.STRING, '"bar"') + insert_str_child(bar) + + rpar = Leaf(token.RPAR, ')') + insert_str_child(rpar) + ``` + + After which point, it follows that `string_leaf.parent is None` and + the node `N` now has the following structure: + + Node( + expr_stmt, [ + Leaf(NAME, 'x'), + Leaf(EQUAL, '='), + Leaf(LPAR, '('), + Leaf(STRING, '"bar"'), + Leaf(RPAR, ')'), + ] + ) + """ + string_parent = string_leaf.parent + string_child_idx = string_leaf.remove() + + def insert_str_child(child: LN) -> None: + nonlocal string_child_idx + + assert string_parent is not None + assert string_child_idx is not None + + string_parent.insert_child(string_child_idx, child) + string_child_idx += 1 + + return insert_str_child + + +def is_valid_index_factory(seq: Sequence[Any]) -> Callable[[int], bool]: + """ + Examples: + ``` + my_list = [1, 2, 3] + + is_valid_index = is_valid_index_factory(my_list) + + assert is_valid_index(0) + assert is_valid_index(2) + + assert not is_valid_index(3) + assert not is_valid_index(-1) + ``` + """ + + def is_valid_index(idx: int) -> bool: + """ + Returns: + True iff @idx is positive AND seq[@idx] does NOT raise an + IndexError. + """ + return 0 <= idx < len(seq) + + return is_valid_index diff --git a/myenv/lib/python3.9/site-packages/black_primer/__init__.py b/myenv/lib/python3.9/site-packages/black_primer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/black_primer/cli.py b/myenv/lib/python3.9/site-packages/black_primer/cli.py new file mode 100644 index 0000000..8524b59 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black_primer/cli.py @@ -0,0 +1,195 @@ +# coding=utf8 + +import asyncio +import json +import logging +import sys +from datetime import datetime +from pathlib import Path +from shutil import rmtree, which +from tempfile import gettempdir +from typing import Any, List, Optional, Union + +import click + +from black_primer import lib + +# If our environment has uvloop installed lets use it +try: + import uvloop + + uvloop.install() +except ImportError: + pass + + +DEFAULT_CONFIG = Path(__file__).parent / "primer.json" +_timestamp = datetime.now().strftime("%Y%m%d%H%M%S") +DEFAULT_WORKDIR = Path(gettempdir()) / f"primer.{_timestamp}" +LOG = logging.getLogger(__name__) + + +def _handle_debug( + ctx: Optional[click.core.Context], + param: Optional[Union[click.core.Option, click.core.Parameter]], + debug: Union[bool, int, str], +) -> Union[bool, int, str]: + """Turn on debugging if asked otherwise INFO default""" + log_level = logging.DEBUG if debug else logging.INFO + logging.basicConfig( + format="[%(asctime)s] %(levelname)s: %(message)s (%(filename)s:%(lineno)d)", + level=log_level, + ) + return debug + + +def load_projects(config_path: Path) -> List[str]: + with open(config_path) as config: + return sorted(json.load(config)["projects"].keys()) + + +# Unfortunately does import time file IO - but appears to be the only +# way to get `black-primer --help` to show projects list +DEFAULT_PROJECTS = load_projects(DEFAULT_CONFIG) + + +def _projects_callback( + ctx: click.core.Context, + param: Optional[Union[click.core.Option, click.core.Parameter]], + projects: str, +) -> List[str]: + requested_projects = set(projects.split(",")) + available_projects = set( + DEFAULT_PROJECTS + if str(DEFAULT_CONFIG) == ctx.params["config"] + else load_projects(ctx.params["config"]) + ) + + unavailable = requested_projects - available_projects + if unavailable: + LOG.error(f"Projects not found: {unavailable}. Available: {available_projects}") + + return sorted(requested_projects & available_projects) + + +async def async_main( + config: str, + debug: bool, + keep: bool, + long_checkouts: bool, + no_diff: bool, + projects: List[str], + rebase: bool, + workdir: str, + workers: int, +) -> int: + work_path = Path(workdir) + if not work_path.exists(): + LOG.debug(f"Creating {work_path}") + work_path.mkdir() + + if not which("black"): + LOG.error("Can not find 'black' executable in PATH. No point in running") + return -1 + + try: + ret_val = await lib.process_queue( + config, + work_path, + workers, + projects, + keep, + long_checkouts, + rebase, + no_diff, + ) + return int(ret_val) + + finally: + if not keep and work_path.exists(): + LOG.debug(f"Removing {work_path}") + rmtree(work_path, onerror=lib.handle_PermissionError) + + +@click.command(context_settings={"help_option_names": ["-h", "--help"]}) +@click.option( + "-c", + "--config", + default=str(DEFAULT_CONFIG), + type=click.Path(exists=True), + show_default=True, + help="JSON config file path", + # Eager - because config path is used by other callback options + is_eager=True, +) +@click.option( + "--debug", + is_flag=True, + callback=_handle_debug, + show_default=True, + help="Turn on debug logging", +) +@click.option( + "-k", + "--keep", + is_flag=True, + show_default=True, + help="Keep workdir + repos post run", +) +@click.option( + "-L", + "--long-checkouts", + is_flag=True, + show_default=True, + help="Pull big projects to test", +) +@click.option( + "--no-diff", + is_flag=True, + show_default=True, + help="Disable showing source file changes in black output", +) +@click.option( + "--projects", + default=",".join(DEFAULT_PROJECTS), + callback=_projects_callback, + show_default=True, + help="Comma separated list of projects to run", +) +@click.option( + "-R", + "--rebase", + is_flag=True, + show_default=True, + help="Rebase project if already checked out", +) +@click.option( + "-w", + "--workdir", + default=str(DEFAULT_WORKDIR), + type=click.Path(exists=False), + show_default=True, + help="Directory path for repo checkouts", +) +@click.option( + "-W", + "--workers", + default=2, + type=int, + show_default=True, + help="Number of parallel worker coroutines", +) +@click.pass_context +def main(ctx: click.core.Context, **kwargs: Any) -> None: + """primer - prime projects for blackening... 🏴""" + LOG.debug(f"Starting {sys.argv[0]}") + # TODO: Change to asyncio.run when Black >= 3.7 only + loop = asyncio.get_event_loop() + try: + ctx.exit(loop.run_until_complete(async_main(**kwargs))) + finally: + loop.close() + + +if __name__ == "__main__": # pragma: nocover + main() diff --git a/myenv/lib/python3.9/site-packages/black_primer/lib.py b/myenv/lib/python3.9/site-packages/black_primer/lib.py new file mode 100644 index 0000000..13724f4 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black_primer/lib.py @@ -0,0 +1,423 @@ +import asyncio +import errno +import json +import logging +import os +import stat +import sys +from functools import partial +from pathlib import Path +from platform import system +from shutil import rmtree, which +from subprocess import CalledProcessError +from sys import version_info +from tempfile import TemporaryDirectory +from typing import ( + Any, + Callable, + Dict, + List, + NamedTuple, + Optional, + Sequence, + Tuple, + Union, +) +from urllib.parse import urlparse + +import click + + +TEN_MINUTES_SECONDS = 600 +WINDOWS = system() == "Windows" +BLACK_BINARY = "black.exe" if WINDOWS else "black" +GIT_BINARY = "git.exe" if WINDOWS else "git" +LOG = logging.getLogger(__name__) + + +# Windows needs a ProactorEventLoop if you want to exec subprocesses +# Starting with 3.8 this is the default - can remove when Black >= 3.8 +# mypy only respects sys.platform if directly in the evaluation +# https://mypy.readthedocs.io/en/latest/common_issues.html#python-version-and-system-platform-checks # noqa: B950 +if sys.platform == "win32": + asyncio.set_event_loop(asyncio.ProactorEventLoop()) + + +class Results(NamedTuple): + stats: Dict[str, int] = {} + failed_projects: Dict[str, CalledProcessError] = {} + + +async def _gen_check_output( + cmd: Sequence[str], + timeout: float = TEN_MINUTES_SECONDS, + env: Optional[Dict[str, str]] = None, + cwd: Optional[Path] = None, + stdin: Optional[bytes] = None, +) -> Tuple[bytes, bytes]: + process = await asyncio.create_subprocess_exec( + *cmd, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.STDOUT, + env=env, + cwd=cwd, + ) + try: + (stdout, stderr) = await asyncio.wait_for(process.communicate(stdin), timeout) + except asyncio.TimeoutError: + process.kill() + await process.wait() + raise + + # A non-optional timeout was supplied to asyncio.wait_for, guaranteeing + # a timeout or completed process. A terminated Python process will have a + # non-empty returncode value. + assert process.returncode is not None + + if process.returncode != 0: + cmd_str = " ".join(cmd) + raise CalledProcessError( + process.returncode, cmd_str, output=stdout, stderr=stderr + ) + + return (stdout, stderr) + + +def analyze_results(project_count: int, results: Results) -> int: + failed_pct = round(((results.stats["failed"] / project_count) * 100), 2) + success_pct = round(((results.stats["success"] / project_count) * 100), 2) + + if results.failed_projects: + click.secho("\nFailed projects:\n", bold=True) + + for project_name, project_cpe in results.failed_projects.items(): + print(f"## {project_name}:") + print(f" - Returned {project_cpe.returncode}") + if project_cpe.stderr: + print(f" - stderr:\n{project_cpe.stderr.decode('utf8')}") + if project_cpe.stdout: + print(f" - stdout:\n{project_cpe.stdout.decode('utf8')}") + print("") + + click.secho("-- primer results 📊 --\n", bold=True) + click.secho( + f"{results.stats['success']} / {project_count} succeeded ({success_pct}%) ✅", + bold=True, + fg="green", + ) + click.secho( + f"{results.stats['failed']} / {project_count} FAILED ({failed_pct}%) 💩", + bold=bool(results.stats["failed"]), + fg="red", + ) + s = "" if results.stats["disabled"] == 1 else "s" + click.echo(f" - {results.stats['disabled']} project{s} disabled by config") + s = "" if results.stats["wrong_py_ver"] == 1 else "s" + click.echo( + f" - {results.stats['wrong_py_ver']} project{s} skipped due to Python version" + ) + click.echo( + f" - {results.stats['skipped_long_checkout']} skipped due to long checkout" + ) + + if results.failed_projects: + failed = ", ".join(results.failed_projects.keys()) + click.secho(f"\nFailed projects: {failed}\n", bold=True) + + return results.stats["failed"] + + +def _flatten_cli_args(cli_args: List[Union[Sequence[str], str]]) -> List[str]: + """Allow a user to put long arguments into a list of strs + to make the JSON human readable""" + flat_args = [] + for arg in cli_args: + if isinstance(arg, str): + flat_args.append(arg) + continue + + args_as_str = "".join(arg) + flat_args.append(args_as_str) + + return flat_args + + +async def black_run( + project_name: str, + repo_path: Optional[Path], + project_config: Dict[str, Any], + results: Results, + no_diff: bool = False, +) -> None: + """Run Black and record failures""" + if not repo_path: + results.stats["failed"] += 1 + results.failed_projects[project_name] = CalledProcessError( + 69, [], f"{project_name} has no repo_path: {repo_path}".encode(), b"" + ) + return + + stdin_test = project_name.upper() == "STDIN" + cmd = [str(which(BLACK_BINARY))] + if "cli_arguments" in project_config and project_config["cli_arguments"]: + cmd.extend(_flatten_cli_args(project_config["cli_arguments"])) + cmd.append("--check") + if not no_diff: + cmd.append("--diff") + + # Workout if we should read in a python file or search from cwd + stdin = None + if stdin_test: + cmd.append("-") + stdin = repo_path.read_bytes() + elif "base_path" in project_config: + cmd.append(project_config["base_path"]) + else: + cmd.append(".") + + timeout = ( + project_config["timeout_seconds"] + if "timeout_seconds" in project_config + else TEN_MINUTES_SECONDS + ) + with TemporaryDirectory() as tmp_path: + # Prevent reading top-level user configs by manipulating environment variables + env = { + **os.environ, + "XDG_CONFIG_HOME": tmp_path, # Unix-like + "USERPROFILE": tmp_path, # Windows (changes `Path.home()` output) + } + + cwd_path = repo_path.parent if stdin_test else repo_path + try: + LOG.debug(f"Running black for {project_name}: {' '.join(cmd)}") + _stdout, _stderr = await _gen_check_output( + cmd, cwd=cwd_path, env=env, stdin=stdin, timeout=timeout + ) + except asyncio.TimeoutError: + results.stats["failed"] += 1 + LOG.error(f"Running black for {repo_path} timed out ({cmd})") + except CalledProcessError as cpe: + # TODO: Tune for smarter for higher signal + # If any other return value than 1 we raise - can disable project in config + if cpe.returncode == 1: + if not project_config["expect_formatting_changes"]: + results.stats["failed"] += 1 + results.failed_projects[repo_path.name] = cpe + else: + results.stats["success"] += 1 + return + elif cpe.returncode > 1: + results.stats["failed"] += 1 + results.failed_projects[repo_path.name] = cpe + return + + LOG.error(f"Unknown error with {repo_path}") + raise + + # If we get here and expect formatting changes something is up + if project_config["expect_formatting_changes"]: + results.stats["failed"] += 1 + results.failed_projects[repo_path.name] = CalledProcessError( + 0, cmd, b"Expected formatting changes but didn't get any!", b"" + ) + return + + results.stats["success"] += 1 + + +async def git_checkout_or_rebase( + work_path: Path, + project_config: Dict[str, Any], + rebase: bool = False, + *, + depth: int = 1, +) -> Optional[Path]: + """git Clone project or rebase""" + git_bin = str(which(GIT_BINARY)) + if not git_bin: + LOG.error("No git binary found") + return None + + repo_url_parts = urlparse(project_config["git_clone_url"]) + path_parts = repo_url_parts.path[1:].split("/", maxsplit=1) + + repo_path: Path = work_path / path_parts[1].replace(".git", "") + cmd = [git_bin, "clone", "--depth", str(depth), project_config["git_clone_url"]] + cwd = work_path + if repo_path.exists() and rebase: + cmd = [git_bin, "pull", "--rebase"] + cwd = repo_path + elif repo_path.exists(): + return repo_path + + try: + _stdout, _stderr = await _gen_check_output(cmd, cwd=cwd) + except (asyncio.TimeoutError, CalledProcessError) as e: + LOG.error(f"Unable to git clone / pull {project_config['git_clone_url']}: {e}") + return None + + return repo_path + + +def handle_PermissionError( + func: Callable[..., None], path: Path, exc: Tuple[Any, Any, Any] +) -> None: + """ + Handle PermissionError during shutil.rmtree. + + This checks if the erroring function is either 'os.rmdir' or 'os.unlink', and that + the error was EACCES (i.e. Permission denied). If true, the path is set writable, + readable, and executable by everyone. Finally, it tries the error causing delete + operation again. + + If the check is false, then the original error will be reraised as this function + can't handle it. + """ + excvalue = exc[1] + LOG.debug(f"Handling {excvalue} from {func.__name__}... ") + if func in (os.rmdir, os.unlink) and excvalue.errno == errno.EACCES: + LOG.debug(f"Setting {path} writable, readable, and executable by everyone... ") + os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # chmod 0777 + func(path) # Try the error causing delete operation again + else: + raise + + +async def load_projects_queue( + config_path: Path, + projects_to_run: List[str], +) -> Tuple[Dict[str, Any], asyncio.Queue]: + """Load project config and fill queue with all the project names""" + with config_path.open("r") as cfp: + config = json.load(cfp) + + # TODO: Offer more options here + # e.g. Run on X random packages etc. + queue: asyncio.Queue = asyncio.Queue(maxsize=len(projects_to_run)) + for project in projects_to_run: + await queue.put(project) + + return config, queue + + +async def project_runner( + idx: int, + config: Dict[str, Any], + queue: asyncio.Queue, + work_path: Path, + results: Results, + long_checkouts: bool = False, + rebase: bool = False, + keep: bool = False, + no_diff: bool = False, +) -> None: + """Check out project and run Black on it + record result""" + loop = asyncio.get_event_loop() + py_version = f"{version_info[0]}.{version_info[1]}" + while True: + try: + project_name = queue.get_nowait() + except asyncio.QueueEmpty: + LOG.debug(f"project_runner {idx} exiting") + return + LOG.debug(f"worker {idx} working on {project_name}") + + project_config = config["projects"][project_name] + + # Check if disabled by config + if "disabled" in project_config and project_config["disabled"]: + results.stats["disabled"] += 1 + LOG.info(f"Skipping {project_name} as it's disabled via config") + continue + + # Check if we should run on this version of Python + if ( + "all" not in project_config["py_versions"] + and py_version not in project_config["py_versions"] + ): + results.stats["wrong_py_ver"] += 1 + LOG.debug(f"Skipping {project_name} as it's not enabled for {py_version}") + continue + + # Check if we're doing big projects / long checkouts + if not long_checkouts and project_config["long_checkout"]: + results.stats["skipped_long_checkout"] += 1 + LOG.debug(f"Skipping {project_name} as it's configured as a long checkout") + continue + + repo_path: Optional[Path] = Path(__file__) + stdin_project = project_name.upper() == "STDIN" + if not stdin_project: + repo_path = await git_checkout_or_rebase(work_path, project_config, rebase) + if not repo_path: + continue + await black_run(project_name, repo_path, project_config, results, no_diff) + + if not keep and not stdin_project: + LOG.debug(f"Removing {repo_path}") + rmtree_partial = partial( + rmtree, path=repo_path, onerror=handle_PermissionError + ) + await loop.run_in_executor(None, rmtree_partial) + + LOG.info(f"Finished {project_name}") + + +async def process_queue( + config_file: str, + work_path: Path, + workers: int, + projects_to_run: List[str], + keep: bool = False, + long_checkouts: bool = False, + rebase: bool = False, + no_diff: bool = False, +) -> int: + """ + Process the queue with X workers and evaluate results + - Success is guaged via the config "expect_formatting_changes" + + Integer return equals the number of failed projects + """ + results = Results() + results.stats["disabled"] = 0 + results.stats["failed"] = 0 + results.stats["skipped_long_checkout"] = 0 + results.stats["success"] = 0 + results.stats["wrong_py_ver"] = 0 + + config, queue = await load_projects_queue(Path(config_file), projects_to_run) + project_count = queue.qsize() + s = "" if project_count == 1 else "s" + LOG.info(f"{project_count} project{s} to run Black over") + if project_count < 1: + return -1 + + s = "" if workers == 1 else "s" + LOG.debug(f"Using {workers} parallel worker{s} to run Black") + # Wait until we finish running all the projects before analyzing + await asyncio.gather( + *[ + project_runner( + i, + config, + queue, + work_path, + results, + long_checkouts, + rebase, + keep, + no_diff, + ) + for i in range(workers) + ] + ) + + LOG.info("Analyzing results") + return analyze_results(project_count, results) + + +if __name__ == "__main__": # pragma: nocover + raise NotImplementedError("lib is a library, funnily enough.") diff --git a/myenv/lib/python3.9/site-packages/black_primer/primer.json b/myenv/lib/python3.9/site-packages/black_primer/primer.json new file mode 100644 index 0000000..8fe61e8 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/black_primer/primer.json @@ -0,0 +1,188 @@ +{ + "configuration_format_version": 20210815, + "projects": { + "STDIN": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": false, + "git_clone_url": "", + "long_checkout": false, + "py_versions": ["all"] + }, + "aioexabgp": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": false, + "git_clone_url": "https://github.com/cooperlees/aioexabgp.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "attrs": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/python-attrs/attrs.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "bandersnatch": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/pypa/bandersnatch.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "channels": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/django/channels.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "cpython": { + "disabled": true, + "disabled_reason": "To big / slow for GitHub Actions but handy to keep config to use manually or in some other CI in the future", + "base_path": "Lib", + "cli_arguments": [ + "--experimental-string-processing", + "--extend-exclude", + [ + "Lib/lib2to3/tests/data/different_encoding.py", + "|Lib/lib2to3/tests/data/false_encoding.py", + "|Lib/lib2to3/tests/data/py2_test_grammar.py", + "|Lib/test/bad_coding.py", + "|Lib/test/bad_coding2.py", + "|Lib/test/badsyntax_3131.py", + "|Lib/test/badsyntax_pep3120.py", + "|Lib/test/test_base64.py", + "|Lib/test/test_exceptions.py", + "|Lib/test/test_grammar.py", + "|Lib/test/test_named_expressions.py", + "|Lib/test/test_patma.py", + "|Lib/test/test_tokenize.py", + "|Lib/test/test_xml_etree.py", + "|Lib/traceback.py" + ] + ], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/python/cpython.git", + "long_checkout": false, + "py_versions": ["3.9", "3.10"], + "timeout_seconds": 900 + }, + "django": { + "cli_arguments": [ + "--experimental-string-processing", + "--skip-string-normalization", + "--extend-exclude", + "/((docs|scripts)/|django/forms/models.py|tests/gis_tests/test_spatialrefsys.py|tests/test_runner_apps/tagged/tests_syntax_error.py)" + ], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/django/django.git", + "long_checkout": false, + "py_versions": ["3.8", "3.9", "3.10"] + }, + "flake8-bugbear": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": false, + "git_clone_url": "https://github.com/PyCQA/flake8-bugbear.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "hypothesis": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/HypothesisWorks/hypothesis.git", + "long_checkout": false, + "py_versions": ["3.8", "3.9", "3.10"] + }, + "pandas": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/pandas-dev/pandas.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "pillow": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/python-pillow/Pillow.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "poetry": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/python-poetry/poetry.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "pyanalyze": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/quora/pyanalyze.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "pyramid": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/Pylons/pyramid.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "ptr": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": false, + "git_clone_url": "https://github.com/facebookincubator/ptr.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "pytest": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/pytest-dev/pytest.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "scikit-lego": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/koaning/scikit-lego", + "long_checkout": false, + "py_versions": ["all"] + }, + "sqlalchemy": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/sqlalchemy/sqlalchemy.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "tox": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/tox-dev/tox.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "typeshed": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/python/typeshed.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "virtualenv": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/pypa/virtualenv.git", + "long_checkout": false, + "py_versions": ["all"] + }, + "warehouse": { + "cli_arguments": ["--experimental-string-processing"], + "expect_formatting_changes": true, + "git_clone_url": "https://github.com/pypa/warehouse.git", + "long_checkout": false, + "py_versions": ["all"] + } + } +} diff --git a/myenv/lib/python3.9/site-packages/blackd/__init__.py b/myenv/lib/python3.9/site-packages/blackd/__init__.py new file mode 100644 index 0000000..cc96640 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blackd/__init__.py @@ -0,0 +1,201 @@ +import asyncio +import logging +from concurrent.futures import Executor, ProcessPoolExecutor +from datetime import datetime +from functools import partial +from multiprocessing import freeze_support +from typing import Set, Tuple + +try: + from aiohttp import web + from .middlewares import cors +except ImportError as ie: + raise ImportError( + f"aiohttp dependency is not installed: {ie}. " + + "Please re-install black with the '[d]' extra install " + + "to obtain aiohttp_cors: `pip install black[d]`" + ) from None + +import black +from black.concurrency import maybe_install_uvloop +import click + +from _black_version import version as __version__ + +# This is used internally by tests to shut down the server prematurely +_stop_signal = asyncio.Event() + +# Request headers +PROTOCOL_VERSION_HEADER = "X-Protocol-Version" +LINE_LENGTH_HEADER = "X-Line-Length" +PYTHON_VARIANT_HEADER = "X-Python-Variant" +SKIP_STRING_NORMALIZATION_HEADER = "X-Skip-String-Normalization" +SKIP_MAGIC_TRAILING_COMMA = "X-Skip-Magic-Trailing-Comma" +FAST_OR_SAFE_HEADER = "X-Fast-Or-Safe" +DIFF_HEADER = "X-Diff" + +BLACK_HEADERS = [ + PROTOCOL_VERSION_HEADER, + LINE_LENGTH_HEADER, + PYTHON_VARIANT_HEADER, + SKIP_STRING_NORMALIZATION_HEADER, + SKIP_MAGIC_TRAILING_COMMA, + FAST_OR_SAFE_HEADER, + DIFF_HEADER, +] + +# Response headers +BLACK_VERSION_HEADER = "X-Black-Version" + + +class InvalidVariantHeader(Exception): + pass + + +@click.command(context_settings={"help_option_names": ["-h", "--help"]}) +@click.option( + "--bind-host", type=str, help="Address to bind the server to.", default="localhost" +) +@click.option("--bind-port", type=int, help="Port to listen on", default=45484) +@click.version_option(version=black.__version__) +def main(bind_host: str, bind_port: int) -> None: + logging.basicConfig(level=logging.INFO) + app = make_app() + ver = black.__version__ + black.out(f"blackd version {ver} listening on {bind_host} port {bind_port}") + web.run_app(app, host=bind_host, port=bind_port, handle_signals=True, print=None) + + +def make_app() -> web.Application: + app = web.Application( + middlewares=[cors(allow_headers=(*BLACK_HEADERS, "Content-Type"))] + ) + executor = ProcessPoolExecutor() + app.add_routes([web.post("/", partial(handle, executor=executor))]) + return app + + +async def handle(request: web.Request, executor: Executor) -> web.Response: + headers = {BLACK_VERSION_HEADER: __version__} + try: + if request.headers.get(PROTOCOL_VERSION_HEADER, "1") != "1": + return web.Response( + status=501, text="This server only supports protocol version 1" + ) + try: + line_length = int( + request.headers.get(LINE_LENGTH_HEADER, black.DEFAULT_LINE_LENGTH) + ) + except ValueError: + return web.Response(status=400, text="Invalid line length header value") + + if PYTHON_VARIANT_HEADER in request.headers: + value = request.headers[PYTHON_VARIANT_HEADER] + try: + pyi, versions = parse_python_variant_header(value) + except InvalidVariantHeader as e: + return web.Response( + status=400, + text=f"Invalid value for {PYTHON_VARIANT_HEADER}: {e.args[0]}", + ) + else: + pyi = False + versions = set() + + skip_string_normalization = bool( + request.headers.get(SKIP_STRING_NORMALIZATION_HEADER, False) + ) + skip_magic_trailing_comma = bool( + request.headers.get(SKIP_MAGIC_TRAILING_COMMA, False) + ) + fast = False + if request.headers.get(FAST_OR_SAFE_HEADER, "safe") == "fast": + fast = True + mode = black.FileMode( + target_versions=versions, + is_pyi=pyi, + line_length=line_length, + string_normalization=not skip_string_normalization, + magic_trailing_comma=not skip_magic_trailing_comma, + ) + req_bytes = await request.content.read() + charset = request.charset if request.charset is not None else "utf8" + req_str = req_bytes.decode(charset) + then = datetime.utcnow() + + loop = asyncio.get_event_loop() + formatted_str = await loop.run_in_executor( + executor, partial(black.format_file_contents, req_str, fast=fast, mode=mode) + ) + + # Only output the diff in the HTTP response + only_diff = bool(request.headers.get(DIFF_HEADER, False)) + if only_diff: + now = datetime.utcnow() + src_name = f"In\t{then} +0000" + dst_name = f"Out\t{now} +0000" + loop = asyncio.get_event_loop() + formatted_str = await loop.run_in_executor( + executor, + partial(black.diff, req_str, formatted_str, src_name, dst_name), + ) + + return web.Response( + content_type=request.content_type, + charset=charset, + headers=headers, + text=formatted_str, + ) + except black.NothingChanged: + return web.Response(status=204, headers=headers) + except black.InvalidInput as e: + return web.Response(status=400, headers=headers, text=str(e)) + except Exception as e: + logging.exception("Exception during handling a request") + return web.Response(status=500, headers=headers, text=str(e)) + + +def parse_python_variant_header(value: str) -> Tuple[bool, Set[black.TargetVersion]]: + if value == "pyi": + return True, set() + else: + versions = set() + for version in value.split(","): + if version.startswith("py"): + version = version[len("py") :] + if "." in version: + major_str, *rest = version.split(".") + else: + major_str = version[0] + rest = [version[1:]] if len(version) > 1 else [] + try: + major = int(major_str) + if major not in (2, 3): + raise InvalidVariantHeader("major version must be 2 or 3") + if len(rest) > 0: + minor = int(rest[0]) + if major == 2 and minor != 7: + raise InvalidVariantHeader( + "minor version must be 7 for Python 2" + ) + else: + # Default to lowest supported minor version. + minor = 7 if major == 2 else 3 + version_str = f"PY{major}{minor}" + if major == 3 and not hasattr(black.TargetVersion, version_str): + raise InvalidVariantHeader(f"3.{minor} is not supported") + versions.add(black.TargetVersion[version_str]) + except (KeyError, ValueError): + raise InvalidVariantHeader("expected e.g. '3.7', 'py3.5'") from None + return False, versions + + +def patched_main() -> None: + maybe_install_uvloop() + freeze_support() + black.patch_click() + main() + + +if __name__ == "__main__": + patched_main() diff --git a/myenv/lib/python3.9/site-packages/blackd/middlewares.py b/myenv/lib/python3.9/site-packages/blackd/middlewares.py new file mode 100644 index 0000000..97994ec --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blackd/middlewares.py @@ -0,0 +1,34 @@ +from typing import Iterable, Awaitable, Callable +from aiohttp.web_response import StreamResponse +from aiohttp.web_request import Request +from aiohttp.web_middlewares import middleware + +Handler = Callable[[Request], Awaitable[StreamResponse]] +Middleware = Callable[[Request, Handler], Awaitable[StreamResponse]] + + +def cors(allow_headers: Iterable[str]) -> Middleware: + @middleware + async def impl(request: Request, handler: Handler) -> StreamResponse: + is_options = request.method == "OPTIONS" + is_preflight = is_options and "Access-Control-Request-Method" in request.headers + if is_preflight: + resp = StreamResponse() + else: + resp = await handler(request) + + origin = request.headers.get("Origin") + if not origin: + return resp + + resp.headers["Access-Control-Allow-Origin"] = "*" + resp.headers["Access-Control-Expose-Headers"] = "*" + if is_options: + resp.headers["Access-Control-Allow-Headers"] = ", ".join(allow_headers) + resp.headers["Access-Control-Allow-Methods"] = ", ".join( + ("OPTIONS", "POST") + ) + + return resp + + return impl # type: ignore diff --git a/myenv/lib/python3.9/site-packages/blib2to3/Grammar.txt b/myenv/lib/python3.9/site-packages/blib2to3/Grammar.txt new file mode 100644 index 0000000..c3001e8 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/Grammar.txt @@ -0,0 +1,251 @@ +# Grammar for 2to3. This grammar supports Python 2.x and 3.x. + +# NOTE WELL: You should also follow all the steps listed at +# https://devguide.python.org/grammar/ + +# Start symbols for the grammar: +# file_input is a module or sequence of commands read from an input file; +# single_input is a single interactive statement; +# eval_input is the input for the eval() and input() functions. +# NB: compound_stmt in single_input is followed by extra NEWLINE! +file_input: (NEWLINE | stmt)* ENDMARKER +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE +eval_input: testlist NEWLINE* ENDMARKER + +decorator: '@' namedexpr_test NEWLINE +decorators: decorator+ +decorated: decorators (classdef | funcdef | async_funcdef) +async_funcdef: ASYNC funcdef +funcdef: 'def' NAME parameters ['->' test] ':' suite +parameters: '(' [typedargslist] ')' + +# The following definition for typedarglist is equivalent to this set of rules: +# +# arguments = argument (',' argument)* +# argument = tfpdef ['=' test] +# kwargs = '**' tname [','] +# args = '*' [tname] +# kwonly_kwargs = (',' argument)* [',' [kwargs]] +# args_kwonly_kwargs = args kwonly_kwargs | kwargs +# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] +# typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs +# typedarglist = arguments ',' '/' [',' [typedargslist_no_posonly]])|(typedargslist_no_posonly)" +# +# It needs to be fully expanded to allow our LL(1) parser to work on it. + +typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [ + ',' [((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])* + [',' ['**' tname [',']]] | '**' tname [',']) + | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])] + ] | ((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])* + [',' ['**' tname [',']]] | '**' tname [',']) + | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + +tname: NAME [':' test] +tfpdef: tname | '(' tfplist ')' +tfplist: tfpdef (',' tfpdef)* [','] + +# The following definition for varargslist is equivalent to this set of rules: +# +# arguments = argument (',' argument )* +# argument = vfpdef ['=' test] +# kwargs = '**' vname [','] +# args = '*' [vname] +# kwonly_kwargs = (',' argument )* [',' [kwargs]] +# args_kwonly_kwargs = args kwonly_kwargs | kwargs +# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] +# vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs +# varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] | (vararglist_no_posonly) +# +# It needs to be fully expanded to allow our LL(1) parser to work on it. + +varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ + ((vfpdef ['=' test] ',')* ('*' [vname] (',' vname ['=' test])* + [',' ['**' vname [',']]] | '**' vname [',']) + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + ]] | ((vfpdef ['=' test] ',')* + ('*' [vname] (',' vname ['=' test])* [',' ['**' vname [',']]]| '**' vname [',']) + | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + +vname: NAME +vfpdef: vname | '(' vfplist ')' +vfplist: vfpdef (',' vfpdef)* [','] + +stmt: simple_stmt | compound_stmt +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE +small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | + import_stmt | global_stmt | exec_stmt | assert_stmt) +expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | + ('=' (yield_expr|testlist_star_expr))*) +annassign: ':' test ['=' (yield_expr|testlist_star_expr)] +testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] +augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | + '<<=' | '>>=' | '**=' | '//=') +# For normal and annotated assignments, additional restrictions enforced by the interpreter +print_stmt: 'print' ( [ test (',' test)* [','] ] | + '>>' test [ (',' test)+ [','] ] ) +del_stmt: 'del' exprlist +pass_stmt: 'pass' +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt +break_stmt: 'break' +continue_stmt: 'continue' +return_stmt: 'return' [testlist_star_expr] +yield_stmt: yield_expr +raise_stmt: 'raise' [test ['from' test | ',' test [',' test]]] +import_stmt: import_name | import_from +import_name: 'import' dotted_as_names +import_from: ('from' ('.'* dotted_name | '.'+) + 'import' ('*' | '(' import_as_names ')' | import_as_names)) +import_as_name: NAME ['as' NAME] +dotted_as_name: dotted_name ['as' NAME] +import_as_names: import_as_name (',' import_as_name)* [','] +dotted_as_names: dotted_as_name (',' dotted_as_name)* +dotted_name: NAME ('.' NAME)* +global_stmt: ('global' | 'nonlocal') NAME (',' NAME)* +exec_stmt: 'exec' expr ['in' test [',' test]] +assert_stmt: 'assert' test [',' test] + +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt | match_stmt +async_stmt: ASYNC (funcdef | with_stmt | for_stmt) +if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite] +while_stmt: 'while' namedexpr_test ':' suite ['else' ':' suite] +for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] +try_stmt: ('try' ':' suite + ((except_clause ':' suite)+ + ['else' ':' suite] + ['finally' ':' suite] | + 'finally' ':' suite)) +with_stmt: 'with' asexpr_test (',' asexpr_test)* ':' suite + +# NB compile.c makes sure that the default except clause is last +except_clause: 'except' [test [(',' | 'as') test]] +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT + +# Backward compatibility cruft to support: +# [ x for x in lambda: True, lambda: False if x() ] +# even while also allowing: +# lambda x: 5 if x else 2 +# (But not a mix of the two) +testlist_safe: old_test [(',' old_test)+ [',']] +old_test: or_test | old_lambdef +old_lambdef: 'lambda' [varargslist] ':' old_test + +namedexpr_test: asexpr_test [':=' asexpr_test] + +# This is actually not a real rule, though since the parser is very +# limited in terms of the strategy about match/case rules, we are inserting +# a virtual case ( as ) as a valid expression. Unless a better +# approach is thought, the only side effect of this seem to be just allowing +# more stuff to be parser (which would fail on the ast). +asexpr_test: test ['as' test] + +test: or_test ['if' or_test 'else' test] | lambdef +or_test: and_test ('or' and_test)* +and_test: not_test ('and' not_test)* +not_test: 'not' not_test | comparison +comparison: expr (comp_op expr)* +comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' +star_expr: '*' expr +expr: xor_expr ('|' xor_expr)* +xor_expr: and_expr ('^' and_expr)* +and_expr: shift_expr ('&' shift_expr)* +shift_expr: arith_expr (('<<'|'>>') arith_expr)* +arith_expr: term (('+'|'-') term)* +term: factor (('*'|'@'|'/'|'%'|'//') factor)* +factor: ('+'|'-'|'~') factor | power +power: [AWAIT] atom trailer* ['**' factor] +atom: ('(' [yield_expr|testlist_gexp] ')' | + '[' [listmaker] ']' | + '{' [dictsetmaker] '}' | + '`' testlist1 '`' | + NAME | NUMBER | STRING+ | '.' '.' '.') +listmaker: (namedexpr_test|star_expr) ( old_comp_for | (',' (namedexpr_test|star_expr))* [','] ) +testlist_gexp: (namedexpr_test|star_expr) ( old_comp_for | (',' (namedexpr_test|star_expr))* [','] ) +lambdef: 'lambda' [varargslist] ':' test +trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME +subscriptlist: subscript (',' subscript)* [','] +subscript: test [':=' test] | [test] ':' [test] [sliceop] +sliceop: ':' [test] +exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] +testlist: test (',' test)* [','] +dictsetmaker: ( ((test ':' test | '**' expr) + (comp_for | (',' (test ':' test | '**' expr))* [','])) | + ((test [':=' test] | star_expr) + (comp_for | (',' (test [':=' test] | star_expr))* [','])) ) + +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite + +arglist: argument (',' argument)* [','] + +# "test '=' test" is really "keyword '=' test", but we have no such token. +# These need to be in a single rule to avoid grammar that is ambiguous +# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, +# we explicitly match '*' here, too, to give it proper precedence. +# Illegal combinations and orderings are blocked in ast.c: +# multiple (test comp_for) arguments are blocked; keyword unpackings +# that precede iterable unpackings are blocked; etc. +argument: ( test [comp_for] | + test ':=' test | + test 'as' test | + test '=' test | + '**' test | + '*' test ) + +comp_iter: comp_for | comp_if +comp_for: [ASYNC] 'for' exprlist 'in' or_test [comp_iter] +comp_if: 'if' old_test [comp_iter] + +# As noted above, testlist_safe extends the syntax allowed in list +# comprehensions and generators. We can't use it indiscriminately in all +# derivations using a comp_for-like pattern because the testlist_safe derivation +# contains comma which clashes with trailing comma in arglist. +# +# This was an issue because the parser would not follow the correct derivation +# when parsing syntactically valid Python code. Since testlist_safe was created +# specifically to handle list comprehensions and generator expressions enclosed +# with parentheses, it's safe to only use it in those. That avoids the issue; we +# can parse code like set(x for x in [],). +# +# The syntax supported by this set of rules is not a valid Python 3 syntax, +# hence the prefix "old". +# +# See https://bugs.python.org/issue27494 +old_comp_iter: old_comp_for | old_comp_if +old_comp_for: [ASYNC] 'for' exprlist 'in' testlist_safe [old_comp_iter] +old_comp_if: 'if' old_test [old_comp_iter] + +testlist1: test (',' test)* + +# not used in grammar, but may appear in "node" passed from Parser to Compiler +encoding_decl: NAME + +yield_expr: 'yield' [yield_arg] +yield_arg: 'from' test | testlist_star_expr + + +# 3.10 match statement definition + +# PS: normally the grammar is much much more restricted, but +# at this moment for not trying to bother much with encoding the +# exact same DSL in a LL(1) parser, we will just accept an expression +# and let the ast.parse() step of the safe mode to reject invalid +# grammar. + +# The reason why it is more restricted is that, patterns are some +# sort of a DSL (more advanced than our LHS on assignments, but +# still in a very limited python subset). They are not really +# expressions, but who cares. If we can parse them, that is enough +# to reformat them. + +match_stmt: "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT + +# This is more permissive than the actual version. For example it +# accepts `match *something:`, even though single-item starred expressions +# are forbidden. +subject_expr: (namedexpr_test|star_expr) (',' (namedexpr_test|star_expr))* [','] + +# cases +case_block: "case" patterns [guard] ':' suite +guard: 'if' namedexpr_test +patterns: pattern ['as' pattern] +pattern: (expr|star_expr) (',' (expr|star_expr))* [','] diff --git a/myenv/lib/python3.9/site-packages/blib2to3/PatternGrammar.txt b/myenv/lib/python3.9/site-packages/blib2to3/PatternGrammar.txt new file mode 100644 index 0000000..36bf814 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/PatternGrammar.txt @@ -0,0 +1,28 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +# A grammar to describe tree matching patterns. +# Not shown here: +# - 'TOKEN' stands for any token (leaf node) +# - 'any' stands for any node (leaf or interior) +# With 'any' we can still specify the sub-structure. + +# The start symbol is 'Matcher'. + +Matcher: Alternatives ENDMARKER + +Alternatives: Alternative ('|' Alternative)* + +Alternative: (Unit | NegatedUnit)+ + +Unit: [NAME '='] ( STRING [Repeater] + | NAME [Details] [Repeater] + | '(' Alternatives ')' [Repeater] + | '[' Alternatives ']' + ) + +NegatedUnit: 'not' (STRING | NAME [Details] | '(' Alternatives ')') + +Repeater: '*' | '+' | '{' NUMBER [',' NUMBER] '}' + +Details: '<' Alternatives '>' diff --git a/myenv/lib/python3.9/site-packages/blib2to3/__init__.py b/myenv/lib/python3.9/site-packages/blib2to3/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/__init__.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/__init__.py new file mode 100644 index 0000000..af39048 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""The pgen2 package.""" diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/conv.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/conv.py new file mode 100644 index 0000000..fa9825e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/conv.py @@ -0,0 +1,256 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +# mypy: ignore-errors + +"""Convert graminit.[ch] spit out by pgen to Python code. + +Pgen is the Python parser generator. It is useful to quickly create a +parser from a grammar file in Python's grammar notation. But I don't +want my parsers to be written in C (yet), so I'm translating the +parsing tables to Python data structures and writing a Python parse +engine. + +Note that the token numbers are constants determined by the standard +Python tokenizer. The standard token module defines these numbers and +their names (the names are not used much). The token numbers are +hardcoded into the Python tokenizer and into pgen. A Python +implementation of the Python tokenizer is also available, in the +standard tokenize module. + +On the other hand, symbol numbers (representing the grammar's +non-terminals) are assigned by pgen based on the actual grammar +input. + +Note: this module is pretty much obsolete; the pgen module generates +equivalent grammar tables directly from the Grammar.txt input file +without having to invoke the Python pgen C program. + +""" + +# Python imports +import re + +# Local imports +from pgen2 import grammar, token + + +class Converter(grammar.Grammar): + """Grammar subclass that reads classic pgen output files. + + The run() method reads the tables as produced by the pgen parser + generator, typically contained in two C files, graminit.h and + graminit.c. The other methods are for internal use only. + + See the base class for more documentation. + + """ + + def run(self, graminit_h, graminit_c): + """Load the grammar tables from the text files written by pgen.""" + self.parse_graminit_h(graminit_h) + self.parse_graminit_c(graminit_c) + self.finish_off() + + def parse_graminit_h(self, filename): + """Parse the .h file written by pgen. (Internal) + + This file is a sequence of #define statements defining the + nonterminals of the grammar as numbers. We build two tables + mapping the numbers to names and back. + + """ + try: + f = open(filename) + except OSError as err: + print("Can't open %s: %s" % (filename, err)) + return False + self.symbol2number = {} + self.number2symbol = {} + lineno = 0 + for line in f: + lineno += 1 + mo = re.match(r"^#define\s+(\w+)\s+(\d+)$", line) + if not mo and line.strip(): + print("%s(%s): can't parse %s" % (filename, lineno, line.strip())) + else: + symbol, number = mo.groups() + number = int(number) + assert symbol not in self.symbol2number + assert number not in self.number2symbol + self.symbol2number[symbol] = number + self.number2symbol[number] = symbol + return True + + def parse_graminit_c(self, filename): + """Parse the .c file written by pgen. (Internal) + + The file looks as follows. The first two lines are always this: + + #include "pgenheaders.h" + #include "grammar.h" + + After that come four blocks: + + 1) one or more state definitions + 2) a table defining dfas + 3) a table defining labels + 4) a struct defining the grammar + + A state definition has the following form: + - one or more arc arrays, each of the form: + static arc arcs__[] = { + {, }, + ... + }; + - followed by a state array, of the form: + static state states_[] = { + {, arcs__}, + ... + }; + + """ + try: + f = open(filename) + except OSError as err: + print("Can't open %s: %s" % (filename, err)) + return False + # The code below essentially uses f's iterator-ness! + lineno = 0 + + # Expect the two #include lines + lineno, line = lineno + 1, next(f) + assert line == '#include "pgenheaders.h"\n', (lineno, line) + lineno, line = lineno + 1, next(f) + assert line == '#include "grammar.h"\n', (lineno, line) + + # Parse the state definitions + lineno, line = lineno + 1, next(f) + allarcs = {} + states = [] + while line.startswith("static arc "): + while line.startswith("static arc "): + mo = re.match(r"static arc arcs_(\d+)_(\d+)\[(\d+)\] = {$", line) + assert mo, (lineno, line) + n, m, k = list(map(int, mo.groups())) + arcs = [] + for _ in range(k): + lineno, line = lineno + 1, next(f) + mo = re.match(r"\s+{(\d+), (\d+)},$", line) + assert mo, (lineno, line) + i, j = list(map(int, mo.groups())) + arcs.append((i, j)) + lineno, line = lineno + 1, next(f) + assert line == "};\n", (lineno, line) + allarcs[(n, m)] = arcs + lineno, line = lineno + 1, next(f) + mo = re.match(r"static state states_(\d+)\[(\d+)\] = {$", line) + assert mo, (lineno, line) + s, t = list(map(int, mo.groups())) + assert s == len(states), (lineno, line) + state = [] + for _ in range(t): + lineno, line = lineno + 1, next(f) + mo = re.match(r"\s+{(\d+), arcs_(\d+)_(\d+)},$", line) + assert mo, (lineno, line) + k, n, m = list(map(int, mo.groups())) + arcs = allarcs[n, m] + assert k == len(arcs), (lineno, line) + state.append(arcs) + states.append(state) + lineno, line = lineno + 1, next(f) + assert line == "};\n", (lineno, line) + lineno, line = lineno + 1, next(f) + self.states = states + + # Parse the dfas + dfas = {} + mo = re.match(r"static dfa dfas\[(\d+)\] = {$", line) + assert mo, (lineno, line) + ndfas = int(mo.group(1)) + for i in range(ndfas): + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+{(\d+), "(\w+)", (\d+), (\d+), states_(\d+),$', line) + assert mo, (lineno, line) + symbol = mo.group(2) + number, x, y, z = list(map(int, mo.group(1, 3, 4, 5))) + assert self.symbol2number[symbol] == number, (lineno, line) + assert self.number2symbol[number] == symbol, (lineno, line) + assert x == 0, (lineno, line) + state = states[z] + assert y == len(state), (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+("(?:\\\d\d\d)*")},$', line) + assert mo, (lineno, line) + first = {} + rawbitset = eval(mo.group(1)) + for i, c in enumerate(rawbitset): + byte = ord(c) + for j in range(8): + if byte & (1 << j): + first[i * 8 + j] = 1 + dfas[number] = (state, first) + lineno, line = lineno + 1, next(f) + assert line == "};\n", (lineno, line) + self.dfas = dfas + + # Parse the labels + labels = [] + lineno, line = lineno + 1, next(f) + mo = re.match(r"static label labels\[(\d+)\] = {$", line) + assert mo, (lineno, line) + nlabels = int(mo.group(1)) + for i in range(nlabels): + lineno, line = lineno + 1, next(f) + mo = re.match(r'\s+{(\d+), (0|"\w+")},$', line) + assert mo, (lineno, line) + x, y = mo.groups() + x = int(x) + if y == "0": + y = None + else: + y = eval(y) + labels.append((x, y)) + lineno, line = lineno + 1, next(f) + assert line == "};\n", (lineno, line) + self.labels = labels + + # Parse the grammar struct + lineno, line = lineno + 1, next(f) + assert line == "grammar _PyParser_Grammar = {\n", (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r"\s+(\d+),$", line) + assert mo, (lineno, line) + ndfas = int(mo.group(1)) + assert ndfas == len(self.dfas) + lineno, line = lineno + 1, next(f) + assert line == "\tdfas,\n", (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r"\s+{(\d+), labels},$", line) + assert mo, (lineno, line) + nlabels = int(mo.group(1)) + assert nlabels == len(self.labels), (lineno, line) + lineno, line = lineno + 1, next(f) + mo = re.match(r"\s+(\d+)$", line) + assert mo, (lineno, line) + start = int(mo.group(1)) + assert start in self.number2symbol, (lineno, line) + self.start = start + lineno, line = lineno + 1, next(f) + assert line == "};\n", (lineno, line) + try: + lineno, line = lineno + 1, next(f) + except StopIteration: + pass + else: + assert 0, (lineno, line) + + def finish_off(self): + """Create additional useful structures. (Internal).""" + self.keywords = {} # map from keyword strings to arc labels + self.tokens = {} # map from numeric token values to arc labels + for ilabel, (type, value) in enumerate(self.labels): + if type == token.NAME and value is not None: + self.keywords[value] = ilabel + elif value is None: + self.tokens[type] = ilabel diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/driver.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/driver.py new file mode 100644 index 0000000..8fe8206 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/driver.py @@ -0,0 +1,327 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +# Modifications: +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""Parser driver. + +This provides a high-level interface to parse a file into a syntax tree. + +""" + +__author__ = "Guido van Rossum " + +__all__ = ["Driver", "load_grammar"] + +# Python imports +import io +import os +import logging +import pkgutil +import sys +from typing import ( + Any, + cast, + IO, + Iterable, + List, + Optional, + Text, + Iterator, + Tuple, + TypeVar, + Generic, + Union, +) +from contextlib import contextmanager +from dataclasses import dataclass, field + +# Pgen imports +from . import grammar, parse, token, tokenize, pgen +from logging import Logger +from blib2to3.pytree import NL +from blib2to3.pgen2.grammar import Grammar +from blib2to3.pgen2.tokenize import GoodTokenInfo + +Path = Union[str, "os.PathLike[str]"] + + +@dataclass +class ReleaseRange: + start: int + end: Optional[int] = None + tokens: List[Any] = field(default_factory=list) + + def lock(self) -> None: + total_eaten = len(self.tokens) + self.end = self.start + total_eaten + + +class TokenProxy: + def __init__(self, generator: Any) -> None: + self._tokens = generator + self._counter = 0 + self._release_ranges: List[ReleaseRange] = [] + + @contextmanager + def release(self) -> Iterator["TokenProxy"]: + release_range = ReleaseRange(self._counter) + self._release_ranges.append(release_range) + try: + yield self + finally: + # Lock the last release range to the final position that + # has been eaten. + release_range.lock() + + def eat(self, point: int) -> Any: + eaten_tokens = self._release_ranges[-1].tokens + if point < len(eaten_tokens): + return eaten_tokens[point] + else: + while point >= len(eaten_tokens): + token = next(self._tokens) + eaten_tokens.append(token) + return token + + def __iter__(self) -> "TokenProxy": + return self + + def __next__(self) -> Any: + # If the current position is already compromised (looked up) + # return the eaten token, if not just go further on the given + # token producer. + for release_range in self._release_ranges: + assert release_range.end is not None + + start, end = release_range.start, release_range.end + if start <= self._counter < end: + token = release_range.tokens[self._counter - start] + break + else: + token = next(self._tokens) + self._counter += 1 + return token + + def can_advance(self, to: int) -> bool: + # Try to eat, fail if it can't. The eat operation is cached + # so there wont be any additional cost of eating here + try: + self.eat(to) + except StopIteration: + return False + else: + return True + + +class Driver(object): + def __init__(self, grammar: Grammar, logger: Optional[Logger] = None) -> None: + self.grammar = grammar + if logger is None: + logger = logging.getLogger(__name__) + self.logger = logger + + def parse_tokens(self, tokens: Iterable[GoodTokenInfo], debug: bool = False) -> NL: + """Parse a series of tokens and return the syntax tree.""" + # XXX Move the prefix computation into a wrapper around tokenize. + proxy = TokenProxy(tokens) + + p = parse.Parser(self.grammar) + p.setup(proxy=proxy) + + lineno = 1 + column = 0 + indent_columns: List[int] = [] + type = value = start = end = line_text = None + prefix = "" + + for quintuple in proxy: + type, value, start, end, line_text = quintuple + if start != (lineno, column): + assert (lineno, column) <= start, ((lineno, column), start) + s_lineno, s_column = start + if lineno < s_lineno: + prefix += "\n" * (s_lineno - lineno) + lineno = s_lineno + column = 0 + if column < s_column: + prefix += line_text[column:s_column] + column = s_column + if type in (tokenize.COMMENT, tokenize.NL): + prefix += value + lineno, column = end + if value.endswith("\n"): + lineno += 1 + column = 0 + continue + if type == token.OP: + type = grammar.opmap[value] + if debug: + assert type is not None + self.logger.debug( + "%s %r (prefix=%r)", token.tok_name[type], value, prefix + ) + if type == token.INDENT: + indent_columns.append(len(value)) + _prefix = prefix + value + prefix = "" + value = "" + elif type == token.DEDENT: + _indent_col = indent_columns.pop() + prefix, _prefix = self._partially_consume_prefix(prefix, _indent_col) + if p.addtoken(cast(int, type), value, (prefix, start)): + if debug: + self.logger.debug("Stop.") + break + prefix = "" + if type in {token.INDENT, token.DEDENT}: + prefix = _prefix + lineno, column = end + if value.endswith("\n"): + lineno += 1 + column = 0 + else: + # We never broke out -- EOF is too soon (how can this happen???) + assert start is not None + raise parse.ParseError("incomplete input", type, value, (prefix, start)) + assert p.rootnode is not None + return p.rootnode + + def parse_stream_raw(self, stream: IO[Text], debug: bool = False) -> NL: + """Parse a stream and return the syntax tree.""" + tokens = tokenize.generate_tokens(stream.readline, grammar=self.grammar) + return self.parse_tokens(tokens, debug) + + def parse_stream(self, stream: IO[Text], debug: bool = False) -> NL: + """Parse a stream and return the syntax tree.""" + return self.parse_stream_raw(stream, debug) + + def parse_file( + self, filename: Path, encoding: Optional[Text] = None, debug: bool = False + ) -> NL: + """Parse a file and return the syntax tree.""" + with io.open(filename, "r", encoding=encoding) as stream: + return self.parse_stream(stream, debug) + + def parse_string(self, text: Text, debug: bool = False) -> NL: + """Parse a string and return the syntax tree.""" + tokens = tokenize.generate_tokens( + io.StringIO(text).readline, grammar=self.grammar + ) + return self.parse_tokens(tokens, debug) + + def _partially_consume_prefix(self, prefix: Text, column: int) -> Tuple[Text, Text]: + lines: List[str] = [] + current_line = "" + current_column = 0 + wait_for_nl = False + for char in prefix: + current_line += char + if wait_for_nl: + if char == "\n": + if current_line.strip() and current_column < column: + res = "".join(lines) + return res, prefix[len(res) :] + + lines.append(current_line) + current_line = "" + current_column = 0 + wait_for_nl = False + elif char in " \t": + current_column += 1 + elif char == "\n": + # unexpected empty line + current_column = 0 + else: + # indent is finished + wait_for_nl = True + return "".join(lines), current_line + + +def _generate_pickle_name(gt: Path, cache_dir: Optional[Path] = None) -> Text: + head, tail = os.path.splitext(gt) + if tail == ".txt": + tail = "" + name = head + tail + ".".join(map(str, sys.version_info)) + ".pickle" + if cache_dir: + return os.path.join(cache_dir, os.path.basename(name)) + else: + return name + + +def load_grammar( + gt: Text = "Grammar.txt", + gp: Optional[Text] = None, + save: bool = True, + force: bool = False, + logger: Optional[Logger] = None, +) -> Grammar: + """Load the grammar (maybe from a pickle).""" + if logger is None: + logger = logging.getLogger(__name__) + gp = _generate_pickle_name(gt) if gp is None else gp + if force or not _newer(gp, gt): + logger.info("Generating grammar tables from %s", gt) + g: grammar.Grammar = pgen.generate_grammar(gt) + if save: + logger.info("Writing grammar tables to %s", gp) + try: + g.dump(gp) + except OSError as e: + logger.info("Writing failed: %s", e) + else: + g = grammar.Grammar() + g.load(gp) + return g + + +def _newer(a: Text, b: Text) -> bool: + """Inquire whether file a was written since file b.""" + if not os.path.exists(a): + return False + if not os.path.exists(b): + return True + return os.path.getmtime(a) >= os.path.getmtime(b) + + +def load_packaged_grammar( + package: str, grammar_source: Text, cache_dir: Optional[Path] = None +) -> grammar.Grammar: + """Normally, loads a pickled grammar by doing + pkgutil.get_data(package, pickled_grammar) + where *pickled_grammar* is computed from *grammar_source* by adding the + Python version and using a ``.pickle`` extension. + + However, if *grammar_source* is an extant file, load_grammar(grammar_source) + is called instead. This facilitates using a packaged grammar file when needed + but preserves load_grammar's automatic regeneration behavior when possible. + + """ + if os.path.isfile(grammar_source): + gp = _generate_pickle_name(grammar_source, cache_dir) if cache_dir else None + return load_grammar(grammar_source, gp=gp) + pickled_name = _generate_pickle_name(os.path.basename(grammar_source), cache_dir) + data = pkgutil.get_data(package, pickled_name) + assert data is not None + g = grammar.Grammar() + g.loads(data) + return g + + +def main(*args: Text) -> bool: + """Main program, when run as a script: produce grammar pickle files. + + Calls load_grammar for each argument, a path to a grammar text file. + """ + if not args: + args = tuple(sys.argv[1:]) + logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(message)s") + for gt in args: + load_grammar(gt, save=True, force=True) + return True + + +if __name__ == "__main__": + sys.exit(int(not main())) diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/grammar.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/grammar.py new file mode 100644 index 0000000..5685107 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/grammar.py @@ -0,0 +1,225 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""This module defines the data structures used to represent a grammar. + +These are a bit arcane because they are derived from the data +structures used by Python's 'pgen' parser generator. + +There's also a table here mapping operators to their names in the +token module; the Python tokenize module reports all operators as the +fallback token code OP, but the parser needs the actual token code. + +""" + +# Python imports +import os +import pickle +import tempfile +from typing import Any, Dict, List, Optional, Text, Tuple, TypeVar, Union + +# Local imports +from . import token + +_P = TypeVar("_P", bound="Grammar") +Label = Tuple[int, Optional[Text]] +DFA = List[List[Tuple[int, int]]] +DFAS = Tuple[DFA, Dict[int, int]] +Path = Union[str, "os.PathLike[str]"] + + +class Grammar(object): + """Pgen parsing tables conversion class. + + Once initialized, this class supplies the grammar tables for the + parsing engine implemented by parse.py. The parsing engine + accesses the instance variables directly. The class here does not + provide initialization of the tables; several subclasses exist to + do this (see the conv and pgen modules). + + The load() method reads the tables from a pickle file, which is + much faster than the other ways offered by subclasses. The pickle + file is written by calling dump() (after loading the grammar + tables using a subclass). The report() method prints a readable + representation of the tables to stdout, for debugging. + + The instance variables are as follows: + + symbol2number -- a dict mapping symbol names to numbers. Symbol + numbers are always 256 or higher, to distinguish + them from token numbers, which are between 0 and + 255 (inclusive). + + number2symbol -- a dict mapping numbers to symbol names; + these two are each other's inverse. + + states -- a list of DFAs, where each DFA is a list of + states, each state is a list of arcs, and each + arc is a (i, j) pair where i is a label and j is + a state number. The DFA number is the index into + this list. (This name is slightly confusing.) + Final states are represented by a special arc of + the form (0, j) where j is its own state number. + + dfas -- a dict mapping symbol numbers to (DFA, first) + pairs, where DFA is an item from the states list + above, and first is a set of tokens that can + begin this grammar rule (represented by a dict + whose values are always 1). + + labels -- a list of (x, y) pairs where x is either a token + number or a symbol number, and y is either None + or a string; the strings are keywords. The label + number is the index in this list; label numbers + are used to mark state transitions (arcs) in the + DFAs. + + start -- the number of the grammar's start symbol. + + keywords -- a dict mapping keyword strings to arc labels. + + tokens -- a dict mapping token numbers to arc labels. + + """ + + def __init__(self) -> None: + self.symbol2number: Dict[str, int] = {} + self.number2symbol: Dict[int, str] = {} + self.states: List[DFA] = [] + self.dfas: Dict[int, DFAS] = {} + self.labels: List[Label] = [(0, "EMPTY")] + self.keywords: Dict[str, int] = {} + self.soft_keywords: Dict[str, int] = {} + self.tokens: Dict[int, int] = {} + self.symbol2label: Dict[str, int] = {} + self.start = 256 + # Python 3.7+ parses async as a keyword, not an identifier + self.async_keywords = False + + def dump(self, filename: Path) -> None: + """Dump the grammar tables to a pickle file.""" + + # mypyc generates objects that don't have a __dict__, but they + # do have __getstate__ methods that will return an equivalent + # dictionary + if hasattr(self, "__dict__"): + d = self.__dict__ + else: + d = self.__getstate__() # type: ignore + + with tempfile.NamedTemporaryFile( + dir=os.path.dirname(filename), delete=False + ) as f: + pickle.dump(d, f, pickle.HIGHEST_PROTOCOL) + os.replace(f.name, filename) + + def _update(self, attrs: Dict[str, Any]) -> None: + for k, v in attrs.items(): + setattr(self, k, v) + + def load(self, filename: Path) -> None: + """Load the grammar tables from a pickle file.""" + with open(filename, "rb") as f: + d = pickle.load(f) + self._update(d) + + def loads(self, pkl: bytes) -> None: + """Load the grammar tables from a pickle bytes object.""" + self._update(pickle.loads(pkl)) + + def copy(self: _P) -> _P: + """ + Copy the grammar. + """ + new = self.__class__() + for dict_attr in ( + "symbol2number", + "number2symbol", + "dfas", + "keywords", + "soft_keywords", + "tokens", + "symbol2label", + ): + setattr(new, dict_attr, getattr(self, dict_attr).copy()) + new.labels = self.labels[:] + new.states = self.states[:] + new.start = self.start + new.async_keywords = self.async_keywords + return new + + def report(self) -> None: + """Dump the grammar tables to standard output, for debugging.""" + from pprint import pprint + + print("s2n") + pprint(self.symbol2number) + print("n2s") + pprint(self.number2symbol) + print("states") + pprint(self.states) + print("dfas") + pprint(self.dfas) + print("labels") + pprint(self.labels) + print("start", self.start) + + +# Map from operator to number (since tokenize doesn't do this) + +opmap_raw = """ +( LPAR +) RPAR +[ LSQB +] RSQB +: COLON +, COMMA +; SEMI ++ PLUS +- MINUS +* STAR +/ SLASH +| VBAR +& AMPER +< LESS +> GREATER += EQUAL +. DOT +% PERCENT +` BACKQUOTE +{ LBRACE +} RBRACE +@ AT +@= ATEQUAL +== EQEQUAL +!= NOTEQUAL +<> NOTEQUAL +<= LESSEQUAL +>= GREATEREQUAL +~ TILDE +^ CIRCUMFLEX +<< LEFTSHIFT +>> RIGHTSHIFT +** DOUBLESTAR ++= PLUSEQUAL +-= MINEQUAL +*= STAREQUAL +/= SLASHEQUAL +%= PERCENTEQUAL +&= AMPEREQUAL +|= VBAREQUAL +^= CIRCUMFLEXEQUAL +<<= LEFTSHIFTEQUAL +>>= RIGHTSHIFTEQUAL +**= DOUBLESTAREQUAL +// DOUBLESLASH +//= DOUBLESLASHEQUAL +-> RARROW +:= COLONEQUAL +""" + +opmap = {} +for line in opmap_raw.splitlines(): + if line: + op, name = line.split() + opmap[op] = getattr(token, name) diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/literals.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/literals.py new file mode 100644 index 0000000..b5fe428 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/literals.py @@ -0,0 +1,68 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""Safely evaluate Python string literals without using eval().""" + +import re + +from typing import Dict, Match, Text + + +simple_escapes: Dict[Text, Text] = { + "a": "\a", + "b": "\b", + "f": "\f", + "n": "\n", + "r": "\r", + "t": "\t", + "v": "\v", + "'": "'", + '"': '"', + "\\": "\\", +} + + +def escape(m: Match[Text]) -> Text: + all, tail = m.group(0, 1) + assert all.startswith("\\") + esc = simple_escapes.get(tail) + if esc is not None: + return esc + if tail.startswith("x"): + hexes = tail[1:] + if len(hexes) < 2: + raise ValueError("invalid hex string escape ('\\%s')" % tail) + try: + i = int(hexes, 16) + except ValueError: + raise ValueError("invalid hex string escape ('\\%s')" % tail) from None + else: + try: + i = int(tail, 8) + except ValueError: + raise ValueError("invalid octal string escape ('\\%s')" % tail) from None + return chr(i) + + +def evalString(s: Text) -> Text: + assert s.startswith("'") or s.startswith('"'), repr(s[:1]) + q = s[0] + if s[:3] == q * 3: + q = q * 3 + assert s.endswith(q), repr(s[-len(q) :]) + assert len(s) >= 2 * len(q) + s = s[len(q) : -len(q)] + return re.sub(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})", escape, s) + + +def test() -> None: + for i in range(256): + c = chr(i) + s = repr(c) + e = evalString(s) + if e != c: + print(i, c, s, e) + + +if __name__ == "__main__": + test() diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/parse.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/parse.py new file mode 100644 index 0000000..e5dad3a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/parse.py @@ -0,0 +1,346 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""Parser engine for the grammar tables generated by pgen. + +The grammar table must be loaded first. + +See Parser/parser.c in the Python distribution for additional info on +how this parsing engine works. + +""" +import copy +from contextlib import contextmanager + +# Local imports +from . import grammar, token, tokenize +from typing import ( + cast, + Any, + Optional, + Text, + Union, + Tuple, + Dict, + List, + Iterator, + Callable, + Set, + TYPE_CHECKING, +) +from blib2to3.pgen2.grammar import Grammar +from blib2to3.pytree import convert, NL, Context, RawNode, Leaf, Node + +if TYPE_CHECKING: + from blib2to3.driver import TokenProxy + + +Results = Dict[Text, NL] +Convert = Callable[[Grammar, RawNode], Union[Node, Leaf]] +DFA = List[List[Tuple[int, int]]] +DFAS = Tuple[DFA, Dict[int, int]] + + +def lam_sub(grammar: Grammar, node: RawNode) -> NL: + assert node[3] is not None + return Node(type=node[0], children=node[3], context=node[2]) + + +class Recorder: + def __init__(self, parser: "Parser", ilabels: List[int], context: Context) -> None: + self.parser = parser + self._ilabels = ilabels + self.context = context # not really matter + + self._dead_ilabels: Set[int] = set() + self._start_point = self.parser.stack + self._points = {ilabel: copy.deepcopy(self._start_point) for ilabel in ilabels} + + @property + def ilabels(self) -> Set[int]: + return self._dead_ilabels.symmetric_difference(self._ilabels) + + @contextmanager + def switch_to(self, ilabel: int) -> Iterator[None]: + self.parser.stack = self._points[ilabel] + try: + yield + except ParseError: + self._dead_ilabels.add(ilabel) + finally: + self.parser.stack = self._start_point + + def add_token(self, tok_type: int, tok_val: Text, raw: bool = False) -> None: + func: Callable[..., Any] + if raw: + func = self.parser._addtoken + else: + func = self.parser.addtoken + + for ilabel in self.ilabels: + with self.switch_to(ilabel): + args = [tok_type, tok_val, self.context] + if raw: + args.insert(0, ilabel) + func(*args) + + def determine_route(self, value: Text = None, force: bool = False) -> Optional[int]: + alive_ilabels = self.ilabels + if len(alive_ilabels) == 0: + *_, most_successful_ilabel = self._dead_ilabels + raise ParseError("bad input", most_successful_ilabel, value, self.context) + + ilabel, *rest = alive_ilabels + if force or not rest: + return ilabel + else: + return None + + +class ParseError(Exception): + """Exception to signal the parser is stuck.""" + + def __init__( + self, msg: Text, type: Optional[int], value: Optional[Text], context: Context + ) -> None: + Exception.__init__( + self, "%s: type=%r, value=%r, context=%r" % (msg, type, value, context) + ) + self.msg = msg + self.type = type + self.value = value + self.context = context + + +class Parser(object): + """Parser engine. + + The proper usage sequence is: + + p = Parser(grammar, [converter]) # create instance + p.setup([start]) # prepare for parsing + : + if p.addtoken(...): # parse a token; may raise ParseError + break + root = p.rootnode # root of abstract syntax tree + + A Parser instance may be reused by calling setup() repeatedly. + + A Parser instance contains state pertaining to the current token + sequence, and should not be used concurrently by different threads + to parse separate token sequences. + + See driver.py for how to get input tokens by tokenizing a file or + string. + + Parsing is complete when addtoken() returns True; the root of the + abstract syntax tree can then be retrieved from the rootnode + instance variable. When a syntax error occurs, addtoken() raises + the ParseError exception. There is no error recovery; the parser + cannot be used after a syntax error was reported (but it can be + reinitialized by calling setup()). + + """ + + def __init__(self, grammar: Grammar, convert: Optional[Convert] = None) -> None: + """Constructor. + + The grammar argument is a grammar.Grammar instance; see the + grammar module for more information. + + The parser is not ready yet for parsing; you must call the + setup() method to get it started. + + The optional convert argument is a function mapping concrete + syntax tree nodes to abstract syntax tree nodes. If not + given, no conversion is done and the syntax tree produced is + the concrete syntax tree. If given, it must be a function of + two arguments, the first being the grammar (a grammar.Grammar + instance), and the second being the concrete syntax tree node + to be converted. The syntax tree is converted from the bottom + up. + + **post-note: the convert argument is ignored since for Black's + usage, convert will always be blib2to3.pytree.convert. Allowing + this to be dynamic hurts mypyc's ability to use early binding. + These docs are left for historical and informational value. + + A concrete syntax tree node is a (type, value, context, nodes) + tuple, where type is the node type (a token or symbol number), + value is None for symbols and a string for tokens, context is + None or an opaque value used for error reporting (typically a + (lineno, offset) pair), and nodes is a list of children for + symbols, and None for tokens. + + An abstract syntax tree node may be anything; this is entirely + up to the converter function. + + """ + self.grammar = grammar + # See note in docstring above. TL;DR this is ignored. + self.convert = convert or lam_sub + + def setup(self, proxy: "TokenProxy", start: Optional[int] = None) -> None: + """Prepare for parsing. + + This *must* be called before starting to parse. + + The optional argument is an alternative start symbol; it + defaults to the grammar's start symbol. + + You can use a Parser instance to parse any number of programs; + each time you call setup() the parser is reset to an initial + state determined by the (implicit or explicit) start symbol. + + """ + if start is None: + start = self.grammar.start + # Each stack entry is a tuple: (dfa, state, node). + # A node is a tuple: (type, value, context, children), + # where children is a list of nodes or None, and context may be None. + newnode: RawNode = (start, None, None, []) + stackentry = (self.grammar.dfas[start], 0, newnode) + self.stack: List[Tuple[DFAS, int, RawNode]] = [stackentry] + self.rootnode: Optional[NL] = None + self.used_names: Set[str] = set() + self.proxy = proxy + + def addtoken(self, type: int, value: Text, context: Context) -> bool: + """Add a token; return True iff this is the end of the program.""" + # Map from token to label + ilabels = self.classify(type, value, context) + assert len(ilabels) >= 1 + + # If we have only one state to advance, we'll directly + # take it as is. + if len(ilabels) == 1: + [ilabel] = ilabels + return self._addtoken(ilabel, type, value, context) + + # If there are multiple states which we can advance (only + # happen under soft-keywords), then we will try all of them + # in parallel and as soon as one state can reach further than + # the rest, we'll choose that one. This is a pretty hacky + # and hopefully temporary algorithm. + # + # For a more detailed explanation, check out this post: + # https://tree.science/what-the-backtracking.html + + with self.proxy.release() as proxy: + counter, force = 0, False + recorder = Recorder(self, ilabels, context) + recorder.add_token(type, value, raw=True) + + next_token_value = value + while recorder.determine_route(next_token_value) is None: + if not proxy.can_advance(counter): + force = True + break + + next_token_type, next_token_value, *_ = proxy.eat(counter) + if next_token_type == tokenize.OP: + next_token_type = grammar.opmap[next_token_value] + + recorder.add_token(next_token_type, next_token_value) + counter += 1 + + ilabel = cast(int, recorder.determine_route(next_token_value, force=force)) + assert ilabel is not None + + return self._addtoken(ilabel, type, value, context) + + def _addtoken(self, ilabel: int, type: int, value: Text, context: Context) -> bool: + # Loop until the token is shifted; may raise exceptions + while True: + dfa, state, node = self.stack[-1] + states, first = dfa + arcs = states[state] + # Look for a state with this label + for i, newstate in arcs: + t = self.grammar.labels[i][0] + if t >= 256: + # See if it's a symbol and if we're in its first set + itsdfa = self.grammar.dfas[t] + itsstates, itsfirst = itsdfa + if ilabel in itsfirst: + # Push a symbol + self.push(t, itsdfa, newstate, context) + break # To continue the outer while loop + + elif ilabel == i: + # Look it up in the list of labels + # Shift a token; we're done with it + self.shift(type, value, newstate, context) + # Pop while we are in an accept-only state + state = newstate + while states[state] == [(0, state)]: + self.pop() + if not self.stack: + # Done parsing! + return True + dfa, state, node = self.stack[-1] + states, first = dfa + # Done with this token + return False + + else: + if (0, state) in arcs: + # An accepting state, pop it and try something else + self.pop() + if not self.stack: + # Done parsing, but another token is input + raise ParseError("too much input", type, value, context) + else: + # No success finding a transition + raise ParseError("bad input", type, value, context) + + def classify(self, type: int, value: Text, context: Context) -> List[int]: + """Turn a token into a label. (Internal) + + Depending on whether the value is a soft-keyword or not, + this function may return multiple labels to choose from.""" + if type == token.NAME: + # Keep a listing of all used names + self.used_names.add(value) + # Check for reserved words + if value in self.grammar.keywords: + return [self.grammar.keywords[value]] + elif value in self.grammar.soft_keywords: + assert type in self.grammar.tokens + return [ + self.grammar.soft_keywords[value], + self.grammar.tokens[type], + ] + + ilabel = self.grammar.tokens.get(type) + if ilabel is None: + raise ParseError("bad token", type, value, context) + return [ilabel] + + def shift(self, type: int, value: Text, newstate: int, context: Context) -> None: + """Shift a token. (Internal)""" + dfa, state, node = self.stack[-1] + rawnode: RawNode = (type, value, context, None) + newnode = convert(self.grammar, rawnode) + assert node[-1] is not None + node[-1].append(newnode) + self.stack[-1] = (dfa, newstate, node) + + def push(self, type: int, newdfa: DFAS, newstate: int, context: Context) -> None: + """Push a nonterminal. (Internal)""" + dfa, state, node = self.stack[-1] + newnode: RawNode = (type, None, context, []) + self.stack[-1] = (dfa, newstate, node) + self.stack.append((newdfa, 0, newnode)) + + def pop(self) -> None: + """Pop a nonterminal. (Internal)""" + popdfa, popstate, popnode = self.stack.pop() + newnode = convert(self.grammar, popnode) + if self.stack: + dfa, state, node = self.stack[-1] + assert node[-1] is not None + node[-1].append(newnode) + else: + self.rootnode = newnode + self.rootnode.used_names = self.used_names diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/pgen.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/pgen.py new file mode 100644 index 0000000..631682a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/pgen.py @@ -0,0 +1,433 @@ +# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +# Pgen imports +from . import grammar, token, tokenize + +from typing import ( + Any, + Dict, + IO, + Iterator, + List, + Optional, + Text, + Tuple, + Union, + Sequence, + NoReturn, +) +from blib2to3.pgen2 import grammar +from blib2to3.pgen2.tokenize import GoodTokenInfo +import os + + +Path = Union[str, "os.PathLike[str]"] + + +class PgenGrammar(grammar.Grammar): + pass + + +class ParserGenerator(object): + + filename: Path + stream: IO[Text] + generator: Iterator[GoodTokenInfo] + first: Dict[Text, Optional[Dict[Text, int]]] + + def __init__(self, filename: Path, stream: Optional[IO[Text]] = None) -> None: + close_stream = None + if stream is None: + stream = open(filename) + close_stream = stream.close + self.filename = filename + self.stream = stream + self.generator = tokenize.generate_tokens(stream.readline) + self.gettoken() # Initialize lookahead + self.dfas, self.startsymbol = self.parse() + if close_stream is not None: + close_stream() + self.first = {} # map from symbol name to set of tokens + self.addfirstsets() + + def make_grammar(self) -> PgenGrammar: + c = PgenGrammar() + names = list(self.dfas.keys()) + names.sort() + names.remove(self.startsymbol) + names.insert(0, self.startsymbol) + for name in names: + i = 256 + len(c.symbol2number) + c.symbol2number[name] = i + c.number2symbol[i] = name + for name in names: + dfa = self.dfas[name] + states = [] + for state in dfa: + arcs = [] + for label, next in sorted(state.arcs.items()): + arcs.append((self.make_label(c, label), dfa.index(next))) + if state.isfinal: + arcs.append((0, dfa.index(state))) + states.append(arcs) + c.states.append(states) + c.dfas[c.symbol2number[name]] = (states, self.make_first(c, name)) + c.start = c.symbol2number[self.startsymbol] + return c + + def make_first(self, c: PgenGrammar, name: Text) -> Dict[int, int]: + rawfirst = self.first[name] + assert rawfirst is not None + first = {} + for label in sorted(rawfirst): + ilabel = self.make_label(c, label) + ##assert ilabel not in first # XXX failed on <> ... != + first[ilabel] = 1 + return first + + def make_label(self, c: PgenGrammar, label: Text) -> int: + # XXX Maybe this should be a method on a subclass of converter? + ilabel = len(c.labels) + if label[0].isalpha(): + # Either a symbol name or a named token + if label in c.symbol2number: + # A symbol name (a non-terminal) + if label in c.symbol2label: + return c.symbol2label[label] + else: + c.labels.append((c.symbol2number[label], None)) + c.symbol2label[label] = ilabel + return ilabel + else: + # A named token (NAME, NUMBER, STRING) + itoken = getattr(token, label, None) + assert isinstance(itoken, int), label + assert itoken in token.tok_name, label + if itoken in c.tokens: + return c.tokens[itoken] + else: + c.labels.append((itoken, None)) + c.tokens[itoken] = ilabel + return ilabel + else: + # Either a keyword or an operator + assert label[0] in ('"', "'"), label + value = eval(label) + if value[0].isalpha(): + if label[0] == '"': + keywords = c.soft_keywords + else: + keywords = c.keywords + + # A keyword + if value in keywords: + return keywords[value] + else: + c.labels.append((token.NAME, value)) + keywords[value] = ilabel + return ilabel + else: + # An operator (any non-numeric token) + itoken = grammar.opmap[value] # Fails if unknown token + if itoken in c.tokens: + return c.tokens[itoken] + else: + c.labels.append((itoken, None)) + c.tokens[itoken] = ilabel + return ilabel + + def addfirstsets(self) -> None: + names = list(self.dfas.keys()) + names.sort() + for name in names: + if name not in self.first: + self.calcfirst(name) + # print name, self.first[name].keys() + + def calcfirst(self, name: Text) -> None: + dfa = self.dfas[name] + self.first[name] = None # dummy to detect left recursion + state = dfa[0] + totalset: Dict[str, int] = {} + overlapcheck = {} + for label, next in state.arcs.items(): + if label in self.dfas: + if label in self.first: + fset = self.first[label] + if fset is None: + raise ValueError("recursion for rule %r" % name) + else: + self.calcfirst(label) + fset = self.first[label] + assert fset is not None + totalset.update(fset) + overlapcheck[label] = fset + else: + totalset[label] = 1 + overlapcheck[label] = {label: 1} + inverse: Dict[str, str] = {} + for label, itsfirst in overlapcheck.items(): + for symbol in itsfirst: + if symbol in inverse: + raise ValueError( + "rule %s is ambiguous; %s is in the first sets of %s as well" + " as %s" % (name, symbol, label, inverse[symbol]) + ) + inverse[symbol] = label + self.first[name] = totalset + + def parse(self) -> Tuple[Dict[Text, List["DFAState"]], Text]: + dfas = {} + startsymbol: Optional[str] = None + # MSTART: (NEWLINE | RULE)* ENDMARKER + while self.type != token.ENDMARKER: + while self.type == token.NEWLINE: + self.gettoken() + # RULE: NAME ':' RHS NEWLINE + name = self.expect(token.NAME) + self.expect(token.OP, ":") + a, z = self.parse_rhs() + self.expect(token.NEWLINE) + # self.dump_nfa(name, a, z) + dfa = self.make_dfa(a, z) + # self.dump_dfa(name, dfa) + oldlen = len(dfa) + self.simplify_dfa(dfa) + newlen = len(dfa) + dfas[name] = dfa + # print name, oldlen, newlen + if startsymbol is None: + startsymbol = name + assert startsymbol is not None + return dfas, startsymbol + + def make_dfa(self, start: "NFAState", finish: "NFAState") -> List["DFAState"]: + # To turn an NFA into a DFA, we define the states of the DFA + # to correspond to *sets* of states of the NFA. Then do some + # state reduction. Let's represent sets as dicts with 1 for + # values. + assert isinstance(start, NFAState) + assert isinstance(finish, NFAState) + + def closure(state: NFAState) -> Dict[NFAState, int]: + base: Dict[NFAState, int] = {} + addclosure(state, base) + return base + + def addclosure(state: NFAState, base: Dict[NFAState, int]) -> None: + assert isinstance(state, NFAState) + if state in base: + return + base[state] = 1 + for label, next in state.arcs: + if label is None: + addclosure(next, base) + + states = [DFAState(closure(start), finish)] + for state in states: # NB states grows while we're iterating + arcs: Dict[str, Dict[NFAState, int]] = {} + for nfastate in state.nfaset: + for label, next in nfastate.arcs: + if label is not None: + addclosure(next, arcs.setdefault(label, {})) + for label, nfaset in sorted(arcs.items()): + for st in states: + if st.nfaset == nfaset: + break + else: + st = DFAState(nfaset, finish) + states.append(st) + state.addarc(st, label) + return states # List of DFAState instances; first one is start + + def dump_nfa(self, name: Text, start: "NFAState", finish: "NFAState") -> None: + print("Dump of NFA for", name) + todo = [start] + for i, state in enumerate(todo): + print(" State", i, state is finish and "(final)" or "") + for label, next in state.arcs: + if next in todo: + j = todo.index(next) + else: + j = len(todo) + todo.append(next) + if label is None: + print(" -> %d" % j) + else: + print(" %s -> %d" % (label, j)) + + def dump_dfa(self, name: Text, dfa: Sequence["DFAState"]) -> None: + print("Dump of DFA for", name) + for i, state in enumerate(dfa): + print(" State", i, state.isfinal and "(final)" or "") + for label, next in sorted(state.arcs.items()): + print(" %s -> %d" % (label, dfa.index(next))) + + def simplify_dfa(self, dfa: List["DFAState"]) -> None: + # This is not theoretically optimal, but works well enough. + # Algorithm: repeatedly look for two states that have the same + # set of arcs (same labels pointing to the same nodes) and + # unify them, until things stop changing. + + # dfa is a list of DFAState instances + changes = True + while changes: + changes = False + for i, state_i in enumerate(dfa): + for j in range(i + 1, len(dfa)): + state_j = dfa[j] + if state_i == state_j: + # print " unify", i, j + del dfa[j] + for state in dfa: + state.unifystate(state_j, state_i) + changes = True + break + + def parse_rhs(self) -> Tuple["NFAState", "NFAState"]: + # RHS: ALT ('|' ALT)* + a, z = self.parse_alt() + if self.value != "|": + return a, z + else: + aa = NFAState() + zz = NFAState() + aa.addarc(a) + z.addarc(zz) + while self.value == "|": + self.gettoken() + a, z = self.parse_alt() + aa.addarc(a) + z.addarc(zz) + return aa, zz + + def parse_alt(self) -> Tuple["NFAState", "NFAState"]: + # ALT: ITEM+ + a, b = self.parse_item() + while self.value in ("(", "[") or self.type in (token.NAME, token.STRING): + c, d = self.parse_item() + b.addarc(c) + b = d + return a, b + + def parse_item(self) -> Tuple["NFAState", "NFAState"]: + # ITEM: '[' RHS ']' | ATOM ['+' | '*'] + if self.value == "[": + self.gettoken() + a, z = self.parse_rhs() + self.expect(token.OP, "]") + a.addarc(z) + return a, z + else: + a, z = self.parse_atom() + value = self.value + if value not in ("+", "*"): + return a, z + self.gettoken() + z.addarc(a) + if value == "+": + return a, z + else: + return a, a + + def parse_atom(self) -> Tuple["NFAState", "NFAState"]: + # ATOM: '(' RHS ')' | NAME | STRING + if self.value == "(": + self.gettoken() + a, z = self.parse_rhs() + self.expect(token.OP, ")") + return a, z + elif self.type in (token.NAME, token.STRING): + a = NFAState() + z = NFAState() + a.addarc(z, self.value) + self.gettoken() + return a, z + else: + self.raise_error( + "expected (...) or NAME or STRING, got %s/%s", self.type, self.value + ) + assert False + + def expect(self, type: int, value: Optional[Any] = None) -> Text: + if self.type != type or (value is not None and self.value != value): + self.raise_error( + "expected %s/%s, got %s/%s", type, value, self.type, self.value + ) + value = self.value + self.gettoken() + return value + + def gettoken(self) -> None: + tup = next(self.generator) + while tup[0] in (tokenize.COMMENT, tokenize.NL): + tup = next(self.generator) + self.type, self.value, self.begin, self.end, self.line = tup + # print token.tok_name[self.type], repr(self.value) + + def raise_error(self, msg: str, *args: Any) -> NoReturn: + if args: + try: + msg = msg % args + except: + msg = " ".join([msg] + list(map(str, args))) + raise SyntaxError(msg, (self.filename, self.end[0], self.end[1], self.line)) + + +class NFAState(object): + arcs: List[Tuple[Optional[Text], "NFAState"]] + + def __init__(self) -> None: + self.arcs = [] # list of (label, NFAState) pairs + + def addarc(self, next: "NFAState", label: Optional[Text] = None) -> None: + assert label is None or isinstance(label, str) + assert isinstance(next, NFAState) + self.arcs.append((label, next)) + + +class DFAState(object): + nfaset: Dict[NFAState, Any] + isfinal: bool + arcs: Dict[Text, "DFAState"] + + def __init__(self, nfaset: Dict[NFAState, Any], final: NFAState) -> None: + assert isinstance(nfaset, dict) + assert isinstance(next(iter(nfaset)), NFAState) + assert isinstance(final, NFAState) + self.nfaset = nfaset + self.isfinal = final in nfaset + self.arcs = {} # map from label to DFAState + + def addarc(self, next: "DFAState", label: Text) -> None: + assert isinstance(label, str) + assert label not in self.arcs + assert isinstance(next, DFAState) + self.arcs[label] = next + + def unifystate(self, old: "DFAState", new: "DFAState") -> None: + for label, next in self.arcs.items(): + if next is old: + self.arcs[label] = new + + def __eq__(self, other: Any) -> bool: + # Equality test -- ignore the nfaset instance variable + assert isinstance(other, DFAState) + if self.isfinal != other.isfinal: + return False + # Can't just return self.arcs == other.arcs, because that + # would invoke this method recursively, with cycles... + if len(self.arcs) != len(other.arcs): + return False + for label, next in self.arcs.items(): + if next is not other.arcs.get(label): + return False + return True + + __hash__: Any = None # For Py3 compatibility. + + +def generate_grammar(filename: Path = "Grammar.txt") -> PgenGrammar: + p = ParserGenerator(filename) + return p.make_grammar() diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/token.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/token.py new file mode 100644 index 0000000..1e0dec9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/token.py @@ -0,0 +1,94 @@ +"""Token constants (from "token.h").""" + +import sys +from typing import Dict + +if sys.version_info < (3, 8): + from typing_extensions import Final +else: + from typing import Final + +# Taken from Python (r53757) and modified to include some tokens +# originally monkeypatched in by pgen2.tokenize + +# --start constants-- +ENDMARKER: Final = 0 +NAME: Final = 1 +NUMBER: Final = 2 +STRING: Final = 3 +NEWLINE: Final = 4 +INDENT: Final = 5 +DEDENT: Final = 6 +LPAR: Final = 7 +RPAR: Final = 8 +LSQB: Final = 9 +RSQB: Final = 10 +COLON: Final = 11 +COMMA: Final = 12 +SEMI: Final = 13 +PLUS: Final = 14 +MINUS: Final = 15 +STAR: Final = 16 +SLASH: Final = 17 +VBAR: Final = 18 +AMPER: Final = 19 +LESS: Final = 20 +GREATER: Final = 21 +EQUAL: Final = 22 +DOT: Final = 23 +PERCENT: Final = 24 +BACKQUOTE: Final = 25 +LBRACE: Final = 26 +RBRACE: Final = 27 +EQEQUAL: Final = 28 +NOTEQUAL: Final = 29 +LESSEQUAL: Final = 30 +GREATEREQUAL: Final = 31 +TILDE: Final = 32 +CIRCUMFLEX: Final = 33 +LEFTSHIFT: Final = 34 +RIGHTSHIFT: Final = 35 +DOUBLESTAR: Final = 36 +PLUSEQUAL: Final = 37 +MINEQUAL: Final = 38 +STAREQUAL: Final = 39 +SLASHEQUAL: Final = 40 +PERCENTEQUAL: Final = 41 +AMPEREQUAL: Final = 42 +VBAREQUAL: Final = 43 +CIRCUMFLEXEQUAL: Final = 44 +LEFTSHIFTEQUAL: Final = 45 +RIGHTSHIFTEQUAL: Final = 46 +DOUBLESTAREQUAL: Final = 47 +DOUBLESLASH: Final = 48 +DOUBLESLASHEQUAL: Final = 49 +AT: Final = 50 +ATEQUAL: Final = 51 +OP: Final = 52 +COMMENT: Final = 53 +NL: Final = 54 +RARROW: Final = 55 +AWAIT: Final = 56 +ASYNC: Final = 57 +ERRORTOKEN: Final = 58 +COLONEQUAL: Final = 59 +N_TOKENS: Final = 60 +NT_OFFSET: Final = 256 +# --end constants-- + +tok_name: Final[Dict[int, str]] = {} +for _name, _value in list(globals().items()): + if type(_value) is type(0): + tok_name[_value] = _name + + +def ISTERMINAL(x: int) -> bool: + return x < NT_OFFSET + + +def ISNONTERMINAL(x: int) -> bool: + return x >= NT_OFFSET + + +def ISEOF(x: int) -> bool: + return x == ENDMARKER diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pgen2/tokenize.py b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/tokenize.py new file mode 100644 index 0000000..a7e17df --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pgen2/tokenize.py @@ -0,0 +1,688 @@ +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation. +# All rights reserved. + +# mypy: allow-untyped-defs, allow-untyped-calls + +"""Tokenization help for Python programs. + +generate_tokens(readline) is a generator that breaks a stream of +text into Python tokens. It accepts a readline-like method which is called +repeatedly to get the next line of input (or "" for EOF). It generates +5-tuples with these members: + + the token type (see token.py) + the token (a string) + the starting (row, column) indices of the token (a 2-tuple of ints) + the ending (row, column) indices of the token (a 2-tuple of ints) + the original line (string) + +It is designed to match the working of the Python tokenizer exactly, except +that it produces COMMENT tokens for comments and gives type OP for all +operators + +Older entry points + tokenize_loop(readline, tokeneater) + tokenize(readline, tokeneater=printtoken) +are the same, except instead of generating tokens, tokeneater is a callback +function to which the 5 fields described above are passed as 5 arguments, +each time a new token is found.""" + +import sys +from typing import ( + Callable, + Iterable, + Iterator, + List, + Optional, + Text, + Tuple, + Pattern, + Union, + cast, +) + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +from blib2to3.pgen2.token import * +from blib2to3.pgen2.grammar import Grammar + +__author__ = "Ka-Ping Yee " +__credits__ = "GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, Skip Montanaro" + +import re +from codecs import BOM_UTF8, lookup +from blib2to3.pgen2.token import * + +from . import token + +__all__ = [x for x in dir(token) if x[0] != "_"] + [ + "tokenize", + "generate_tokens", + "untokenize", +] +del token + + +def group(*choices): + return "(" + "|".join(choices) + ")" + + +def any(*choices): + return group(*choices) + "*" + + +def maybe(*choices): + return group(*choices) + "?" + + +def _combinations(*l): + return set(x + y for x in l for y in l + ("",) if x.casefold() != y.casefold()) + + +Whitespace = r"[ \f\t]*" +Comment = r"#[^\r\n]*" +Ignore = Whitespace + any(r"\\\r?\n" + Whitespace) + maybe(Comment) +Name = ( # this is invalid but it's fine because Name comes after Number in all groups + r"[^\s#\(\)\[\]\{\}+\-*/!@$%^&=|;:'\",\.<>/?`~\\]+" +) + +Binnumber = r"0[bB]_?[01]+(?:_[01]+)*" +Hexnumber = r"0[xX]_?[\da-fA-F]+(?:_[\da-fA-F]+)*[lL]?" +Octnumber = r"0[oO]?_?[0-7]+(?:_[0-7]+)*[lL]?" +Decnumber = group(r"[1-9]\d*(?:_\d+)*[lL]?", "0[lL]?") +Intnumber = group(Binnumber, Hexnumber, Octnumber, Decnumber) +Exponent = r"[eE][-+]?\d+(?:_\d+)*" +Pointfloat = group(r"\d+(?:_\d+)*\.(?:\d+(?:_\d+)*)?", r"\.\d+(?:_\d+)*") + maybe( + Exponent +) +Expfloat = r"\d+(?:_\d+)*" + Exponent +Floatnumber = group(Pointfloat, Expfloat) +Imagnumber = group(r"\d+(?:_\d+)*[jJ]", Floatnumber + r"[jJ]") +Number = group(Imagnumber, Floatnumber, Intnumber) + +# Tail end of ' string. +Single = r"[^'\\]*(?:\\.[^'\\]*)*'" +# Tail end of " string. +Double = r'[^"\\]*(?:\\.[^"\\]*)*"' +# Tail end of ''' string. +Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" +# Tail end of """ string. +Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' +_litprefix = r"(?:[uUrRbBfF]|[rR][fFbB]|[fFbBuU][rR])?" +Triple = group(_litprefix + "'''", _litprefix + '"""') +# Single-line ' or " string. +String = group( + _litprefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", + _litprefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"', +) + +# Because of leftmost-then-longest match semantics, be sure to put the +# longest operators first (e.g., if = came before ==, == would get +# recognized as two instances of =). +Operator = group( + r"\*\*=?", + r">>=?", + r"<<=?", + r"<>", + r"!=", + r"//=?", + r"->", + r"[+\-*/%&@|^=<>:]=?", + r"~", +) + +Bracket = "[][(){}]" +Special = group(r"\r?\n", r"[:;.,`@]") +Funny = group(Operator, Bracket, Special) + +# First (or only) line of ' or " string. +ContStr = group( + _litprefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + group("'", r"\\\r?\n"), + _litprefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + group('"', r"\\\r?\n"), +) +PseudoExtras = group(r"\\\r?\n", Comment, Triple) +PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) + +pseudoprog: Final = re.compile(PseudoToken, re.UNICODE) +single3prog = re.compile(Single3) +double3prog = re.compile(Double3) + +_strprefixes = ( + _combinations("r", "R", "f", "F") + | _combinations("r", "R", "b", "B") + | {"u", "U", "ur", "uR", "Ur", "UR"} +) + +endprogs: Final = { + "'": re.compile(Single), + '"': re.compile(Double), + "'''": single3prog, + '"""': double3prog, + **{f"{prefix}'''": single3prog for prefix in _strprefixes}, + **{f'{prefix}"""': double3prog for prefix in _strprefixes}, + **{prefix: None for prefix in _strprefixes}, +} + +triple_quoted: Final = ( + {"'''", '"""'} + | {f"{prefix}'''" for prefix in _strprefixes} + | {f'{prefix}"""' for prefix in _strprefixes} +) +single_quoted: Final = ( + {"'", '"'} + | {f"{prefix}'" for prefix in _strprefixes} + | {f'{prefix}"' for prefix in _strprefixes} +) + +tabsize = 8 + + +class TokenError(Exception): + pass + + +class StopTokenizing(Exception): + pass + + +def printtoken(type, token, xxx_todo_changeme, xxx_todo_changeme1, line): # for testing + (srow, scol) = xxx_todo_changeme + (erow, ecol) = xxx_todo_changeme1 + print( + "%d,%d-%d,%d:\t%s\t%s" % (srow, scol, erow, ecol, tok_name[type], repr(token)) + ) + + +Coord = Tuple[int, int] +TokenEater = Callable[[int, Text, Coord, Coord, Text], None] + + +def tokenize(readline: Callable[[], Text], tokeneater: TokenEater = printtoken) -> None: + """ + The tokenize() function accepts two parameters: one representing the + input stream, and one providing an output mechanism for tokenize(). + + The first parameter, readline, must be a callable object which provides + the same interface as the readline() method of built-in file objects. + Each call to the function should return one line of input as a string. + + The second parameter, tokeneater, must also be a callable object. It is + called once for each token, with five arguments, corresponding to the + tuples generated by generate_tokens(). + """ + try: + tokenize_loop(readline, tokeneater) + except StopTokenizing: + pass + + +# backwards compatible interface +def tokenize_loop(readline, tokeneater): + for token_info in generate_tokens(readline): + tokeneater(*token_info) + + +GoodTokenInfo = Tuple[int, Text, Coord, Coord, Text] +TokenInfo = Union[Tuple[int, str], GoodTokenInfo] + + +class Untokenizer: + + tokens: List[Text] + prev_row: int + prev_col: int + + def __init__(self) -> None: + self.tokens = [] + self.prev_row = 1 + self.prev_col = 0 + + def add_whitespace(self, start: Coord) -> None: + row, col = start + assert row <= self.prev_row + col_offset = col - self.prev_col + if col_offset: + self.tokens.append(" " * col_offset) + + def untokenize(self, iterable: Iterable[TokenInfo]) -> Text: + for t in iterable: + if len(t) == 2: + self.compat(cast(Tuple[int, str], t), iterable) + break + tok_type, token, start, end, line = cast( + Tuple[int, Text, Coord, Coord, Text], t + ) + self.add_whitespace(start) + self.tokens.append(token) + self.prev_row, self.prev_col = end + if tok_type in (NEWLINE, NL): + self.prev_row += 1 + self.prev_col = 0 + return "".join(self.tokens) + + def compat(self, token: Tuple[int, Text], iterable: Iterable[TokenInfo]) -> None: + startline = False + indents = [] + toks_append = self.tokens.append + toknum, tokval = token + if toknum in (NAME, NUMBER): + tokval += " " + if toknum in (NEWLINE, NL): + startline = True + for tok in iterable: + toknum, tokval = tok[:2] + + if toknum in (NAME, NUMBER, ASYNC, AWAIT): + tokval += " " + + if toknum == INDENT: + indents.append(tokval) + continue + elif toknum == DEDENT: + indents.pop() + continue + elif toknum in (NEWLINE, NL): + startline = True + elif startline and indents: + toks_append(indents[-1]) + startline = False + toks_append(tokval) + + +cookie_re = re.compile(r"^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)", re.ASCII) +blank_re = re.compile(br"^[ \t\f]*(?:[#\r\n]|$)", re.ASCII) + + +def _get_normal_name(orig_enc: str) -> str: + """Imitates get_normal_name in tokenizer.c.""" + # Only care about the first 12 characters. + enc = orig_enc[:12].lower().replace("_", "-") + if enc == "utf-8" or enc.startswith("utf-8-"): + return "utf-8" + if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or enc.startswith( + ("latin-1-", "iso-8859-1-", "iso-latin-1-") + ): + return "iso-8859-1" + return orig_enc + + +def detect_encoding(readline: Callable[[], bytes]) -> Tuple[str, List[bytes]]: + """ + The detect_encoding() function is used to detect the encoding that should + be used to decode a Python source file. It requires one argument, readline, + in the same way as the tokenize() generator. + + It will call readline a maximum of twice, and return the encoding used + (as a string) and a list of any lines (left as bytes) it has read + in. + + It detects the encoding from the presence of a utf-8 bom or an encoding + cookie as specified in pep-0263. If both a bom and a cookie are present, but + disagree, a SyntaxError will be raised. If the encoding cookie is an invalid + charset, raise a SyntaxError. Note that if a utf-8 bom is found, + 'utf-8-sig' is returned. + + If no encoding is specified, then the default of 'utf-8' will be returned. + """ + bom_found = False + encoding = None + default = "utf-8" + + def read_or_stop() -> bytes: + try: + return readline() + except StopIteration: + return bytes() + + def find_cookie(line: bytes) -> Optional[str]: + try: + line_string = line.decode("ascii") + except UnicodeDecodeError: + return None + match = cookie_re.match(line_string) + if not match: + return None + encoding = _get_normal_name(match.group(1)) + try: + codec = lookup(encoding) + except LookupError: + # This behaviour mimics the Python interpreter + raise SyntaxError("unknown encoding: " + encoding) + + if bom_found: + if codec.name != "utf-8": + # This behaviour mimics the Python interpreter + raise SyntaxError("encoding problem: utf-8") + encoding += "-sig" + return encoding + + first = read_or_stop() + if first.startswith(BOM_UTF8): + bom_found = True + first = first[3:] + default = "utf-8-sig" + if not first: + return default, [] + + encoding = find_cookie(first) + if encoding: + return encoding, [first] + if not blank_re.match(first): + return default, [first] + + second = read_or_stop() + if not second: + return default, [first] + + encoding = find_cookie(second) + if encoding: + return encoding, [first, second] + + return default, [first, second] + + +def untokenize(iterable: Iterable[TokenInfo]) -> Text: + """Transform tokens back into Python source code. + + Each element returned by the iterable must be a token sequence + with at least two elements, a token number and token value. If + only two tokens are passed, the resulting output is poor. + + Round-trip invariant for full input: + Untokenized source will match input source exactly + + Round-trip invariant for limited input: + # Output text will tokenize the back to the input + t1 = [tok[:2] for tok in generate_tokens(f.readline)] + newcode = untokenize(t1) + readline = iter(newcode.splitlines(1)).next + t2 = [tok[:2] for tokin generate_tokens(readline)] + assert t1 == t2 + """ + ut = Untokenizer() + return ut.untokenize(iterable) + + +def generate_tokens( + readline: Callable[[], Text], grammar: Optional[Grammar] = None +) -> Iterator[GoodTokenInfo]: + """ + The generate_tokens() generator requires one argument, readline, which + must be a callable object which provides the same interface as the + readline() method of built-in file objects. Each call to the function + should return one line of input as a string. Alternately, readline + can be a callable function terminating with StopIteration: + readline = open(myfile).next # Example of alternate readline + + The generator produces 5-tuples with these members: the token type; the + token string; a 2-tuple (srow, scol) of ints specifying the row and + column where the token begins in the source; a 2-tuple (erow, ecol) of + ints specifying the row and column where the token ends in the source; + and the line on which the token was found. The line passed is the + logical line; continuation lines are included. + """ + lnum = parenlev = continued = 0 + numchars: Final = "0123456789" + contstr, needcont = "", 0 + contline: Optional[str] = None + indents = [0] + + # If we know we're parsing 3.7+, we can unconditionally parse `async` and + # `await` as keywords. + async_keywords = False if grammar is None else grammar.async_keywords + # 'stashed' and 'async_*' are used for async/await parsing + stashed: Optional[GoodTokenInfo] = None + async_def = False + async_def_indent = 0 + async_def_nl = False + + strstart: Tuple[int, int] + endprog: Pattern[str] + + while 1: # loop over lines in stream + try: + line = readline() + except StopIteration: + line = "" + lnum += 1 + pos, max = 0, len(line) + + if contstr: # continued string + assert contline is not None + if not line: + raise TokenError("EOF in multi-line string", strstart) + endmatch = endprog.match(line) + if endmatch: + pos = end = endmatch.end(0) + yield ( + STRING, + contstr + line[:end], + strstart, + (lnum, end), + contline + line, + ) + contstr, needcont = "", 0 + contline = None + elif needcont and line[-2:] != "\\\n" and line[-3:] != "\\\r\n": + yield ( + ERRORTOKEN, + contstr + line, + strstart, + (lnum, len(line)), + contline, + ) + contstr = "" + contline = None + continue + else: + contstr = contstr + line + contline = contline + line + continue + + elif parenlev == 0 and not continued: # new statement + if not line: + break + column = 0 + while pos < max: # measure leading whitespace + if line[pos] == " ": + column += 1 + elif line[pos] == "\t": + column = (column // tabsize + 1) * tabsize + elif line[pos] == "\f": + column = 0 + else: + break + pos += 1 + if pos == max: + break + + if stashed: + yield stashed + stashed = None + + if line[pos] in "\r\n": # skip blank lines + yield (NL, line[pos:], (lnum, pos), (lnum, len(line)), line) + continue + + if line[pos] == "#": # skip comments + comment_token = line[pos:].rstrip("\r\n") + nl_pos = pos + len(comment_token) + yield ( + COMMENT, + comment_token, + (lnum, pos), + (lnum, nl_pos), + line, + ) + yield (NL, line[nl_pos:], (lnum, nl_pos), (lnum, len(line)), line) + continue + + if column > indents[-1]: # count indents + indents.append(column) + yield (INDENT, line[:pos], (lnum, 0), (lnum, pos), line) + + while column < indents[-1]: # count dedents + if column not in indents: + raise IndentationError( + "unindent does not match any outer indentation level", + ("", lnum, pos, line), + ) + indents = indents[:-1] + + if async_def and async_def_indent >= indents[-1]: + async_def = False + async_def_nl = False + async_def_indent = 0 + + yield (DEDENT, "", (lnum, pos), (lnum, pos), line) + + if async_def and async_def_nl and async_def_indent >= indents[-1]: + async_def = False + async_def_nl = False + async_def_indent = 0 + + else: # continued statement + if not line: + raise TokenError("EOF in multi-line statement", (lnum, 0)) + continued = 0 + + while pos < max: + pseudomatch = pseudoprog.match(line, pos) + if pseudomatch: # scan for tokens + start, end = pseudomatch.span(1) + spos, epos, pos = (lnum, start), (lnum, end), end + token, initial = line[start:end], line[start] + + if initial in numchars or ( + initial == "." and token != "." + ): # ordinary number + yield (NUMBER, token, spos, epos, line) + elif initial in "\r\n": + newline = NEWLINE + if parenlev > 0: + newline = NL + elif async_def: + async_def_nl = True + if stashed: + yield stashed + stashed = None + yield (newline, token, spos, epos, line) + + elif initial == "#": + assert not token.endswith("\n") + if stashed: + yield stashed + stashed = None + yield (COMMENT, token, spos, epos, line) + elif token in triple_quoted: + endprog = endprogs[token] + endmatch = endprog.match(line, pos) + if endmatch: # all on one line + pos = endmatch.end(0) + token = line[start:pos] + if stashed: + yield stashed + stashed = None + yield (STRING, token, spos, (lnum, pos), line) + else: + strstart = (lnum, start) # multiple lines + contstr = line[start:] + contline = line + break + elif ( + initial in single_quoted + or token[:2] in single_quoted + or token[:3] in single_quoted + ): + if token[-1] == "\n": # continued string + strstart = (lnum, start) + endprog = ( + endprogs[initial] + or endprogs[token[1]] + or endprogs[token[2]] + ) + contstr, needcont = line[start:], 1 + contline = line + break + else: # ordinary string + if stashed: + yield stashed + stashed = None + yield (STRING, token, spos, epos, line) + elif initial.isidentifier(): # ordinary name + if token in ("async", "await"): + if async_keywords or async_def: + yield ( + ASYNC if token == "async" else AWAIT, + token, + spos, + epos, + line, + ) + continue + + tok = (NAME, token, spos, epos, line) + if token == "async" and not stashed: + stashed = tok + continue + + if token in ("def", "for"): + if stashed and stashed[0] == NAME and stashed[1] == "async": + + if token == "def": + async_def = True + async_def_indent = indents[-1] + + yield ( + ASYNC, + stashed[1], + stashed[2], + stashed[3], + stashed[4], + ) + stashed = None + + if stashed: + yield stashed + stashed = None + + yield tok + elif initial == "\\": # continued stmt + # This yield is new; needed for better idempotency: + if stashed: + yield stashed + stashed = None + yield (NL, token, spos, (lnum, pos), line) + continued = 1 + else: + if initial in "([{": + parenlev += 1 + elif initial in ")]}": + parenlev -= 1 + if stashed: + yield stashed + stashed = None + yield (OP, token, spos, epos, line) + else: + yield (ERRORTOKEN, line[pos], (lnum, pos), (lnum, pos + 1), line) + pos += 1 + + if stashed: + yield stashed + stashed = None + + for indent in indents[1:]: # pop remaining indent levels + yield (DEDENT, "", (lnum, 0), (lnum, 0), "") + yield (ENDMARKER, "", (lnum, 0), (lnum, 0), "") + + +if __name__ == "__main__": # testing + import sys + + if len(sys.argv) > 1: + tokenize(open(sys.argv[1]).readline) + else: + tokenize(sys.stdin.readline) diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pygram.py b/myenv/lib/python3.9/site-packages/blib2to3/pygram.py new file mode 100644 index 0000000..aa20b81 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pygram.py @@ -0,0 +1,212 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +"""Export the Python grammar and symbols.""" + +# Python imports +import os + +from typing import Union + +# Local imports +from .pgen2 import token +from .pgen2 import driver + +from .pgen2.grammar import Grammar + +# Moved into initialize because mypyc can't handle __file__ (XXX bug) +# # The grammar file +# _GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), "Grammar.txt") +# _PATTERN_GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), +# "PatternGrammar.txt") + + +class Symbols(object): + def __init__(self, grammar: Grammar) -> None: + """Initializer. + + Creates an attribute for each grammar symbol (nonterminal), + whose value is the symbol's type (an int >= 256). + """ + for name, symbol in grammar.symbol2number.items(): + setattr(self, name, symbol) + + +class _python_symbols(Symbols): + and_expr: int + and_test: int + annassign: int + arglist: int + argument: int + arith_expr: int + asexpr_test: int + assert_stmt: int + async_funcdef: int + async_stmt: int + atom: int + augassign: int + break_stmt: int + case_block: int + classdef: int + comp_for: int + comp_if: int + comp_iter: int + comp_op: int + comparison: int + compound_stmt: int + continue_stmt: int + decorated: int + decorator: int + decorators: int + del_stmt: int + dictsetmaker: int + dotted_as_name: int + dotted_as_names: int + dotted_name: int + encoding_decl: int + eval_input: int + except_clause: int + exec_stmt: int + expr: int + expr_stmt: int + exprlist: int + factor: int + file_input: int + flow_stmt: int + for_stmt: int + funcdef: int + global_stmt: int + guard: int + if_stmt: int + import_as_name: int + import_as_names: int + import_from: int + import_name: int + import_stmt: int + lambdef: int + listmaker: int + match_stmt: int + namedexpr_test: int + not_test: int + old_comp_for: int + old_comp_if: int + old_comp_iter: int + old_lambdef: int + old_test: int + or_test: int + parameters: int + pass_stmt: int + pattern: int + patterns: int + power: int + print_stmt: int + raise_stmt: int + return_stmt: int + shift_expr: int + simple_stmt: int + single_input: int + sliceop: int + small_stmt: int + subject_expr: int + star_expr: int + stmt: int + subscript: int + subscriptlist: int + suite: int + term: int + test: int + testlist: int + testlist1: int + testlist_gexp: int + testlist_safe: int + testlist_star_expr: int + tfpdef: int + tfplist: int + tname: int + trailer: int + try_stmt: int + typedargslist: int + varargslist: int + vfpdef: int + vfplist: int + vname: int + while_stmt: int + with_stmt: int + xor_expr: int + yield_arg: int + yield_expr: int + yield_stmt: int + + +class _pattern_symbols(Symbols): + Alternative: int + Alternatives: int + Details: int + Matcher: int + NegatedUnit: int + Repeater: int + Unit: int + + +python_grammar: Grammar +python_grammar_no_print_statement: Grammar +python_grammar_no_print_statement_no_exec_statement: Grammar +python_grammar_no_print_statement_no_exec_statement_async_keywords: Grammar +python_grammar_no_exec_statement: Grammar +pattern_grammar: Grammar +python_grammar_soft_keywords: Grammar + +python_symbols: _python_symbols +pattern_symbols: _pattern_symbols + + +def initialize(cache_dir: Union[str, "os.PathLike[str]", None] = None) -> None: + global python_grammar + global python_grammar_no_print_statement + global python_grammar_no_print_statement_no_exec_statement + global python_grammar_no_print_statement_no_exec_statement_async_keywords + global python_grammar_soft_keywords + global python_symbols + global pattern_grammar + global pattern_symbols + + # The grammar file + _GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), "Grammar.txt") + _PATTERN_GRAMMAR_FILE = os.path.join( + os.path.dirname(__file__), "PatternGrammar.txt" + ) + + # Python 2 + python_grammar = driver.load_packaged_grammar("blib2to3", _GRAMMAR_FILE, cache_dir) + soft_keywords = python_grammar.soft_keywords.copy() + python_grammar.soft_keywords.clear() + + python_symbols = _python_symbols(python_grammar) + + # Python 2 + from __future__ import print_function + python_grammar_no_print_statement = python_grammar.copy() + del python_grammar_no_print_statement.keywords["print"] + + # Python 3.0-3.6 + python_grammar_no_print_statement_no_exec_statement = python_grammar.copy() + del python_grammar_no_print_statement_no_exec_statement.keywords["print"] + del python_grammar_no_print_statement_no_exec_statement.keywords["exec"] + + # Python 3.7+ + python_grammar_no_print_statement_no_exec_statement_async_keywords = ( + python_grammar_no_print_statement_no_exec_statement.copy() + ) + python_grammar_no_print_statement_no_exec_statement_async_keywords.async_keywords = ( + True + ) + + # Python 3.10+ + python_grammar_soft_keywords = ( + python_grammar_no_print_statement_no_exec_statement_async_keywords.copy() + ) + python_grammar_soft_keywords.soft_keywords = soft_keywords + + pattern_grammar = driver.load_packaged_grammar( + "blib2to3", _PATTERN_GRAMMAR_FILE, cache_dir + ) + pattern_symbols = _pattern_symbols(pattern_grammar) diff --git a/myenv/lib/python3.9/site-packages/blib2to3/pytree.py b/myenv/lib/python3.9/site-packages/blib2to3/pytree.py new file mode 100644 index 0000000..bd86270 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/blib2to3/pytree.py @@ -0,0 +1,980 @@ +# Copyright 2006 Google, Inc. All Rights Reserved. +# Licensed to PSF under a Contributor Agreement. + +""" +Python parse tree definitions. + +This is a very concrete parse tree; we need to keep every token and +even the comments and whitespace between tokens. + +There's also a pattern matching implementation here. +""" + +# mypy: allow-untyped-defs + +from typing import ( + Any, + Dict, + Iterator, + List, + Optional, + Text, + Tuple, + TypeVar, + Union, + Set, + Iterable, +) +from blib2to3.pgen2.grammar import Grammar + +__author__ = "Guido van Rossum " + +import sys +from io import StringIO + +HUGE: int = 0x7FFFFFFF # maximum repeat count, default max + +_type_reprs: Dict[int, Union[Text, int]] = {} + + +def type_repr(type_num: int) -> Union[Text, int]: + global _type_reprs + if not _type_reprs: + from .pygram import python_symbols + + # printing tokens is possible but not as useful + # from .pgen2 import token // token.__dict__.items(): + for name in dir(python_symbols): + val = getattr(python_symbols, name) + if type(val) == int: + _type_reprs[val] = name + return _type_reprs.setdefault(type_num, type_num) + + +_P = TypeVar("_P", bound="Base") + +NL = Union["Node", "Leaf"] +Context = Tuple[Text, Tuple[int, int]] +RawNode = Tuple[int, Optional[Text], Optional[Context], Optional[List[NL]]] + + +class Base(object): + + """ + Abstract base class for Node and Leaf. + + This provides some default functionality and boilerplate using the + template pattern. + + A node may be a subnode of at most one parent. + """ + + # Default values for instance variables + type: int # int: token number (< 256) or symbol number (>= 256) + parent: Optional["Node"] = None # Parent node pointer, or None + children: List[NL] # List of subnodes + was_changed: bool = False + was_checked: bool = False + + def __new__(cls, *args, **kwds): + """Constructor that prevents Base from being instantiated.""" + assert cls is not Base, "Cannot instantiate Base" + return object.__new__(cls) + + def __eq__(self, other: Any) -> bool: + """ + Compare two nodes for equality. + + This calls the method _eq(). + """ + if self.__class__ is not other.__class__: + return NotImplemented + return self._eq(other) + + @property + def prefix(self) -> Text: + raise NotImplementedError + + def _eq(self: _P, other: _P) -> bool: + """ + Compare two nodes for equality. + + This is called by __eq__ and __ne__. It is only called if the two nodes + have the same type. This must be implemented by the concrete subclass. + Nodes should be considered equal if they have the same structure, + ignoring the prefix string and other context information. + """ + raise NotImplementedError + + def __deepcopy__(self: _P, memo: Any) -> _P: + return self.clone() + + def clone(self: _P) -> _P: + """ + Return a cloned (deep) copy of self. + + This must be implemented by the concrete subclass. + """ + raise NotImplementedError + + def post_order(self) -> Iterator[NL]: + """ + Return a post-order iterator for the tree. + + This must be implemented by the concrete subclass. + """ + raise NotImplementedError + + def pre_order(self) -> Iterator[NL]: + """ + Return a pre-order iterator for the tree. + + This must be implemented by the concrete subclass. + """ + raise NotImplementedError + + def replace(self, new: Union[NL, List[NL]]) -> None: + """Replace this node with a new one in the parent.""" + assert self.parent is not None, str(self) + assert new is not None + if not isinstance(new, list): + new = [new] + l_children = [] + found = False + for ch in self.parent.children: + if ch is self: + assert not found, (self.parent.children, self, new) + if new is not None: + l_children.extend(new) + found = True + else: + l_children.append(ch) + assert found, (self.children, self, new) + self.parent.children = l_children + self.parent.changed() + self.parent.invalidate_sibling_maps() + for x in new: + x.parent = self.parent + self.parent = None + + def get_lineno(self) -> Optional[int]: + """Return the line number which generated the invocant node.""" + node = self + while not isinstance(node, Leaf): + if not node.children: + return None + node = node.children[0] + return node.lineno + + def changed(self) -> None: + if self.was_changed: + return + if self.parent: + self.parent.changed() + self.was_changed = True + + def remove(self) -> Optional[int]: + """ + Remove the node from the tree. Returns the position of the node in its + parent's children before it was removed. + """ + if self.parent: + for i, node in enumerate(self.parent.children): + if node is self: + del self.parent.children[i] + self.parent.changed() + self.parent.invalidate_sibling_maps() + self.parent = None + return i + return None + + @property + def next_sibling(self) -> Optional[NL]: + """ + The node immediately following the invocant in their parent's children + list. If the invocant does not have a next sibling, it is None + """ + if self.parent is None: + return None + + if self.parent.next_sibling_map is None: + self.parent.update_sibling_maps() + assert self.parent.next_sibling_map is not None + return self.parent.next_sibling_map[id(self)] + + @property + def prev_sibling(self) -> Optional[NL]: + """ + The node immediately preceding the invocant in their parent's children + list. If the invocant does not have a previous sibling, it is None. + """ + if self.parent is None: + return None + + if self.parent.prev_sibling_map is None: + self.parent.update_sibling_maps() + assert self.parent.prev_sibling_map is not None + return self.parent.prev_sibling_map[id(self)] + + def leaves(self) -> Iterator["Leaf"]: + for child in self.children: + yield from child.leaves() + + def depth(self) -> int: + if self.parent is None: + return 0 + return 1 + self.parent.depth() + + def get_suffix(self) -> Text: + """ + Return the string immediately following the invocant node. This is + effectively equivalent to node.next_sibling.prefix + """ + next_sib = self.next_sibling + if next_sib is None: + return "" + prefix = next_sib.prefix + return prefix + + +class Node(Base): + + """Concrete implementation for interior nodes.""" + + fixers_applied: Optional[List[Any]] + used_names: Optional[Set[Text]] + + def __init__( + self, + type: int, + children: List[NL], + context: Optional[Any] = None, + prefix: Optional[Text] = None, + fixers_applied: Optional[List[Any]] = None, + ) -> None: + """ + Initializer. + + Takes a type constant (a symbol number >= 256), a sequence of + child nodes, and an optional context keyword argument. + + As a side effect, the parent pointers of the children are updated. + """ + assert type >= 256, type + self.type = type + self.children = list(children) + for ch in self.children: + assert ch.parent is None, repr(ch) + ch.parent = self + self.invalidate_sibling_maps() + if prefix is not None: + self.prefix = prefix + if fixers_applied: + self.fixers_applied = fixers_applied[:] + else: + self.fixers_applied = None + + def __repr__(self) -> Text: + """Return a canonical string representation.""" + assert self.type is not None + return "%s(%s, %r)" % ( + self.__class__.__name__, + type_repr(self.type), + self.children, + ) + + def __str__(self) -> Text: + """ + Return a pretty string representation. + + This reproduces the input source exactly. + """ + return "".join(map(str, self.children)) + + def _eq(self, other) -> bool: + """Compare two nodes for equality.""" + return (self.type, self.children) == (other.type, other.children) + + def clone(self) -> "Node": + assert self.type is not None + """Return a cloned (deep) copy of self.""" + return Node( + self.type, + [ch.clone() for ch in self.children], + fixers_applied=self.fixers_applied, + ) + + def post_order(self) -> Iterator[NL]: + """Return a post-order iterator for the tree.""" + for child in self.children: + yield from child.post_order() + yield self + + def pre_order(self) -> Iterator[NL]: + """Return a pre-order iterator for the tree.""" + yield self + for child in self.children: + yield from child.pre_order() + + @property + def prefix(self) -> Text: + """ + The whitespace and comments preceding this node in the input. + """ + if not self.children: + return "" + return self.children[0].prefix + + @prefix.setter + def prefix(self, prefix) -> None: + if self.children: + self.children[0].prefix = prefix + + def set_child(self, i: int, child: NL) -> None: + """ + Equivalent to 'node.children[i] = child'. This method also sets the + child's parent attribute appropriately. + """ + child.parent = self + self.children[i].parent = None + self.children[i] = child + self.changed() + self.invalidate_sibling_maps() + + def insert_child(self, i: int, child: NL) -> None: + """ + Equivalent to 'node.children.insert(i, child)'. This method also sets + the child's parent attribute appropriately. + """ + child.parent = self + self.children.insert(i, child) + self.changed() + self.invalidate_sibling_maps() + + def append_child(self, child: NL) -> None: + """ + Equivalent to 'node.children.append(child)'. This method also sets the + child's parent attribute appropriately. + """ + child.parent = self + self.children.append(child) + self.changed() + self.invalidate_sibling_maps() + + def invalidate_sibling_maps(self) -> None: + self.prev_sibling_map: Optional[Dict[int, Optional[NL]]] = None + self.next_sibling_map: Optional[Dict[int, Optional[NL]]] = None + + def update_sibling_maps(self) -> None: + _prev: Dict[int, Optional[NL]] = {} + _next: Dict[int, Optional[NL]] = {} + self.prev_sibling_map = _prev + self.next_sibling_map = _next + previous: Optional[NL] = None + for current in self.children: + _prev[id(current)] = previous + _next[id(previous)] = current + previous = current + _next[id(current)] = None + + +class Leaf(Base): + + """Concrete implementation for leaf nodes.""" + + # Default values for instance variables + value: Text + fixers_applied: List[Any] + bracket_depth: int + opening_bracket: "Leaf" + used_names: Optional[Set[Text]] + _prefix = "" # Whitespace and comments preceding this token in the input + lineno: int = 0 # Line where this token starts in the input + column: int = 0 # Column where this token starts in the input + + def __init__( + self, + type: int, + value: Text, + context: Optional[Context] = None, + prefix: Optional[Text] = None, + fixers_applied: List[Any] = [], + ) -> None: + """ + Initializer. + + Takes a type constant (a token number < 256), a string value, and an + optional context keyword argument. + """ + + assert 0 <= type < 256, type + if context is not None: + self._prefix, (self.lineno, self.column) = context + self.type = type + self.value = value + if prefix is not None: + self._prefix = prefix + self.fixers_applied: Optional[List[Any]] = fixers_applied[:] + self.children = [] + + def __repr__(self) -> str: + """Return a canonical string representation.""" + from .pgen2.token import tok_name + + assert self.type is not None + return "%s(%s, %r)" % ( + self.__class__.__name__, + tok_name.get(self.type, self.type), + self.value, + ) + + def __str__(self) -> Text: + """ + Return a pretty string representation. + + This reproduces the input source exactly. + """ + return self._prefix + str(self.value) + + def _eq(self, other) -> bool: + """Compare two nodes for equality.""" + return (self.type, self.value) == (other.type, other.value) + + def clone(self) -> "Leaf": + assert self.type is not None + """Return a cloned (deep) copy of self.""" + return Leaf( + self.type, + self.value, + (self.prefix, (self.lineno, self.column)), + fixers_applied=self.fixers_applied, + ) + + def leaves(self) -> Iterator["Leaf"]: + yield self + + def post_order(self) -> Iterator["Leaf"]: + """Return a post-order iterator for the tree.""" + yield self + + def pre_order(self) -> Iterator["Leaf"]: + """Return a pre-order iterator for the tree.""" + yield self + + @property + def prefix(self) -> Text: + """ + The whitespace and comments preceding this token in the input. + """ + return self._prefix + + @prefix.setter + def prefix(self, prefix) -> None: + self.changed() + self._prefix = prefix + + +def convert(gr: Grammar, raw_node: RawNode) -> NL: + """ + Convert raw node information to a Node or Leaf instance. + + This is passed to the parser driver which calls it whenever a reduction of a + grammar rule produces a new complete node, so that the tree is build + strictly bottom-up. + """ + type, value, context, children = raw_node + if children or type in gr.number2symbol: + # If there's exactly one child, return that child instead of + # creating a new node. + assert children is not None + if len(children) == 1: + return children[0] + return Node(type, children, context=context) + else: + return Leaf(type, value or "", context=context) + + +_Results = Dict[Text, NL] + + +class BasePattern(object): + + """ + A pattern is a tree matching pattern. + + It looks for a specific node type (token or symbol), and + optionally for a specific content. + + This is an abstract base class. There are three concrete + subclasses: + + - LeafPattern matches a single leaf node; + - NodePattern matches a single node (usually non-leaf); + - WildcardPattern matches a sequence of nodes of variable length. + """ + + # Defaults for instance variables + type: Optional[int] + type = None # Node type (token if < 256, symbol if >= 256) + content: Any = None # Optional content matching pattern + name: Optional[Text] = None # Optional name used to store match in results dict + + def __new__(cls, *args, **kwds): + """Constructor that prevents BasePattern from being instantiated.""" + assert cls is not BasePattern, "Cannot instantiate BasePattern" + return object.__new__(cls) + + def __repr__(self) -> Text: + assert self.type is not None + args = [type_repr(self.type), self.content, self.name] + while args and args[-1] is None: + del args[-1] + return "%s(%s)" % (self.__class__.__name__, ", ".join(map(repr, args))) + + def _submatch(self, node, results=None) -> bool: + raise NotImplementedError + + def optimize(self) -> "BasePattern": + """ + A subclass can define this as a hook for optimizations. + + Returns either self or another node with the same effect. + """ + return self + + def match(self, node: NL, results: Optional[_Results] = None) -> bool: + """ + Does this pattern exactly match a node? + + Returns True if it matches, False if not. + + If results is not None, it must be a dict which will be + updated with the nodes matching named subpatterns. + + Default implementation for non-wildcard patterns. + """ + if self.type is not None and node.type != self.type: + return False + if self.content is not None: + r: Optional[_Results] = None + if results is not None: + r = {} + if not self._submatch(node, r): + return False + if r: + assert results is not None + results.update(r) + if results is not None and self.name: + results[self.name] = node + return True + + def match_seq(self, nodes: List[NL], results: Optional[_Results] = None) -> bool: + """ + Does this pattern exactly match a sequence of nodes? + + Default implementation for non-wildcard patterns. + """ + if len(nodes) != 1: + return False + return self.match(nodes[0], results) + + def generate_matches(self, nodes: List[NL]) -> Iterator[Tuple[int, _Results]]: + """ + Generator yielding all matches for this pattern. + + Default implementation for non-wildcard patterns. + """ + r: _Results = {} + if nodes and self.match(nodes[0], r): + yield 1, r + + +class LeafPattern(BasePattern): + def __init__( + self, + type: Optional[int] = None, + content: Optional[Text] = None, + name: Optional[Text] = None, + ) -> None: + """ + Initializer. Takes optional type, content, and name. + + The type, if given must be a token type (< 256). If not given, + this matches any *leaf* node; the content may still be required. + + The content, if given, must be a string. + + If a name is given, the matching node is stored in the results + dict under that key. + """ + if type is not None: + assert 0 <= type < 256, type + if content is not None: + assert isinstance(content, str), repr(content) + self.type = type + self.content = content + self.name = name + + def match(self, node: NL, results=None): + """Override match() to insist on a leaf node.""" + if not isinstance(node, Leaf): + return False + return BasePattern.match(self, node, results) + + def _submatch(self, node, results=None): + """ + Match the pattern's content to the node's children. + + This assumes the node type matches and self.content is not None. + + Returns True if it matches, False if not. + + If results is not None, it must be a dict which will be + updated with the nodes matching named subpatterns. + + When returning False, the results dict may still be updated. + """ + return self.content == node.value + + +class NodePattern(BasePattern): + + wildcards: bool = False + + def __init__( + self, + type: Optional[int] = None, + content: Optional[Iterable[Text]] = None, + name: Optional[Text] = None, + ) -> None: + """ + Initializer. Takes optional type, content, and name. + + The type, if given, must be a symbol type (>= 256). If the + type is None this matches *any* single node (leaf or not), + except if content is not None, in which it only matches + non-leaf nodes that also match the content pattern. + + The content, if not None, must be a sequence of Patterns that + must match the node's children exactly. If the content is + given, the type must not be None. + + If a name is given, the matching node is stored in the results + dict under that key. + """ + if type is not None: + assert type >= 256, type + if content is not None: + assert not isinstance(content, str), repr(content) + newcontent = list(content) + for i, item in enumerate(newcontent): + assert isinstance(item, BasePattern), (i, item) + # I don't even think this code is used anywhere, but it does cause + # unreachable errors from mypy. This function's signature does look + # odd though *shrug*. + if isinstance(item, WildcardPattern): # type: ignore[unreachable] + self.wildcards = True # type: ignore[unreachable] + self.type = type + self.content = newcontent + self.name = name + + def _submatch(self, node, results=None) -> bool: + """ + Match the pattern's content to the node's children. + + This assumes the node type matches and self.content is not None. + + Returns True if it matches, False if not. + + If results is not None, it must be a dict which will be + updated with the nodes matching named subpatterns. + + When returning False, the results dict may still be updated. + """ + if self.wildcards: + for c, r in generate_matches(self.content, node.children): + if c == len(node.children): + if results is not None: + results.update(r) + return True + return False + if len(self.content) != len(node.children): + return False + for subpattern, child in zip(self.content, node.children): + if not subpattern.match(child, results): + return False + return True + + +class WildcardPattern(BasePattern): + + """ + A wildcard pattern can match zero or more nodes. + + This has all the flexibility needed to implement patterns like: + + .* .+ .? .{m,n} + (a b c | d e | f) + (...)* (...)+ (...)? (...){m,n} + + except it always uses non-greedy matching. + """ + + min: int + max: int + + def __init__( + self, + content: Optional[Text] = None, + min: int = 0, + max: int = HUGE, + name: Optional[Text] = None, + ) -> None: + """ + Initializer. + + Args: + content: optional sequence of subsequences of patterns; + if absent, matches one node; + if present, each subsequence is an alternative [*] + min: optional minimum number of times to match, default 0 + max: optional maximum number of times to match, default HUGE + name: optional name assigned to this match + + [*] Thus, if content is [[a, b, c], [d, e], [f, g, h]] this is + equivalent to (a b c | d e | f g h); if content is None, + this is equivalent to '.' in regular expression terms. + The min and max parameters work as follows: + min=0, max=maxint: .* + min=1, max=maxint: .+ + min=0, max=1: .? + min=1, max=1: . + If content is not None, replace the dot with the parenthesized + list of alternatives, e.g. (a b c | d e | f g h)* + """ + assert 0 <= min <= max <= HUGE, (min, max) + if content is not None: + f = lambda s: tuple(s) + wrapped_content = tuple(map(f, content)) # Protect against alterations + # Check sanity of alternatives + assert len(wrapped_content), repr( + wrapped_content + ) # Can't have zero alternatives + for alt in wrapped_content: + assert len(alt), repr(alt) # Can have empty alternatives + self.content = wrapped_content + self.min = min + self.max = max + self.name = name + + def optimize(self) -> Any: + """Optimize certain stacked wildcard patterns.""" + subpattern = None + if ( + self.content is not None + and len(self.content) == 1 + and len(self.content[0]) == 1 + ): + subpattern = self.content[0][0] + if self.min == 1 and self.max == 1: + if self.content is None: + return NodePattern(name=self.name) + if subpattern is not None and self.name == subpattern.name: + return subpattern.optimize() + if ( + self.min <= 1 + and isinstance(subpattern, WildcardPattern) + and subpattern.min <= 1 + and self.name == subpattern.name + ): + return WildcardPattern( + subpattern.content, + self.min * subpattern.min, + self.max * subpattern.max, + subpattern.name, + ) + return self + + def match(self, node, results=None) -> bool: + """Does this pattern exactly match a node?""" + return self.match_seq([node], results) + + def match_seq(self, nodes, results=None) -> bool: + """Does this pattern exactly match a sequence of nodes?""" + for c, r in self.generate_matches(nodes): + if c == len(nodes): + if results is not None: + results.update(r) + if self.name: + results[self.name] = list(nodes) + return True + return False + + def generate_matches(self, nodes) -> Iterator[Tuple[int, _Results]]: + """ + Generator yielding matches for a sequence of nodes. + + Args: + nodes: sequence of nodes + + Yields: + (count, results) tuples where: + count: the match comprises nodes[:count]; + results: dict containing named submatches. + """ + if self.content is None: + # Shortcut for special case (see __init__.__doc__) + for count in range(self.min, 1 + min(len(nodes), self.max)): + r = {} + if self.name: + r[self.name] = nodes[:count] + yield count, r + elif self.name == "bare_name": + yield self._bare_name_matches(nodes) + else: + # The reason for this is that hitting the recursion limit usually + # results in some ugly messages about how RuntimeErrors are being + # ignored. We only have to do this on CPython, though, because other + # implementations don't have this nasty bug in the first place. + if hasattr(sys, "getrefcount"): + save_stderr = sys.stderr + sys.stderr = StringIO() + try: + for count, r in self._recursive_matches(nodes, 0): + if self.name: + r[self.name] = nodes[:count] + yield count, r + except RuntimeError: + # We fall back to the iterative pattern matching scheme if the recursive + # scheme hits the recursion limit. + for count, r in self._iterative_matches(nodes): + if self.name: + r[self.name] = nodes[:count] + yield count, r + finally: + if hasattr(sys, "getrefcount"): + sys.stderr = save_stderr + + def _iterative_matches(self, nodes) -> Iterator[Tuple[int, _Results]]: + """Helper to iteratively yield the matches.""" + nodelen = len(nodes) + if 0 >= self.min: + yield 0, {} + + results = [] + # generate matches that use just one alt from self.content + for alt in self.content: + for c, r in generate_matches(alt, nodes): + yield c, r + results.append((c, r)) + + # for each match, iterate down the nodes + while results: + new_results = [] + for c0, r0 in results: + # stop if the entire set of nodes has been matched + if c0 < nodelen and c0 <= self.max: + for alt in self.content: + for c1, r1 in generate_matches(alt, nodes[c0:]): + if c1 > 0: + r = {} + r.update(r0) + r.update(r1) + yield c0 + c1, r + new_results.append((c0 + c1, r)) + results = new_results + + def _bare_name_matches(self, nodes) -> Tuple[int, _Results]: + """Special optimized matcher for bare_name.""" + count = 0 + r = {} # type: _Results + done = False + max = len(nodes) + while not done and count < max: + done = True + for leaf in self.content: + if leaf[0].match(nodes[count], r): + count += 1 + done = False + break + assert self.name is not None + r[self.name] = nodes[:count] + return count, r + + def _recursive_matches(self, nodes, count) -> Iterator[Tuple[int, _Results]]: + """Helper to recursively yield the matches.""" + assert self.content is not None + if count >= self.min: + yield 0, {} + if count < self.max: + for alt in self.content: + for c0, r0 in generate_matches(alt, nodes): + for c1, r1 in self._recursive_matches(nodes[c0:], count + 1): + r = {} + r.update(r0) + r.update(r1) + yield c0 + c1, r + + +class NegatedPattern(BasePattern): + def __init__(self, content: Optional[Any] = None) -> None: + """ + Initializer. + + The argument is either a pattern or None. If it is None, this + only matches an empty sequence (effectively '$' in regex + lingo). If it is not None, this matches whenever the argument + pattern doesn't have any matches. + """ + if content is not None: + assert isinstance(content, BasePattern), repr(content) + self.content = content + + def match(self, node, results=None) -> bool: + # We never match a node in its entirety + return False + + def match_seq(self, nodes, results=None) -> bool: + # We only match an empty sequence of nodes in its entirety + return len(nodes) == 0 + + def generate_matches(self, nodes) -> Iterator[Tuple[int, _Results]]: + if self.content is None: + # Return a match if there is an empty sequence + if len(nodes) == 0: + yield 0, {} + else: + # Return a match if the argument pattern has no matches + for c, r in self.content.generate_matches(nodes): + return + yield 0, {} + + +def generate_matches( + patterns: List[BasePattern], nodes: List[NL] +) -> Iterator[Tuple[int, _Results]]: + """ + Generator yielding matches for a sequence of patterns and nodes. + + Args: + patterns: a sequence of patterns + nodes: a sequence of nodes + + Yields: + (count, results) tuples where: + count: the entire sequence of patterns matches nodes[:count]; + results: dict containing named submatches. + """ + if not patterns: + yield 0, {} + else: + p, rest = patterns[0], patterns[1:] + for c0, r0 in p.generate_matches(nodes): + if not rest: + yield c0, r0 + else: + for c1, r1 in generate_matches(rest, nodes[c0:]): + r = {} + r.update(r0) + r.update(r1) + yield c0 + c1, r diff --git a/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/LICENSE new file mode 100644 index 0000000..c2fda9a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/LICENSE @@ -0,0 +1,21 @@ +This package contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# +This is a bundle of X.509 certificates of public Certificate Authorities +(CA). These were automatically extracted from Mozilla's root certificates +file (certdata.txt). This file can be found in the mozilla source tree: +http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# +It contains the certificates in PEM format and therefore +can be directly used with curl / libcurl / php_curl, or with +an Apache+mod_ssl webserver for SSL client authentication. +Just configure this file as the SSLCACertificateFile.# + +***** BEGIN LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +***** END LICENSE BLOCK ***** +@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/METADATA b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/METADATA new file mode 100644 index 0000000..6f8de5d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/METADATA @@ -0,0 +1,81 @@ +Metadata-Version: 2.1 +Name: certifi +Version: 2022.6.15 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://github.com/certifi/python-certifi +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Source, https://github.com/certifi/python-certifi +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Requires-Python: >=3.6 +License-File: LICENSE + +Certifi: Python SSL Certificates +================================ + +Certifi provides Mozilla's carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' + +Or from the command line:: + + $ python -m certifi + /usr/local/lib/python3.7/site-packages/certifi/cacert.pem + +Enjoy! + +1024-bit Root Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Browsers and certificate authorities have concluded that 1024-bit keys are +unacceptably weak for certificates, particularly root certificates. For this +reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its +bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) +certificate from the same CA. Because Mozilla removed these certificates from +its bundle, ``certifi`` removed them as well. + +In previous versions, ``certifi`` provided the ``certifi.old_where()`` function +to intentionally re-add the 1024-bit roots back into your bundle. This was not +recommended in production and therefore was removed at the end of 2018. + +.. _`Requests`: https://requests.readthedocs.io/en/master/ + +Addition/Removal of Certificates +-------------------------------- + +Certifi does not support any addition/removal or other modification of the +CA trust store content. This project is intended to provide a reliable and +highly portable root of trust to python deployments. Look to upstream projects +for methods to use alternate trust. + + diff --git a/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/RECORD b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/RECORD new file mode 100644 index 0000000..df832c3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/RECORD @@ -0,0 +1,11 @@ +certifi/__init__.py,sha256=SuZ3iYmzdRyUv-PiaZkquUgXtWZ16ICUKgymlEBspx0,94 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/cacert.pem,sha256=pZ_eiDoO-ddKudrQCWieABc9KFlbV0FsmLLugygMbkw,285222 +certifi/core.py,sha256=G5LqCBr4o8bozzzlYBE8nsd_ziB6XcxJiuMV4llFeYY,2515 +certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +certifi-2022.6.15.dist-info/LICENSE,sha256=vp2C82ES-Hp_HXTs1Ih-FGe7roh4qEAEoAEXseR1o-I,1049 +certifi-2022.6.15.dist-info/METADATA,sha256=1sLjV7SjXkcGhJr631JUqCLCDnqgTyFoFe-tRLxakTE,2804 +certifi-2022.6.15.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92 +certifi-2022.6.15.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi-2022.6.15.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +certifi-2022.6.15.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/WHEEL new file mode 100644 index 0000000..5bad85f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/top_level.txt new file mode 100644 index 0000000..963eac5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi-2022.6.15.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/myenv/lib/python3.9/site-packages/certifi/__init__.py b/myenv/lib/python3.9/site-packages/certifi/__init__.py new file mode 100644 index 0000000..bdeb06b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2022.06.15" diff --git a/myenv/lib/python3.9/site-packages/certifi/__main__.py b/myenv/lib/python3.9/site-packages/certifi/__main__.py new file mode 100644 index 0000000..8945b5d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/myenv/lib/python3.9/site-packages/certifi/cacert.pem b/myenv/lib/python3.9/site-packages/certifi/cacert.pem new file mode 100644 index 0000000..ee9be4c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi/cacert.pem @@ -0,0 +1,4685 @@ + +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2" +# Serial: 1289 +# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b +# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 +# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3" +# Serial: 1478 +# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf +# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 +# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 +# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 +# Label: "Security Communication Root CA" +# Serial: 0 +# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a +# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 +# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Label: "XRamp Global CA Root" +# Serial: 107108908803651509692980124233745014957 +# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 +# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 +# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root CA" +# Serial: 17154717934120587862167794914071425081 +# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 +# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 +# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert High Assurance EV Root CA" +# Serial: 3553400076410547919724730734378100087 +# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a +# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 +# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Label: "SwissSign Gold CA - G2" +# Serial: 13492815561806991280 +# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 +# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 +# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Label: "SwissSign Silver CA - G2" +# Serial: 5700383053117599563 +# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 +# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb +# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=SecureTrust CA O=SecureTrust Corporation +# Subject: CN=SecureTrust CA O=SecureTrust Corporation +# Label: "SecureTrust CA" +# Serial: 17199774589125277788362757014266862032 +# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 +# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 +# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +# Issuer: CN=Secure Global CA O=SecureTrust Corporation +# Subject: CN=Secure Global CA O=SecureTrust Corporation +# Label: "Secure Global CA" +# Serial: 9751836167731051554232119481456978597 +# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de +# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b +# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO Certification Authority O=COMODO CA Limited +# Label: "COMODO Certification Authority" +# Serial: 104350513648249232941998508985834464573 +# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 +# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b +# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Label: "Network Solutions Certificate Authority" +# Serial: 116697915152937497490437556386812487904 +# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e +# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce +# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Issuer: CN=Certigna O=Dhimyotis +# Subject: CN=Certigna O=Dhimyotis +# Label: "Certigna" +# Serial: 18364802974209362175 +# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff +# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 +# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Label: "ePKI Root Certification Authority" +# Serial: 28956088682735189655030529057352760477 +# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 +# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 +# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +# Issuer: O=certSIGN OU=certSIGN ROOT CA +# Subject: O=certSIGN OU=certSIGN ROOT CA +# Label: "certSIGN ROOT CA" +# Serial: 35210227249154 +# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 +# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b +# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" +# Serial: 80544274841616 +# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 +# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 +# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Label: "Hongkong Post Root CA 1" +# Serial: 1000 +# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca +# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 +# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Label: "SecureSign RootCA11" +# Serial: 1 +# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 +# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 +# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Label: "Microsec e-Szigno Root CA 2009" +# Serial: 14014712776195784473 +# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 +# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e +# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 6047274297262753887 +# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 +# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa +# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +# Issuer: CN=Izenpe.com O=IZENPE S.A. +# Subject: CN=Izenpe.com O=IZENPE S.A. +# Label: "Izenpe.com" +# Serial: 917563065490389241595536686991402621 +# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 +# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 +# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Services Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 +# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f +# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Label: "TWCA Root Certification Authority" +# Serial: 1 +# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 +# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 +# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Label: "Security Communication RootCA2" +# Serial: 0 +# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 +# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 +# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Label: "EC-ACC" +# Serial: -23701579247955709139626555126524820479 +# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09 +# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8 +# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99 +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE----- + +# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Label: "Actalis Authentication Root CA" +# Serial: 6271844772424770508 +# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 +# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac +# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 2 Root CA" +# Serial: 2 +# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 +# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 +# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 3 Root CA" +# Serial: 2 +# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec +# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 +# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 3" +# Serial: 1 +# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef +# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 +# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 2009" +# Serial: 623603 +# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f +# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 +# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 EV 2009" +# Serial: 623604 +# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 +# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 +# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R2 O=Disig a.s. +# Subject: CN=CA Disig Root R2 O=Disig a.s. +# Label: "CA Disig Root R2" +# Serial: 10572350602393338211 +# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 +# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 +# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Label: "ACCVRAIZ1" +# Serial: 6828503384748696800 +# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 +# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 +# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA Global Root CA" +# Serial: 3262 +# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 +# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 +# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Label: "TeliaSonera Root CA v1" +# Serial: 199041966741090107964904287217786801558 +# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c +# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 +# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Label: "E-Tugra Certification Authority" +# Serial: 7667447206703254355 +# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 +# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 +# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 2" +# Serial: 1 +# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a +# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 +# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot 2011 O=Atos +# Subject: CN=Atos TrustedRoot 2011 O=Atos +# Label: "Atos TrustedRoot 2011" +# Serial: 6643877497813316402 +# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 +# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 +# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 1 G3" +# Serial: 687049649626669250736271037606554624078720034195 +# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab +# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 +# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2 G3" +# Serial: 390156079458959257446133169266079962026824725800 +# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 +# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 +# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3 G3" +# Serial: 268090761170461462463995952157327242137089239581 +# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 +# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d +# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Label: "Staat der Nederlanden EV Root CA" +# Serial: 10000013 +# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba +# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb +# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Label: "IdenTrust Commercial Root CA 1" +# Serial: 13298821034946342390520003877796839426 +# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 +# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 +# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Label: "IdenTrust Public Sector Root CA 1" +# Serial: 13298821034946342390521976156843933698 +# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba +# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd +# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority +# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority +# Label: "CFCA EV ROOT" +# Serial: 407555286 +# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 +# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 +# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GB CA" +# Serial: 157768595616588414422159278966750757568 +# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d +# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed +# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Label: "SZAFIR ROOT CA2" +# Serial: 357043034767186914217277344587386743377558296292 +# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 +# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de +# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA 2" +# Serial: 44979900017204383099463764357512596969 +# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 +# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 +# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce +# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 +# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef +# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 +# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Label: "AC RAIZ FNMT-RCM" +# Serial: 485876308206448804701554682760554759 +# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d +# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 +# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 1 O=Amazon +# Subject: CN=Amazon Root CA 1 O=Amazon +# Label: "Amazon Root CA 1" +# Serial: 143266978916655856878034712317230054538369994 +# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 +# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 +# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 2 O=Amazon +# Subject: CN=Amazon Root CA 2 O=Amazon +# Label: "Amazon Root CA 2" +# Serial: 143266982885963551818349160658925006970653239 +# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 +# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a +# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 3 O=Amazon +# Subject: CN=Amazon Root CA 3 O=Amazon +# Label: "Amazon Root CA 3" +# Serial: 143266986699090766294700635381230934788665930 +# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 +# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e +# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 4 O=Amazon +# Subject: CN=Amazon Root CA 4 O=Amazon +# Label: "Amazon Root CA 4" +# Serial: 143266989758080763974105200630763877849284878 +# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd +# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be +# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" +# Serial: 1 +# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 +# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca +# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Label: "GDCA TrustAUTH R5 ROOT" +# Serial: 9009899650740120186 +# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 +# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 +# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-1" +# Serial: 15752444095811006489 +# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 +# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a +# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y +IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB +pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h +IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG +A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU +cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid +RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V +seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme +9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV +EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW +hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ +DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I +/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ +yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts +L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN +zl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-2" +# Serial: 2711694510199101698 +# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 +# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 +# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig +Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk +MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg +Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD +VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy +dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ +QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq +1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp +2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK +DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape +az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF +3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 +oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM +g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 +mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd +BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U +nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX +dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ +MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL +/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX +CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa +ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW +2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 +N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 +Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB +As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp +5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu +1uwJ +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor ECA-1" +# Serial: 9548242946988625984 +# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c +# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd +# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y +IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig +RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb +3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA +BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 +3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou +owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ +wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF +ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf +BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv +civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 +AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 +soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI +WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi +tJ/X5g== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Label: "SSL.com Root Certification Authority RSA" +# Serial: 8875640296558310041 +# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 +# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb +# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com Root Certification Authority ECC" +# Serial: 8495723813297216424 +# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e +# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a +# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority RSA R2" +# Serial: 6248227494352943350 +# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 +# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a +# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority ECC" +# Serial: 3182246526754555285 +# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 +# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d +# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Label: "GlobalSign Root CA - R6" +# Serial: 1417766617973444989252670301619537 +# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae +# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 +# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GC CA" +# Serial: 44084345621038548146064804565436152554 +# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 +# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 +# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +# Issuer: CN=UCA Global G2 Root O=UniTrust +# Subject: CN=UCA Global G2 Root O=UniTrust +# Label: "UCA Global G2 Root" +# Serial: 124779693093741543919145257850076631279 +# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 +# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a +# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Extended Validation Root O=UniTrust +# Subject: CN=UCA Extended Validation Root O=UniTrust +# Label: "UCA Extended Validation Root" +# Serial: 106100277556486529736699587978573607008 +# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 +# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a +# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- + +# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Label: "Certigna Root CA" +# Serial: 269714418870597844693661054334862075617 +# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 +# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 +# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign Root CA - G1" +# Serial: 235931866688319308814040 +# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac +# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c +# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign ECC Root CA - G3" +# Serial: 287880440101571086945156 +# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 +# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 +# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Label: "emSign Root CA - C1" +# Serial: 825510296613316004955058 +# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 +# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 +# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Label: "emSign ECC Root CA - C3" +# Serial: 582948710642506000014504 +# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 +# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 +# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Label: "Hongkong Post Root CA 3" +# Serial: 46170865288971385588281144162979347873371282084 +# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 +# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 +# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 +-----BEGIN CERTIFICATE----- +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 +mpv0 +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G4" +# Serial: 289383649854506086828220374796556676440 +# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 +# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 +# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft ECC Root Certificate Authority 2017" +# Serial: 136839042543790627607696632466672567020 +# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 +# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 +# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft RSA Root Certificate Authority 2017" +# Serial: 40975477897264996090493496164228220339 +# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 +# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 +# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Label: "e-Szigno Root CA 2017" +# Serial: 411379200276854331539784714 +# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 +# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 +# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- + +# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Label: "certSIGN Root CA G2" +# Serial: 313609486401300475190 +# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 +# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 +# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global Certification Authority" +# Serial: 1846098327275375458322922162 +# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e +# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 +# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P256 Certification Authority" +# Serial: 4151900041497450638097112925 +# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 +# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf +# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P384 Certification Authority" +# Serial: 2704997926503831671788816187 +# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 +# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 +# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE----- + +# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Label: "NAVER Global Root Certification Authority" +# Serial: 9013692873798656336226253319739695165984492813 +# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b +# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 +# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE----- + +# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" +# Serial: 131542671362353147877283741781055151509 +# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb +# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a +# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Label: "GlobalSign Root R46" +# Serial: 1552617688466950547958867513931858518042577 +# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef +# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 +# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Label: "GlobalSign Root E46" +# Serial: 1552617690338932563915843282459653771421763 +# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f +# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 +# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Label: "GLOBALTRUST 2020" +# Serial: 109160994242082918454945253 +# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8 +# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2 +# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG +A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw +FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx +MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u +aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b +RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z +YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 +QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw +yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ +BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ +SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH +r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 +4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me +dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw +q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 +nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu +H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC +XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd +6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf ++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi +kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 +wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB +TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C +MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn +4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I +aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy +qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Label: "ANF Secure Server Root CA" +# Serial: 996390341000653745 +# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 +# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 +# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum EC-384 CA" +# Serial: 160250656287871593594747141429395092468 +# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 +# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed +# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Root CA" +# Serial: 40870380103424195783807378461123655149 +# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 +# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 +# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Label: "TunTrust Root CA" +# Serial: 108534058042236574382096126452369648152337120275 +# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4 +# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb +# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41 +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg +Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv +b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG +EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u +IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ +n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd +2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF +VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ +GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF +li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU +r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 +eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb +MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg +jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB +7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW +5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE +ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z +xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu +QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 +FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH +22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP +xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn +dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 +Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b +nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ +CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH +u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj +d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS RSA Root CA 2021" +# Serial: 76817823531813593706434026085292783742 +# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91 +# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d +# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l +mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE +4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv +a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M +pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw +Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b +LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY +AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB +AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq +E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr +W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ +CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU +X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 +f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja +H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP +JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P +zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt +jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 +/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT +BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 +aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW +xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU +63ZTGI0RmLo= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS ECC Root CA 2021" +# Serial: 137515985548005187474074462014555733966 +# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 +# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 +# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v +dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG +A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 +KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y +STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD +AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw +SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN +nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 1977337328857672817 +# MD5 Fingerprint: 4e:6e:9b:54:4c:ca:b7:fa:48:e4:90:b1:15:4b:1c:a3 +# SHA1 Fingerprint: 0b:be:c2:27:22:49:cb:39:aa:db:35:5c:53:e3:8c:ae:78:ff:b6:fe +# SHA256 Fingerprint: 57:de:05:83:ef:d2:b2:6e:03:61:da:99:da:9d:f4:64:8d:ef:7e:e8:44:1c:3b:72:8a:fa:9b:cd:e0:f9:b2:6a +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- + +# Issuer: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. +# Subject: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. +# Label: "vTrus ECC Root CA" +# Serial: 630369271402956006249506845124680065938238527194 +# MD5 Fingerprint: de:4b:c1:f5:52:8c:9b:43:e1:3e:8f:55:54:17:8d:85 +# SHA1 Fingerprint: f6:9c:db:b0:fc:f6:02:13:b6:52:32:a6:a3:91:3f:16:70:da:c3:e1 +# SHA256 Fingerprint: 30:fb:ba:2c:32:23:8e:2a:98:54:7a:f9:79:31:e5:50:42:8b:9b:3f:1c:8e:eb:66:33:dc:fa:86:c5:b2:7d:d3 +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw +RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY +BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz +MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u +LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 +v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd +e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw +V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA +AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG +GJTO +-----END CERTIFICATE----- + +# Issuer: CN=vTrus Root CA O=iTrusChina Co.,Ltd. +# Subject: CN=vTrus Root CA O=iTrusChina Co.,Ltd. +# Label: "vTrus Root CA" +# Serial: 387574501246983434957692974888460947164905180485 +# MD5 Fingerprint: b8:c9:37:df:fa:6b:31:84:64:c5:ea:11:6a:1b:75:fc +# SHA1 Fingerprint: 84:1a:69:fb:f5:cd:1a:25:34:13:3d:e3:f8:fc:b8:99:d0:c9:14:b7 +# SHA256 Fingerprint: 8a:71:de:65:59:33:6f:42:6c:26:e5:38:80:d0:0d:88:a1:8d:a4:c6:a9:1f:0d:cb:61:94:e2:06:c5:c9:63:87 +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL +BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x +FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx +MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s +THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc +IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU +AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ +GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 +8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH +flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt +J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim +0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN +pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ +UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW +OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB +AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet +8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j +bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM +Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv +TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS +S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr +I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 +b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB +UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P +Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven +sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X2 O=Internet Security Research Group +# Subject: CN=ISRG Root X2 O=Internet Security Research Group +# Label: "ISRG Root X2" +# Serial: 87493402998870891108772069816698636114 +# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 +# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af +# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- + +# Issuer: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. +# Subject: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. +# Label: "HiPKI Root CA - G1" +# Serial: 60966262342023497858655262305426234976 +# MD5 Fingerprint: 69:45:df:16:65:4b:e8:68:9a:8f:76:5f:ff:80:9e:d3 +# SHA1 Fingerprint: 6a:92:e4:a8:ee:1b:ec:96:45:37:e3:29:57:49:cd:96:e3:e5:d2:60 +# SHA256 Fingerprint: f0:15:ce:3c:c2:39:bf:ef:06:4b:e9:f1:d2:c4:17:e1:a0:26:4a:0a:94:be:1f:0c:8d:12:18:64:eb:69:49:cc +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa +Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 +YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw +qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv +Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 +lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz +Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ +KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK +FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj +HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr +y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ +/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM +a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 +fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG +SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc +SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza +ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc +XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg +iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho +L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF +Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr +kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ +vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU +YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 159662223612894884239637590694 +# MD5 Fingerprint: 26:29:f8:6d:e1:88:bf:a2:65:7f:aa:c4:cd:0f:7f:fc +# SHA1 Fingerprint: 6b:a0:b0:98:e1:71:ef:5a:ad:fe:48:15:80:77:10:f4:bd:6f:0b:28 +# SHA256 Fingerprint: b0:85:d7:0b:96:4f:19:1a:73:e4:af:0d:54:ae:7a:0e:07:aa:fd:af:9b:71:dd:08:62:13:8a:b7:32:5a:24:a2 +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 159662320309726417404178440727 +# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 +# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a +# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R2 O=Google Trust Services LLC +# Subject: CN=GTS Root R2 O=Google Trust Services LLC +# Label: "GTS Root R2" +# Serial: 159662449406622349769042896298 +# MD5 Fingerprint: 1e:39:c0:53:e6:1e:29:82:0b:ca:52:55:36:5d:57:dc +# SHA1 Fingerprint: 9a:44:49:76:32:db:de:fa:d0:bc:fb:5a:7b:17:bd:9e:56:09:24:94 +# SHA256 Fingerprint: 8d:25:cd:97:22:9d:bf:70:35:6b:da:4e:b3:cc:73:40:31:e2:4c:f0:0f:af:cf:d3:2d:c7:6e:b5:84:1c:7e:a8 +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt +nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY +6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu +MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k +RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg +f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV ++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo +dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa +G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq +gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H +vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC +B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u +NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg +yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev +HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 +xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR +TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg +JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV +7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl +6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R3 O=Google Trust Services LLC +# Subject: CN=GTS Root R3 O=Google Trust Services LLC +# Label: "GTS Root R3" +# Serial: 159662495401136852707857743206 +# MD5 Fingerprint: 3e:e7:9d:58:02:94:46:51:94:e5:e0:22:4a:8b:e7:73 +# SHA1 Fingerprint: ed:e5:71:80:2b:c8:92:b9:5b:83:3c:d2:32:68:3f:09:cd:a0:1e:46 +# SHA256 Fingerprint: 34:d8:a7:3e:e2:08:d9:bc:db:0d:95:65:20:93:4b:4e:40:e6:94:82:59:6e:8b:6f:73:c8:42:6b:01:0a:6f:48 +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G +jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 +4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 +VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm +ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 159662532700760215368942768210 +# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 +# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 +# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + +# Issuer: CN=Telia Root CA v2 O=Telia Finland Oyj +# Subject: CN=Telia Root CA v2 O=Telia Finland Oyj +# Label: "Telia Root CA v2" +# Serial: 7288924052977061235122729490515358 +# MD5 Fingerprint: 0e:8f:ac:aa:82:df:85:b1:f4:dc:10:1c:fc:99:d9:48 +# SHA1 Fingerprint: b9:99:cd:d1:73:50:8a:c4:47:05:08:9c:8c:88:fb:be:a0:2b:40:cd +# SHA256 Fingerprint: 24:2b:69:74:2f:cb:1e:5b:2a:bf:98:89:8b:94:57:21:87:54:4e:5b:4d:99:11:78:65:73:62:1f:6a:74:b8:2c +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx +CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE +AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 +NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ +MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq +AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 +vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 +lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD +n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT +7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o +6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC +TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 +WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R +DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI +pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj +YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy +rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi +0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM +A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS +SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K +TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF +6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er +3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt +Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT +VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW +ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA +rBPuUBQemMc= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH +# Subject: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH +# Label: "D-TRUST BR Root CA 1 2020" +# Serial: 165870826978392376648679885835942448534 +# MD5 Fingerprint: b5:aa:4b:d5:ed:f7:e3:55:2e:8f:72:0a:f3:75:b8:ed +# SHA1 Fingerprint: 1f:5b:98:f0:e3:b5:f7:74:3c:ed:e6:b0:36:7d:32:cd:f4:09:41:67 +# SHA256 Fingerprint: e5:9a:aa:81:60:09:c2:2b:ff:5b:25:ba:d3:7d:f3:06:f0:49:79:7c:1f:81:d8:5a:b0:89:e6:57:bd:8f:00:44 +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 +NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS +zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 +QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ +VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW +wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV +dWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH +# Subject: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH +# Label: "D-TRUST EV Root CA 1 2020" +# Serial: 126288379621884218666039612629459926992 +# MD5 Fingerprint: 8c:2d:9d:70:9f:48:99:11:06:11:fb:e9:cb:30:c0:6e +# SHA1 Fingerprint: 61:db:8c:21:59:69:03:90:d8:7c:9c:12:86:54:cf:9d:3d:f4:dd:07 +# SHA256 Fingerprint: 08:17:0d:1a:a3:64:53:90:1a:2f:95:92:45:e3:47:db:0c:8d:37:ab:aa:bc:56:b8:1a:a1:00:dc:95:89:70:db +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 +NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC +/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD +wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 +OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA +y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb +gfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. +# Subject: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. +# Label: "DigiCert TLS ECC P384 Root G5" +# Serial: 13129116028163249804115411775095713523 +# MD5 Fingerprint: d3:71:04:6a:43:1c:db:a6:59:e1:a8:a3:aa:c5:71:ed +# SHA1 Fingerprint: 17:f3:de:5e:9f:0f:19:e9:8e:f6:1f:32:26:6e:20:c4:07:ae:30:ee +# SHA256 Fingerprint: 01:8e:13:f0:77:25:32:cf:80:9b:d1:b1:72:81:86:72:83:fc:48:c6:e1:3b:e9:c6:98:12:85:4a:49:0c:1b:05 +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. +# Subject: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. +# Label: "DigiCert TLS RSA4096 Root G5" +# Serial: 11930366277458970227240571539258396554 +# MD5 Fingerprint: ac:fe:f7:34:96:a9:f2:b3:b4:12:4b:e4:27:41:6f:e1 +# SHA1 Fingerprint: a7:88:49:dc:5d:7c:75:8c:8c:de:39:98:56:b3:aa:d0:b2:a5:71:35 +# SHA256 Fingerprint: 37:1a:00:dc:05:33:b3:72:1a:7e:eb:40:e8:41:9e:70:79:9d:2b:0a:0f:2c:1d:80:69:31:65:f7:ce:c4:ad:75 +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- + +# Issuer: CN=Certainly Root R1 O=Certainly +# Subject: CN=Certainly Root R1 O=Certainly +# Label: "Certainly Root R1" +# Serial: 188833316161142517227353805653483829216 +# MD5 Fingerprint: 07:70:d4:3e:82:87:a0:fa:33:36:13:f4:fa:33:e7:12 +# SHA1 Fingerprint: a0:50:ee:0f:28:71:f4:27:b2:12:6d:6f:50:96:25:ba:cc:86:42:af +# SHA256 Fingerprint: 77:b8:2c:d8:64:4c:43:05:f7:ac:c5:cb:15:6b:45:67:50:04:03:3d:51:c6:0c:62:02:a8:e0:c3:34:67:d3:a0 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw +PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy +dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 +YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 +1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT +vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed +aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 +1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 +r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 +cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ +wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ +6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA +2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH +Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR +eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u +d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr +PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi +1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd +rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di +taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 +lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj +yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn +Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy +yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n +wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 +OV+KmalBWQewLK8= +-----END CERTIFICATE----- + +# Issuer: CN=Certainly Root E1 O=Certainly +# Subject: CN=Certainly Root E1 O=Certainly +# Label: "Certainly Root E1" +# Serial: 8168531406727139161245376702891150584 +# MD5 Fingerprint: 0a:9e:ca:cd:3e:52:50:c6:36:f3:4b:a3:ed:a7:53:e9 +# SHA1 Fingerprint: f9:e1:6d:dc:01:89:cf:d5:82:45:63:3e:c5:37:7d:c2:eb:93:6f:2b +# SHA256 Fingerprint: b4:58:5f:22:e4:ac:75:6a:4e:86:12:a1:36:1c:5d:9d:03:1a:93:fd:84:fe:bb:77:8f:a3:06:8b:0f:c4:2d:c2 +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu +bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ +BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s +eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK ++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 +QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 +hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm +ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG +BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Global Root CA RSA v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center +# Subject: CN=E-Tugra Global Root CA RSA v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center +# Label: "E-Tugra Global Root CA RSA v3" +# Serial: 75951268308633135324246244059508261641472512052 +# MD5 Fingerprint: 22:be:10:f6:c2:f8:03:88:73:5f:33:29:47:28:47:a4 +# SHA1 Fingerprint: e9:a8:5d:22:14:52:1c:5b:aa:0a:b4:be:24:6a:23:8a:c9:ba:e2:a9 +# SHA256 Fingerprint: ef:66:b0:b1:0a:3c:db:9f:2e:36:48:c7:6b:d2:af:18:ea:d2:bf:e6:f1:17:65:5e:28:c4:06:0d:a1:a3:f4:c2 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Global Root CA ECC v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center +# Subject: CN=E-Tugra Global Root CA ECC v3 O=E-Tugra EBG A.S. OU=E-Tugra Trust Center +# Label: "E-Tugra Global Root CA ECC v3" +# Serial: 218504919822255052842371958738296604628416471745 +# MD5 Fingerprint: 46:bc:81:bb:f1:b5:1e:f7:4b:96:bc:14:e2:e7:27:64 +# SHA1 Fingerprint: 8a:2f:af:57:53:b1:b0:e6:a1:04:ec:5b:6a:69:71:6d:f6:1c:e2:84 +# SHA256 Fingerprint: 87:3f:46:85:fa:7f:56:36:25:25:2e:6d:36:bc:d7:f1:6f:c2:49:51:f2:64:e4:7e:1b:95:4f:49:08:cd:ca:13 +-----BEGIN CERTIFICATE----- +MIICpTCCAiqgAwIBAgIUJkYZdzHhT28oNt45UYbm1JeIIsEwCgYIKoZIzj0EAwMw +gYAxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVn +cmEgRUJHIEEuUy4xHTAbBgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYD +VQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENBIEVDQyB2MzAeFw0yMDAzMTgwOTQ2 +NThaFw00NTAzMTIwOTQ2NThaMIGAMQswCQYDVQQGEwJUUjEPMA0GA1UEBxMGQW5r +YXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1Z3Jh +IFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBF +Q0MgdjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASOmCm/xxAeJ9urA8woLNheSBkQ +KczLWYHMjLiSF4mDKpL2w6QdTGLVn9agRtwcvHbB40fQWxPa56WzZkjnIZpKT4YK +fWzqTTKACrJ6CZtpS5iB4i7sAnCWH/31Rs7K3IKjYzBhMA8GA1UdEwEB/wQFMAMB +Af8wHwYDVR0jBBgwFoAU/4Ixcj75xGZsrTie0bBRiKWQzPUwHQYDVR0OBBYEFP+C +MXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNp +ADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/6 +7W4WAie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFx +vmjkI6TZraE3 +-----END CERTIFICATE----- diff --git a/myenv/lib/python3.9/site-packages/certifi/core.py b/myenv/lib/python3.9/site-packages/certifi/core.py new file mode 100644 index 0000000..497d938 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/certifi/core.py @@ -0,0 +1,68 @@ +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem or its contents. +""" +import os +import types +from typing import Union + +try: + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + + return _CACERT_PATH + + +except ImportError: + Package = Union[types.ModuleType, str] + Resource = Union[str, "os.PathLike"] + + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text( + package: Package, + resource: Resource, + encoding: str = 'utf-8', + errors: str = 'strict' + ) -> str: + with open(where(), encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where() -> str: + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + +def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/myenv/lib/python3.9/site-packages/certifi/py.typed b/myenv/lib/python3.9/site-packages/certifi/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/LICENSE new file mode 100644 index 0000000..29225ee --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/LICENSE @@ -0,0 +1,26 @@ + +Except when otherwise stated (look for LICENSE files in directories or +information at the beginning of each file) all software and +documentation is licensed as follows: + + The MIT License + + 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. + diff --git a/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/METADATA b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/METADATA new file mode 100644 index 0000000..538e679 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/METADATA @@ -0,0 +1,34 @@ +Metadata-Version: 2.1 +Name: cffi +Version: 1.15.1 +Summary: Foreign Function Interface for Python calling C code. +Home-page: http://cffi.readthedocs.org +Author: Armin Rigo, Maciej Fijalkowski +Author-email: python-cffi@googlegroups.com +License: MIT +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: License :: OSI Approved :: MIT License +License-File: LICENSE +Requires-Dist: pycparser + + +CFFI +==== + +Foreign Function Interface for Python calling C code. +Please see the `Documentation `_. + +Contact +------- + +`Mailing list `_ diff --git a/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/RECORD b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/RECORD new file mode 100644 index 0000000..e19bbf9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/RECORD @@ -0,0 +1,28 @@ +_cffi_backend.cpython-39-darwin.so,sha256=g3b3EkJ_bteITLFqq1CQ04r_H2TV6SWbw3OcmnViTU0,202424 +cffi/_cffi_include.h,sha256=tKnA1rdSoPHp23FnDL1mDGwFo-Uj6fXfA6vA6kcoEUc,14800 +cffi/backend_ctypes.py,sha256=h5ZIzLc6BFVXnGyc9xPqZWUS7qGy7yFSDqXe68Sa8z4,42454 +cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877 +cffi/setuptools_ext.py,sha256=RUR17N5f8gpiQBBlXL34P9FtOu1mhHIaAf3WJlg5S4I,8931 +cffi/_cffi_errors.h,sha256=zQXt7uR_m8gUW-fI2hJg0KoSkJFwXv8RGUkEDZ177dQ,3908 +cffi/__init__.py,sha256=6xB_tafGvhhM5Xvj0Ova3oPC2SEhVlLTEObVLnazeiM,513 +cffi/cffi_opcode.py,sha256=v9RdD_ovA8rCtqsC95Ivki5V667rAOhGgs3fb2q9xpM,5724 +cffi/vengine_gen.py,sha256=5dX7s1DU6pTBOMI6oTVn_8Bnmru_lj932B6b4v29Hlg,26684 +cffi/pkgconfig.py,sha256=LP1w7vmWvmKwyqLaU1Z243FOWGNQMrgMUZrvgFuOlco,4374 +cffi/model.py,sha256=_GH_UF1Rn9vC4AvmgJm6qj7RUXXG3eqKPc8bPxxyBKE,21768 +cffi/ffiplatform.py,sha256=HMXqR8ks2wtdsNxGaWpQ_PyqIvtiuos_vf1qKCy-cwg,4046 +cffi/api.py,sha256=yxJalIePbr1mz_WxAHokSwyP5CVYde44m-nolHnbJNo,42064 +cffi/vengine_cpy.py,sha256=YglN8YS-UaHEv2k2cxgotNWE87dHX20-68EyKoiKUYA,43320 +cffi/_embedding.h,sha256=9tnjF44QRobR8z0FGqAmAZY-wMSBOae1SUPqHccowqc,17680 +cffi/commontypes.py,sha256=QS4uxCDI7JhtTyjh1hlnCA-gynmaszWxJaRRLGkJa1A,2689 +cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747 +cffi/recompiler.py,sha256=YgVYTh2CrXIobo-vMk7_K9mwAXdd_LqB4-IbYABQ488,64598 +cffi/cparser.py,sha256=rO_1pELRw1gI1DE1m4gi2ik5JMfpxouAACLXpRPlVEA,44231 +cffi/verifier.py,sha256=ESwuXWXtXrKEagCKveLRDjFzLNCyaKdqAgAlKREcyhY,11253 +cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976 +cffi-1.15.1.dist-info/LICENSE,sha256=BLgPWwd7vtaICM_rreteNSPyqMmpZJXFh72W3x6sKjM,1294 +cffi-1.15.1.dist-info/WHEEL,sha256=pfjXB0CCNW4PSSqQc2t4Up6p3o0jxBnHy_2o38FQkyE,109 +cffi-1.15.1.dist-info/entry_points.txt,sha256=y6jTxnyeuLnL-XJcDv8uML3n6wyYiGRg8MTp_QGJ9Ho,75 +cffi-1.15.1.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 +cffi-1.15.1.dist-info/METADATA,sha256=KP4G3WmavRgDGwD2b8Y_eDsM1YeV6ckcG6Alz3-D8VY,1144 +cffi-1.15.1.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +cffi-1.15.1.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/WHEEL new file mode 100644 index 0000000..ef5e11a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: false +Tag: cp39-cp39-macosx_10_9_x86_64 + diff --git a/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/entry_points.txt b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/entry_points.txt new file mode 100644 index 0000000..4b0274f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[distutils.setup_keywords] +cffi_modules = cffi.setuptools_ext:cffi_modules diff --git a/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/top_level.txt new file mode 100644 index 0000000..f645779 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi-1.15.1.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_cffi_backend +cffi diff --git a/myenv/lib/python3.9/site-packages/cffi/__init__.py b/myenv/lib/python3.9/site-packages/cffi/__init__.py new file mode 100644 index 0000000..90e2e65 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/__init__.py @@ -0,0 +1,14 @@ +__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError', + 'FFIError'] + +from .api import FFI +from .error import CDefError, FFIError, VerificationError, VerificationMissing +from .error import PkgConfigError + +__version__ = "1.15.1" +__version_info__ = (1, 15, 1) + +# The verifier module file names are based on the CRC32 of a string that +# contains the following version number. It may be older than __version__ +# if nothing is clearly incompatible. +__version_verifier_modules__ = "0.8.6" diff --git a/myenv/lib/python3.9/site-packages/cffi/_cffi_errors.h b/myenv/lib/python3.9/site-packages/cffi/_cffi_errors.h new file mode 100644 index 0000000..158e059 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/_cffi_errors.h @@ -0,0 +1,149 @@ +#ifndef CFFI_MESSAGEBOX +# ifdef _MSC_VER +# define CFFI_MESSAGEBOX 1 +# else +# define CFFI_MESSAGEBOX 0 +# endif +#endif + + +#if CFFI_MESSAGEBOX +/* Windows only: logic to take the Python-CFFI embedding logic + initialization errors and display them in a background thread + with MessageBox. The idea is that if the whole program closes + as a result of this problem, then likely it is already a console + program and you can read the stderr output in the console too. + If it is not a console program, then it will likely show its own + dialog to complain, or generally not abruptly close, and for this + case the background thread should stay alive. +*/ +static void *volatile _cffi_bootstrap_text; + +static PyObject *_cffi_start_error_capture(void) +{ + PyObject *result = NULL; + PyObject *x, *m, *bi; + + if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, + (void *)1, NULL) != NULL) + return (PyObject *)1; + + m = PyImport_AddModule("_cffi_error_capture"); + if (m == NULL) + goto error; + + result = PyModule_GetDict(m); + if (result == NULL) + goto error; + +#if PY_MAJOR_VERSION >= 3 + bi = PyImport_ImportModule("builtins"); +#else + bi = PyImport_ImportModule("__builtin__"); +#endif + if (bi == NULL) + goto error; + PyDict_SetItemString(result, "__builtins__", bi); + Py_DECREF(bi); + + x = PyRun_String( + "import sys\n" + "class FileLike:\n" + " def write(self, x):\n" + " try:\n" + " of.write(x)\n" + " except: pass\n" + " self.buf += x\n" + " def flush(self):\n" + " pass\n" + "fl = FileLike()\n" + "fl.buf = ''\n" + "of = sys.stderr\n" + "sys.stderr = fl\n" + "def done():\n" + " sys.stderr = of\n" + " return fl.buf\n", /* make sure the returned value stays alive */ + Py_file_input, + result, result); + Py_XDECREF(x); + + error: + if (PyErr_Occurred()) + { + PyErr_WriteUnraisable(Py_None); + PyErr_Clear(); + } + return result; +} + +#pragma comment(lib, "user32.lib") + +static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) +{ + Sleep(666); /* may be interrupted if the whole process is closing */ +#if PY_MAJOR_VERSION >= 3 + MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, + L"Python-CFFI error", + MB_OK | MB_ICONERROR); +#else + MessageBoxA(NULL, (char *)_cffi_bootstrap_text, + "Python-CFFI error", + MB_OK | MB_ICONERROR); +#endif + _cffi_bootstrap_text = NULL; + return 0; +} + +static void _cffi_stop_error_capture(PyObject *ecap) +{ + PyObject *s; + void *text; + + if (ecap == (PyObject *)1) + return; + + if (ecap == NULL) + goto error; + + s = PyRun_String("done()", Py_eval_input, ecap, ecap); + if (s == NULL) + goto error; + + /* Show a dialog box, but in a background thread, and + never show multiple dialog boxes at once. */ +#if PY_MAJOR_VERSION >= 3 + text = PyUnicode_AsWideCharString(s, NULL); +#else + text = PyString_AsString(s); +#endif + + _cffi_bootstrap_text = text; + + if (text != NULL) + { + HANDLE h; + h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, + NULL, 0, NULL); + if (h != NULL) + CloseHandle(h); + } + /* decref the string, but it should stay alive as 'fl.buf' + in the small module above. It will really be freed only if + we later get another similar error. So it's a leak of at + most one copy of the small module. That's fine for this + situation which is usually a "fatal error" anyway. */ + Py_DECREF(s); + PyErr_Clear(); + return; + + error: + _cffi_bootstrap_text = NULL; + PyErr_Clear(); +} + +#else + +static PyObject *_cffi_start_error_capture(void) { return NULL; } +static void _cffi_stop_error_capture(PyObject *ecap) { } + +#endif diff --git a/myenv/lib/python3.9/site-packages/cffi/_cffi_include.h b/myenv/lib/python3.9/site-packages/cffi/_cffi_include.h new file mode 100644 index 0000000..e4c0a67 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/_cffi_include.h @@ -0,0 +1,385 @@ +#define _CFFI_ + +/* We try to define Py_LIMITED_API before including Python.h. + + Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and + Py_REF_DEBUG are not defined. This is a best-effort approximation: + we can learn about Py_DEBUG from pyconfig.h, but it is unclear if + the same works for the other two macros. Py_DEBUG implies them, + but not the other way around. + + The implementation is messy (issue #350): on Windows, with _MSC_VER, + we have to define Py_LIMITED_API even before including pyconfig.h. + In that case, we guess what pyconfig.h will do to the macros above, + and check our guess after the #include. + + Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv + version >= 16.0.0. With older versions of either, you don't get a + copy of PYTHON3.DLL in the virtualenv. We can't check the version of + CPython *before* we even include pyconfig.h. ffi.set_source() puts + a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is + running on Windows < 3.5, as an attempt at fixing it, but that's + arguably wrong because it may not be the target version of Python. + Still better than nothing I guess. As another workaround, you can + remove the definition of Py_LIMITED_API here. + + See also 'py_limited_api' in cffi/setuptools_ext.py. +*/ +#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) +# ifdef _MSC_VER +# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# include + /* sanity-check: Py_LIMITED_API will cause crashes if any of these + are also defined. Normally, the Python file PC/pyconfig.h does not + cause any of these to be defined, with the exception that _DEBUG + causes Py_DEBUG. Double-check that. */ +# ifdef Py_LIMITED_API +# if defined(Py_DEBUG) +# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" +# endif +# if defined(Py_TRACE_REFS) +# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" +# endif +# if defined(Py_REF_DEBUG) +# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" +# endif +# endif +# else +# include +# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# endif +#endif + +#include +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "parse_c_type.h" + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#ifdef __GNUC__ +# define _CFFI_UNUSED_FN __attribute__((unused)) +#else +# define _CFFI_UNUSED_FN /* nothing */ +#endif + +#ifdef __cplusplus +# ifndef _Bool + typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ +# endif +#endif + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + not used any more +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ + PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) +#define _CFFI_CPIDX 25 +#define _cffi_call_python \ + ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) +#define _cffi_to_c_wchar3216_t \ + ((int(*)(PyObject *))_cffi_exports[26]) +#define _cffi_from_c_wchar3216_t \ + ((PyObject *(*)(int))_cffi_exports[27]) +#define _CFFI_NUM_EXPORTS 28 + +struct _cffi_ctypedescr; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; + +#define _cffi_type(index) ( \ + assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ + (struct _cffi_ctypedescr *)_cffi_types[index]) + +static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, + const struct _cffi_type_context_s *ctx) +{ + PyObject *module, *o_arg, *new_module; + void *raw[] = { + (void *)module_name, + (void *)version, + (void *)_cffi_exports, + (void *)ctx, + }; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + o_arg = PyLong_FromVoidPtr((void *)raw); + if (o_arg == NULL) + goto failure; + + new_module = PyObject_CallMethod( + module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); + + Py_DECREF(o_arg); + Py_DECREF(module); + return new_module; + + failure: + Py_XDECREF(module); + return NULL; +} + + +#ifdef HAVE_WCHAR_H +typedef wchar_t _cffi_wchar_t; +#else +typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ +#endif + +_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 2) + return (uint16_t)_cffi_to_c_wchar_t(o); + else + return (uint16_t)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) +{ + if (sizeof(_cffi_wchar_t) == 2) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 4) + return (int)_cffi_to_c_wchar_t(o); + else + return (int)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) +{ + if (sizeof(_cffi_wchar_t) == 4) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +_CFFI_UNUSED_FN static int +_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +_CFFI_UNUSED_FN static void +_cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +/********** end CPython-specific section **********/ +#else +_CFFI_UNUSED_FN +static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); +# define _cffi_call_python _cffi_call_python_org +#endif + + +#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) + +#define _cffi_prim_int(size, sign) \ + ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ + (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ + (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ + (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ + _CFFI__UNKNOWN_PRIM) + +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + +#define _cffi_check_int(got, got_nonpos, expected) \ + ((got_nonpos) == (expected <= 0) && \ + (got) == (unsigned long long)expected) + +#ifdef MS_WIN32 +# define _cffi_stdcall __stdcall +#else +# define _cffi_stdcall /* nothing */ +#endif + +#ifdef __cplusplus +} +#endif diff --git a/myenv/lib/python3.9/site-packages/cffi/_embedding.h b/myenv/lib/python3.9/site-packages/cffi/_embedding.h new file mode 100644 index 0000000..8e8df88 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/_embedding.h @@ -0,0 +1,528 @@ + +/***** Support code for embedding *****/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined(_WIN32) +# define CFFI_DLLEXPORT __declspec(dllexport) +#elif defined(__GNUC__) +# define CFFI_DLLEXPORT __attribute__((visibility("default"))) +#else +# define CFFI_DLLEXPORT /* nothing */ +#endif + + +/* There are two global variables of type _cffi_call_python_fnptr: + + * _cffi_call_python, which we declare just below, is the one called + by ``extern "Python"`` implementations. + + * _cffi_call_python_org, which on CPython is actually part of the + _cffi_exports[] array, is the function pointer copied from + _cffi_backend. If _cffi_start_python() fails, then this is set + to NULL; otherwise, it should never be NULL. + + After initialization is complete, both are equal. However, the + first one remains equal to &_cffi_start_and_call_python until the + very end of initialization, when we are (or should be) sure that + concurrent threads also see a completely initialized world, and + only then is it changed. +*/ +#undef _cffi_call_python +typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *); +static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *); +static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python; + + +#ifndef _MSC_VER + /* --- Assuming a GCC not infinitely old --- */ +# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n) +# define cffi_write_barrier() __sync_synchronize() +# if !defined(__amd64__) && !defined(__x86_64__) && \ + !defined(__i386__) && !defined(__i386) +# define cffi_read_barrier() __sync_synchronize() +# else +# define cffi_read_barrier() (void)0 +# endif +#else + /* --- Windows threads version --- */ +# include +# define cffi_compare_and_swap(l,o,n) \ + (InterlockedCompareExchangePointer(l,n,o) == (o)) +# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) +# define cffi_read_barrier() (void)0 +static volatile LONG _cffi_dummy; +#endif + +#ifdef WITH_THREAD +# ifndef _MSC_VER +# include + static pthread_mutex_t _cffi_embed_startup_lock; +# else + static CRITICAL_SECTION _cffi_embed_startup_lock; +# endif + static char _cffi_embed_startup_lock_ready = 0; +#endif + +static void _cffi_acquire_reentrant_mutex(void) +{ + static void *volatile lock = NULL; + + while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: pthread_mutex_init() should be very fast, and + this is only run at start-up anyway. */ + } + +#ifdef WITH_THREAD + if (!_cffi_embed_startup_lock_ready) { +# ifndef _MSC_VER + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_cffi_embed_startup_lock, &attr); +# else + InitializeCriticalSection(&_cffi_embed_startup_lock); +# endif + _cffi_embed_startup_lock_ready = 1; + } +#endif + + while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) + ; + +#ifndef _MSC_VER + pthread_mutex_lock(&_cffi_embed_startup_lock); +#else + EnterCriticalSection(&_cffi_embed_startup_lock); +#endif +} + +static void _cffi_release_reentrant_mutex(void) +{ +#ifndef _MSC_VER + pthread_mutex_unlock(&_cffi_embed_startup_lock); +#else + LeaveCriticalSection(&_cffi_embed_startup_lock); +#endif +} + + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + +#include "_cffi_errors.h" + + +#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */ + +static void _cffi_py_initialize(void) +{ + /* XXX use initsigs=0, which "skips initialization registration of + signal handlers, which might be useful when Python is + embedded" according to the Python docs. But review and think + if it should be a user-controllable setting. + + XXX we should also give a way to write errors to a buffer + instead of to stderr. + + XXX if importing 'site' fails, CPython (any version) calls + exit(). Should we try to work around this behavior here? + */ + Py_InitializeEx(0); +} + +static int _cffi_initialize_python(void) +{ + /* This initializes Python, imports _cffi_backend, and then the + present .dll/.so is set up as a CPython C extension module. + */ + int result; + PyGILState_STATE state; + PyObject *pycode=NULL, *global_dict=NULL, *x; + PyObject *builtins; + + state = PyGILState_Ensure(); + + /* Call the initxxx() function from the present module. It will + create and initialize us as a CPython extension module, instead + of letting the startup Python code do it---it might reimport + the same .dll/.so and get maybe confused on some platforms. + It might also have troubles locating the .dll/.so again for all + I know. + */ + (void)_CFFI_PYTHON_STARTUP_FUNC(); + if (PyErr_Occurred()) + goto error; + + /* Now run the Python code provided to ffi.embedding_init_code(). + */ + pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, + "", + Py_file_input); + if (pycode == NULL) + goto error; + global_dict = PyDict_New(); + if (global_dict == NULL) + goto error; + builtins = PyEval_GetBuiltins(); + if (builtins == NULL) + goto error; + if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) + goto error; + x = PyEval_EvalCode( +#if PY_MAJOR_VERSION < 3 + (PyCodeObject *) +#endif + pycode, global_dict, global_dict); + if (x == NULL) + goto error; + Py_DECREF(x); + + /* Done! Now if we've been called from + _cffi_start_and_call_python() in an ``extern "Python"``, we can + only hope that the Python code did correctly set up the + corresponding @ffi.def_extern() function. Otherwise, the + general logic of ``extern "Python"`` functions (inside the + _cffi_backend module) will find that the reference is still + missing and print an error. + */ + result = 0; + done: + Py_XDECREF(pycode); + Py_XDECREF(global_dict); + PyGILState_Release(state); + return result; + + error:; + { + /* Print as much information as potentially useful. + Debugging load-time failures with embedding is not fun + */ + PyObject *ecap; + PyObject *exception, *v, *tb, *f, *modules, *mod; + PyErr_Fetch(&exception, &v, &tb); + ecap = _cffi_start_error_capture(); + f = PySys_GetObject((char *)"stderr"); + if (f != NULL && f != Py_None) { + PyFile_WriteString( + "Failed to initialize the Python-CFFI embedding logic:\n\n", f); + } + + if (exception != NULL) { + PyErr_NormalizeException(&exception, &v, &tb); + PyErr_Display(exception, v, tb); + } + Py_XDECREF(exception); + Py_XDECREF(v); + Py_XDECREF(tb); + + if (f != NULL && f != Py_None) { + PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME + "\ncompiled with cffi version: 1.15.1" + "\n_cffi_backend module: ", f); + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, "_cffi_backend"); + if (mod == NULL) { + PyFile_WriteString("not loaded", f); + } + else { + v = PyObject_GetAttrString(mod, "__file__"); + PyFile_WriteObject(v, f, 0); + Py_XDECREF(v); + } + PyFile_WriteString("\nsys.path: ", f); + PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); + PyFile_WriteString("\n\n", f); + } + _cffi_stop_error_capture(ecap); + } + result = -1; + goto done; +} + +#if PY_VERSION_HEX < 0x03080000 +PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ +#endif + +static int _cffi_carefully_make_gil(void) +{ + /* This does the basic initialization of Python. It can be called + completely concurrently from unrelated threads. It assumes + that we don't hold the GIL before (if it exists), and we don't + hold it afterwards. + + (What it really does used to be completely different in Python 2 + and Python 3, with the Python 2 solution avoiding the spin-lock + around the Py_InitializeEx() call. However, after recent changes + to CPython 2.7 (issue #358) it no longer works. So we use the + Python 3 solution everywhere.) + + This initializes Python by calling Py_InitializeEx(). + Important: this must not be called concurrently at all. + So we use a global variable as a simple spin lock. This global + variable must be from 'libpythonX.Y.so', not from this + cffi-based extension module, because it must be shared from + different cffi-based extension modules. + + In Python < 3.8, we choose + _PyParser_TokenNames[0] as a completely arbitrary pointer value + that is never written to. The default is to point to the + string "ENDMARKER". We change it temporarily to point to the + next character in that string. (Yes, I know it's REALLY + obscure.) + + In Python >= 3.8, this string array is no longer writable, so + instead we pick PyCapsuleType.tp_version_tag. We can't change + Python < 3.8 because someone might use a mixture of cffi + embedded modules, some of which were compiled before this file + changed. + */ + +#ifdef WITH_THREAD +# if PY_VERSION_HEX < 0x03080000 + char *volatile *lock = (char *volatile *)_PyParser_TokenNames; + char *old_value, *locked_value; + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = old_value + 1; + if (old_value[0] == 'E') { + assert(old_value[1] == 'N'); + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value[0] == 'N'); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# else + int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; + int old_value, locked_value; + assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = -42; + if (old_value == 0) { + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value == locked_value); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# endif +#endif + + /* call Py_InitializeEx() */ + if (!Py_IsInitialized()) { + _cffi_py_initialize(); +#if PY_VERSION_HEX < 0x03070000 + PyEval_InitThreads(); +#endif + PyEval_SaveThread(); /* release the GIL */ + /* the returned tstate must be the one that has been stored into the + autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ + } + else { +#if PY_VERSION_HEX < 0x03070000 + /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ + PyGILState_STATE state = PyGILState_Ensure(); + PyEval_InitThreads(); + PyGILState_Release(state); +#endif + } + +#ifdef WITH_THREAD + /* release the lock */ + while (!cffi_compare_and_swap(lock, locked_value, old_value)) + ; +#endif + + return 0; +} + +/********** end CPython-specific section **********/ + + +#else + + +/********** PyPy-specific section **********/ + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ + +static struct _cffi_pypy_init_s { + const char *name; + void *func; /* function pointer */ + const char *code; +} _cffi_pypy_init = { + _CFFI_MODULE_NAME, + _CFFI_PYTHON_STARTUP_FUNC, + _CFFI_PYTHON_STARTUP_CODE, +}; + +extern int pypy_carefully_make_gil(const char *); +extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); + +static int _cffi_carefully_make_gil(void) +{ + return pypy_carefully_make_gil(_CFFI_MODULE_NAME); +} + +static int _cffi_initialize_python(void) +{ + return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); +} + +/********** end PyPy-specific section **********/ + + +#endif + + +#ifdef __GNUC__ +__attribute__((noinline)) +#endif +static _cffi_call_python_fnptr _cffi_start_python(void) +{ + /* Delicate logic to initialize Python. This function can be + called multiple times concurrently, e.g. when the process calls + its first ``extern "Python"`` functions in multiple threads at + once. It can also be called recursively, in which case we must + ignore it. We also have to consider what occurs if several + different cffi-based extensions reach this code in parallel + threads---it is a different copy of the code, then, and we + can't have any shared global variable unless it comes from + 'libpythonX.Y.so'. + + Idea: + + * _cffi_carefully_make_gil(): "carefully" call + PyEval_InitThreads() (possibly with Py_InitializeEx() first). + + * then we use a (local) custom lock to make sure that a call to this + cffi-based extension will wait if another call to the *same* + extension is running the initialization in another thread. + It is reentrant, so that a recursive call will not block, but + only one from a different thread. + + * then we grab the GIL and (Python 2) we call Py_InitializeEx(). + At this point, concurrent calls to Py_InitializeEx() are not + possible: we have the GIL. + + * do the rest of the specific initialization, which may + temporarily release the GIL but not the custom lock. + Only release the custom lock when we are done. + */ + static char called = 0; + + if (_cffi_carefully_make_gil() != 0) + return NULL; + + _cffi_acquire_reentrant_mutex(); + + /* Here the GIL exists, but we don't have it. We're only protected + from concurrency by the reentrant mutex. */ + + /* This file only initializes the embedded module once, the first + time this is called, even if there are subinterpreters. */ + if (!called) { + called = 1; /* invoke _cffi_initialize_python() only once, + but don't set '_cffi_call_python' right now, + otherwise concurrent threads won't call + this function at all (we need them to wait) */ + if (_cffi_initialize_python() == 0) { + /* now initialization is finished. Switch to the fast-path. */ + + /* We would like nobody to see the new value of + '_cffi_call_python' without also seeing the rest of the + data initialized. However, this is not possible. But + the new value of '_cffi_call_python' is the function + 'cffi_call_python()' from _cffi_backend. So: */ + cffi_write_barrier(); + /* ^^^ we put a write barrier here, and a corresponding + read barrier at the start of cffi_call_python(). This + ensures that after that read barrier, we see everything + done here before the write barrier. + */ + + assert(_cffi_call_python_org != NULL); + _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; + } + else { + /* initialization failed. Reset this to NULL, even if it was + already set to some other value. Future calls to + _cffi_start_python() are still forced to occur, and will + always return NULL from now on. */ + _cffi_call_python_org = NULL; + } + } + + _cffi_release_reentrant_mutex(); + + return (_cffi_call_python_fnptr)_cffi_call_python_org; +} + +static +void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args) +{ + _cffi_call_python_fnptr fnptr; + int current_err = errno; +#ifdef _MSC_VER + int current_lasterr = GetLastError(); +#endif + fnptr = _cffi_start_python(); + if (fnptr == NULL) { + fprintf(stderr, "function %s() called, but initialization code " + "failed. Returning 0.\n", externpy->name); + memset(args, 0, externpy->size_of_result); + } +#ifdef _MSC_VER + SetLastError(current_lasterr); +#endif + errno = current_err; + + if (fnptr != NULL) + fnptr(externpy, args); +} + + +/* The cffi_start_python() function makes sure Python is initialized + and our cffi module is set up. It can be called manually from the + user C code. The same effect is obtained automatically from any + dll-exported ``extern "Python"`` function. This function returns + -1 if initialization failed, 0 if all is OK. */ +_CFFI_UNUSED_FN +static int cffi_start_python(void) +{ + if (_cffi_call_python == &_cffi_start_and_call_python) { + if (_cffi_start_python() == NULL) + return -1; + } + cffi_read_barrier(); + return 0; +} + +#undef cffi_compare_and_swap +#undef cffi_write_barrier +#undef cffi_read_barrier + +#ifdef __cplusplus +} +#endif diff --git a/myenv/lib/python3.9/site-packages/cffi/api.py b/myenv/lib/python3.9/site-packages/cffi/api.py new file mode 100644 index 0000000..999a8ae --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/api.py @@ -0,0 +1,965 @@ +import sys, types +from .lock import allocate_lock +from .error import CDefError +from . import model + +try: + callable +except NameError: + # Python 3.1 + from collections import Callable + callable = lambda x: isinstance(x, Callable) + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +_unspecified = object() + + + +class FFI(object): + r''' + The main top-level class that you instantiate once, or once per module. + + Example usage: + + ffi = FFI() + ffi.cdef(""" + int printf(const char *, ...); + """) + + C = ffi.dlopen(None) # standard library + -or- + C = ffi.verify() # use a C compiler: verify the decl above is right + + C.printf("hello, %s!\n", ffi.new("char[]", "world")) + ''' + + def __init__(self, backend=None): + """Create an FFI instance. The 'backend' argument is used to + select a non-default backend, mostly for tests. + """ + if backend is None: + # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with + # _cffi_backend.so compiled. + import _cffi_backend as backend + from . import __version__ + if backend.__version__ != __version__: + # bad version! Try to be as explicit as possible. + if hasattr(backend, '__file__'): + # CPython + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( + __version__, __file__, + backend.__version__, backend.__file__)) + else: + # PyPy + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( + __version__, __file__, backend.__version__)) + # (If you insist you can also try to pass the option + # 'backend=backend_ctypes.CTypesBackend()', but don't + # rely on it! It's probably not going to work well.) + + from . import cparser + self._backend = backend + self._lock = allocate_lock() + self._parser = cparser.Parser() + self._cached_btypes = {} + self._parsed_types = types.ModuleType('parsed_types').__dict__ + self._new_types = types.ModuleType('new_types').__dict__ + self._function_caches = [] + self._libraries = [] + self._cdefsources = [] + self._included_ffis = [] + self._windows_unicode = None + self._init_once_cache = {} + self._cdef_version = None + self._embedding = None + self._typecache = model.get_typecache(backend) + if hasattr(backend, 'set_ffi'): + backend.set_ffi(self) + for name in list(backend.__dict__): + if name.startswith('RTLD_'): + setattr(self, name, getattr(backend, name)) + # + with self._lock: + self.BVoidP = self._get_cached_btype(model.voidp_type) + self.BCharA = self._get_cached_btype(model.char_array_type) + if isinstance(backend, types.ModuleType): + # _cffi_backend: attach these constants to the class + if not hasattr(FFI, 'NULL'): + FFI.NULL = self.cast(self.BVoidP, 0) + FFI.CData, FFI.CType = backend._get_types() + else: + # ctypes backend: attach these constants to the instance + self.NULL = self.cast(self.BVoidP, 0) + self.CData, self.CType = backend._get_types() + self.buffer = backend.buffer + + def cdef(self, csource, override=False, packed=False, pack=None): + """Parse the given C source. This registers all declared functions, + types, and global variables. The functions and global variables can + then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. + The types can be used in 'ffi.new()' and other functions. + If 'packed' is specified as True, all structs declared inside this + cdef are packed, i.e. laid out without any field alignment at all. + Alternatively, 'pack' can be a small integer, and requests for + alignment greater than that are ignored (pack=1 is equivalent to + packed=True). + """ + self._cdef(csource, override=override, packed=packed, pack=pack) + + def embedding_api(self, csource, packed=False, pack=None): + self._cdef(csource, packed=packed, pack=pack, dllexport=True) + if self._embedding is None: + self._embedding = '' + + def _cdef(self, csource, override=False, **options): + if not isinstance(csource, str): # unicode, on Python 2 + if not isinstance(csource, basestring): + raise TypeError("cdef() argument must be a string") + csource = csource.encode('ascii') + with self._lock: + self._cdef_version = object() + self._parser.parse(csource, override=override, **options) + self._cdefsources.append(csource) + if override: + for cache in self._function_caches: + cache.clear() + finishlist = self._parser._recomplete + if finishlist: + self._parser._recomplete = [] + for tp in finishlist: + tp.finish_backend_type(self, finishlist) + + def dlopen(self, name, flags=0): + """Load and return a dynamic library identified by 'name'. + The standard C library can be loaded by passing None. + Note that functions and types declared by 'ffi.cdef()' are not + linked to a particular library, just like C headers; in the + library we only look for the actual (untyped) symbols. + """ + if not (isinstance(name, basestring) or + name is None or + isinstance(name, self.CData)): + raise TypeError("dlopen(name): name must be a file name, None, " + "or an already-opened 'void *' handle") + with self._lock: + lib, function_cache = _make_ffi_library(self, name, flags) + self._function_caches.append(function_cache) + self._libraries.append(lib) + return lib + + def dlclose(self, lib): + """Close a library obtained with ffi.dlopen(). After this call, + access to functions or variables from the library will fail + (possibly with a segmentation fault). + """ + type(lib).__cffi_close__(lib) + + def _typeof_locked(self, cdecl): + # call me with the lock! + key = cdecl + if key in self._parsed_types: + return self._parsed_types[key] + # + if not isinstance(cdecl, str): # unicode, on Python 2 + cdecl = cdecl.encode('ascii') + # + type = self._parser.parse_type(cdecl) + really_a_function_type = type.is_raw_function + if really_a_function_type: + type = type.as_function_pointer() + btype = self._get_cached_btype(type) + result = btype, really_a_function_type + self._parsed_types[key] = result + return result + + def _typeof(self, cdecl, consider_function_as_funcptr=False): + # string -> ctype object + try: + result = self._parsed_types[cdecl] + except KeyError: + with self._lock: + result = self._typeof_locked(cdecl) + # + btype, really_a_function_type = result + if really_a_function_type and not consider_function_as_funcptr: + raise CDefError("the type %r is a function type, not a " + "pointer-to-function type" % (cdecl,)) + return btype + + def typeof(self, cdecl): + """Parse the C type given as a string and return the + corresponding object. + It can also be used on 'cdata' instance to get its C type. + """ + if isinstance(cdecl, basestring): + return self._typeof(cdecl) + if isinstance(cdecl, self.CData): + return self._backend.typeof(cdecl) + if isinstance(cdecl, types.BuiltinFunctionType): + res = _builtin_function_type(cdecl) + if res is not None: + return res + if (isinstance(cdecl, types.FunctionType) + and hasattr(cdecl, '_cffi_base_type')): + with self._lock: + return self._get_cached_btype(cdecl._cffi_base_type) + raise TypeError(type(cdecl)) + + def sizeof(self, cdecl): + """Return the size in bytes of the argument. It can be a + string naming a C type, or a 'cdata' instance. + """ + if isinstance(cdecl, basestring): + BType = self._typeof(cdecl) + return self._backend.sizeof(BType) + else: + return self._backend.sizeof(cdecl) + + def alignof(self, cdecl): + """Return the natural alignment size in bytes of the C type + given as a string. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.alignof(cdecl) + + def offsetof(self, cdecl, *fields_or_indexes): + """Return the offset of the named field inside the given + structure or array, which must be given as a C type name. + You can give several field names in case of nested structures. + You can also give numeric values which correspond to array + items, in case of an array type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._typeoffsetof(cdecl, *fields_or_indexes)[1] + + def new(self, cdecl, init=None): + """Allocate an instance according to the specified C type and + return a pointer to it. The specified C type must be either a + pointer or an array: ``new('X *')`` allocates an X and returns + a pointer to it, whereas ``new('X[n]')`` allocates an array of + n X'es and returns an array referencing it (which works + mostly like a pointer, like in C). You can also use + ``new('X[]', n)`` to allocate an array of a non-constant + length n. + + The memory is initialized following the rules of declaring a + global variable in C: by default it is zero-initialized, but + an explicit initializer can be given which can be used to + fill all or part of the memory. + + When the returned object goes out of scope, the memory + is freed. In other words the returned object has + ownership of the value of type 'cdecl' that it points to. This + means that the raw data can be used as long as this object is + kept alive, but must not be used for a longer time. Be careful + about that when copying the pointer to the memory somewhere + else, e.g. into another structure. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.newp(cdecl, init) + + def new_allocator(self, alloc=None, free=None, + should_clear_after_alloc=True): + """Return a new allocator, i.e. a function that behaves like ffi.new() + but uses the provided low-level 'alloc' and 'free' functions. + + 'alloc' is called with the size as argument. If it returns NULL, a + MemoryError is raised. 'free' is called with the result of 'alloc' + as argument. Both can be either Python function or directly C + functions. If 'free' is None, then no free function is called. + If both 'alloc' and 'free' are None, the default is used. + + If 'should_clear_after_alloc' is set to False, then the memory + returned by 'alloc' is assumed to be already cleared (or you are + fine with garbage); otherwise CFFI will clear it. + """ + compiled_ffi = self._backend.FFI() + allocator = compiled_ffi.new_allocator(alloc, free, + should_clear_after_alloc) + def allocate(cdecl, init=None): + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return allocator(cdecl, init) + return allocate + + def cast(self, cdecl, source): + """Similar to a C cast: returns an instance of the named C + type initialized with the given 'source'. The source is + casted between integers or pointers of any type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.cast(cdecl, source) + + def string(self, cdata, maxlen=-1): + """Return a Python string (or unicode string) from the 'cdata'. + If 'cdata' is a pointer or array of characters or bytes, returns + the null-terminated string. The returned string extends until + the first null character, or at most 'maxlen' characters. If + 'cdata' is an array then 'maxlen' defaults to its length. + + If 'cdata' is a pointer or array of wchar_t, returns a unicode + string following the same rules. + + If 'cdata' is a single character or byte or a wchar_t, returns + it as a string or unicode string. + + If 'cdata' is an enum, returns the value of the enumerator as a + string, or 'NUMBER' if the value is out of range. + """ + return self._backend.string(cdata, maxlen) + + def unpack(self, cdata, length): + """Unpack an array of C data of the given length, + returning a Python string/unicode/list. + + If 'cdata' is a pointer to 'char', returns a byte string. + It does not stop at the first null. This is equivalent to: + ffi.buffer(cdata, length)[:] + + If 'cdata' is a pointer to 'wchar_t', returns a unicode string. + 'length' is measured in wchar_t's; it is not the size in bytes. + + If 'cdata' is a pointer to anything else, returns a list of + 'length' items. This is a faster equivalent to: + [cdata[i] for i in range(length)] + """ + return self._backend.unpack(cdata, length) + + #def buffer(self, cdata, size=-1): + # """Return a read-write buffer object that references the raw C data + # pointed to by the given 'cdata'. The 'cdata' must be a pointer or + # an array. Can be passed to functions expecting a buffer, or directly + # manipulated with: + # + # buf[:] get a copy of it in a regular string, or + # buf[idx] as a single character + # buf[:] = ... + # buf[idx] = ... change the content + # """ + # note that 'buffer' is a type, set on this instance by __init__ + + def from_buffer(self, cdecl, python_buffer=_unspecified, + require_writable=False): + """Return a cdata of the given type pointing to the data of the + given Python object, which must support the buffer interface. + Note that this is not meant to be used on the built-in types + str or unicode (you can build 'char[]' arrays explicitly) + but only on objects containing large quantities of raw data + in some other format, like 'array.array' or numpy arrays. + + The first argument is optional and default to 'char[]'. + """ + if python_buffer is _unspecified: + cdecl, python_buffer = self.BCharA, cdecl + elif isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.from_buffer(cdecl, python_buffer, + require_writable) + + def memmove(self, dest, src, n): + """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. + + Like the C function memmove(), the memory areas may overlap; + apart from that it behaves like the C function memcpy(). + + 'src' can be any cdata ptr or array, or any Python buffer object. + 'dest' can be any cdata ptr or array, or a writable Python buffer + object. The size to copy, 'n', is always measured in bytes. + + Unlike other methods, this one supports all Python buffer including + byte strings and bytearrays---but it still does not support + non-contiguous buffers. + """ + return self._backend.memmove(dest, src, n) + + def callback(self, cdecl, python_callable=None, error=None, onerror=None): + """Return a callback object or a decorator making such a + callback object. 'cdecl' must name a C function pointer type. + The callback invokes the specified 'python_callable' (which may + be provided either directly or via a decorator). Important: the + callback object must be manually kept alive for as long as the + callback may be invoked from the C level. + """ + def callback_decorator_wrap(python_callable): + if not callable(python_callable): + raise TypeError("the 'python_callable' argument " + "is not callable") + return self._backend.callback(cdecl, python_callable, + error, onerror) + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) + if python_callable is None: + return callback_decorator_wrap # decorator mode + else: + return callback_decorator_wrap(python_callable) # direct mode + + def getctype(self, cdecl, replace_with=''): + """Return a string giving the C type 'cdecl', which may be itself + a string or a object. If 'replace_with' is given, it gives + extra text to append (or insert for more complicated C types), like + a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + replace_with = replace_with.strip() + if (replace_with.startswith('*') + and '&[' in self._backend.getcname(cdecl, '&')): + replace_with = '(%s)' % replace_with + elif replace_with and not replace_with[0] in '[(': + replace_with = ' ' + replace_with + return self._backend.getcname(cdecl, replace_with) + + def gc(self, cdata, destructor, size=0): + """Return a new cdata object that points to the same + data. Later, when this new cdata object is garbage-collected, + 'destructor(old_cdata_object)' will be called. + + The optional 'size' gives an estimate of the size, used to + trigger the garbage collection more eagerly. So far only used + on PyPy. It tells the GC that the returned object keeps alive + roughly 'size' bytes of external memory. + """ + return self._backend.gcp(cdata, destructor, size) + + def _get_cached_btype(self, type): + assert self._lock.acquire(False) is False + # call me with the lock! + try: + BType = self._cached_btypes[type] + except KeyError: + finishlist = [] + BType = type.get_cached_btype(self, finishlist) + for type in finishlist: + type.finish_backend_type(self, finishlist) + return BType + + def verify(self, source='', tmpdir=None, **kwargs): + """Verify that the current ffi signatures compile on this + machine, and return a dynamic library object. The dynamic + library can be used to call functions and access global + variables declared in this 'ffi'. The library is compiled + by the C compiler: it gives you C-level API compatibility + (including calling macros). This is unlike 'ffi.dlopen()', + which requires binary compatibility in the signatures. + """ + from .verifier import Verifier, _caller_dir_pycache + # + # If set_unicode(True) was called, insert the UNICODE and + # _UNICODE macro declarations + if self._windows_unicode: + self._apply_windows_unicode(kwargs) + # + # Set the tmpdir here, and not in Verifier.__init__: it picks + # up the caller's directory, which we want to be the caller of + # ffi.verify(), as opposed to the caller of Veritier(). + tmpdir = tmpdir or _caller_dir_pycache() + # + # Make a Verifier() and use it to load the library. + self.verifier = Verifier(self, source, tmpdir, **kwargs) + lib = self.verifier.load_library() + # + # Save the loaded library for keep-alive purposes, even + # if the caller doesn't keep it alive itself (it should). + self._libraries.append(lib) + return lib + + def _get_errno(self): + return self._backend.get_errno() + def _set_errno(self, errno): + self._backend.set_errno(errno) + errno = property(_get_errno, _set_errno, None, + "the value of 'errno' from/to the C calls") + + def getwinerror(self, code=-1): + return self._backend.getwinerror(code) + + def _pointer_to(self, ctype): + with self._lock: + return model.pointer_cache(self, ctype) + + def addressof(self, cdata, *fields_or_indexes): + """Return the address of a . + If 'fields_or_indexes' are given, returns the address of that + field or array item in the structure or array, recursively in + case of nested structures. + """ + try: + ctype = self._backend.typeof(cdata) + except TypeError: + if '__addressof__' in type(cdata).__dict__: + return type(cdata).__addressof__(cdata, *fields_or_indexes) + raise + if fields_or_indexes: + ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) + else: + if ctype.kind == "pointer": + raise TypeError("addressof(pointer)") + offset = 0 + ctypeptr = self._pointer_to(ctype) + return self._backend.rawaddressof(ctypeptr, cdata, offset) + + def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): + ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) + for field1 in fields_or_indexes: + ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) + offset += offset1 + return ctype, offset + + def include(self, ffi_to_include): + """Includes the typedefs, structs, unions and enums defined + in another FFI instance. Usage is similar to a #include in C, + where a part of the program might include types defined in + another part for its own usage. Note that the include() + method has no effect on functions, constants and global + variables, which must anyway be accessed directly from the + lib object returned by the original FFI instance. + """ + if not isinstance(ffi_to_include, FFI): + raise TypeError("ffi.include() expects an argument that is also of" + " type cffi.FFI, not %r" % ( + type(ffi_to_include).__name__,)) + if ffi_to_include is self: + raise ValueError("self.include(self)") + with ffi_to_include._lock: + with self._lock: + self._parser.include(ffi_to_include._parser) + self._cdefsources.append('[') + self._cdefsources.extend(ffi_to_include._cdefsources) + self._cdefsources.append(']') + self._included_ffis.append(ffi_to_include) + + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + + def release(self, x): + self._backend.release(x) + + def set_unicode(self, enabled_flag): + """Windows: if 'enabled_flag' is True, enable the UNICODE and + _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR + to be (pointers to) wchar_t. If 'enabled_flag' is False, + declare these types to be (pointers to) plain 8-bit characters. + This is mostly for backward compatibility; you usually want True. + """ + if self._windows_unicode is not None: + raise ValueError("set_unicode() can only be called once") + enabled_flag = bool(enabled_flag) + if enabled_flag: + self.cdef("typedef wchar_t TBYTE;" + "typedef wchar_t TCHAR;" + "typedef const wchar_t *LPCTSTR;" + "typedef const wchar_t *PCTSTR;" + "typedef wchar_t *LPTSTR;" + "typedef wchar_t *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + else: + self.cdef("typedef char TBYTE;" + "typedef char TCHAR;" + "typedef const char *LPCTSTR;" + "typedef const char *PCTSTR;" + "typedef char *LPTSTR;" + "typedef char *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + self._windows_unicode = enabled_flag + + def _apply_windows_unicode(self, kwds): + defmacros = kwds.get('define_macros', ()) + if not isinstance(defmacros, (list, tuple)): + raise TypeError("'define_macros' must be a list or tuple") + defmacros = list(defmacros) + [('UNICODE', '1'), + ('_UNICODE', '1')] + kwds['define_macros'] = defmacros + + def _apply_embedding_fix(self, kwds): + # must include an argument like "-lpython2.7" for the compiler + def ensure(key, value): + lst = kwds.setdefault(key, []) + if value not in lst: + lst.append(value) + # + if '__pypy__' in sys.builtin_module_names: + import os + if sys.platform == "win32": + # we need 'libpypy-c.lib'. Current distributions of + # pypy (>= 4.1) contain it as 'libs/python27.lib'. + pythonlib = "python{0[0]}{0[1]}".format(sys.version_info) + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'libs')) + else: + # we need 'libpypy-c.{so,dylib}', which should be by + # default located in 'sys.prefix/bin' for installed + # systems. + if sys.version_info < (3,): + pythonlib = "pypy-c" + else: + pythonlib = "pypy3-c" + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'bin')) + # On uninstalled pypy's, the libpypy-c is typically found in + # .../pypy/goal/. + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) + else: + if sys.platform == "win32": + template = "python%d%d" + if hasattr(sys, 'gettotalrefcount'): + template += '_d' + else: + try: + import sysconfig + except ImportError: # 2.6 + from distutils import sysconfig + template = "python%d.%d" + if sysconfig.get_config_var('DEBUG_EXT'): + template += sysconfig.get_config_var('DEBUG_EXT') + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + if hasattr(sys, 'abiflags'): + pythonlib += sys.abiflags + ensure('libraries', pythonlib) + if sys.platform == "win32": + ensure('extra_link_args', '/MANIFEST') + + def set_source(self, module_name, source, source_extension='.c', **kwds): + import os + if hasattr(self, '_assigned_source'): + raise ValueError("set_source() cannot be called several times " + "per ffi object") + if not isinstance(module_name, basestring): + raise TypeError("'module_name' must be a string") + if os.sep in module_name or (os.altsep and os.altsep in module_name): + raise ValueError("'module_name' must not contain '/': use a dotted " + "name to make a 'package.module' location") + self._assigned_source = (str(module_name), source, + source_extension, kwds) + + def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, + source_extension='.c', **kwds): + from . import pkgconfig + if not isinstance(pkgconfig_libs, list): + raise TypeError("the pkgconfig_libs argument must be a list " + "of package names") + kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs) + pkgconfig.merge_flags(kwds, kwds2) + self.set_source(module_name, source, source_extension, **kwds) + + def distutils_extension(self, tmpdir='build', verbose=True): + from distutils.dir_util import mkpath + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored + return self.verifier.get_extension() + raise ValueError("set_source() must be called before" + " distutils_extension()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("distutils_extension() is only for C extension " + "modules, not for dlopen()-style pure Python " + "modules") + mkpath(tmpdir) + ext, updated = recompile(self, module_name, + source, tmpdir=tmpdir, extradir=tmpdir, + source_extension=source_extension, + call_c_compiler=False, **kwds) + if verbose: + if updated: + sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) + else: + sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) + return ext + + def emit_c_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("emit_c_code() is only for C extension modules, " + "not for dlopen()-style pure Python modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def emit_python_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is not None: + raise TypeError("emit_python_code() is only for dlopen()-style " + "pure Python modules, not for C extension modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def compile(self, tmpdir='.', verbose=0, target=None, debug=None): + """The 'target' argument gives the final file name of the + compiled DLL. Use '*' to force distutils' choice, suitable for + regular CPython C API modules. Use a file name ending in '.*' + to ask for the system's default extension for dynamic libraries + (.so/.dll/.dylib). + + The default is '*' when building a non-embedded C API extension, + and (module_name + '.*') when building an embedded library. + """ + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before compile()") + module_name, source, source_extension, kwds = self._assigned_source + return recompile(self, module_name, source, tmpdir=tmpdir, + target=target, source_extension=source_extension, + compiler_verbose=verbose, debug=debug, **kwds) + + def init_once(self, func, tag): + # Read _init_once_cache[tag], which is either (False, lock) if + # we're calling the function now in some thread, or (True, result). + # Don't call setdefault() in most cases, to avoid allocating and + # immediately freeing a lock; but still use setdefaut() to avoid + # races. + try: + x = self._init_once_cache[tag] + except KeyError: + x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) + # Common case: we got (True, result), so we return the result. + if x[0]: + return x[1] + # Else, it's a lock. Acquire it to serialize the following tests. + with x[1]: + # Read again from _init_once_cache the current status. + x = self._init_once_cache[tag] + if x[0]: + return x[1] + # Call the function and store the result back. + result = func() + self._init_once_cache[tag] = (True, result) + return result + + def embedding_init_code(self, pysource): + if self._embedding: + raise ValueError("embedding_init_code() can only be called once") + # fix 'pysource' before it gets dumped into the C file: + # - remove empty lines at the beginning, so it starts at "line 1" + # - dedent, if all non-empty lines are indented + # - check for SyntaxErrors + import re + match = re.match(r'\s*\n', pysource) + if match: + pysource = pysource[match.end():] + lines = pysource.splitlines() or [''] + prefix = re.match(r'\s*', lines[0]).group() + for i in range(1, len(lines)): + line = lines[i] + if line.rstrip(): + while not line.startswith(prefix): + prefix = prefix[:-1] + i = len(prefix) + lines = [line[i:]+'\n' for line in lines] + pysource = ''.join(lines) + # + compile(pysource, "cffi_init", "exec") + # + self._embedding = pysource + + def def_extern(self, *args, **kwds): + raise ValueError("ffi.def_extern() is only available on API-mode FFI " + "objects") + + def list_types(self): + """Returns the user type names known to this FFI instance. + This returns a tuple containing three lists of names: + (typedef_names, names_of_structs, names_of_unions) + """ + typedefs = [] + structs = [] + unions = [] + for key in self._parser._declarations: + if key.startswith('typedef '): + typedefs.append(key[8:]) + elif key.startswith('struct '): + structs.append(key[7:]) + elif key.startswith('union '): + unions.append(key[6:]) + typedefs.sort() + structs.sort() + unions.sort() + return (typedefs, structs, unions) + + +def _load_backend_lib(backend, name, flags): + import os + if not isinstance(name, basestring): + if sys.platform != "win32" or name is not None: + return backend.load_library(name, flags) + name = "c" # Windows: load_library(None) fails, but this works + # on Python 2 (backward compatibility hack only) + first_error = None + if '.' in name or '/' in name or os.sep in name: + try: + return backend.load_library(name, flags) + except OSError as e: + first_error = e + import ctypes.util + path = ctypes.util.find_library(name) + if path is None: + if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): + raise OSError("dlopen(None) cannot work on Windows for Python 3 " + "(see http://bugs.python.org/issue23606)") + msg = ("ctypes.util.find_library() did not manage " + "to locate a library called %r" % (name,)) + if first_error is not None: + msg = "%s. Additionally, %s" % (first_error, msg) + raise OSError(msg) + return backend.load_library(path, flags) + +def _make_ffi_library(ffi, libname, flags): + backend = ffi._backend + backendlib = _load_backend_lib(backend, libname, flags) + # + def accessor_function(name): + key = 'function ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + value = backendlib.load_function(BType, name) + library.__dict__[name] = value + # + def accessor_variable(name): + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + read_variable = backendlib.read_variable + write_variable = backendlib.write_variable + setattr(FFILibrary, name, property( + lambda self: read_variable(BType, name), + lambda self, value: write_variable(BType, name, value))) + # + def addressof_var(name): + try: + return addr_variables[name] + except KeyError: + with ffi._lock: + if name not in addr_variables: + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + if BType.kind != 'array': + BType = model.pointer_cache(ffi, BType) + p = backendlib.load_function(BType, name) + addr_variables[name] = p + return addr_variables[name] + # + def accessor_constant(name): + raise NotImplementedError("non-integer constant '%s' cannot be " + "accessed from a dlopen() library" % (name,)) + # + def accessor_int_constant(name): + library.__dict__[name] = ffi._parser._int_constants[name] + # + accessors = {} + accessors_version = [False] + addr_variables = {} + # + def update_accessors(): + if accessors_version[0] is ffi._cdef_version: + return + # + for key, (tp, _) in ffi._parser._declarations.items(): + if not isinstance(tp, model.EnumType): + tag, name = key.split(' ', 1) + if tag == 'function': + accessors[name] = accessor_function + elif tag == 'variable': + accessors[name] = accessor_variable + elif tag == 'constant': + accessors[name] = accessor_constant + else: + for i, enumname in enumerate(tp.enumerators): + def accessor_enum(name, tp=tp, i=i): + tp.check_not_partial() + library.__dict__[name] = tp.enumvalues[i] + accessors[enumname] = accessor_enum + for name in ffi._parser._int_constants: + accessors.setdefault(name, accessor_int_constant) + accessors_version[0] = ffi._cdef_version + # + def make_accessor(name): + with ffi._lock: + if name in library.__dict__ or name in FFILibrary.__dict__: + return # added by another thread while waiting for the lock + if name not in accessors: + update_accessors() + if name not in accessors: + raise AttributeError(name) + accessors[name](name) + # + class FFILibrary(object): + def __getattr__(self, name): + make_accessor(name) + return getattr(self, name) + def __setattr__(self, name, value): + try: + property = getattr(self.__class__, name) + except AttributeError: + make_accessor(name) + setattr(self, name, value) + else: + property.__set__(self, value) + def __dir__(self): + with ffi._lock: + update_accessors() + return accessors.keys() + def __addressof__(self, name): + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + make_accessor(name) + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + raise AttributeError("cffi library has no function or " + "global variable named '%s'" % (name,)) + def __cffi_close__(self): + backendlib.close_lib() + self.__dict__.clear() + # + if isinstance(libname, basestring): + try: + if not isinstance(libname, str): # unicode, on Python 2 + libname = libname.encode('utf-8') + FFILibrary.__name__ = 'FFILibrary_%s' % libname + except UnicodeError: + pass + library = FFILibrary() + return library, library.__dict__ + +def _builtin_function_type(func): + # a hack to make at least ffi.typeof(builtin_function) work, + # if the builtin function was obtained by 'vengine_cpy'. + import sys + try: + module = sys.modules[func.__module__] + ffi = module._cffi_original_ffi + types_of_builtin_funcs = module._cffi_types_of_builtin_funcs + tp = types_of_builtin_funcs[func] + except (KeyError, AttributeError, TypeError): + return None + else: + with ffi._lock: + return ffi._get_cached_btype(tp) diff --git a/myenv/lib/python3.9/site-packages/cffi/backend_ctypes.py b/myenv/lib/python3.9/site-packages/cffi/backend_ctypes.py new file mode 100644 index 0000000..e7956a7 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/backend_ctypes.py @@ -0,0 +1,1121 @@ +import ctypes, ctypes.util, operator, sys +from . import model + +if sys.version_info < (3,): + bytechr = chr +else: + unicode = str + long = int + xrange = range + bytechr = lambda num: bytes([num]) + +class CTypesType(type): + pass + +class CTypesData(object): + __metaclass__ = CTypesType + __slots__ = ['__weakref__'] + __name__ = '' + + def __init__(self, *args): + raise TypeError("cannot instantiate %r" % (self.__class__,)) + + @classmethod + def _newp(cls, init): + raise TypeError("expected a pointer or array ctype, got '%s'" + % (cls._get_c_name(),)) + + @staticmethod + def _to_ctypes(value): + raise TypeError + + @classmethod + def _arg_to_ctypes(cls, *value): + try: + ctype = cls._ctype + except AttributeError: + raise TypeError("cannot create an instance of %r" % (cls,)) + if value: + res = cls._to_ctypes(*value) + if not isinstance(res, ctype): + res = cls._ctype(res) + else: + res = cls._ctype() + return res + + @classmethod + def _create_ctype_obj(cls, init): + if init is None: + return cls._arg_to_ctypes() + else: + return cls._arg_to_ctypes(init) + + @staticmethod + def _from_ctypes(ctypes_value): + raise TypeError + + @classmethod + def _get_c_name(cls, replace_with=''): + return cls._reftypename.replace(' &', replace_with) + + @classmethod + def _fix_class(cls): + cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__module__ = 'ffi' + + def _get_own_repr(self): + raise NotImplementedError + + def _addr_repr(self, address): + if address == 0: + return 'NULL' + else: + if address < 0: + address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) + return '0x%x' % address + + def __repr__(self, c_name=None): + own = self._get_own_repr() + return '' % (c_name or self._get_c_name(), own) + + def _convert_to_address(self, BClass): + if BClass is None: + raise TypeError("cannot convert %r to an address" % ( + self._get_c_name(),)) + else: + raise TypeError("cannot convert %r to %r" % ( + self._get_c_name(), BClass._get_c_name())) + + @classmethod + def _get_size(cls): + return ctypes.sizeof(cls._ctype) + + def _get_size_of_instance(self): + return ctypes.sizeof(self._ctype) + + @classmethod + def _cast_from(cls, source): + raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) + + def _cast_to_integer(self): + return self._convert_to_address(None) + + @classmethod + def _alignment(cls): + return ctypes.alignment(cls._ctype) + + def __iter__(self): + raise TypeError("cdata %r does not support iteration" % ( + self._get_c_name()),) + + def _make_cmp(name): + cmpfunc = getattr(operator, name) + def cmp(self, other): + v_is_ptr = not isinstance(self, CTypesGenericPrimitive) + w_is_ptr = (isinstance(other, CTypesData) and + not isinstance(other, CTypesGenericPrimitive)) + if v_is_ptr and w_is_ptr: + return cmpfunc(self._convert_to_address(None), + other._convert_to_address(None)) + elif v_is_ptr or w_is_ptr: + return NotImplemented + else: + if isinstance(self, CTypesGenericPrimitive): + self = self._value + if isinstance(other, CTypesGenericPrimitive): + other = other._value + return cmpfunc(self, other) + cmp.func_name = name + return cmp + + __eq__ = _make_cmp('__eq__') + __ne__ = _make_cmp('__ne__') + __lt__ = _make_cmp('__lt__') + __le__ = _make_cmp('__le__') + __gt__ = _make_cmp('__gt__') + __ge__ = _make_cmp('__ge__') + + def __hash__(self): + return hash(self._convert_to_address(None)) + + def _to_string(self, maxlen): + raise TypeError("string(): %r" % (self,)) + + +class CTypesGenericPrimitive(CTypesData): + __slots__ = [] + + def __hash__(self): + return hash(self._value) + + def _get_own_repr(self): + return repr(self._from_ctypes(self._value)) + + +class CTypesGenericArray(CTypesData): + __slots__ = [] + + @classmethod + def _newp(cls, init): + return cls(init) + + def __iter__(self): + for i in xrange(len(self)): + yield self[i] + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + +class CTypesGenericPtr(CTypesData): + __slots__ = ['_address', '_as_ctype_ptr'] + _automatic_casts = False + kind = "pointer" + + @classmethod + def _newp(cls, init): + return cls(init) + + @classmethod + def _cast_from(cls, source): + if source is None: + address = 0 + elif isinstance(source, CTypesData): + address = source._cast_to_integer() + elif isinstance(source, (int, long)): + address = source + else: + raise TypeError("bad type for cast to %r: %r" % + (cls, type(source).__name__)) + return cls._new_pointer_at(address) + + @classmethod + def _new_pointer_at(cls, address): + self = cls.__new__(cls) + self._address = address + self._as_ctype_ptr = ctypes.cast(address, cls._ctype) + return self + + def _get_own_repr(self): + try: + return self._addr_repr(self._address) + except AttributeError: + return '???' + + def _cast_to_integer(self): + return self._address + + def __nonzero__(self): + return bool(self._address) + __bool__ = __nonzero__ + + @classmethod + def _to_ctypes(cls, value): + if not isinstance(value, CTypesData): + raise TypeError("unexpected %s object" % type(value).__name__) + address = value._convert_to_address(cls) + return ctypes.cast(address, cls._ctype) + + @classmethod + def _from_ctypes(cls, ctypes_ptr): + address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 + return cls._new_pointer_at(address) + + @classmethod + def _initialize(cls, ctypes_ptr, value): + if value: + ctypes_ptr.contents = cls._to_ctypes(value).contents + + def _convert_to_address(self, BClass): + if (BClass in (self.__class__, None) or BClass._automatic_casts + or self._automatic_casts): + return self._address + else: + return CTypesData._convert_to_address(self, BClass) + + +class CTypesBaseStructOrUnion(CTypesData): + __slots__ = ['_blob'] + + @classmethod + def _create_ctype_obj(cls, init): + # may be overridden + raise TypeError("cannot instantiate opaque type %s" % (cls,)) + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + @classmethod + def _offsetof(cls, fieldname): + return getattr(cls._ctype, fieldname).offset + + def _convert_to_address(self, BClass): + if getattr(BClass, '_BItem', None) is self.__class__: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @classmethod + def _from_ctypes(cls, ctypes_struct_or_union): + self = cls.__new__(cls) + self._blob = ctypes_struct_or_union + return self + + @classmethod + def _to_ctypes(cls, value): + return value._blob + + def __repr__(self, c_name=None): + return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) + + +class CTypesBackend(object): + + PRIMITIVE_TYPES = { + 'char': ctypes.c_char, + 'short': ctypes.c_short, + 'int': ctypes.c_int, + 'long': ctypes.c_long, + 'long long': ctypes.c_longlong, + 'signed char': ctypes.c_byte, + 'unsigned char': ctypes.c_ubyte, + 'unsigned short': ctypes.c_ushort, + 'unsigned int': ctypes.c_uint, + 'unsigned long': ctypes.c_ulong, + 'unsigned long long': ctypes.c_ulonglong, + 'float': ctypes.c_float, + 'double': ctypes.c_double, + '_Bool': ctypes.c_bool, + } + + for _name in ['unsigned long long', 'unsigned long', + 'unsigned int', 'unsigned short', 'unsigned char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] + + for _name in ['long long', 'long', 'int', 'short', 'signed char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] + PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] + + + def __init__(self): + self.RTLD_LAZY = 0 # not supported anyway by ctypes + self.RTLD_NOW = 0 + self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL + self.RTLD_LOCAL = ctypes.RTLD_LOCAL + + def set_ffi(self, ffi): + self.ffi = ffi + + def _get_types(self): + return CTypesData, CTypesType + + def load_library(self, path, flags=0): + cdll = ctypes.CDLL(path, flags) + return CTypesLibrary(self, cdll) + + def new_void_type(self): + class CTypesVoid(CTypesData): + __slots__ = [] + _reftypename = 'void &' + @staticmethod + def _from_ctypes(novalue): + return None + @staticmethod + def _to_ctypes(novalue): + if novalue is not None: + raise TypeError("None expected, got %s object" % + (type(novalue).__name__,)) + return None + CTypesVoid._fix_class() + return CTypesVoid + + def new_primitive_type(self, name): + if name == 'wchar_t': + raise NotImplementedError(name) + ctype = self.PRIMITIVE_TYPES[name] + if name == 'char': + kind = 'char' + elif name in ('float', 'double'): + kind = 'float' + else: + if name in ('signed char', 'unsigned char'): + kind = 'byte' + elif name == '_Bool': + kind = 'bool' + else: + kind = 'int' + is_signed = (ctype(-1).value == -1) + # + def _cast_source_to_int(source): + if isinstance(source, (int, long, float)): + source = int(source) + elif isinstance(source, CTypesData): + source = source._cast_to_integer() + elif isinstance(source, bytes): + source = ord(source) + elif source is None: + source = 0 + else: + raise TypeError("bad type for cast to %r: %r" % + (CTypesPrimitive, type(source).__name__)) + return source + # + kind1 = kind + class CTypesPrimitive(CTypesGenericPrimitive): + __slots__ = ['_value'] + _ctype = ctype + _reftypename = '%s &' % name + kind = kind1 + + def __init__(self, value): + self._value = value + + @staticmethod + def _create_ctype_obj(init): + if init is None: + return ctype() + return ctype(CTypesPrimitive._to_ctypes(init)) + + if kind == 'int' or kind == 'byte': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = ctype(source).value # cast within range + return cls(source) + def __int__(self): + return self._value + + if kind == 'bool': + @classmethod + def _cast_from(cls, source): + if not isinstance(source, (int, long, float)): + source = _cast_source_to_int(source) + return cls(bool(source)) + def __int__(self): + return int(self._value) + + if kind == 'char': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = bytechr(source & 0xFF) + return cls(source) + def __int__(self): + return ord(self._value) + + if kind == 'float': + @classmethod + def _cast_from(cls, source): + if isinstance(source, float): + pass + elif isinstance(source, CTypesGenericPrimitive): + if hasattr(source, '__float__'): + source = float(source) + else: + source = int(source) + else: + source = _cast_source_to_int(source) + source = ctype(source).value # fix precision + return cls(source) + def __int__(self): + return int(self._value) + def __float__(self): + return self._value + + _cast_to_integer = __int__ + + if kind == 'int' or kind == 'byte' or kind == 'bool': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long)): + if isinstance(x, CTypesData): + x = int(x) + else: + raise TypeError("integer expected, got %s" % + type(x).__name__) + if ctype(x).value != x: + if not is_signed and x < 0: + raise OverflowError("%s: negative integer" % name) + else: + raise OverflowError("%s: integer out of bounds" + % name) + return x + + if kind == 'char': + @staticmethod + def _to_ctypes(x): + if isinstance(x, bytes) and len(x) == 1: + return x + if isinstance(x, CTypesPrimitive): # > + return x._value + raise TypeError("character expected, got %s" % + type(x).__name__) + def __nonzero__(self): + return ord(self._value) != 0 + else: + def __nonzero__(self): + return self._value != 0 + __bool__ = __nonzero__ + + if kind == 'float': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long, float, CTypesData)): + raise TypeError("float expected, got %s" % + type(x).__name__) + return ctype(x).value + + @staticmethod + def _from_ctypes(value): + return getattr(value, 'value', value) + + @staticmethod + def _initialize(blob, init): + blob.value = CTypesPrimitive._to_ctypes(init) + + if kind == 'char': + def _to_string(self, maxlen): + return self._value + if kind == 'byte': + def _to_string(self, maxlen): + return chr(self._value & 0xff) + # + CTypesPrimitive._fix_class() + return CTypesPrimitive + + def new_pointer_type(self, BItem): + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'charp' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' + else: + kind = 'generic' + # + class CTypesPtr(CTypesGenericPtr): + __slots__ = ['_own'] + if kind == 'charp': + __slots__ += ['__as_strbuf'] + _BItem = BItem + if hasattr(BItem, '_ctype'): + _ctype = ctypes.POINTER(BItem._ctype) + _bitem_size = ctypes.sizeof(BItem._ctype) + else: + _ctype = ctypes.c_void_p + if issubclass(BItem, CTypesGenericArray): + _reftypename = BItem._get_c_name('(* &)') + else: + _reftypename = BItem._get_c_name(' * &') + + def __init__(self, init): + ctypeobj = BItem._create_ctype_obj(init) + if kind == 'charp': + self.__as_strbuf = ctypes.create_string_buffer( + ctypeobj.value + b'\x00') + self._as_ctype_ptr = ctypes.cast( + self.__as_strbuf, self._ctype) + else: + self._as_ctype_ptr = ctypes.pointer(ctypeobj) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own = True + + def __add__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address + + other * self._bitem_size) + else: + return NotImplemented + + def __sub__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address - + other * self._bitem_size) + elif type(self) is type(other): + return (self._address - other._address) // self._bitem_size + else: + return NotImplemented + + def __getitem__(self, index): + if getattr(self, '_own', False) and index != 0: + raise IndexError + return BItem._from_ctypes(self._as_ctype_ptr[index]) + + def __setitem__(self, index, value): + self._as_ctype_ptr[index] = BItem._to_ctypes(value) + + if kind == 'charp' or kind == 'voidp': + @classmethod + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) + else: + return super(CTypesPtr, cls)._arg_to_ctypes(*value) + + if kind == 'charp' or kind == 'bytep': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = sys.maxsize + p = ctypes.cast(self._as_ctype_ptr, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % ( + ctypes.sizeof(self._as_ctype_ptr.contents),) + return super(CTypesPtr, self)._get_own_repr() + # + if (BItem is self.ffi._get_cached_btype(model.void_type) or + BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): + CTypesPtr._automatic_casts = True + # + CTypesPtr._fix_class() + return CTypesPtr + + def new_array_type(self, CTypesPtr, length): + if length is None: + brackets = ' &[]' + else: + brackets = ' &[%d]' % length + BItem = CTypesPtr._BItem + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'char' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'byte' + else: + kind = 'generic' + # + class CTypesArray(CTypesGenericArray): + __slots__ = ['_blob', '_own'] + if length is not None: + _ctype = BItem._ctype * length + else: + __slots__.append('_ctype') + _reftypename = BItem._get_c_name(brackets) + _declared_length = length + _CTPtr = CTypesPtr + + def __init__(self, init): + if length is None: + if isinstance(init, (int, long)): + len1 = init + init = None + elif kind == 'char' and isinstance(init, bytes): + len1 = len(init) + 1 # extra null + else: + init = tuple(init) + len1 = len(init) + self._ctype = BItem._ctype * len1 + self._blob = self._ctype() + self._own = True + if init is not None: + self._initialize(self._blob, init) + + @staticmethod + def _initialize(blob, init): + if isinstance(init, bytes): + init = [init[i:i+1] for i in range(len(init))] + else: + if isinstance(init, CTypesGenericArray): + if (len(init) != len(blob) or + not isinstance(init, CTypesArray)): + raise TypeError("length/type mismatch: %s" % (init,)) + init = tuple(init) + if len(init) > len(blob): + raise IndexError("too many initializers") + addr = ctypes.cast(blob, ctypes.c_void_p).value + PTR = ctypes.POINTER(BItem._ctype) + itemsize = ctypes.sizeof(BItem._ctype) + for i, value in enumerate(init): + p = ctypes.cast(addr + i * itemsize, PTR) + BItem._initialize(p.contents, value) + + def __len__(self): + return len(self._blob) + + def __getitem__(self, index): + if not (0 <= index < len(self._blob)): + raise IndexError + return BItem._from_ctypes(self._blob[index]) + + def __setitem__(self, index, value): + if not (0 <= index < len(self._blob)): + raise IndexError + self._blob[index] = BItem._to_ctypes(value) + + if kind == 'char' or kind == 'byte': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = len(self._blob) + p = ctypes.cast(self._blob, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % (ctypes.sizeof(self._blob),) + return super(CTypesArray, self)._get_own_repr() + + def _convert_to_address(self, BClass): + if BClass in (CTypesPtr, None) or BClass._automatic_casts: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @staticmethod + def _from_ctypes(ctypes_array): + self = CTypesArray.__new__(CTypesArray) + self._blob = ctypes_array + return self + + @staticmethod + def _arg_to_ctypes(value): + return CTypesPtr._arg_to_ctypes(value) + + def __add__(self, other): + if isinstance(other, (int, long)): + return CTypesPtr._new_pointer_at( + ctypes.addressof(self._blob) + + other * ctypes.sizeof(BItem._ctype)) + else: + return NotImplemented + + @classmethod + def _cast_from(cls, source): + raise NotImplementedError("casting to %r" % ( + cls._get_c_name(),)) + # + CTypesArray._fix_class() + return CTypesArray + + def _new_struct_or_union(self, kind, name, base_ctypes_class): + # + class struct_or_union(base_ctypes_class): + pass + struct_or_union.__name__ = '%s_%s' % (kind, name) + kind1 = kind + # + class CTypesStructOrUnion(CTypesBaseStructOrUnion): + __slots__ = ['_blob'] + _ctype = struct_or_union + _reftypename = '%s &' % (name,) + _kind = kind = kind1 + # + CTypesStructOrUnion._fix_class() + return CTypesStructOrUnion + + def new_struct_type(self, name): + return self._new_struct_or_union('struct', name, ctypes.Structure) + + def new_union_type(self, name): + return self._new_struct_or_union('union', name, ctypes.Union) + + def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, + totalsize=-1, totalalignment=-1, sflags=0, + pack=0): + if totalsize >= 0 or totalalignment >= 0: + raise NotImplementedError("the ctypes backend of CFFI does not support " + "structures completed by verify(); please " + "compile and install the _cffi_backend module.") + struct_or_union = CTypesStructOrUnion._ctype + fnames = [fname for (fname, BField, bitsize) in fields] + btypes = [BField for (fname, BField, bitsize) in fields] + bitfields = [bitsize for (fname, BField, bitsize) in fields] + # + bfield_types = {} + cfields = [] + for (fname, BField, bitsize) in fields: + if bitsize < 0: + cfields.append((fname, BField._ctype)) + bfield_types[fname] = BField + else: + cfields.append((fname, BField._ctype, bitsize)) + bfield_types[fname] = Ellipsis + if sflags & 8: + struct_or_union._pack_ = 1 + elif pack: + struct_or_union._pack_ = pack + struct_or_union._fields_ = cfields + CTypesStructOrUnion._bfield_types = bfield_types + # + @staticmethod + def _create_ctype_obj(init): + result = struct_or_union() + if init is not None: + initialize(result, init) + return result + CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj + # + def initialize(blob, init): + if is_union: + if len(init) > 1: + raise ValueError("union initializer: %d items given, but " + "only one supported (use a dict if needed)" + % (len(init),)) + if not isinstance(init, dict): + if isinstance(init, (bytes, unicode)): + raise TypeError("union initializer: got a str") + init = tuple(init) + if len(init) > len(fnames): + raise ValueError("too many values for %s initializer" % + CTypesStructOrUnion._get_c_name()) + init = dict(zip(fnames, init)) + addr = ctypes.addressof(blob) + for fname, value in init.items(): + BField, bitsize = name2fieldtype[fname] + assert bitsize < 0, \ + "not implemented: initializer with bit fields" + offset = CTypesStructOrUnion._offsetof(fname) + PTR = ctypes.POINTER(BField._ctype) + p = ctypes.cast(addr + offset, PTR) + BField._initialize(p.contents, value) + is_union = CTypesStructOrUnion._kind == 'union' + name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) + # + for fname, BField, bitsize in fields: + if fname == '': + raise NotImplementedError("nested anonymous structs/unions") + if hasattr(CTypesStructOrUnion, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + if bitsize < 0: + def getter(self, fname=fname, BField=BField, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BField._from_ctypes(p.contents) + def setter(self, value, fname=fname, BField=BField): + setattr(self._blob, fname, BField._to_ctypes(value)) + # + if issubclass(BField, CTypesGenericArray): + setter = None + if BField._declared_length == 0: + def getter(self, fname=fname, BFieldPtr=BField._CTPtr, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BFieldPtr._from_ctypes(p) + # + else: + def getter(self, fname=fname, BField=BField): + return BField._from_ctypes(getattr(self._blob, fname)) + def setter(self, value, fname=fname, BField=BField): + # xxx obscure workaround + value = BField._to_ctypes(value) + oldvalue = getattr(self._blob, fname) + setattr(self._blob, fname, value) + if value != getattr(self._blob, fname): + setattr(self._blob, fname, oldvalue) + raise OverflowError("value too large for bitfield") + setattr(CTypesStructOrUnion, fname, property(getter, setter)) + # + CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) + for fname in fnames: + if hasattr(CTypesPtr, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + def getter(self, fname=fname): + return getattr(self[0], fname) + def setter(self, value, fname=fname): + setattr(self[0], fname, value) + setattr(CTypesPtr, fname, property(getter, setter)) + + def new_function_type(self, BArgs, BResult, has_varargs): + nameargs = [BArg._get_c_name() for BArg in BArgs] + if has_varargs: + nameargs.append('...') + nameargs = ', '.join(nameargs) + # + class CTypesFunctionPtr(CTypesGenericPtr): + __slots__ = ['_own_callback', '_name'] + _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), + *[BArg._ctype for BArg in BArgs], + use_errno=True) + _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) + + def __init__(self, init, error=None): + # create a callback to the Python callable init() + import traceback + assert not has_varargs, "varargs not supported for callbacks" + if getattr(BResult, '_ctype', None) is not None: + error = BResult._from_ctypes( + BResult._create_ctype_obj(error)) + else: + error = None + def callback(*args): + args2 = [] + for arg, BArg in zip(args, BArgs): + args2.append(BArg._from_ctypes(arg)) + try: + res2 = init(*args2) + res2 = BResult._to_ctypes(res2) + except: + traceback.print_exc() + res2 = error + if issubclass(BResult, CTypesGenericPtr): + if res2: + res2 = ctypes.cast(res2, ctypes.c_void_p).value + # .value: http://bugs.python.org/issue1574593 + else: + res2 = None + #print repr(res2) + return res2 + if issubclass(BResult, CTypesGenericPtr): + # The only pointers callbacks can return are void*s: + # http://bugs.python.org/issue5710 + callback_ctype = ctypes.CFUNCTYPE( + ctypes.c_void_p, + *[BArg._ctype for BArg in BArgs], + use_errno=True) + else: + callback_ctype = CTypesFunctionPtr._ctype + self._as_ctype_ptr = callback_ctype(callback) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own_callback = init + + @staticmethod + def _initialize(ctypes_ptr, value): + if value: + raise NotImplementedError("ctypes backend: not supported: " + "initializers for function pointers") + + def __repr__(self): + c_name = getattr(self, '_name', None) + if c_name: + i = self._reftypename.index('(* &)') + if self._reftypename[i-1] not in ' )*': + c_name = ' ' + c_name + c_name = self._reftypename.replace('(* &)', c_name) + return CTypesData.__repr__(self, c_name) + + def _get_own_repr(self): + if getattr(self, '_own_callback', None) is not None: + return 'calling %r' % (self._own_callback,) + return super(CTypesFunctionPtr, self)._get_own_repr() + + def __call__(self, *args): + if has_varargs: + assert len(args) >= len(BArgs) + extraargs = args[len(BArgs):] + args = args[:len(BArgs)] + else: + assert len(args) == len(BArgs) + ctypes_args = [] + for arg, BArg in zip(args, BArgs): + ctypes_args.append(BArg._arg_to_ctypes(arg)) + if has_varargs: + for i, arg in enumerate(extraargs): + if arg is None: + ctypes_args.append(ctypes.c_void_p(0)) # NULL + continue + if not isinstance(arg, CTypesData): + raise TypeError( + "argument %d passed in the variadic part " + "needs to be a cdata object (got %s)" % + (1 + len(BArgs) + i, type(arg).__name__)) + ctypes_args.append(arg._arg_to_ctypes(arg)) + result = self._as_ctype_ptr(*ctypes_args) + return BResult._from_ctypes(result) + # + CTypesFunctionPtr._fix_class() + return CTypesFunctionPtr + + def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): + assert isinstance(name, str) + reverse_mapping = dict(zip(reversed(enumvalues), + reversed(enumerators))) + # + class CTypesEnum(CTypesInt): + __slots__ = [] + _reftypename = '%s &' % name + + def _get_own_repr(self): + value = self._value + try: + return '%d: %s' % (value, reverse_mapping[value]) + except KeyError: + return str(value) + + def _to_string(self, maxlen): + value = self._value + try: + return reverse_mapping[value] + except KeyError: + return str(value) + # + CTypesEnum._fix_class() + return CTypesEnum + + def get_errno(self): + return ctypes.get_errno() + + def set_errno(self, value): + ctypes.set_errno(value) + + def string(self, b, maxlen=-1): + return b._to_string(maxlen) + + def buffer(self, bptr, size=-1): + raise NotImplementedError("buffer() with ctypes backend") + + def sizeof(self, cdata_or_BType): + if isinstance(cdata_or_BType, CTypesData): + return cdata_or_BType._get_size_of_instance() + else: + assert issubclass(cdata_or_BType, CTypesData) + return cdata_or_BType._get_size() + + def alignof(self, BType): + assert issubclass(BType, CTypesData) + return BType._alignment() + + def newp(self, BType, source): + if not issubclass(BType, CTypesData): + raise TypeError + return BType._newp(source) + + def cast(self, BType, source): + return BType._cast_from(source) + + def callback(self, BType, source, error, onerror): + assert onerror is None # XXX not implemented + return BType(source, error) + + _weakref_cache_ref = None + + def gcp(self, cdata, destructor, size=0): + if self._weakref_cache_ref is None: + import weakref + class MyRef(weakref.ref): + def __eq__(self, other): + myref = self() + return self is other or ( + myref is not None and myref is other()) + def __ne__(self, other): + return not (self == other) + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(self()) + return self._hash + self._weakref_cache_ref = {}, MyRef + weak_cache, MyRef = self._weakref_cache_ref + + if destructor is None: + try: + del weak_cache[MyRef(cdata)] + except KeyError: + raise TypeError("Can remove destructor only on a object " + "previously returned by ffi.gc()") + return None + + def remove(k): + cdata, destructor = weak_cache.pop(k, (None, None)) + if destructor is not None: + destructor(cdata) + + new_cdata = self.cast(self.typeof(cdata), cdata) + assert new_cdata is not cdata + weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) + return new_cdata + + typeof = type + + def getcname(self, BType, replace_with): + return BType._get_c_name(replace_with) + + def typeoffsetof(self, BType, fieldname, num=0): + if isinstance(fieldname, str): + if num == 0 and issubclass(BType, CTypesGenericPtr): + BType = BType._BItem + if not issubclass(BType, CTypesBaseStructOrUnion): + raise TypeError("expected a struct or union ctype") + BField = BType._bfield_types[fieldname] + if BField is Ellipsis: + raise TypeError("not supported for bitfields") + return (BField, BType._offsetof(fieldname)) + elif isinstance(fieldname, (int, long)): + if issubclass(BType, CTypesGenericArray): + BType = BType._CTPtr + if not issubclass(BType, CTypesGenericPtr): + raise TypeError("expected an array or ptr ctype") + BItem = BType._BItem + offset = BItem._get_size() * fieldname + if offset > sys.maxsize: + raise OverflowError + return (BItem, offset) + else: + raise TypeError(type(fieldname)) + + def rawaddressof(self, BTypePtr, cdata, offset=None): + if isinstance(cdata, CTypesBaseStructOrUnion): + ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) + elif isinstance(cdata, CTypesGenericPtr): + if offset is None or not issubclass(type(cdata)._BItem, + CTypesBaseStructOrUnion): + raise TypeError("unexpected cdata type") + ptr = type(cdata)._to_ctypes(cdata) + elif isinstance(cdata, CTypesGenericArray): + ptr = type(cdata)._to_ctypes(cdata) + else: + raise TypeError("expected a ") + if offset: + ptr = ctypes.cast( + ctypes.c_void_p( + ctypes.cast(ptr, ctypes.c_void_p).value + offset), + type(ptr)) + return BTypePtr._from_ctypes(ptr) + + +class CTypesLibrary(object): + + def __init__(self, backend, cdll): + self.backend = backend + self.cdll = cdll + + def load_function(self, BType, name): + c_func = getattr(self.cdll, name) + funcobj = BType._from_ctypes(c_func) + funcobj._name = name + return funcobj + + def read_variable(self, BType, name): + try: + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + except AttributeError as e: + raise NotImplementedError(e) + return BType._from_ctypes(ctypes_obj) + + def write_variable(self, BType, name, value): + new_ctypes_obj = BType._to_ctypes(value) + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + ctypes.memmove(ctypes.addressof(ctypes_obj), + ctypes.addressof(new_ctypes_obj), + ctypes.sizeof(BType._ctype)) diff --git a/myenv/lib/python3.9/site-packages/cffi/cffi_opcode.py b/myenv/lib/python3.9/site-packages/cffi/cffi_opcode.py new file mode 100644 index 0000000..a0df98d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/cffi_opcode.py @@ -0,0 +1,187 @@ +from .error import VerificationError + +class CffiOp(object): + def __init__(self, op, arg): + self.op = op + self.arg = arg + + def as_c_expr(self): + if self.op is None: + assert isinstance(self.arg, str) + return '(_cffi_opcode_t)(%s)' % (self.arg,) + classname = CLASS_NAME[self.op] + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) + + def as_python_bytes(self): + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): + raise VerificationError("cannot emit to Python: %r" % (self.arg,)) + return format_four_bytes((self.arg << 8) | self.op) + + def __str__(self): + classname = CLASS_NAME.get(self.op, self.op) + return '(%s %s)' % (classname, self.arg) + +def format_four_bytes(num): + return '\\x%02X\\x%02X\\x%02X\\x%02X' % ( + (num >> 24) & 0xFF, + (num >> 16) & 0xFF, + (num >> 8) & 0xFF, + (num ) & 0xFF) + +OP_PRIMITIVE = 1 +OP_POINTER = 3 +OP_ARRAY = 5 +OP_OPEN_ARRAY = 7 +OP_STRUCT_UNION = 9 +OP_ENUM = 11 +OP_FUNCTION = 13 +OP_FUNCTION_END = 15 +OP_NOOP = 17 +OP_BITFIELD = 19 +OP_TYPENAME = 21 +OP_CPYTHON_BLTN_V = 23 # varargs +OP_CPYTHON_BLTN_N = 25 # noargs +OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) +OP_CONSTANT = 29 +OP_CONSTANT_INT = 31 +OP_GLOBAL_VAR = 33 +OP_DLOPEN_FUNC = 35 +OP_DLOPEN_CONST = 37 +OP_GLOBAL_VAR_F = 39 +OP_EXTERN_PYTHON = 41 + +PRIM_VOID = 0 +PRIM_BOOL = 1 +PRIM_CHAR = 2 +PRIM_SCHAR = 3 +PRIM_UCHAR = 4 +PRIM_SHORT = 5 +PRIM_USHORT = 6 +PRIM_INT = 7 +PRIM_UINT = 8 +PRIM_LONG = 9 +PRIM_ULONG = 10 +PRIM_LONGLONG = 11 +PRIM_ULONGLONG = 12 +PRIM_FLOAT = 13 +PRIM_DOUBLE = 14 +PRIM_LONGDOUBLE = 15 + +PRIM_WCHAR = 16 +PRIM_INT8 = 17 +PRIM_UINT8 = 18 +PRIM_INT16 = 19 +PRIM_UINT16 = 20 +PRIM_INT32 = 21 +PRIM_UINT32 = 22 +PRIM_INT64 = 23 +PRIM_UINT64 = 24 +PRIM_INTPTR = 25 +PRIM_UINTPTR = 26 +PRIM_PTRDIFF = 27 +PRIM_SIZE = 28 +PRIM_SSIZE = 29 +PRIM_INT_LEAST8 = 30 +PRIM_UINT_LEAST8 = 31 +PRIM_INT_LEAST16 = 32 +PRIM_UINT_LEAST16 = 33 +PRIM_INT_LEAST32 = 34 +PRIM_UINT_LEAST32 = 35 +PRIM_INT_LEAST64 = 36 +PRIM_UINT_LEAST64 = 37 +PRIM_INT_FAST8 = 38 +PRIM_UINT_FAST8 = 39 +PRIM_INT_FAST16 = 40 +PRIM_UINT_FAST16 = 41 +PRIM_INT_FAST32 = 42 +PRIM_UINT_FAST32 = 43 +PRIM_INT_FAST64 = 44 +PRIM_UINT_FAST64 = 45 +PRIM_INTMAX = 46 +PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 +PRIM_CHAR16 = 50 +PRIM_CHAR32 = 51 + +_NUM_PRIM = 52 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 + +_IO_FILE_STRUCT = -1 + +PRIMITIVE_TO_INDEX = { + 'char': PRIM_CHAR, + 'short': PRIM_SHORT, + 'int': PRIM_INT, + 'long': PRIM_LONG, + 'long long': PRIM_LONGLONG, + 'signed char': PRIM_SCHAR, + 'unsigned char': PRIM_UCHAR, + 'unsigned short': PRIM_USHORT, + 'unsigned int': PRIM_UINT, + 'unsigned long': PRIM_ULONG, + 'unsigned long long': PRIM_ULONGLONG, + 'float': PRIM_FLOAT, + 'double': PRIM_DOUBLE, + 'long double': PRIM_LONGDOUBLE, + 'float _Complex': PRIM_FLOATCOMPLEX, + 'double _Complex': PRIM_DOUBLECOMPLEX, + '_Bool': PRIM_BOOL, + 'wchar_t': PRIM_WCHAR, + 'char16_t': PRIM_CHAR16, + 'char32_t': PRIM_CHAR32, + 'int8_t': PRIM_INT8, + 'uint8_t': PRIM_UINT8, + 'int16_t': PRIM_INT16, + 'uint16_t': PRIM_UINT16, + 'int32_t': PRIM_INT32, + 'uint32_t': PRIM_UINT32, + 'int64_t': PRIM_INT64, + 'uint64_t': PRIM_UINT64, + 'intptr_t': PRIM_INTPTR, + 'uintptr_t': PRIM_UINTPTR, + 'ptrdiff_t': PRIM_PTRDIFF, + 'size_t': PRIM_SIZE, + 'ssize_t': PRIM_SSIZE, + 'int_least8_t': PRIM_INT_LEAST8, + 'uint_least8_t': PRIM_UINT_LEAST8, + 'int_least16_t': PRIM_INT_LEAST16, + 'uint_least16_t': PRIM_UINT_LEAST16, + 'int_least32_t': PRIM_INT_LEAST32, + 'uint_least32_t': PRIM_UINT_LEAST32, + 'int_least64_t': PRIM_INT_LEAST64, + 'uint_least64_t': PRIM_UINT_LEAST64, + 'int_fast8_t': PRIM_INT_FAST8, + 'uint_fast8_t': PRIM_UINT_FAST8, + 'int_fast16_t': PRIM_INT_FAST16, + 'uint_fast16_t': PRIM_UINT_FAST16, + 'int_fast32_t': PRIM_INT_FAST32, + 'uint_fast32_t': PRIM_UINT_FAST32, + 'int_fast64_t': PRIM_INT_FAST64, + 'uint_fast64_t': PRIM_UINT_FAST64, + 'intmax_t': PRIM_INTMAX, + 'uintmax_t': PRIM_UINTMAX, + } + +F_UNION = 0x01 +F_CHECK_FIELDS = 0x02 +F_PACKED = 0x04 +F_EXTERNAL = 0x08 +F_OPAQUE = 0x10 + +G_FLAGS = dict([('_CFFI_' + _key, globals()[_key]) + for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED', + 'F_EXTERNAL', 'F_OPAQUE']]) + +CLASS_NAME = {} +for _name, _value in list(globals().items()): + if _name.startswith('OP_') and isinstance(_value, int): + CLASS_NAME[_value] = _name[3:] diff --git a/myenv/lib/python3.9/site-packages/cffi/commontypes.py b/myenv/lib/python3.9/site-packages/cffi/commontypes.py new file mode 100644 index 0000000..8ec97c7 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/commontypes.py @@ -0,0 +1,80 @@ +import sys +from . import model +from .error import FFIError + + +COMMON_TYPES = {} + +try: + # fetch "bool" and all simple Windows types + from _cffi_backend import _get_common_types + _get_common_types(COMMON_TYPES) +except ImportError: + pass + +COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') +COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above + +for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + if _type.endswith('_t'): + COMMON_TYPES[_type] = _type +del _type + +_CACHE = {} + +def resolve_common_type(parser, commontype): + try: + return _CACHE[commontype] + except KeyError: + cdecl = COMMON_TYPES.get(commontype, commontype) + if not isinstance(cdecl, str): + result, quals = cdecl, 0 # cdecl is already a BaseType + elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + result, quals = model.PrimitiveType(cdecl), 0 + elif cdecl == 'set-unicode-needed': + raise FFIError("The Windows type %r is only available after " + "you call ffi.set_unicode()" % (commontype,)) + else: + if commontype == cdecl: + raise FFIError( + "Unsupported type: %r. Please look at " + "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations " + "and file an issue if you think this type should really " + "be supported." % (commontype,)) + result, quals = parser.parse_type_and_quals(cdecl) # recursive + + assert isinstance(result, model.BaseTypeByIdentity) + _CACHE[commontype] = result, quals + return result, quals + + +# ____________________________________________________________ +# extra types for Windows (most of them are in commontypes.c) + + +def win_common_types(): + return { + "UNICODE_STRING": model.StructType( + "_UNICODE_STRING", + ["Length", + "MaximumLength", + "Buffer"], + [model.PrimitiveType("unsigned short"), + model.PrimitiveType("unsigned short"), + model.PointerType(model.PrimitiveType("wchar_t"))], + [-1, -1, -1]), + "PUNICODE_STRING": "UNICODE_STRING *", + "PCUNICODE_STRING": "const UNICODE_STRING *", + + "TBYTE": "set-unicode-needed", + "TCHAR": "set-unicode-needed", + "LPCTSTR": "set-unicode-needed", + "PCTSTR": "set-unicode-needed", + "LPTSTR": "set-unicode-needed", + "PTSTR": "set-unicode-needed", + "PTBYTE": "set-unicode-needed", + "PTCHAR": "set-unicode-needed", + } + +if sys.platform == 'win32': + COMMON_TYPES.update(win_common_types()) diff --git a/myenv/lib/python3.9/site-packages/cffi/cparser.py b/myenv/lib/python3.9/site-packages/cffi/cparser.py new file mode 100644 index 0000000..74830e9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/cparser.py @@ -0,0 +1,1006 @@ +from . import model +from .commontypes import COMMON_TYPES, resolve_common_type +from .error import FFIError, CDefError +try: + from . import _pycparser as pycparser +except ImportError: + import pycparser +import weakref, re, sys + +try: + if sys.version_info < (3,): + import thread as _thread + else: + import _thread + lock = _thread.allocate_lock() +except ImportError: + lock = None + +def _workaround_for_static_import_finders(): + # Issue #392: packaging tools like cx_Freeze can not find these + # because pycparser uses exec dynamic import. This is an obscure + # workaround. This function is never called. + import pycparser.yacctab + import pycparser.lextab + +CDEF_SOURCE_STRING = "" +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) +_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) +_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") +_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") +_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") +_r_words = re.compile(r"\w+|\S") +_parser_cache = None +_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) +_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") +_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") +_r_cdecl = re.compile(r"\b__cdecl\b") +_r_extern_python = re.compile(r'\bextern\s*"' + r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') +_r_star_const_space = re.compile( # matches "* const " + r"[*]\s*((const|volatile|restrict)\b\s*)+") +_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" + r"\.\.\.") +_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") + +def _get_parser(): + global _parser_cache + if _parser_cache is None: + _parser_cache = pycparser.CParser() + return _parser_cache + +def _workaround_for_old_pycparser(csource): + # Workaround for a pycparser issue (fixed between pycparser 2.10 and + # 2.14): "char*const***" gives us a wrong syntax tree, the same as + # for "char***(*const)". This means we can't tell the difference + # afterwards. But "char(*const(***))" gives us the right syntax + # tree. The issue only occurs if there are several stars in + # sequence with no parenthesis inbetween, just possibly qualifiers. + # Attempt to fix it by adding some parentheses in the source: each + # time we see "* const" or "* const *", we add an opening + # parenthesis before each star---the hard part is figuring out where + # to close them. + parts = [] + while True: + match = _r_star_const_space.search(csource) + if not match: + break + #print repr(''.join(parts)+csource), '=>', + parts.append(csource[:match.start()]) + parts.append('('); closing = ')' + parts.append(match.group()) # e.g. "* const " + endpos = match.end() + if csource.startswith('*', endpos): + parts.append('('); closing += ')' + level = 0 + i = endpos + while i < len(csource): + c = csource[i] + if c == '(': + level += 1 + elif c == ')': + if level == 0: + break + level -= 1 + elif c in ',;=': + if level == 0: + break + i += 1 + csource = csource[endpos:i] + closing + csource[i:] + #print repr(''.join(parts)+csource) + parts.append(csource) + return ''.join(parts) + +def _preprocess_extern_python(csource): + # input: `extern "Python" int foo(int);` or + # `extern "Python" { int foo(int); }` + # output: + # void __cffi_extern_python_start; + # int foo(int); + # void __cffi_extern_python_stop; + # + # input: `extern "Python+C" int foo(int);` + # output: + # void __cffi_extern_python_plus_c_start; + # int foo(int); + # void __cffi_extern_python_stop; + parts = [] + while True: + match = _r_extern_python.search(csource) + if not match: + break + endpos = match.end() - 1 + #print + #print ''.join(parts)+csource + #print '=>' + parts.append(csource[:match.start()]) + if 'C' in match.group(1): + parts.append('void __cffi_extern_python_plus_c_start; ') + else: + parts.append('void __cffi_extern_python_start; ') + if csource[endpos] == '{': + # grouping variant + closing = csource.find('}', endpos) + if closing < 0: + raise CDefError("'extern \"Python\" {': no '}' found") + if csource.find('{', endpos + 1, closing) >= 0: + raise NotImplementedError("cannot use { } inside a block " + "'extern \"Python\" { ... }'") + parts.append(csource[endpos+1:closing]) + csource = csource[closing+1:] + else: + # non-grouping variant + semicolon = csource.find(';', endpos) + if semicolon < 0: + raise CDefError("'extern \"Python\": no ';' found") + parts.append(csource[endpos:semicolon+1]) + csource = csource[semicolon+1:] + parts.append(' void __cffi_extern_python_stop;') + #print ''.join(parts)+csource + #print + parts.append(csource) + return ''.join(parts) + +def _warn_for_string_literal(csource): + if '"' not in csource: + return + for line in csource.splitlines(): + if '"' in line and not line.lstrip().startswith('#'): + import warnings + warnings.warn("String literal found in cdef() or type source. " + "String literals are ignored here, but you should " + "remove them anyway because some character sequences " + "confuse pre-parsing.") + break + +def _warn_for_non_extern_non_static_global_variable(decl): + if not decl.storage: + import warnings + warnings.warn("Global variable '%s' in cdef(): for consistency " + "with C it should have a storage class specifier " + "(usually 'extern')" % (decl.name,)) + +def _remove_line_directives(csource): + # _r_line_directive matches whole lines, without the final \n, if they + # start with '#line' with some spacing allowed, or '#NUMBER'. This + # function stores them away and replaces them with exactly the string + # '#line@N', where N is the index in the list 'line_directives'. + line_directives = [] + def replace(m): + i = len(line_directives) + line_directives.append(m.group()) + return '#line@%d' % i + csource = _r_line_directive.sub(replace, csource) + return csource, line_directives + +def _put_back_line_directives(csource, line_directives): + def replace(m): + s = m.group() + if not s.startswith('#line@'): + raise AssertionError("unexpected #line directive " + "(should have been processed and removed") + return line_directives[int(s[6:])] + return _r_line_directive.sub(replace, csource) + +def _preprocess(csource): + # First, remove the lines of the form '#line N "filename"' because + # the "filename" part could confuse the rest + csource, line_directives = _remove_line_directives(csource) + # Remove comments. NOTE: this only work because the cdef() section + # should not contain any string literals (except in line directives)! + def replace_keeping_newlines(m): + return ' ' + m.group().count('\n') * '\n' + csource = _r_comment.sub(replace_keeping_newlines, csource) + # Remove the "#define FOO x" lines + macros = {} + for match in _r_define.finditer(csource): + macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() + macros[macroname] = macrovalue + csource = _r_define.sub('', csource) + # + if pycparser.__version__ < '2.14': + csource = _workaround_for_old_pycparser(csource) + # + # BIG HACK: replace WINAPI or __stdcall with "volatile const". + # It doesn't make sense for the return type of a function to be + # "volatile volatile const", so we abuse it to detect __stdcall... + # Hack number 2 is that "int(volatile *fptr)();" is not valid C + # syntax, so we place the "volatile" before the opening parenthesis. + csource = _r_stdcall2.sub(' volatile volatile const(', csource) + csource = _r_stdcall1.sub(' volatile volatile const ', csource) + csource = _r_cdecl.sub(' ', csource) + # + # Replace `extern "Python"` with start/end markers + csource = _preprocess_extern_python(csource) + # + # Now there should not be any string literal left; warn if we get one + _warn_for_string_literal(csource) + # + # Replace "[...]" with "[__dotdotdotarray__]" + csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) + # + # Replace "...}" with "__dotdotdotNUM__}". This construction should + # occur only at the end of enums; at the end of structs we have "...;}" + # and at the end of vararg functions "...);". Also replace "=...[,}]" + # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when + # giving an unknown value. + matches = list(_r_partial_enum.finditer(csource)) + for number, match in enumerate(reversed(matches)): + p = match.start() + if csource[p] == '=': + p2 = csource.find('...', p, match.end()) + assert p2 > p + csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, + csource[p2+3:]) + else: + assert csource[p:p+3] == '...' + csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, + csource[p+3:]) + # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" + csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) + # Replace "float ..." or "double..." with "__dotdotdotfloat__" + csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) + # Replace all remaining "..." with the same name, "__dotdotdot__", + # which is declared with a typedef for the purpose of C parsing. + csource = csource.replace('...', ' __dotdotdot__ ') + # Finally, put back the line directives + csource = _put_back_line_directives(csource, line_directives) + return csource, macros + +def _common_type_names(csource): + # Look in the source for what looks like usages of types from the + # list of common types. A "usage" is approximated here as the + # appearance of the word, minus a "definition" of the type, which + # is the last word in a "typedef" statement. Approximative only + # but should be fine for all the common types. + look_for_words = set(COMMON_TYPES) + look_for_words.add(';') + look_for_words.add(',') + look_for_words.add('(') + look_for_words.add(')') + look_for_words.add('typedef') + words_used = set() + is_typedef = False + paren = 0 + previous_word = '' + for word in _r_words.findall(csource): + if word in look_for_words: + if word == ';': + if is_typedef: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + is_typedef = False + elif word == 'typedef': + is_typedef = True + paren = 0 + elif word == '(': + paren += 1 + elif word == ')': + paren -= 1 + elif word == ',': + if is_typedef and paren == 0: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + else: # word in COMMON_TYPES + words_used.add(word) + previous_word = word + return words_used + + +class Parser(object): + + def __init__(self): + self._declarations = {} + self._included_declarations = set() + self._anonymous_counter = 0 + self._structnode2type = weakref.WeakKeyDictionary() + self._options = {} + self._int_constants = {} + self._recomplete = [] + self._uses_new_feature = None + + def _parse(self, csource): + csource, macros = _preprocess(csource) + # XXX: for more efficiency we would need to poke into the + # internals of CParser... the following registers the + # typedefs, because their presence or absence influences the + # parsing itself (but what they are typedef'ed to plays no role) + ctn = _common_type_names(csource) + typenames = [] + for name in sorted(self._declarations): + if name.startswith('typedef '): + name = name[8:] + typenames.append(name) + ctn.discard(name) + typenames += sorted(ctn) + # + csourcelines = [] + csourcelines.append('# 1 ""') + for typename in typenames: + csourcelines.append('typedef int %s;' % typename) + csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' + ' __dotdotdot__;') + # this forces pycparser to consider the following in the file + # called from line 1 + csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) + csourcelines.append(csource) + fullcsource = '\n'.join(csourcelines) + if lock is not None: + lock.acquire() # pycparser is not thread-safe... + try: + ast = _get_parser().parse(fullcsource) + except pycparser.c_parser.ParseError as e: + self.convert_pycparser_error(e, csource) + finally: + if lock is not None: + lock.release() + # csource will be used to find buggy source text + return ast, macros, csource + + def _convert_pycparser_error(self, e, csource): + # xxx look for ":NUM:" at the start of str(e) + # and interpret that as a line number. This will not work if + # the user gives explicit ``# NUM "FILE"`` directives. + line = None + msg = str(e) + match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) + if match: + linenum = int(match.group(1), 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] + return line + + def convert_pycparser_error(self, e, csource): + line = self._convert_pycparser_error(e, csource) + + msg = str(e) + if line: + msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) + else: + msg = 'parse error\n%s' % (msg,) + raise CDefError(msg) + + def parse(self, csource, override=False, packed=False, pack=None, + dllexport=False): + if packed: + if packed != True: + raise ValueError("'packed' should be False or True; use " + "'pack' to give another value") + if pack: + raise ValueError("cannot give both 'pack' and 'packed'") + pack = 1 + elif pack: + if pack & (pack - 1): + raise ValueError("'pack' must be a power of two, not %r" % + (pack,)) + else: + pack = 0 + prev_options = self._options + try: + self._options = {'override': override, + 'packed': pack, + 'dllexport': dllexport} + self._internal_parse(csource) + finally: + self._options = prev_options + + def _internal_parse(self, csource): + ast, macros, csource = self._parse(csource) + # add the macros + self._process_macros(macros) + # find the first "__dotdotdot__" and use that as a separator + # between the repeated typedefs and the real csource + iterator = iter(ast.ext) + for decl in iterator: + if decl.name == '__dotdotdot__': + break + else: + assert 0 + current_decl = None + # + try: + self._inside_extern_python = '__cffi_extern_python_stop' + for decl in iterator: + current_decl = decl + if isinstance(decl, pycparser.c_ast.Decl): + self._parse_decl(decl) + elif isinstance(decl, pycparser.c_ast.Typedef): + if not decl.name: + raise CDefError("typedef does not declare any name", + decl) + quals = 0 + if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and + decl.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_type(decl) + elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and + isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and + isinstance(decl.type.type.type, + pycparser.c_ast.IdentifierType) and + decl.type.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_ptr_type(decl) + else: + realtype, quals = self._get_type_and_quals( + decl.type, name=decl.name, partial_length_ok=True, + typedef_example="*(%s *)0" % (decl.name,)) + self._declare('typedef ' + decl.name, realtype, quals=quals) + elif decl.__class__.__name__ == 'Pragma': + pass # skip pragma, only in pycparser 2.15 + else: + raise CDefError("unexpected <%s>: this construct is valid " + "C but not valid in cdef()" % + decl.__class__.__name__, decl) + except CDefError as e: + if len(e.args) == 1: + e.args = e.args + (current_decl,) + raise + except FFIError as e: + msg = self._convert_pycparser_error(e, csource) + if msg: + e.args = (e.args[0] + "\n *** Err: %s" % msg,) + raise + + def _add_constants(self, key, val): + if key in self._int_constants: + if self._int_constants[key] == val: + return # ignore identical double declarations + raise FFIError( + "multiple declarations of constant: %s" % (key,)) + self._int_constants[key] = val + + def _add_integer_constant(self, name, int_str): + int_str = int_str.lower().rstrip("ul") + neg = int_str.startswith('-') + if neg: + int_str = int_str[1:] + # "010" is not valid oct in py3 + if (int_str.startswith("0") and int_str != '0' + and not int_str.startswith("0x")): + int_str = "0o" + int_str[1:] + pyvalue = int(int_str, 0) + if neg: + pyvalue = -pyvalue + self._add_constants(name, pyvalue) + self._declare('macro ' + name, pyvalue) + + def _process_macros(self, macros): + for key, value in macros.items(): + value = value.strip() + if _r_int_literal.match(value): + self._add_integer_constant(key, value) + elif value == '...': + self._declare('macro ' + key, value) + else: + raise CDefError( + 'only supports one of the following syntax:\n' + ' #define %s ... (literally dot-dot-dot)\n' + ' #define %s NUMBER (with NUMBER an integer' + ' constant, decimal/hex/octal)\n' + 'got:\n' + ' #define %s %s' + % (key, key, key, value)) + + def _declare_function(self, tp, quals, decl): + tp = self._get_type_pointer(tp, quals) + if self._options.get('dllexport'): + tag = 'dllexport_python ' + elif self._inside_extern_python == '__cffi_extern_python_start': + tag = 'extern_python ' + elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': + tag = 'extern_python_plus_c ' + else: + tag = 'function ' + self._declare(tag + decl.name, tp) + + def _parse_decl(self, decl): + node = decl.type + if isinstance(node, pycparser.c_ast.FuncDecl): + tp, quals = self._get_type_and_quals(node, name=decl.name) + assert isinstance(tp, model.RawFunctionType) + self._declare_function(tp, quals, decl) + else: + if isinstance(node, pycparser.c_ast.Struct): + self._get_struct_union_enum_type('struct', node) + elif isinstance(node, pycparser.c_ast.Union): + self._get_struct_union_enum_type('union', node) + elif isinstance(node, pycparser.c_ast.Enum): + self._get_struct_union_enum_type('enum', node) + elif not decl.name: + raise CDefError("construct does not declare any variable", + decl) + # + if decl.name: + tp, quals = self._get_type_and_quals(node, + partial_length_ok=True) + if tp.is_raw_function: + self._declare_function(tp, quals, decl) + elif (tp.is_integer_type() and + hasattr(decl, 'init') and + hasattr(decl.init, 'value') and + _r_int_literal.match(decl.init.value)): + self._add_integer_constant(decl.name, decl.init.value) + elif (tp.is_integer_type() and + isinstance(decl.init, pycparser.c_ast.UnaryOp) and + decl.init.op == '-' and + hasattr(decl.init.expr, 'value') and + _r_int_literal.match(decl.init.expr.value)): + self._add_integer_constant(decl.name, + '-' + decl.init.expr.value) + elif (tp is model.void_type and + decl.name.startswith('__cffi_extern_python_')): + # hack: `extern "Python"` in the C source is replaced + # with "void __cffi_extern_python_start;" and + # "void __cffi_extern_python_stop;" + self._inside_extern_python = decl.name + else: + if self._inside_extern_python !='__cffi_extern_python_stop': + raise CDefError( + "cannot declare constants or " + "variables with 'extern \"Python\"'") + if (quals & model.Q_CONST) and not tp.is_array_type: + self._declare('constant ' + decl.name, tp, quals=quals) + else: + _warn_for_non_extern_non_static_global_variable(decl) + self._declare('variable ' + decl.name, tp, quals=quals) + + def parse_type(self, cdecl): + return self.parse_type_and_quals(cdecl)[0] + + def parse_type_and_quals(self, cdecl): + ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] + assert not macros + exprnode = ast.ext[-1].type.args.params[0] + if isinstance(exprnode, pycparser.c_ast.ID): + raise CDefError("unknown identifier '%s'" % (exprnode.name,)) + return self._get_type_and_quals(exprnode.type) + + def _declare(self, name, obj, included=False, quals=0): + if name in self._declarations: + prevobj, prevquals = self._declarations[name] + if prevobj is obj and prevquals == quals: + return + if not self._options.get('override'): + raise FFIError( + "multiple declarations of %s (for interactive usage, " + "try cdef(xx, override=True))" % (name,)) + assert '__dotdotdot__' not in name.split() + self._declarations[name] = (obj, quals) + if included: + self._included_declarations.add(obj) + + def _extract_quals(self, type): + quals = 0 + if isinstance(type, (pycparser.c_ast.TypeDecl, + pycparser.c_ast.PtrDecl)): + if 'const' in type.quals: + quals |= model.Q_CONST + if 'volatile' in type.quals: + quals |= model.Q_VOLATILE + if 'restrict' in type.quals: + quals |= model.Q_RESTRICT + return quals + + def _get_type_pointer(self, type, quals, declname=None): + if isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + if (isinstance(type, model.StructOrUnionOrEnum) and + type.name.startswith('$') and type.name[1:].isdigit() and + type.forcename is None and declname is not None): + return model.NamedPointerType(type, declname, quals) + return model.PointerType(type, quals) + + def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, + typedef_example=None): + # first, dereference typedefs, if we have it already parsed, we're good + if (isinstance(typenode, pycparser.c_ast.TypeDecl) and + isinstance(typenode.type, pycparser.c_ast.IdentifierType) and + len(typenode.type.names) == 1 and + ('typedef ' + typenode.type.names[0]) in self._declarations): + tp, quals = self._declarations['typedef ' + typenode.type.names[0]] + quals |= self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.ArrayDecl): + # array type + if typenode.dim is None: + length = None + else: + length = self._parse_constant( + typenode.dim, partial_length_ok=partial_length_ok) + # a hack: in 'typedef int foo_t[...][...];', don't use '...' as + # the length but use directly the C expression that would be + # generated by recompiler.py. This lets the typedef be used in + # many more places within recompiler.py + if typedef_example is not None: + if length == '...': + length = '_cffi_array_len(%s)' % (typedef_example,) + typedef_example = "*" + typedef_example + # + tp, quals = self._get_type_and_quals(typenode.type, + partial_length_ok=partial_length_ok, + typedef_example=typedef_example) + return model.ArrayType(tp, length), quals + # + if isinstance(typenode, pycparser.c_ast.PtrDecl): + # pointer type + itemtype, itemquals = self._get_type_and_quals(typenode.type) + tp = self._get_type_pointer(itemtype, itemquals, declname=name) + quals = self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.TypeDecl): + quals = self._extract_quals(typenode) + type = typenode.type + if isinstance(type, pycparser.c_ast.IdentifierType): + # assume a primitive type. get it from .names, but reduce + # synonyms to a single chosen combination + names = list(type.names) + if names != ['signed', 'char']: # keep this unmodified + prefixes = {} + while names: + name = names[0] + if name in ('short', 'long', 'signed', 'unsigned'): + prefixes[name] = prefixes.get(name, 0) + 1 + del names[0] + else: + break + # ignore the 'signed' prefix below, and reorder the others + newnames = [] + for prefix in ('unsigned', 'short', 'long'): + for i in range(prefixes.get(prefix, 0)): + newnames.append(prefix) + if not names: + names = ['int'] # implicitly + if names == ['int']: # but kill it if 'short' or 'long' + if 'short' in prefixes or 'long' in prefixes: + names = [] + names = newnames + names + ident = ' '.join(names) + if ident == 'void': + return model.void_type, quals + if ident == '__dotdotdot__': + raise FFIError(':%d: bad usage of "..."' % + typenode.coord.line) + tp0, quals0 = resolve_common_type(self, ident) + return tp0, (quals | quals0) + # + if isinstance(type, pycparser.c_ast.Struct): + # 'struct foobar' + tp = self._get_struct_union_enum_type('struct', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Union): + # 'union foobar' + tp = self._get_struct_union_enum_type('union', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Enum): + # 'enum foobar' + tp = self._get_struct_union_enum_type('enum', type, name) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.FuncDecl): + # a function type + return self._parse_function_type(typenode, name), 0 + # + # nested anonymous structs or unions end up here + if isinstance(typenode, pycparser.c_ast.Struct): + return self._get_struct_union_enum_type('struct', typenode, name, + nested=True), 0 + if isinstance(typenode, pycparser.c_ast.Union): + return self._get_struct_union_enum_type('union', typenode, name, + nested=True), 0 + # + raise FFIError(":%d: bad or unsupported type declaration" % + typenode.coord.line) + + def _parse_function_type(self, typenode, funcname=None): + params = list(getattr(typenode.args, 'params', [])) + for i, arg in enumerate(params): + if not hasattr(arg, 'type'): + raise CDefError("%s arg %d: unknown type '%s'" + " (if you meant to use the old C syntax of giving" + " untyped arguments, it is not supported)" + % (funcname or 'in expression', i + 1, + getattr(arg, 'name', '?'))) + ellipsis = ( + len(params) > 0 and + isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and + isinstance(params[-1].type.type, + pycparser.c_ast.IdentifierType) and + params[-1].type.type.names == ['__dotdotdot__']) + if ellipsis: + params.pop() + if not params: + raise CDefError( + "%s: a function with only '(...)' as argument" + " is not correct C" % (funcname or 'in expression')) + args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) + for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] + result, quals = self._get_type_and_quals(typenode.type) + # the 'quals' on the result type are ignored. HACK: we absure them + # to detect __stdcall functions: we textually replace "__stdcall" + # with "volatile volatile const" above. + abi = None + if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway + if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: + abi = '__stdcall' + return model.RawFunctionType(tuple(args), result, ellipsis, abi) + + def _as_func_arg(self, type, quals): + if isinstance(type, model.ArrayType): + return model.PointerType(type.item, quals) + elif isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + else: + return type + + def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): + # First, a level of caching on the exact 'type' node of the AST. + # This is obscure, but needed because pycparser "unrolls" declarations + # such as "typedef struct { } foo_t, *foo_p" and we end up with + # an AST that is not a tree, but a DAG, with the "type" node of the + # two branches foo_t and foo_p of the trees being the same node. + # It's a bit silly but detecting "DAG-ness" in the AST tree seems + # to be the only way to distinguish this case from two independent + # structs. See test_struct_with_two_usages. + try: + return self._structnode2type[type] + except KeyError: + pass + # + # Note that this must handle parsing "struct foo" any number of + # times and always return the same StructType object. Additionally, + # one of these times (not necessarily the first), the fields of + # the struct can be specified with "struct foo { ...fields... }". + # If no name is given, then we have to create a new anonymous struct + # with no caching; in this case, the fields are either specified + # right now or never. + # + force_name = name + name = type.name + # + # get the type or create it if needed + if name is None: + # 'force_name' is used to guess a more readable name for + # anonymous structs, for the common case "typedef struct { } foo". + if force_name is not None: + explicit_name = '$%s' % force_name + else: + self._anonymous_counter += 1 + explicit_name = '$%d' % self._anonymous_counter + tp = None + else: + explicit_name = name + key = '%s %s' % (kind, name) + tp, _ = self._declarations.get(key, (None, None)) + # + if tp is None: + if kind == 'struct': + tp = model.StructType(explicit_name, None, None, None) + elif kind == 'union': + tp = model.UnionType(explicit_name, None, None, None) + elif kind == 'enum': + if explicit_name == '__dotdotdot__': + raise CDefError("Enums cannot be declared with ...") + tp = self._build_enum_type(explicit_name, type.values) + else: + raise AssertionError("kind = %r" % (kind,)) + if name is not None: + self._declare(key, tp) + else: + if kind == 'enum' and type.values is not None: + raise NotImplementedError( + "enum %s: the '{}' declaration should appear on the first " + "time the enum is mentioned, not later" % explicit_name) + if not tp.forcename: + tp.force_the_name(force_name) + if tp.forcename and '$' in tp.name: + self._declare('anonymous %s' % tp.forcename, tp) + # + self._structnode2type[type] = tp + # + # enums: done here + if kind == 'enum': + return tp + # + # is there a 'type.decls'? If yes, then this is the place in the + # C sources that declare the fields. If no, then just return the + # existing type, possibly still incomplete. + if type.decls is None: + return tp + # + if tp.fldnames is not None: + raise CDefError("duplicate declaration of struct %s" % name) + fldnames = [] + fldtypes = [] + fldbitsize = [] + fldquals = [] + for decl in type.decls: + if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and + ''.join(decl.type.names) == '__dotdotdot__'): + # XXX pycparser is inconsistent: 'names' should be a list + # of strings, but is sometimes just one string. Use + # str.join() as a way to cope with both. + self._make_partial(tp, nested) + continue + if decl.bitsize is None: + bitsize = -1 + else: + bitsize = self._parse_constant(decl.bitsize) + self._partial_length = False + type, fqual = self._get_type_and_quals(decl.type, + partial_length_ok=True) + if self._partial_length: + self._make_partial(tp, nested) + if isinstance(type, model.StructType) and type.partial: + self._make_partial(tp, nested) + fldnames.append(decl.name or '') + fldtypes.append(type) + fldbitsize.append(bitsize) + fldquals.append(fqual) + tp.fldnames = tuple(fldnames) + tp.fldtypes = tuple(fldtypes) + tp.fldbitsize = tuple(fldbitsize) + tp.fldquals = tuple(fldquals) + if fldbitsize != [-1] * len(fldbitsize): + if isinstance(tp, model.StructType) and tp.partial: + raise NotImplementedError("%s: using both bitfields and '...;'" + % (tp,)) + tp.packed = self._options.get('packed') + if tp.completed: # must be re-completed: it is not opaque any more + tp.completed = 0 + self._recomplete.append(tp) + return tp + + def _make_partial(self, tp, nested): + if not isinstance(tp, model.StructOrUnion): + raise CDefError("%s cannot be partial" % (tp,)) + if not tp.has_c_name() and not nested: + raise NotImplementedError("%s is partial but has no C name" %(tp,)) + tp.partial = True + + def _parse_constant(self, exprnode, partial_length_ok=False): + # for now, limited to expressions that are an immediate number + # or positive/negative number + if isinstance(exprnode, pycparser.c_ast.Constant): + s = exprnode.value + if '0' <= s[0] <= '9': + s = s.rstrip('uUlL') + try: + if s.startswith('0'): + return int(s, 8) + else: + return int(s, 10) + except ValueError: + if len(s) > 1: + if s.lower()[0:2] == '0x': + return int(s, 16) + elif s.lower()[0:2] == '0b': + return int(s, 2) + raise CDefError("invalid constant %r" % (s,)) + elif s[0] == "'" and s[-1] == "'" and ( + len(s) == 3 or (len(s) == 4 and s[1] == "\\")): + return ord(s[-2]) + else: + raise CDefError("invalid constant %r" % (s,)) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '+'): + return self._parse_constant(exprnode.expr) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '-'): + return -self._parse_constant(exprnode.expr) + # load previously defined int constant + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name in self._int_constants): + return self._int_constants[exprnode.name] + # + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name == '__dotdotdotarray__'): + if partial_length_ok: + self._partial_length = True + return '...' + raise FFIError(":%d: unsupported '[...]' here, cannot derive " + "the actual array length in this context" + % exprnode.coord.line) + # + if isinstance(exprnode, pycparser.c_ast.BinaryOp): + left = self._parse_constant(exprnode.left) + right = self._parse_constant(exprnode.right) + if exprnode.op == '+': + return left + right + elif exprnode.op == '-': + return left - right + elif exprnode.op == '*': + return left * right + elif exprnode.op == '/': + return self._c_div(left, right) + elif exprnode.op == '%': + return left - self._c_div(left, right) * right + elif exprnode.op == '<<': + return left << right + elif exprnode.op == '>>': + return left >> right + elif exprnode.op == '&': + return left & right + elif exprnode.op == '|': + return left | right + elif exprnode.op == '^': + return left ^ right + # + raise FFIError(":%d: unsupported expression: expected a " + "simple numeric constant" % exprnode.coord.line) + + def _c_div(self, a, b): + result = a // b + if ((a < 0) ^ (b < 0)) and (a % b) != 0: + result += 1 + return result + + def _build_enum_type(self, explicit_name, decls): + if decls is not None: + partial = False + enumerators = [] + enumvalues = [] + nextenumvalue = 0 + for enum in decls.enumerators: + if _r_enum_dotdotdot.match(enum.name): + partial = True + continue + if enum.value is not None: + nextenumvalue = self._parse_constant(enum.value) + enumerators.append(enum.name) + enumvalues.append(nextenumvalue) + self._add_constants(enum.name, nextenumvalue) + nextenumvalue += 1 + enumerators = tuple(enumerators) + enumvalues = tuple(enumvalues) + tp = model.EnumType(explicit_name, enumerators, enumvalues) + tp.partial = partial + else: # opaque enum + tp = model.EnumType(explicit_name, (), ()) + return tp + + def include(self, other): + for name, (tp, quals) in other._declarations.items(): + if name.startswith('anonymous $enum_$'): + continue # fix for test_anonymous_enum_include + kind = name.split(' ', 1)[0] + if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): + self._declare(name, tp, included=True, quals=quals) + for k, v in other._int_constants.items(): + self._add_constants(k, v) + + def _get_unknown_type(self, decl): + typenames = decl.type.type.names + if typenames == ['__dotdotdot__']: + return model.unknown_type(decl.name) + + if typenames == ['__dotdotdotint__']: + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef int... %s'" % decl.name + return model.UnknownIntegerType(decl.name) + + if typenames == ['__dotdotdotfloat__']: + # note: not for 'long double' so far + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef float... %s'" % decl.name + return model.UnknownFloatType(decl.name) + + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) + + def _get_unknown_ptr_type(self, decl): + if decl.type.type.type.names == ['__dotdotdot__']: + return model.unknown_ptr_type(decl.name) + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) diff --git a/myenv/lib/python3.9/site-packages/cffi/error.py b/myenv/lib/python3.9/site-packages/cffi/error.py new file mode 100644 index 0000000..0a27247 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/error.py @@ -0,0 +1,31 @@ + +class FFIError(Exception): + __module__ = 'cffi' + +class CDefError(Exception): + __module__ = 'cffi' + def __str__(self): + try: + current_decl = self.args[1] + filename = current_decl.coord.file + linenum = current_decl.coord.line + prefix = '%s:%d: ' % (filename, linenum) + except (AttributeError, TypeError, IndexError): + prefix = '' + return '%s%s' % (prefix, self.args[0]) + +class VerificationError(Exception): + """ An error raised when verification fails + """ + __module__ = 'cffi' + +class VerificationMissing(Exception): + """ An error raised when incomplete structures are passed into + cdef, but no verification has been done + """ + __module__ = 'cffi' + +class PkgConfigError(Exception): + """ An error raised for missing modules in pkg-config + """ + __module__ = 'cffi' diff --git a/myenv/lib/python3.9/site-packages/cffi/ffiplatform.py b/myenv/lib/python3.9/site-packages/cffi/ffiplatform.py new file mode 100644 index 0000000..8531346 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/ffiplatform.py @@ -0,0 +1,127 @@ +import sys, os +from .error import VerificationError + + +LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', + 'extra_objects', 'depends'] + +def get_extension(srcfilename, modname, sources=(), **kwds): + _hack_at_distutils() + from distutils.core import Extension + allsources = [srcfilename] + for src in sources: + allsources.append(os.path.normpath(src)) + return Extension(name=modname, sources=allsources, **kwds) + +def compile(tmpdir, ext, compiler_verbose=0, debug=None): + """Compile a C extension module using distutils.""" + + _hack_at_distutils() + saved_environ = os.environ.copy() + try: + outputfilename = _build(tmpdir, ext, compiler_verbose, debug) + outputfilename = os.path.abspath(outputfilename) + finally: + # workaround for a distutils bugs where some env vars can + # become longer and longer every time it is used + for key, value in saved_environ.items(): + if os.environ.get(key) != value: + os.environ[key] = value + return outputfilename + +def _build(tmpdir, ext, compiler_verbose=0, debug=None): + # XXX compact but horrible :-( + from distutils.core import Distribution + import distutils.errors, distutils.log + # + dist = Distribution({'ext_modules': [ext]}) + dist.parse_config_files() + options = dist.get_option_dict('build_ext') + if debug is None: + debug = sys.flags.debug + options['debug'] = ('ffiplatform', debug) + options['force'] = ('ffiplatform', True) + options['build_lib'] = ('ffiplatform', tmpdir) + options['build_temp'] = ('ffiplatform', tmpdir) + # + try: + old_level = distutils.log.set_threshold(0) or 0 + try: + distutils.log.set_verbosity(compiler_verbose) + dist.run_command('build_ext') + cmd_obj = dist.get_command_obj('build_ext') + [soname] = cmd_obj.get_outputs() + finally: + distutils.log.set_threshold(old_level) + except (distutils.errors.CompileError, + distutils.errors.LinkError) as e: + raise VerificationError('%s: %s' % (e.__class__.__name__, e)) + # + return soname + +try: + from os.path import samefile +except ImportError: + def samefile(f1, f2): + return os.path.abspath(f1) == os.path.abspath(f2) + +def maybe_relative_path(path): + if not os.path.isabs(path): + return path # already relative + dir = path + names = [] + while True: + prevdir = dir + dir, name = os.path.split(prevdir) + if dir == prevdir or not dir: + return path # failed to make it relative + names.append(name) + try: + if samefile(dir, os.curdir): + names.reverse() + return os.path.join(*names) + except OSError: + pass + +# ____________________________________________________________ + +try: + int_or_long = (int, long) + import cStringIO +except NameError: + int_or_long = int # Python 3 + import io as cStringIO + +def _flatten(x, f): + if isinstance(x, str): + f.write('%ds%s' % (len(x), x)) + elif isinstance(x, dict): + keys = sorted(x.keys()) + f.write('%dd' % len(keys)) + for key in keys: + _flatten(key, f) + _flatten(x[key], f) + elif isinstance(x, (list, tuple)): + f.write('%dl' % len(x)) + for value in x: + _flatten(value, f) + elif isinstance(x, int_or_long): + f.write('%di' % (x,)) + else: + raise TypeError( + "the keywords to verify() contains unsupported object %r" % (x,)) + +def flatten(x): + f = cStringIO.StringIO() + _flatten(x, f) + return f.getvalue() + +def _hack_at_distutils(): + # Windows-only workaround for some configurations: see + # https://bugs.python.org/issue23246 (Python 2.7 with + # a specific MS compiler suite download) + if sys.platform == "win32": + try: + import setuptools # for side-effects, patches distutils + except ImportError: + pass diff --git a/myenv/lib/python3.9/site-packages/cffi/lock.py b/myenv/lib/python3.9/site-packages/cffi/lock.py new file mode 100644 index 0000000..db91b71 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/lock.py @@ -0,0 +1,30 @@ +import sys + +if sys.version_info < (3,): + try: + from thread import allocate_lock + except ImportError: + from dummy_thread import allocate_lock +else: + try: + from _thread import allocate_lock + except ImportError: + from _dummy_thread import allocate_lock + + +##import sys +##l1 = allocate_lock + +##class allocate_lock(object): +## def __init__(self): +## self._real = l1() +## def __enter__(self): +## for i in range(4, 0, -1): +## print sys._getframe(i).f_code +## print +## return self._real.__enter__() +## def __exit__(self, *args): +## return self._real.__exit__(*args) +## def acquire(self, f): +## assert f is False +## return self._real.acquire(f) diff --git a/myenv/lib/python3.9/site-packages/cffi/model.py b/myenv/lib/python3.9/site-packages/cffi/model.py new file mode 100644 index 0000000..ad1c176 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/model.py @@ -0,0 +1,617 @@ +import types +import weakref + +from .lock import allocate_lock +from .error import CDefError, VerificationError, VerificationMissing + +# type qualifiers +Q_CONST = 0x01 +Q_RESTRICT = 0x02 +Q_VOLATILE = 0x04 + +def qualify(quals, replace_with): + if quals & Q_CONST: + replace_with = ' const ' + replace_with.lstrip() + if quals & Q_VOLATILE: + replace_with = ' volatile ' + replace_with.lstrip() + if quals & Q_RESTRICT: + # It seems that __restrict is supported by gcc and msvc. + # If you hit some different compiler, add a #define in + # _cffi_include.h for it (and in its copies, documented there) + replace_with = ' __restrict ' + replace_with.lstrip() + return replace_with + + +class BaseTypeByIdentity(object): + is_array_type = False + is_raw_function = False + + def get_c_name(self, replace_with='', context='a C file', quals=0): + result = self.c_name_with_marker + assert result.count('&') == 1 + # some logic duplication with ffi.getctype()... :-( + replace_with = replace_with.strip() + if replace_with: + if replace_with.startswith('*') and '&[' in result: + replace_with = '(%s)' % replace_with + elif not replace_with[0] in '[(': + replace_with = ' ' + replace_with + replace_with = qualify(quals, replace_with) + result = result.replace('&', replace_with) + if '$' in result: + raise VerificationError( + "cannot generate '%s' in %s: unknown type name" + % (self._get_c_name(), context)) + return result + + def _get_c_name(self): + return self.c_name_with_marker.replace('&', '') + + def has_c_name(self): + return '$' not in self._get_c_name() + + def is_integer_type(self): + return False + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + try: + BType = ffi._cached_btypes[self] + except KeyError: + BType = self.build_backend_type(ffi, finishlist) + BType2 = ffi._cached_btypes.setdefault(self, BType) + assert BType2 is BType + return BType + + def __repr__(self): + return '<%s>' % (self._get_c_name(),) + + def _get_items(self): + return [(name, getattr(self, name)) for name in self._attrs_] + + +class BaseType(BaseTypeByIdentity): + + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self._get_items() == other._get_items()) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.__class__, tuple(self._get_items()))) + + +class VoidType(BaseType): + _attrs_ = () + + def __init__(self): + self.c_name_with_marker = 'void&' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_void_type') + +void_type = VoidType() + + +class BasePrimitiveType(BaseType): + def is_complex_type(self): + return False + + +class PrimitiveType(BasePrimitiveType): + _attrs_ = ('name',) + + ALL_PRIMITIVE_TYPES = { + 'char': 'c', + 'short': 'i', + 'int': 'i', + 'long': 'i', + 'long long': 'i', + 'signed char': 'i', + 'unsigned char': 'i', + 'unsigned short': 'i', + 'unsigned int': 'i', + 'unsigned long': 'i', + 'unsigned long long': 'i', + 'float': 'f', + 'double': 'f', + 'long double': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', + '_Bool': 'i', + # the following types are not primitive in the C sense + 'wchar_t': 'c', + 'char16_t': 'c', + 'char32_t': 'c', + 'int8_t': 'i', + 'uint8_t': 'i', + 'int16_t': 'i', + 'uint16_t': 'i', + 'int32_t': 'i', + 'uint32_t': 'i', + 'int64_t': 'i', + 'uint64_t': 'i', + 'int_least8_t': 'i', + 'uint_least8_t': 'i', + 'int_least16_t': 'i', + 'uint_least16_t': 'i', + 'int_least32_t': 'i', + 'uint_least32_t': 'i', + 'int_least64_t': 'i', + 'uint_least64_t': 'i', + 'int_fast8_t': 'i', + 'uint_fast8_t': 'i', + 'int_fast16_t': 'i', + 'uint_fast16_t': 'i', + 'int_fast32_t': 'i', + 'uint_fast32_t': 'i', + 'int_fast64_t': 'i', + 'uint_fast64_t': 'i', + 'intptr_t': 'i', + 'uintptr_t': 'i', + 'intmax_t': 'i', + 'uintmax_t': 'i', + 'ptrdiff_t': 'i', + 'size_t': 'i', + 'ssize_t': 'i', + } + + def __init__(self, name): + assert name in self.ALL_PRIMITIVE_TYPES + self.name = name + self.c_name_with_marker = name + '&' + + def is_char_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'c' + def is_integer_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' + def is_float_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_primitive_type', self.name) + + +class UnknownIntegerType(BasePrimitiveType): + _attrs_ = ('name',) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def is_integer_type(self): + return True + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("integer type '%s' can only be used after " + "compilation" % self.name) + +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + + +class BaseFunctionType(BaseType): + _attrs_ = ('args', 'result', 'ellipsis', 'abi') + + def __init__(self, args, result, ellipsis, abi=None): + self.args = args + self.result = result + self.ellipsis = ellipsis + self.abi = abi + # + reprargs = [arg._get_c_name() for arg in self.args] + if self.ellipsis: + reprargs.append('...') + reprargs = reprargs or ['void'] + replace_with = self._base_pattern % (', '.join(reprargs),) + if abi is not None: + replace_with = replace_with[:1] + abi + ' ' + replace_with[1:] + self.c_name_with_marker = ( + self.result.c_name_with_marker.replace('&', replace_with)) + + +class RawFunctionType(BaseFunctionType): + # Corresponds to a C type like 'int(int)', which is the C type of + # a function, but not a pointer-to-function. The backend has no + # notion of such a type; it's used temporarily by parsing. + _base_pattern = '(&)(%s)' + is_raw_function = True + + def build_backend_type(self, ffi, finishlist): + raise CDefError("cannot render the type %r: it is a function " + "type, not a pointer-to-function type" % (self,)) + + def as_function_pointer(self): + return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi) + + +class FunctionPtrType(BaseFunctionType): + _base_pattern = '(*&)(%s)' + + def build_backend_type(self, ffi, finishlist): + result = self.result.get_cached_btype(ffi, finishlist) + args = [] + for tp in self.args: + args.append(tp.get_cached_btype(ffi, finishlist)) + abi_args = () + if self.abi == "__stdcall": + if not self.ellipsis: # __stdcall ignored for variadic funcs + try: + abi_args = (ffi._backend.FFI_STDCALL,) + except AttributeError: + pass + return global_cache(self, ffi, 'new_function_type', + tuple(args), result, self.ellipsis, *abi_args) + + def as_raw_function(self): + return RawFunctionType(self.args, self.result, self.ellipsis, self.abi) + + +class PointerType(BaseType): + _attrs_ = ('totype', 'quals') + + def __init__(self, totype, quals=0): + self.totype = totype + self.quals = quals + extra = qualify(quals, " *&") + if totype.is_array_type: + extra = "(%s)" % (extra.lstrip(),) + self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) + + def build_backend_type(self, ffi, finishlist): + BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) + return global_cache(self, ffi, 'new_pointer_type', BItem) + +voidp_type = PointerType(void_type) + +def ConstPointerType(totype): + return PointerType(totype, Q_CONST) + +const_voidp_type = ConstPointerType(void_type) + + +class NamedPointerType(PointerType): + _attrs_ = ('totype', 'name') + + def __init__(self, totype, name, quals=0): + PointerType.__init__(self, totype, quals) + self.name = name + self.c_name_with_marker = name + '&' + + +class ArrayType(BaseType): + _attrs_ = ('item', 'length') + is_array_type = True + + def __init__(self, item, length): + self.item = item + self.length = length + # + if length is None: + brackets = '&[]' + elif length == '...': + brackets = '&[/*...*/]' + else: + brackets = '&[%s]' % length + self.c_name_with_marker = ( + self.item.c_name_with_marker.replace('&', brackets)) + + def length_is_unknown(self): + return isinstance(self.length, str) + + def resolve_length(self, newlength): + return ArrayType(self.item, newlength) + + def build_backend_type(self, ffi, finishlist): + if self.length_is_unknown(): + raise CDefError("cannot render the type %r: unknown length" % + (self,)) + self.item.get_cached_btype(ffi, finishlist) # force the item BType + BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) + return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) + +char_array_type = ArrayType(PrimitiveType('char'), None) + + +class StructOrUnionOrEnum(BaseTypeByIdentity): + _attrs_ = ('name',) + forcename = None + + def build_c_name_with_marker(self): + name = self.forcename or '%s %s' % (self.kind, self.name) + self.c_name_with_marker = name + '&' + + def force_the_name(self, forcename): + self.forcename = forcename + self.build_c_name_with_marker() + + def get_official_name(self): + assert self.c_name_with_marker.endswith('&') + return self.c_name_with_marker[:-1] + + +class StructOrUnion(StructOrUnionOrEnum): + fixedlayout = None + completed = 0 + partial = False + packed = 0 + + def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): + self.name = name + self.fldnames = fldnames + self.fldtypes = fldtypes + self.fldbitsize = fldbitsize + self.fldquals = fldquals + self.build_c_name_with_marker() + + def anonymous_struct_fields(self): + if self.fldtypes is not None: + for name, type in zip(self.fldnames, self.fldtypes): + if name == '' and isinstance(type, StructOrUnion): + yield type + + def enumfields(self, expand_anonymous_struct_union=True): + fldquals = self.fldquals + if fldquals is None: + fldquals = (0,) * len(self.fldnames) + for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, + self.fldbitsize, fldquals): + if (name == '' and isinstance(type, StructOrUnion) + and expand_anonymous_struct_union): + # nested anonymous struct/union + for result in type.enumfields(): + yield result + else: + yield (name, type, bitsize, quals) + + def force_flatten(self): + # force the struct or union to have a declaration that lists + # directly all fields returned by enumfields(), flattening + # nested anonymous structs/unions. + names = [] + types = [] + bitsizes = [] + fldquals = [] + for name, type, bitsize, quals in self.enumfields(): + names.append(name) + types.append(type) + bitsizes.append(bitsize) + fldquals.append(quals) + self.fldnames = tuple(names) + self.fldtypes = tuple(types) + self.fldbitsize = tuple(bitsizes) + self.fldquals = tuple(fldquals) + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, + can_delay) + if not can_delay: + self.finish_backend_type(ffi, finishlist) + return BType + + def finish_backend_type(self, ffi, finishlist): + if self.completed: + if self.completed != 2: + raise NotImplementedError("recursive structure declaration " + "for '%s'" % (self.name,)) + return + BType = ffi._cached_btypes[self] + # + self.completed = 1 + # + if self.fldtypes is None: + pass # not completing it: it's an opaque struct + # + elif self.fixedlayout is None: + fldtypes = [tp.get_cached_btype(ffi, finishlist) + for tp in self.fldtypes] + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) + extra_flags = () + if self.packed: + if self.packed == 1: + extra_flags = (8,) # SF_PACKED + else: + extra_flags = (0, self.packed) + ffi._backend.complete_struct_or_union(BType, lst, self, + -1, -1, *extra_flags) + # + else: + fldtypes = [] + fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout + for i in range(len(self.fldnames)): + fsize = fieldsize[i] + ftype = self.fldtypes[i] + # + if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): + # fix the length to match the total size + BItemType = ftype.item.get_cached_btype(ffi, finishlist) + nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) + if nrest != 0: + self._verification_error( + "field '%s.%s' has a bogus size?" % ( + self.name, self.fldnames[i] or '{}')) + ftype = ftype.resolve_length(nlen) + self.fldtypes = (self.fldtypes[:i] + (ftype,) + + self.fldtypes[i+1:]) + # + BFieldType = ftype.get_cached_btype(ffi, finishlist) + if isinstance(ftype, ArrayType) and ftype.length is None: + assert fsize == 0 + else: + bitemsize = ffi.sizeof(BFieldType) + if bitemsize != fsize: + self._verification_error( + "field '%s.%s' is declared as %d bytes, but is " + "really %d bytes" % (self.name, + self.fldnames[i] or '{}', + bitemsize, fsize)) + fldtypes.append(BFieldType) + # + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)) + ffi._backend.complete_struct_or_union(BType, lst, self, + totalsize, totalalignment) + self.completed = 2 + + def _verification_error(self, msg): + raise VerificationError(msg) + + def check_not_partial(self): + if self.partial and self.fixedlayout is None: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + finishlist.append(self) + # + return global_cache(self, ffi, 'new_%s_type' % self.kind, + self.get_official_name(), key=self) + + +class StructType(StructOrUnion): + kind = 'struct' + + +class UnionType(StructOrUnion): + kind = 'union' + + +class EnumType(StructOrUnionOrEnum): + kind = 'enum' + partial = False + partial_resolved = False + + def __init__(self, name, enumerators, enumvalues, baseinttype=None): + self.name = name + self.enumerators = enumerators + self.enumvalues = enumvalues + self.baseinttype = baseinttype + self.build_c_name_with_marker() + + def force_the_name(self, forcename): + StructOrUnionOrEnum.force_the_name(self, forcename) + if self.forcename is None: + name = self.get_official_name() + self.forcename = '$' + name.replace(' ', '_') + + def check_not_partial(self): + if self.partial and not self.partial_resolved: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + base_btype = self.build_baseinttype(ffi, finishlist) + return global_cache(self, ffi, 'new_enum_type', + self.get_official_name(), + self.enumerators, self.enumvalues, + base_btype, key=self) + + def build_baseinttype(self, ffi, finishlist): + if self.baseinttype is not None: + return self.baseinttype.get_cached_btype(ffi, finishlist) + # + if self.enumvalues: + smallest_value = min(self.enumvalues) + largest_value = max(self.enumvalues) + else: + import warnings + try: + # XXX! The goal is to ensure that the warnings.warn() + # will not suppress the warning. We want to get it + # several times if we reach this point several times. + __warningregistry__.clear() + except NameError: + pass + warnings.warn("%r has no values explicitly defined; " + "guessing that it is equivalent to 'unsigned int'" + % self._get_c_name()) + smallest_value = largest_value = 0 + if smallest_value < 0: # needs a signed type + sign = 1 + candidate1 = PrimitiveType("int") + candidate2 = PrimitiveType("long") + else: + sign = 0 + candidate1 = PrimitiveType("unsigned int") + candidate2 = PrimitiveType("unsigned long") + btype1 = candidate1.get_cached_btype(ffi, finishlist) + btype2 = candidate2.get_cached_btype(ffi, finishlist) + size1 = ffi.sizeof(btype1) + size2 = ffi.sizeof(btype2) + if (smallest_value >= ((-1) << (8*size1-1)) and + largest_value < (1 << (8*size1-sign))): + return btype1 + if (smallest_value >= ((-1) << (8*size2-1)) and + largest_value < (1 << (8*size2-sign))): + return btype2 + raise CDefError("%s values don't all fit into either 'long' " + "or 'unsigned long'" % self._get_c_name()) + +def unknown_type(name, structname=None): + if structname is None: + structname = '$%s' % name + tp = StructType(structname, None, None, None) + tp.force_the_name(name) + tp.origin = "unknown_type" + return tp + +def unknown_ptr_type(name, structname=None): + if structname is None: + structname = '$$%s' % name + tp = StructType(structname, None, None, None) + return NamedPointerType(tp, name) + + +global_lock = allocate_lock() +_typecache_cffi_backend = weakref.WeakValueDictionary() + +def get_typecache(backend): + # returns _typecache_cffi_backend if backend is the _cffi_backend + # module, or type(backend).__typecache if backend is an instance of + # CTypesBackend (or some FakeBackend class during tests) + if isinstance(backend, types.ModuleType): + return _typecache_cffi_backend + with global_lock: + if not hasattr(type(backend), '__typecache'): + type(backend).__typecache = weakref.WeakValueDictionary() + return type(backend).__typecache + +def global_cache(srctype, ffi, funcname, *args, **kwds): + key = kwds.pop('key', (funcname, args)) + assert not kwds + try: + return ffi._typecache[key] + except KeyError: + pass + try: + res = getattr(ffi._backend, funcname)(*args) + except NotImplementedError as e: + raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) + # note that setdefault() on WeakValueDictionary is not atomic + # and contains a rare bug (http://bugs.python.org/issue19542); + # we have to use a lock and do it ourselves + cache = ffi._typecache + with global_lock: + res1 = cache.get(key) + if res1 is None: + cache[key] = res + return res + else: + return res1 + +def pointer_cache(ffi, BType): + return global_cache('?', ffi, 'new_pointer_type', BType) + +def attach_exception_info(e, name): + if e.args and type(e.args[0]) is str: + e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:] diff --git a/myenv/lib/python3.9/site-packages/cffi/parse_c_type.h b/myenv/lib/python3.9/site-packages/cffi/parse_c_type.h new file mode 100644 index 0000000..84e4ef8 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/parse_c_type.h @@ -0,0 +1,181 @@ + +/* This part is from file 'cffi/parse_c_type.h'. It is copied at the + beginning of C sources generated by CFFI's ffi.set_source(). */ + +typedef void *_cffi_opcode_t; + +#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) +#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) +#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) + +#define _CFFI_OP_PRIMITIVE 1 +#define _CFFI_OP_POINTER 3 +#define _CFFI_OP_ARRAY 5 +#define _CFFI_OP_OPEN_ARRAY 7 +#define _CFFI_OP_STRUCT_UNION 9 +#define _CFFI_OP_ENUM 11 +#define _CFFI_OP_FUNCTION 13 +#define _CFFI_OP_FUNCTION_END 15 +#define _CFFI_OP_NOOP 17 +#define _CFFI_OP_BITFIELD 19 +#define _CFFI_OP_TYPENAME 21 +#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs +#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs +#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) +#define _CFFI_OP_CONSTANT 29 +#define _CFFI_OP_CONSTANT_INT 31 +#define _CFFI_OP_GLOBAL_VAR 33 +#define _CFFI_OP_DLOPEN_FUNC 35 +#define _CFFI_OP_DLOPEN_CONST 37 +#define _CFFI_OP_GLOBAL_VAR_F 39 +#define _CFFI_OP_EXTERN_PYTHON 41 + +#define _CFFI_PRIM_VOID 0 +#define _CFFI_PRIM_BOOL 1 +#define _CFFI_PRIM_CHAR 2 +#define _CFFI_PRIM_SCHAR 3 +#define _CFFI_PRIM_UCHAR 4 +#define _CFFI_PRIM_SHORT 5 +#define _CFFI_PRIM_USHORT 6 +#define _CFFI_PRIM_INT 7 +#define _CFFI_PRIM_UINT 8 +#define _CFFI_PRIM_LONG 9 +#define _CFFI_PRIM_ULONG 10 +#define _CFFI_PRIM_LONGLONG 11 +#define _CFFI_PRIM_ULONGLONG 12 +#define _CFFI_PRIM_FLOAT 13 +#define _CFFI_PRIM_DOUBLE 14 +#define _CFFI_PRIM_LONGDOUBLE 15 + +#define _CFFI_PRIM_WCHAR 16 +#define _CFFI_PRIM_INT8 17 +#define _CFFI_PRIM_UINT8 18 +#define _CFFI_PRIM_INT16 19 +#define _CFFI_PRIM_UINT16 20 +#define _CFFI_PRIM_INT32 21 +#define _CFFI_PRIM_UINT32 22 +#define _CFFI_PRIM_INT64 23 +#define _CFFI_PRIM_UINT64 24 +#define _CFFI_PRIM_INTPTR 25 +#define _CFFI_PRIM_UINTPTR 26 +#define _CFFI_PRIM_PTRDIFF 27 +#define _CFFI_PRIM_SIZE 28 +#define _CFFI_PRIM_SSIZE 29 +#define _CFFI_PRIM_INT_LEAST8 30 +#define _CFFI_PRIM_UINT_LEAST8 31 +#define _CFFI_PRIM_INT_LEAST16 32 +#define _CFFI_PRIM_UINT_LEAST16 33 +#define _CFFI_PRIM_INT_LEAST32 34 +#define _CFFI_PRIM_UINT_LEAST32 35 +#define _CFFI_PRIM_INT_LEAST64 36 +#define _CFFI_PRIM_UINT_LEAST64 37 +#define _CFFI_PRIM_INT_FAST8 38 +#define _CFFI_PRIM_UINT_FAST8 39 +#define _CFFI_PRIM_INT_FAST16 40 +#define _CFFI_PRIM_UINT_FAST16 41 +#define _CFFI_PRIM_INT_FAST32 42 +#define _CFFI_PRIM_UINT_FAST32 43 +#define _CFFI_PRIM_INT_FAST64 44 +#define _CFFI_PRIM_UINT_FAST64 45 +#define _CFFI_PRIM_INTMAX 46 +#define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 +#define _CFFI_PRIM_CHAR16 50 +#define _CFFI_PRIM_CHAR32 51 + +#define _CFFI__NUM_PRIM 52 +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) + +#define _CFFI__IO_FILE_STRUCT (-1) + + +struct _cffi_global_s { + const char *name; + void *address; + _cffi_opcode_t type_op; + void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown + // OP_CPYTHON_BLTN_*: addr of direct function +}; + +struct _cffi_getconst_s { + unsigned long long value; + const struct _cffi_type_context_s *ctx; + int gindex; +}; + +struct _cffi_struct_union_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_STRUCT_UNION + int flags; // _CFFI_F_* flags below + size_t size; + int alignment; + int first_field_index; // -> _cffi_fields array + int num_fields; +}; +#define _CFFI_F_UNION 0x01 // is a union, not a struct +#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the + // "standard layout" or if some are missing +#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct +#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() +#define _CFFI_F_OPAQUE 0x10 // opaque + +struct _cffi_field_s { + const char *name; + size_t field_offset; + size_t field_size; + _cffi_opcode_t field_type_op; +}; + +struct _cffi_enum_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_ENUM + int type_prim; // _CFFI_PRIM_xxx + const char *enumerators; // comma-delimited string +}; + +struct _cffi_typename_s { + const char *name; + int type_index; /* if opaque, points to a possibly artificial + OP_STRUCT which is itself opaque */ +}; + +struct _cffi_type_context_s { + _cffi_opcode_t *types; + const struct _cffi_global_s *globals; + const struct _cffi_field_s *fields; + const struct _cffi_struct_union_s *struct_unions; + const struct _cffi_enum_s *enums; + const struct _cffi_typename_s *typenames; + int num_globals; + int num_struct_unions; + int num_enums; + int num_typenames; + const char *const *includes; + int num_types; + int flags; /* future extension */ +}; + +struct _cffi_parse_info_s { + const struct _cffi_type_context_s *ctx; + _cffi_opcode_t *output; + unsigned int output_size; + size_t error_location; + const char *error_message; +}; + +struct _cffi_externpy_s { + const char *name; + size_t size_of_result; + void *reserved1, *reserved2; +}; + +#ifdef _CFFI_INTERNAL +static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); +static int search_in_globals(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +#endif diff --git a/myenv/lib/python3.9/site-packages/cffi/pkgconfig.py b/myenv/lib/python3.9/site-packages/cffi/pkgconfig.py new file mode 100644 index 0000000..5c93f15 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/pkgconfig.py @@ -0,0 +1,121 @@ +# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi +import sys, os, subprocess + +from .error import PkgConfigError + + +def merge_flags(cfg1, cfg2): + """Merge values from cffi config flags cfg2 to cf1 + + Example: + merge_flags({"libraries": ["one"]}, {"libraries": ["two"]}) + {"libraries": ["one", "two"]} + """ + for key, value in cfg2.items(): + if key not in cfg1: + cfg1[key] = value + else: + if not isinstance(cfg1[key], list): + raise TypeError("cfg1[%r] should be a list of strings" % (key,)) + if not isinstance(value, list): + raise TypeError("cfg2[%r] should be a list of strings" % (key,)) + cfg1[key].extend(value) + return cfg1 + + +def call(libname, flag, encoding=sys.getfilesystemencoding()): + """Calls pkg-config and returns the output if found + """ + a = ["pkg-config", "--print-errors"] + a.append(flag) + a.append(libname) + try: + pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except EnvironmentError as e: + raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),)) + + bout, berr = pc.communicate() + if pc.returncode != 0: + try: + berr = berr.decode(encoding) + except Exception: + pass + raise PkgConfigError(berr.strip()) + + if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x + try: + bout = bout.decode(encoding) + except UnicodeDecodeError: + raise PkgConfigError("pkg-config %s %s returned bytes that cannot " + "be decoded with encoding %r:\n%r" % + (flag, libname, encoding, bout)) + + if os.altsep != '\\' and '\\' in bout: + raise PkgConfigError("pkg-config %s %s returned an unsupported " + "backslash-escaped output:\n%r" % + (flag, libname, bout)) + return bout + + +def flags_from_pkgconfig(libs): + r"""Return compiler line flags for FFI.set_source based on pkg-config output + + Usage + ... + ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"]) + + If pkg-config is installed on build machine, then arguments include_dirs, + library_dirs, libraries, define_macros, extra_compile_args and + extra_link_args are extended with an output of pkg-config for libfoo and + libbar. + + Raises PkgConfigError in case the pkg-config call fails. + """ + + def get_include_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-I")] + + def get_library_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-L")] + + def get_libraries(string): + return [x[2:] for x in string.split() if x.startswith("-l")] + + # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils + def get_macros(string): + def _macro(x): + x = x[2:] # drop "-D" + if '=' in x: + return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar") + else: + return (x, None) # "-Dfoo" => ("foo", None) + return [_macro(x) for x in string.split() if x.startswith("-D")] + + def get_other_cflags(string): + return [x for x in string.split() if not x.startswith("-I") and + not x.startswith("-D")] + + def get_other_libs(string): + return [x for x in string.split() if not x.startswith("-L") and + not x.startswith("-l")] + + # return kwargs for given libname + def kwargs(libname): + fse = sys.getfilesystemencoding() + all_cflags = call(libname, "--cflags") + all_libs = call(libname, "--libs") + return { + "include_dirs": get_include_dirs(all_cflags), + "library_dirs": get_library_dirs(all_libs), + "libraries": get_libraries(all_libs), + "define_macros": get_macros(all_cflags), + "extra_compile_args": get_other_cflags(all_cflags), + "extra_link_args": get_other_libs(all_libs), + } + + # merge all arguments together + ret = {} + for libname in libs: + lib_flags = kwargs(libname) + merge_flags(ret, lib_flags) + return ret diff --git a/myenv/lib/python3.9/site-packages/cffi/recompiler.py b/myenv/lib/python3.9/site-packages/cffi/recompiler.py new file mode 100644 index 0000000..5d9d32d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/recompiler.py @@ -0,0 +1,1581 @@ +import os, sys, io +from . import ffiplatform, model +from .error import VerificationError +from .cffi_opcode import * + +VERSION_BASE = 0x2601 +VERSION_EMBEDDED = 0x2701 +VERSION_CHAR16CHAR32 = 0x2801 + +USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or + sys.version_info >= (3, 5)) + + +class GlobalExpr: + def __init__(self, name, address, type_op, size=0, check_value=0): + self.name = name + self.address = address + self.type_op = type_op + self.size = size + self.check_value = check_value + + def as_c_expr(self): + return ' { "%s", (void *)%s, %s, (void *)%s },' % ( + self.name, self.address, self.type_op.as_c_expr(), self.size) + + def as_python_expr(self): + return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, + self.check_value) + +class FieldExpr: + def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): + self.name = name + self.field_offset = field_offset + self.field_size = field_size + self.fbitsize = fbitsize + self.field_type_op = field_type_op + + def as_c_expr(self): + spaces = " " * len(self.name) + return (' { "%s", %s,\n' % (self.name, self.field_offset) + + ' %s %s,\n' % (spaces, self.field_size) + + ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) + + def as_python_expr(self): + raise NotImplementedError + + def as_field_python_expr(self): + if self.field_type_op.op == OP_NOOP: + size_expr = '' + elif self.field_type_op.op == OP_BITFIELD: + size_expr = format_four_bytes(self.fbitsize) + else: + raise NotImplementedError + return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), + size_expr, + self.name) + +class StructUnionExpr: + def __init__(self, name, type_index, flags, size, alignment, comment, + first_field_index, c_fields): + self.name = name + self.type_index = type_index + self.flags = flags + self.size = size + self.alignment = alignment + self.comment = comment + self.first_field_index = first_field_index + self.c_fields = c_fields + + def as_c_expr(self): + return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) + + '\n %s, %s, ' % (self.size, self.alignment) + + '%d, %d ' % (self.first_field_index, len(self.c_fields)) + + ('/* %s */ ' % self.comment if self.comment else '') + + '},') + + def as_python_expr(self): + flags = eval(self.flags, G_FLAGS) + fields_expr = [c_field.as_field_python_expr() + for c_field in self.c_fields] + return "(b'%s%s%s',%s)" % ( + format_four_bytes(self.type_index), + format_four_bytes(flags), + self.name, + ','.join(fields_expr)) + +class EnumExpr: + def __init__(self, name, type_index, size, signed, allenums): + self.name = name + self.type_index = type_index + self.size = size + self.signed = signed + self.allenums = allenums + + def as_c_expr(self): + return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' + ' "%s" },' % (self.name, self.type_index, + self.size, self.signed, self.allenums)) + + def as_python_expr(self): + prim_index = { + (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, + (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, + (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, + (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, + }[self.size, self.signed] + return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), + format_four_bytes(prim_index), + self.name, self.allenums) + +class TypenameExpr: + def __init__(self, name, type_index): + self.name = name + self.type_index = type_index + + def as_c_expr(self): + return ' { "%s", %d },' % (self.name, self.type_index) + + def as_python_expr(self): + return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) + + +# ____________________________________________________________ + + +class Recompiler: + _num_externpy = 0 + + def __init__(self, ffi, module_name, target_is_python=False): + self.ffi = ffi + self.module_name = module_name + self.target_is_python = target_is_python + self._version = VERSION_BASE + + def needs_version(self, ver): + self._version = max(self._version, ver) + + def collect_type_table(self): + self._typesdict = {} + self._generate("collecttype") + # + all_decls = sorted(self._typesdict, key=str) + # + # prepare all FUNCTION bytecode sequences first + self.cffi_types = [] + for tp in all_decls: + if tp.is_raw_function: + assert self._typesdict[tp] is None + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + for tp1 in tp.args: + assert isinstance(tp1, (model.VoidType, + model.BasePrimitiveType, + model.PointerType, + model.StructOrUnionOrEnum, + model.FunctionPtrType)) + if self._typesdict[tp1] is None: + self._typesdict[tp1] = len(self.cffi_types) + self.cffi_types.append(tp1) # placeholder + self.cffi_types.append('END') # placeholder + # + # prepare all OTHER bytecode sequences + for tp in all_decls: + if not tp.is_raw_function and self._typesdict[tp] is None: + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + if tp.is_array_type and tp.length is not None: + self.cffi_types.append('LEN') # placeholder + assert None not in self._typesdict.values() + # + # collect all structs and unions and enums + self._struct_unions = {} + self._enums = {} + for tp in all_decls: + if isinstance(tp, model.StructOrUnion): + self._struct_unions[tp] = None + elif isinstance(tp, model.EnumType): + self._enums[tp] = None + for i, tp in enumerate(sorted(self._struct_unions, + key=lambda tp: tp.name)): + self._struct_unions[tp] = i + for i, tp in enumerate(sorted(self._enums, + key=lambda tp: tp.name)): + self._enums[tp] = i + # + # emit all bytecode sequences now + for tp in all_decls: + method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) + method(tp, self._typesdict[tp]) + # + # consistency check + for op in self.cffi_types: + assert isinstance(op, CffiOp) + self.cffi_types = tuple(self.cffi_types) # don't change any more + + def _enum_fields(self, tp): + # When producing C, expand all anonymous struct/union fields. + # That's necessary to have C code checking the offsets of the + # individual fields contained in them. When producing Python, + # don't do it and instead write it like it is, with the + # corresponding fields having an empty name. Empty names are + # recognized at runtime when we import the generated Python + # file. + expand_anonymous_struct_union = not self.target_is_python + return tp.enumfields(expand_anonymous_struct_union) + + def _do_collect_type(self, tp): + if not isinstance(tp, model.BaseTypeByIdentity): + if isinstance(tp, tuple): + for x in tp: + self._do_collect_type(x) + return + if tp not in self._typesdict: + self._typesdict[tp] = None + if isinstance(tp, model.FunctionPtrType): + self._do_collect_type(tp.as_raw_function()) + elif isinstance(tp, model.StructOrUnion): + if tp.fldtypes is not None and ( + tp not in self.ffi._parser._included_declarations): + for name1, tp1, _, _ in self._enum_fields(tp): + self._do_collect_type(self._field_type(tp, name1, tp1)) + else: + for _, x in tp._get_items(): + self._do_collect_type(x) + + def _generate(self, step_name): + lst = self.ffi._parser._declarations.items() + for name, (tp, quals) in sorted(lst): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in recompile(): %r" % name) + try: + self._current_quals = quals + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + # ---------- + + ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] + + def collect_step_tables(self): + # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. + self._lsts = {} + for step_name in self.ALL_STEPS: + self._lsts[step_name] = [] + self._seen_struct_unions = set() + self._generate("ctx") + self._add_missing_struct_unions() + # + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if step_name != "field": + lst.sort(key=lambda entry: entry.name) + self._lsts[step_name] = tuple(lst) # don't change any more + # + # check for a possible internal inconsistency: _cffi_struct_unions + # should have been generated with exactly self._struct_unions + lst = self._lsts["struct_union"] + for tp, i in self._struct_unions.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._struct_unions) + # same with enums + lst = self._lsts["enum"] + for tp, i in self._enums.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._enums) + + # ---------- + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self, f, preamble): + if self.target_is_python: + assert preamble is None + self.write_py_source_to_f(f) + else: + assert preamble is not None + self.write_c_source_to_f(f, preamble) + + def _rel_readlines(self, filename): + g = open(os.path.join(os.path.dirname(__file__), filename), 'r') + lines = g.readlines() + g.close() + return lines + + def write_c_source_to_f(self, f, preamble): + self._f = f + prnt = self._prnt + if self.ffi._embedding is not None: + prnt('#define _CFFI_USE_EMBEDDING') + if not USE_LIMITED_API: + prnt('#define _CFFI_NO_LIMITED_API') + # + # first the '#include' (actually done by inlining the file's content) + lines = self._rel_readlines('_cffi_include.h') + i = lines.index('#include "parse_c_type.h"\n') + lines[i:i+1] = self._rel_readlines('parse_c_type.h') + prnt(''.join(lines)) + # + # if we have ffi._embedding != None, we give it here as a macro + # and include an extra file + base_module_name = self.module_name.split('.')[-1] + if self.ffi._embedding is not None: + prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) + prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') + self._print_string_literal_in_array(self.ffi._embedding) + prnt('0 };') + prnt('#ifdef PYPY_VERSION') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( + base_module_name,)) + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( + base_module_name,)) + prnt('#else') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( + base_module_name,)) + prnt('#endif') + lines = self._rel_readlines('_embedding.h') + i = lines.index('#include "_cffi_errors.h"\n') + lines[i:i+1] = self._rel_readlines('_cffi_errors.h') + prnt(''.join(lines)) + self.needs_version(VERSION_EMBEDDED) + # + # then paste the C source given by the user, verbatim. + prnt('/************************************************************/') + prnt() + prnt(preamble) + prnt() + prnt('/************************************************************/') + prnt() + # + # the declaration of '_cffi_types' + prnt('static void *_cffi_types[] = {') + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + for i, op in enumerate(self.cffi_types): + comment = '' + if i in typeindex2type: + comment = ' // ' + typeindex2type[i]._get_c_name() + prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) + if not self.cffi_types: + prnt(' 0') + prnt('};') + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._seen_constants = set() + self._generate("decl") + # + # the declaration of '_cffi_globals' and '_cffi_typenames' + nums = {} + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + nums[step_name] = len(lst) + if nums[step_name] > 0: + prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( + step_name, step_name)) + for entry in lst: + prnt(entry.as_c_expr()) + prnt('};') + prnt() + # + # the declaration of '_cffi_includes' + if self.ffi._included_ffis: + prnt('static const char * const _cffi_includes[] = {') + for ffi_to_include in self.ffi._included_ffis: + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is None: + raise VerificationError( + "not implemented yet: ffi.include() of a Python-based " + "ffi inside a C-based ffi") + prnt(' "%s",' % (included_module_name,)) + prnt(' NULL') + prnt('};') + prnt() + # + # the declaration of '_cffi_type_context' + prnt('static const struct _cffi_type_context_s _cffi_type_context = {') + prnt(' _cffi_types,') + for step_name in self.ALL_STEPS: + if nums[step_name] > 0: + prnt(' _cffi_%ss,' % step_name) + else: + prnt(' NULL, /* no %ss */' % step_name) + for step_name in self.ALL_STEPS: + if step_name != "field": + prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) + if self.ffi._included_ffis: + prnt(' _cffi_includes,') + else: + prnt(' NULL, /* no includes */') + prnt(' %d, /* num_types */' % (len(self.cffi_types),)) + flags = 0 + if self._num_externpy > 0 or self.ffi._embedding is not None: + flags |= 1 # set to mean that we use extern "Python" + prnt(' %d, /* flags */' % flags) + prnt('};') + prnt() + # + # the init function + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') + prnt('#endif') + prnt() + prnt('#ifdef PYPY_VERSION') + prnt('PyMODINIT_FUNC') + prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) + prnt('{') + if flags & 1: + prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') + prnt(' _cffi_call_python_org = ' + '(void(*)(struct _cffi_externpy_s *, char *))p[1];') + prnt(' }') + prnt(' p[0] = (const void *)0x%x;' % self._version) + prnt(' p[1] = &_cffi_type_context;') + prnt('#if PY_MAJOR_VERSION >= 3') + prnt(' return NULL;') + prnt('#endif') + prnt('}') + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + prnt('# ifdef _MSC_VER') + prnt(' PyMODINIT_FUNC') + prnt('# if PY_MAJOR_VERSION >= 3') + prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) + prnt('# else') + prnt(' init%s(void) { }' % (base_module_name,)) + prnt('# endif') + prnt('# endif') + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % (base_module_name,)) + prnt('{') + prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#else') + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % (base_module_name,)) + prnt('{') + prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#endif') + prnt() + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility pop') + prnt('#endif') + self._version = None + + def _to_py(self, x): + if isinstance(x, str): + return "b'%s'" % (x,) + if isinstance(x, (list, tuple)): + rep = [self._to_py(item) for item in x] + if len(rep) == 1: + rep.append('') + return "(%s)" % (','.join(rep),) + return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. + + def write_py_source_to_f(self, f): + self._f = f + prnt = self._prnt + # + # header + prnt("# auto-generated file") + prnt("import _cffi_backend") + # + # the 'import' of the included ffis + num_includes = len(self.ffi._included_ffis or ()) + for i in range(num_includes): + ffi_to_include = self.ffi._included_ffis[i] + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is not None: + raise VerificationError( + "not implemented yet: ffi.include() of a C-based " + "ffi inside a Python-based ffi") + prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) + prnt() + prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) + prnt(" _version = 0x%x," % (self._version,)) + self._version = None + # + # the '_types' keyword argument + self.cffi_types = tuple(self.cffi_types) # don't change any more + types_lst = [op.as_python_bytes() for op in self.cffi_types] + prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + # + # the keyword arguments from ALL_STEPS + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if len(lst) > 0 and step_name != "field": + prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) + # + # the '_includes' keyword argument + if num_includes > 0: + prnt(' _includes = (%s,),' % ( + ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) + # + # the footer + prnt(')') + + # ---------- + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) + else: + cname = tp.get_c_name('') + converter = '(%s)_cffi_to_c_%s' % (cname, + tp.name.replace(' ', '_')) + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + '(%s)alloca((size_t)datasize) : NULL;' % ( + tovar, tp.get_c_name(''))) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.BasePrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) + elif tp.name != 'long double' and not tp.is_complex_type(): + cname = tp.name.replace(' ', '_') + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + return '_cffi_from_c_%s(%s)' % (cname, var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs + + def _typedef_type(self, tp, name): + return self._global_type(tp, "(*(%s *)0)" % (name,)) + + def _generate_cpy_typedef_collecttype(self, tp, name): + self._do_collect_type(self._typedef_type(tp, name)) + + def _generate_cpy_typedef_decl(self, tp, name): + pass + + def _typedef_ctx(self, tp, name): + type_index = self._typesdict[tp] + self._lsts["typename"].append(TypenameExpr(name, type_index)) + + def _generate_cpy_typedef_ctx(self, tp, name): + tp = self._typedef_type(tp, name) + self._typedef_ctx(tp, name) + if getattr(tp, "origin", None) == "unknown_type": + self._struct_ctx(tp, tp.name, approxname=None) + elif isinstance(tp, model.NamedPointerType): + self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, + named_ptr=tp) + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + self._do_collect_type(tp.as_raw_function()) + if tp.ellipsis and not self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_function_decl(self, tp, name): + assert not self.target_is_python + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_constant_decl(tp, name) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + # + # ------------------------------ + # the 'd' version of the function, only for addressof(lib, 'func') + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arguments.append(type.get_c_name(' x%d' % i, context)) + call_arguments.append('x%d' % i) + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) + prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) + prnt('{') + call_arguments = ', '.join(call_arguments) + result_code = 'return ' + if isinstance(tp.result, model.VoidType): + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, call_arguments)) + prnt('}') + # + prnt('#ifndef PYPY_VERSION') # ------------------------------ + # + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' x%d' % i, context) + prnt(' %s;' % arg) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + result_decl = ' %s;' % tp.result.get_c_name(' result', context) + prnt(result_decl) + prnt(' PyObject *pyresult;') + else: + result_decl = None + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( + name, len(rng), len(rng), + ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + call_arguments = ['x%d' % i for i in range(len(tp.args))] + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + # + prnt('#else') # ------------------------------ + # + # the PyPy version: need to replace struct/union arguments with + # pointers, and if the result is a struct/union, insert a first + # arg that is a pointer to the result. We also do that for + # complex args and return type. + def need_indirection(type): + return (isinstance(type, model.StructOrUnion) or + (isinstance(type, model.PrimitiveType) and + type.is_complex_type())) + difference = False + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + indirection = '' + if need_indirection(type): + indirection = '*' + difference = True + arg = type.get_c_name(' %sx%d' % (indirection, i), context) + arguments.append(arg) + call_arguments.append('%sx%d' % (indirection, i)) + tp_result = tp.result + if need_indirection(tp_result): + context = 'result of %s' % name + arg = tp_result.get_c_name(' *result', context) + arguments.insert(0, arg) + tp_result = model.void_type + result_decl = None + result_code = '*result = ' + difference = True + if difference: + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, + repr_arguments) + prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) + prnt('{') + if result_decl: + prnt(result_decl) + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + if result_decl: + prnt(' return result;') + prnt('}') + else: + prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) + # + prnt('#endif') # ------------------------------ + prnt() + + def _generate_cpy_function_ctx(self, tp, name): + if tp.ellipsis and not self.target_is_python: + self._generate_cpy_constant_ctx(tp, name) + return + type_index = self._typesdict[tp.as_raw_function()] + numargs = len(tp.args) + if self.target_is_python: + meth_kind = OP_DLOPEN_FUNC + elif numargs == 0: + meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' + elif numargs == 1: + meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' + else: + meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' + self._lsts["global"].append( + GlobalExpr(name, '_cffi_f_%s' % name, + CffiOp(meth_kind, type_index), + size='_cffi_d_%s' % name)) + + # ---------- + # named structs or unions + + def _field_type(self, tp_struct, field_name, tp_field): + if isinstance(tp_field, model.ArrayType): + actual_length = tp_field.length + if actual_length == '...': + ptr_struct_name = tp_struct.get_c_name('*') + actual_length = '_cffi_array_len(((%s)0)->%s)' % ( + ptr_struct_name, field_name) + tp_item = self._field_type(tp_struct, '%s[0]' % field_name, + tp_field.item) + tp_field = model.ArrayType(tp_item, actual_length) + return tp_field + + def _struct_collecttype(self, tp): + self._do_collect_type(tp) + if self.target_is_python: + # also requires nested anon struct/unions in ABI mode, recursively + for fldtype in tp.anonymous_struct_fields(): + self._struct_collecttype(fldtype) + + def _struct_decl(self, tp, cname, approxname): + if tp.fldtypes is None: + return + prnt = self._prnt + checkfuncname = '_cffi_checkfld_%s' % (approxname,) + prnt('_CFFI_UNUSED_FN') + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in self._enum_fields(tp): + try: + if ftype.is_integer_type() or fbitsize >= 0: + # accept all integers, but complain on float or double + if fname != '': + prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " + "an integer */" % (fname, cname, fname)) + continue + # only accept exactly the type declared, except that '[]' + # is interpreted as a '*' and so will match any array length. + # (It would also match '*', but that's harder to detect...) + while (isinstance(ftype, model.ArrayType) + and (ftype.length is None or ftype.length == '...')): + ftype = ftype.item + fname = fname + '[0]' + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) + prnt() + + def _struct_ctx(self, tp, cname, approxname, named_ptr=None): + type_index = self._typesdict[tp] + reason_for_not_expanding = None + flags = [] + if isinstance(tp, model.UnionType): + flags.append("_CFFI_F_UNION") + if tp.fldtypes is None: + flags.append("_CFFI_F_OPAQUE") + reason_for_not_expanding = "opaque" + if (tp not in self.ffi._parser._included_declarations and + (named_ptr is None or + named_ptr not in self.ffi._parser._included_declarations)): + if tp.fldtypes is None: + pass # opaque + elif tp.partial or any(tp.anonymous_struct_fields()): + pass # field layout obtained silently from the C compiler + else: + flags.append("_CFFI_F_CHECK_FIELDS") + if tp.packed: + if tp.packed > 1: + raise NotImplementedError( + "%r is declared with 'pack=%r'; only 0 or 1 are " + "supported in API mode (try to use \"...;\", which " + "does not require a 'pack' declaration)" % + (tp, tp.packed)) + flags.append("_CFFI_F_PACKED") + else: + flags.append("_CFFI_F_EXTERNAL") + reason_for_not_expanding = "external" + flags = '|'.join(flags) or '0' + c_fields = [] + if reason_for_not_expanding is None: + enumfields = list(self._enum_fields(tp)) + for fldname, fldtype, fbitsize, fqual in enumfields: + fldtype = self._field_type(tp, fldname, fldtype) + self._check_not_opaque(fldtype, + "field '%s.%s'" % (tp.name, fldname)) + # cname is None for _add_missing_struct_unions() only + op = OP_NOOP + if fbitsize >= 0: + op = OP_BITFIELD + size = '%d /* bits */' % fbitsize + elif cname is None or ( + isinstance(fldtype, model.ArrayType) and + fldtype.length is None): + size = '(size_t)-1' + else: + size = 'sizeof(((%s)0)->%s)' % ( + tp.get_c_name('*') if named_ptr is None + else named_ptr.name, + fldname) + if cname is None or fbitsize >= 0: + offset = '(size_t)-1' + elif named_ptr is not None: + offset = '((char *)&((%s)0)->%s) - (char *)0' % ( + named_ptr.name, fldname) + else: + offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) + c_fields.append( + FieldExpr(fldname, offset, size, fbitsize, + CffiOp(op, self._typesdict[fldtype]))) + first_field_index = len(self._lsts["field"]) + self._lsts["field"].extend(c_fields) + # + if cname is None: # unknown name, for _add_missing_struct_unions + size = '(size_t)-2' + align = -2 + comment = "unnamed" + else: + if named_ptr is not None: + size = 'sizeof(*(%s)0)' % (named_ptr.name,) + align = '-1 /* unknown alignment */' + else: + size = 'sizeof(%s)' % (cname,) + align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) + comment = None + else: + size = '(size_t)-1' + align = -1 + first_field_index = -1 + comment = reason_for_not_expanding + self._lsts["struct_union"].append( + StructUnionExpr(tp.name, type_index, flags, size, align, comment, + first_field_index, c_fields)) + self._seen_struct_unions.add(tp) + + def _check_not_opaque(self, tp, location): + while isinstance(tp, model.ArrayType): + tp = tp.item + if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: + raise TypeError( + "%s is of an opaque type (not declared in cdef())" % location) + + def _add_missing_struct_unions(self): + # not very nice, but some struct declarations might be missing + # because they don't have any known C name. Check that they are + # not partial (we can't complete or verify them!) and emit them + # anonymously. + lst = list(self._struct_unions.items()) + lst.sort(key=lambda tp_order: tp_order[1]) + for tp, order in lst: + if tp not in self._seen_struct_unions: + if tp.partial: + raise NotImplementedError("internal inconsistency: %r is " + "partial but was not seen at " + "this point" % (tp,)) + if tp.name.startswith('$') and tp.name[1:].isdigit(): + approxname = tp.name[1:] + elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': + approxname = 'FILE' + self._typedef_ctx(tp, 'FILE') + else: + raise NotImplementedError("internal inconsistency: %r" % + (tp,)) + self._struct_ctx(tp, None, approxname) + + def _generate_cpy_struct_collecttype(self, tp, name): + self._struct_collecttype(tp) + _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype + + def _struct_names(self, tp): + cname = tp.get_c_name('') + if ' ' in cname: + return cname, cname.replace(' ', '_') + else: + return cname, '_' + cname + + def _generate_cpy_struct_decl(self, tp, name): + self._struct_decl(tp, *self._struct_names(tp)) + _generate_cpy_union_decl = _generate_cpy_struct_decl + + def _generate_cpy_struct_ctx(self, tp, name): + self._struct_ctx(tp, *self._struct_names(tp)) + _generate_cpy_union_ctx = _generate_cpy_struct_ctx + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_cpy_anonymous_collecttype(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_collecttype(tp, name) + else: + self._struct_collecttype(tp) + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp) + else: + self._struct_decl(tp, name, 'typedef_' + name) + + def _generate_cpy_anonymous_ctx(self, tp, name): + if isinstance(tp, model.EnumType): + self._enum_ctx(tp, name) + else: + self._struct_ctx(tp, name, 'typedef_' + name) + + # ---------- + # constants, declared with "static const ..." + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + check_value=None): + if (category, name) in self._seen_constants: + raise VerificationError( + "duplicate declaration of %s '%s'" % (category, name)) + self._seen_constants.add((category, name)) + # + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + if is_int: + prnt('static int %s(unsigned long long *o)' % funcname) + prnt('{') + prnt(' int n = (%s) <= 0;' % (name,)) + prnt(' *o = (unsigned long long)((%s) | 0);' + ' /* check that %s is an integer */' % (name, name)) + if check_value is not None: + if check_value > 0: + check_value = '%dU' % (check_value,) + prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) + prnt(' n |= 2;') + prnt(' return n;') + prnt('}') + else: + assert check_value is None + prnt('static void %s(char *o)' % funcname) + prnt('{') + prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = tp.is_integer_type() + if not is_int or self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + def _generate_cpy_constant_ctx(self, tp, name): + if not self.target_is_python and tp.is_integer_type(): + type_op = CffiOp(OP_CONSTANT_INT, -1) + else: + if self.target_is_python: + const_kind = OP_DLOPEN_CONST + else: + const_kind = OP_CONSTANT + type_index = self._typesdict[tp] + type_op = CffiOp(const_kind, type_index) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op)) + + # ---------- + # enums + + def _generate_cpy_enum_collecttype(self, tp, name): + self._do_collect_type(tp) + + def _generate_cpy_enum_decl(self, tp, name=None): + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator) + + def _enum_ctx(self, tp, cname): + type_index = self._typesdict[tp] + type_op = CffiOp(OP_ENUM, -1) + if self.target_is_python: + tp.check_not_partial() + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._lsts["global"].append( + GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, + check_value=enumvalue)) + # + if cname is not None and '$' not in cname and not self.target_is_python: + size = "sizeof(%s)" % cname + signed = "((%s)-1) <= 0" % cname + else: + basetp = tp.build_baseinttype(self.ffi, []) + size = self.ffi.sizeof(basetp) + signed = int(int(self.ffi.cast(basetp, -1)) < 0) + allenums = ",".join(tp.enumerators) + self._lsts["enum"].append( + EnumExpr(tp.name, type_index, size, signed, allenums)) + + def _generate_cpy_enum_ctx(self, tp, name): + self._enum_ctx(tp, tp._get_c_name()) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_collecttype(self, tp, name): + pass + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + def _generate_cpy_macro_ctx(self, tp, name): + if tp == '...': + if self.target_is_python: + raise VerificationError( + "cannot use the syntax '...' in '#define %s ...' when " + "using the ABI mode" % (name,)) + check_value = None + else: + check_value = tp # an integer + type_op = CffiOp(OP_CONSTANT_INT, -1) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op, + check_value=check_value)) + + # ---------- + # global variables + + def _global_type(self, tp, global_name): + if isinstance(tp, model.ArrayType): + actual_length = tp.length + if actual_length == '...': + actual_length = '_cffi_array_len(%s)' % (global_name,) + tp_item = self._global_type(tp.item, '%s[0]' % global_name) + tp = model.ArrayType(tp_item, actual_length) + return tp + + def _generate_cpy_variable_collecttype(self, tp, name): + self._do_collect_type(self._global_type(tp, name)) + + def _generate_cpy_variable_decl(self, tp, name): + prnt = self._prnt + tp = self._global_type(tp, name) + if isinstance(tp, model.ArrayType) and tp.length is None: + tp = tp.item + ampersand = '' + else: + ampersand = '&' + # This code assumes that casts from "tp *" to "void *" is a + # no-op, i.e. a function that returns a "tp *" can be called + # as if it returned a "void *". This should be generally true + # on any modern machine. The only exception to that rule (on + # uncommon architectures, and as far as I can tell) might be + # if 'tp' were a function type, but that is not possible here. + # (If 'tp' is a function _pointer_ type, then casts from "fn_t + # **" to "void *" are again no-ops, as far as I can tell.) + decl = '*_cffi_var_%s(void)' % (name,) + prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) + prnt('{') + prnt(' return %s(%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_cpy_variable_ctx(self, tp, name): + tp = self._global_type(tp, name) + type_index = self._typesdict[tp] + if self.target_is_python: + op = OP_GLOBAL_VAR + else: + op = OP_GLOBAL_VAR_F + self._lsts["global"].append( + GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) + + # ---------- + # extern "Python" + + def _generate_cpy_extern_python_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + self._do_collect_type(tp) + _generate_cpy_dllexport_python_collecttype = \ + _generate_cpy_extern_python_plus_c_collecttype = \ + _generate_cpy_extern_python_collecttype + + def _extern_python_decl(self, tp, name, tag_and_space): + prnt = self._prnt + if isinstance(tp.result, model.VoidType): + size_of_result = '0' + else: + context = 'result of %s' % name + size_of_result = '(int)sizeof(%s)' % ( + tp.result.get_c_name('', context),) + prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) + prnt(' { "%s.%s", %s, 0, 0 };' % ( + self.module_name, name, size_of_result)) + prnt() + # + arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' a%d' % i, context) + arguments.append(arg) + # + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s(%s)' % (name, repr_arguments) + if tp.abi == "__stdcall": + name_and_arguments = '_cffi_stdcall ' + name_and_arguments + # + def may_need_128_bits(tp): + return (isinstance(tp, model.PrimitiveType) and + tp.name == 'long double') + # + size_of_a = max(len(tp.args)*8, 8) + if may_need_128_bits(tp.result): + size_of_a = max(size_of_a, 16) + if isinstance(tp.result, model.StructOrUnion): + size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( + tp.result.get_c_name(''), size_of_a, + tp.result.get_c_name(''), size_of_a) + prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) + prnt('{') + prnt(' char a[%s];' % size_of_a) + prnt(' char *p = a;') + for i, type in enumerate(tp.args): + arg = 'a%d' % i + if (isinstance(type, model.StructOrUnion) or + may_need_128_bits(type)): + arg = '&' + arg + type = model.PointerType(type) + prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) + prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) + if not isinstance(tp.result, model.VoidType): + prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) + prnt('}') + prnt() + self._num_externpy += 1 + + def _generate_cpy_extern_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'static ') + + def _generate_cpy_dllexport_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') + + def _generate_cpy_extern_python_plus_c_decl(self, tp, name): + self._extern_python_decl(tp, name, '') + + def _generate_cpy_extern_python_ctx(self, tp, name): + if self.target_is_python: + raise VerificationError( + "cannot use 'extern \"Python\"' in the ABI mode") + if tp.ellipsis: + raise NotImplementedError("a vararg function is extern \"Python\"") + type_index = self._typesdict[tp] + type_op = CffiOp(OP_EXTERN_PYTHON, type_index) + self._lsts["global"].append( + GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) + + _generate_cpy_dllexport_python_ctx = \ + _generate_cpy_extern_python_plus_c_ctx = \ + _generate_cpy_extern_python_ctx + + def _print_string_literal_in_array(self, s): + prnt = self._prnt + prnt('// # NB. this is not a string because of a size limit in MSVC') + if not isinstance(s, bytes): # unicode + s = s.encode('utf-8') # -> bytes + else: + s.decode('utf-8') # got bytes, check for valid utf-8 + try: + s.decode('ascii') + except UnicodeDecodeError: + s = b'# -*- encoding: utf8 -*-\n' + s + for line in s.splitlines(True): + comment = line + if type('//') is bytes: # python2 + line = map(ord, line) # make a list of integers + else: # python3 + # type(line) is bytes, which enumerates like a list of integers + comment = ascii(comment)[1:-1] + prnt(('// ' + comment).rstrip()) + printed_line = '' + for c in line: + if len(printed_line) >= 76: + prnt(printed_line) + printed_line = '' + printed_line += '%d,' % (c,) + prnt(printed_line) + + # ---------- + # emitting the opcodes for individual types + + def _emit_bytecode_VoidType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) + + def _emit_bytecode_PrimitiveType(self, tp, index): + prim_index = PRIMITIVE_TO_INDEX[tp.name] + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) + + def _emit_bytecode_UnknownIntegerType(self, tp, index): + s = ('_cffi_prim_int(sizeof(%s), (\n' + ' ((%s)-1) | 0 /* check that %s is an integer type */\n' + ' ) <= 0)' % (tp.name, tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_RawFunctionType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) + index += 1 + for tp1 in tp.args: + realindex = self._typesdict[tp1] + if index != realindex: + if isinstance(tp1, model.PrimitiveType): + self._emit_bytecode_PrimitiveType(tp1, index) + else: + self.cffi_types[index] = CffiOp(OP_NOOP, realindex) + index += 1 + flags = int(tp.ellipsis) + if tp.abi is not None: + if tp.abi == '__stdcall': + flags |= 2 + else: + raise NotImplementedError("abi=%r" % (tp.abi,)) + self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) + + def _emit_bytecode_PointerType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) + + _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType + _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType + + def _emit_bytecode_FunctionPtrType(self, tp, index): + raw = tp.as_raw_function() + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) + + def _emit_bytecode_ArrayType(self, tp, index): + item_index = self._typesdict[tp.item] + if tp.length is None: + self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) + elif tp.length == '...': + raise VerificationError( + "type %s badly placed: the '...' array length can only be " + "used on global arrays or on fields of structures" % ( + str(tp).replace('/*...*/', '...'),)) + else: + assert self.cffi_types[index + 1] == 'LEN' + self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) + self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) + + def _emit_bytecode_StructType(self, tp, index): + struct_index = self._struct_unions[tp] + self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) + _emit_bytecode_UnionType = _emit_bytecode_StructType + + def _emit_bytecode_EnumType(self, tp, index): + enum_index = self._enums[tp] + self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + +def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): + if verbose: + print("generating %s" % (target_file,)) + recompiler = Recompiler(ffi, module_name, + target_is_python=(preamble is None)) + recompiler.collect_type_table() + recompiler.collect_step_tables() + f = NativeIO() + recompiler.write_source_to_f(f, preamble) + output = f.getvalue() + try: + with open(target_file, 'r') as f1: + if f1.read(len(output) + 1) != output: + raise IOError + if verbose: + print("(already up-to-date)") + return False # already up-to-date + except IOError: + tmp_file = '%s.~%d' % (target_file, os.getpid()) + with open(tmp_file, 'w') as f1: + f1.write(output) + try: + os.rename(tmp_file, target_file) + except OSError: + os.unlink(target_file) + os.rename(tmp_file, target_file) + return True + +def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): + assert preamble is not None + return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, + verbose) + +def make_py_source(ffi, module_name, target_py_file, verbose=False): + return _make_c_or_py_source(ffi, module_name, None, target_py_file, + verbose) + +def _modname_to_file(outputdir, modname, extension): + parts = modname.split('.') + try: + os.makedirs(os.path.join(outputdir, *parts[:-1])) + except OSError: + pass + parts[-1] += extension + return os.path.join(outputdir, *parts), parts + + +# Aaargh. Distutils is not tested at all for the purpose of compiling +# DLLs that are not extension modules. Here are some hacks to work +# around that, in the _patch_for_*() functions... + +def _patch_meth(patchlist, cls, name, new_meth): + old = getattr(cls, name) + patchlist.append((cls, name, old)) + setattr(cls, name, new_meth) + return old + +def _unpatch_meths(patchlist): + for cls, name, old_meth in reversed(patchlist): + setattr(cls, name, old_meth) + +def _patch_for_embedding(patchlist): + if sys.platform == 'win32': + # we must not remove the manifest when building for embedding! + from distutils.msvc9compiler import MSVCCompiler + _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', + lambda self, manifest_file: manifest_file) + + if sys.platform == 'darwin': + # we must not make a '-bundle', but a '-dynamiclib' instead + from distutils.ccompiler import CCompiler + def my_link_shared_object(self, *args, **kwds): + if '-bundle' in self.linker_so: + self.linker_so = list(self.linker_so) + i = self.linker_so.index('-bundle') + self.linker_so[i] = '-dynamiclib' + return old_link_shared_object(self, *args, **kwds) + old_link_shared_object = _patch_meth(patchlist, CCompiler, + 'link_shared_object', + my_link_shared_object) + +def _patch_for_target(patchlist, target): + from distutils.command.build_ext import build_ext + # if 'target' is different from '*', we need to patch some internal + # method to just return this 'target' value, instead of having it + # built from module_name + if target.endswith('.*'): + target = target[:-2] + if sys.platform == 'win32': + target += '.dll' + elif sys.platform == 'darwin': + target += '.dylib' + else: + target += '.so' + _patch_meth(patchlist, build_ext, 'get_ext_filename', + lambda self, ext_name: target) + + +def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, + c_file=None, source_extension='.c', extradir=None, + compiler_verbose=1, target=None, debug=None, **kwds): + if not isinstance(module_name, str): + module_name = module_name.encode('ascii') + if ffi._windows_unicode: + ffi._apply_windows_unicode(kwds) + if preamble is not None: + embedding = (ffi._embedding is not None) + if embedding: + ffi._apply_embedding_fix(kwds) + if c_file is None: + c_file, parts = _modname_to_file(tmpdir, module_name, + source_extension) + if extradir: + parts = [extradir] + parts + ext_c_file = os.path.join(*parts) + else: + ext_c_file = c_file + # + if target is None: + if embedding: + target = '%s.*' % module_name + else: + target = '*' + # + ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) + updated = make_c_source(ffi, module_name, preamble, c_file, + verbose=compiler_verbose) + if call_c_compiler: + patchlist = [] + cwd = os.getcwd() + try: + if embedding: + _patch_for_embedding(patchlist) + if target != '*': + _patch_for_target(patchlist, target) + if compiler_verbose: + if tmpdir == '.': + msg = 'the current directory is' + else: + msg = 'setting the current directory to' + print('%s %r' % (msg, os.path.abspath(tmpdir))) + os.chdir(tmpdir) + outputfilename = ffiplatform.compile('.', ext, + compiler_verbose, debug) + finally: + os.chdir(cwd) + _unpatch_meths(patchlist) + return outputfilename + else: + return ext, updated + else: + if c_file is None: + c_file, _ = _modname_to_file(tmpdir, module_name, '.py') + updated = make_py_source(ffi, module_name, c_file, + verbose=compiler_verbose) + if call_c_compiler: + return c_file + else: + return None, updated + diff --git a/myenv/lib/python3.9/site-packages/cffi/setuptools_ext.py b/myenv/lib/python3.9/site-packages/cffi/setuptools_ext.py new file mode 100644 index 0000000..8fe3614 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/setuptools_ext.py @@ -0,0 +1,219 @@ +import os +import sys + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +def error(msg): + from distutils.errors import DistutilsSetupError + raise DistutilsSetupError(msg) + + +def execfile(filename, glob): + # We use execfile() (here rewritten for Python 3) instead of + # __import__() to load the build script. The problem with + # a normal import is that in some packages, the intermediate + # __init__.py files may already try to import the file that + # we are generating. + with open(filename) as f: + src = f.read() + src += '\n' # Python 2.6 compatibility + code = compile(src, filename, 'exec') + exec(code, glob, glob) + + +def add_cffi_module(dist, mod_spec): + from cffi.api import FFI + + if not isinstance(mod_spec, basestring): + error("argument to 'cffi_modules=...' must be a str or a list of str," + " not %r" % (type(mod_spec).__name__,)) + mod_spec = str(mod_spec) + try: + build_file_name, ffi_var_name = mod_spec.split(':') + except ValueError: + error("%r must be of the form 'path/build.py:ffi_variable'" % + (mod_spec,)) + if not os.path.exists(build_file_name): + ext = '' + rewritten = build_file_name.replace('.', '/') + '.py' + if os.path.exists(rewritten): + ext = ' (rewrite cffi_modules to [%r])' % ( + rewritten + ':' + ffi_var_name,) + error("%r does not name an existing file%s" % (build_file_name, ext)) + + mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} + execfile(build_file_name, mod_vars) + + try: + ffi = mod_vars[ffi_var_name] + except KeyError: + error("%r: object %r not found in module" % (mod_spec, + ffi_var_name)) + if not isinstance(ffi, FFI): + ffi = ffi() # maybe it's a function instead of directly an ffi + if not isinstance(ffi, FFI): + error("%r is not an FFI instance (got %r)" % (mod_spec, + type(ffi).__name__)) + if not hasattr(ffi, '_assigned_source'): + error("%r: the set_source() method was not called" % (mod_spec,)) + module_name, source, source_extension, kwds = ffi._assigned_source + if ffi._windows_unicode: + kwds = kwds.copy() + ffi._apply_windows_unicode(kwds) + + if source is None: + _add_py_module(dist, ffi, module_name) + else: + _add_c_module(dist, ffi, module_name, source, source_extension, kwds) + +def _set_py_limited_api(Extension, kwds): + """ + Add py_limited_api to kwds if setuptools >= 26 is in use. + Do not alter the setting if it already exists. + Setuptools takes care of ignoring the flag on Python 2 and PyPy. + + CPython itself should ignore the flag in a debugging version + (by not listing .abi3.so in the extensions it supports), but + it doesn't so far, creating troubles. That's why we check + for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent + of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401) + + On Windows, with CPython <= 3.4, it's better not to use py_limited_api + because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. + Recently (2020) we started shipping only >= 3.5 wheels, though. So + we'll give it another try and set py_limited_api on Windows >= 3.5. + """ + from cffi import recompiler + + if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') + and recompiler.USE_LIMITED_API): + import setuptools + try: + setuptools_major_version = int(setuptools.__version__.partition('.')[0]) + if setuptools_major_version >= 26: + kwds['py_limited_api'] = True + except ValueError: # certain development versions of setuptools + # If we don't know the version number of setuptools, we + # try to set 'py_limited_api' anyway. At worst, we get a + # warning. + kwds['py_limited_api'] = True + return kwds + +def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): + from distutils.core import Extension + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext + from distutils.dir_util import mkpath + from distutils import log + from cffi import recompiler + + allsources = ['$PLACEHOLDER'] + allsources.extend(kwds.pop('sources', [])) + kwds = _set_py_limited_api(Extension, kwds) + ext = Extension(name=module_name, sources=allsources, **kwds) + + def make_mod(tmpdir, pre_run=None): + c_file = os.path.join(tmpdir, module_name + source_extension) + log.info("generating cffi module %r" % c_file) + mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) + updated = recompiler.make_c_source(ffi, module_name, source, c_file) + if not updated: + log.info("already up-to-date") + return c_file + + if dist.ext_modules is None: + dist.ext_modules = [] + dist.ext_modules.append(ext) + + base_class = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class): + def run(self): + if ext.sources[0] == '$PLACEHOLDER': + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) + base_class.run(self) + dist.cmdclass['build_ext'] = build_ext_make_mod + # NB. multiple runs here will create multiple 'build_ext_make_mod' + # classes. Even in this case the 'build_ext' command should be + # run once; but just in case, the logic above does nothing if + # called again. + + +def _add_py_module(dist, ffi, module_name): + from distutils.dir_util import mkpath + from setuptools.command.build_py import build_py + from setuptools.command.build_ext import build_ext + from distutils import log + from cffi import recompiler + + def generate_mod(py_file): + log.info("generating cffi module %r" % py_file) + mkpath(os.path.dirname(py_file)) + updated = recompiler.make_py_source(ffi, module_name, py_file) + if not updated: + log.info("already up-to-date") + + base_class = dist.cmdclass.get('build_py', build_py) + class build_py_make_mod(base_class): + def run(self): + base_class.run(self) + module_path = module_name.split('.') + module_path[-1] += '.py' + generate_mod(os.path.join(self.build_lib, *module_path)) + def get_source_files(self): + # This is called from 'setup.py sdist' only. Exclude + # the generate .py module in this case. + saved_py_modules = self.py_modules + try: + if saved_py_modules: + self.py_modules = [m for m in saved_py_modules + if m != module_name] + return base_class.get_source_files(self) + finally: + self.py_modules = saved_py_modules + dist.cmdclass['build_py'] = build_py_make_mod + + # distutils and setuptools have no notion I could find of a + # generated python module. If we don't add module_name to + # dist.py_modules, then things mostly work but there are some + # combination of options (--root and --record) that will miss + # the module. So we add it here, which gives a few apparently + # harmless warnings about not finding the file outside the + # build directory. + # Then we need to hack more in get_source_files(); see above. + if dist.py_modules is None: + dist.py_modules = [] + dist.py_modules.append(module_name) + + # the following is only for "build_ext -i" + base_class_2 = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class_2): + def run(self): + base_class_2.run(self) + if self.inplace: + # from get_ext_fullpath() in distutils/command/build_ext.py + module_path = module_name.split('.') + package = '.'.join(module_path[:-1]) + build_py = self.get_finalized_command('build_py') + package_dir = build_py.get_package_dir(package) + file_name = module_path[-1] + '.py' + generate_mod(os.path.join(package_dir, file_name)) + dist.cmdclass['build_ext'] = build_ext_make_mod + +def cffi_modules(dist, attr, value): + assert attr == 'cffi_modules' + if isinstance(value, basestring): + value = [value] + + for cffi_module in value: + add_cffi_module(dist, cffi_module) diff --git a/myenv/lib/python3.9/site-packages/cffi/vengine_cpy.py b/myenv/lib/python3.9/site-packages/cffi/vengine_cpy.py new file mode 100644 index 0000000..6de0df0 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/vengine_cpy.py @@ -0,0 +1,1076 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, imp +from . import model +from .error import VerificationError + + +class VCPythonEngine(object): + _class_key = 'x' + _gen_python_module = True + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self._struct_pending_verification = {} + self._types_of_builtin_functions = {} + + def patch_extension_kwds(self, kwds): + pass + + def find_module(self, module_name, path, so_suffixes): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] not in so_suffixes: + return None + return filename + + def collect_types(self): + self._typesdict = {} + self._generate("collecttype") + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _do_collect_type(self, tp): + if ((not isinstance(tp, model.PrimitiveType) + or tp.name == 'long double') + and tp not in self._typesdict): + num = len(self._typesdict) + self._typesdict[tp] = num + + def write_source_to_f(self): + self.collect_types() + # + # The new module will have a _cffi_setup() function that receives + # objects from the ffi world, and that calls some setup code in + # the module. This setup code is split in several independent + # functions, e.g. one per constant. The functions are "chained" + # by ending in a tail call to each other. + # + # This is further split in two chained lists, depending on if we + # can do it at import-time or if we must wait for _cffi_setup() to + # provide us with the objects. This is needed because we + # need the values of the enum constants in order to build the + # that we may have to pass to _cffi_setup(). + # + # The following two 'chained_list_constants' items contains + # the head of these two chained lists, as a string that gives the + # call to do, if any. + self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] + # + prnt = self._prnt + # first paste some standard set of lines that are mostly '#define' + prnt(cffimod_header) + prnt() + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate("decl") + # + # implement the function _cffi_setup_custom() as calling the + # head of the chained list. + self._generate_setup_custom() + prnt() + # + # produce the method table, including the entries for the + # generated Python->C function wrappers, which are done + # by generate_cpy_function_method(). + prnt('static PyMethodDef _cffi_methods[] = {') + self._generate("method") + prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') + prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') + prnt('};') + prnt() + # + # standard init. + modname = self.verifier.get_module_name() + constants = self._chained_list_constants[False] + prnt('#if PY_MAJOR_VERSION >= 3') + prnt() + prnt('static struct PyModuleDef _cffi_module_def = {') + prnt(' PyModuleDef_HEAD_INIT,') + prnt(' "%s",' % modname) + prnt(' NULL,') + prnt(' -1,') + prnt(' _cffi_methods,') + prnt(' NULL, NULL, NULL, NULL') + prnt('};') + prnt() + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = PyModule_Create(&_cffi_module_def);') + prnt(' if (lib == NULL)') + prnt(' return NULL;') + prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) + prnt(' Py_DECREF(lib);') + prnt(' return NULL;') + prnt(' }') + prnt(' return lib;') + prnt('}') + prnt() + prnt('#else') + prnt() + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) + prnt(' if (lib == NULL)') + prnt(' return;') + prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) + prnt(' return;') + prnt(' return;') + prnt('}') + prnt() + prnt('#endif') + + def load_library(self, flags=None): + # XXX review all usages of 'self' here! + # import it as a new extension module + imp.acquire_lock() + try: + if hasattr(sys, "getdlopenflags"): + previous_flags = sys.getdlopenflags() + try: + if hasattr(sys, "setdlopenflags") and flags is not None: + sys.setdlopenflags(flags) + module = imp.load_dynamic(self.verifier.get_module_name(), + self.verifier.modulefilename) + except ImportError as e: + error = "importing %r: %s" % (self.verifier.modulefilename, e) + raise VerificationError(error) + finally: + if hasattr(sys, "setdlopenflags"): + sys.setdlopenflags(previous_flags) + finally: + imp.release_lock() + # + # call loading_cpy_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + # + # the C code will need the objects. Collect them in + # order in a list. + revmapping = dict([(value, key) + for (key, value) in self._typesdict.items()]) + lst = [revmapping[i] for i in range(len(revmapping))] + lst = list(map(self.ffi._get_cached_btype, lst)) + # + # build the FFILibrary class and instance and call _cffi_setup(). + # this will set up some fields like '_cffi_types', and only then + # it will invoke the chained list of functions that will really + # build (notably) the constant objects, as if they are + # pointers, and store them as attributes on the 'library' object. + class FFILibrary(object): + _cffi_python_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) + library = FFILibrary() + if module._cffi_setup(lst, VerificationError, library): + import warnings + warnings.warn("reimporting %r might overwrite older definitions" + % (self.verifier.get_module_name())) + # + # finally, call the loaded_cpy_xxx() functions. This will perform + # the final adjustments, like copying the Python->C wrapper + # functions from the module to the 'library' object, and setting + # up the FFILibrary class with properties for the global C variables. + self._load(module, 'loaded', library=library) + module._cffi_original_ffi = self.ffi + module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + else: + converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), + tp.name.replace(' ', '_')) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif isinstance(tp, (model.StructOrUnion, model.EnumType)): + # a struct (not a struct pointer) as a function argument + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + 'alloca((size_t)datasize) : NULL;' % (tovar,)) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif tp.name != 'long double': + return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs: generates no code so far + + _generate_cpy_typedef_collecttype = _generate_nothing + _generate_cpy_typedef_decl = _generate_nothing + _generate_cpy_typedef_method = _generate_nothing + _loading_cpy_typedef = _loaded_noop + _loaded_cpy_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + self._do_collect_type(tp) + else: + # don't call _do_collect_type(tp) in this common case, + # otherwise test_autofilled_struct_as_argument fails + for type in tp.args: + self._do_collect_type(type) + self._do_collect_type(tp.result) + + def _generate_cpy_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + prnt(' %s;' % type.get_c_name(' x%d' % i, context)) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + prnt(' %s;' % tp.result.get_c_name(' result', context)) + prnt(' PyObject *pyresult;') + else: + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( + 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + prnt(' { %s%s(%s); }' % ( + result_code, name, + ', '.join(['x%d' % i for i in range(len(tp.args))]))) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + prnt() + + def _generate_cpy_function_method(self, tp, name): + if tp.ellipsis: + return + numargs = len(tp.args) + if numargs == 0: + meth = 'METH_NOARGS' + elif numargs == 1: + meth = 'METH_O' + else: + meth = 'METH_VARARGS' + self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) + + _loading_cpy_function = _loaded_noop + + def _loaded_cpy_function(self, tp, name, module, library): + if tp.ellipsis: + return + func = getattr(module, name) + setattr(library, name, func) + self._types_of_builtin_functions[func] = tp + + # ---------- + # named structs + + _generate_cpy_struct_collecttype = _generate_nothing + def _generate_cpy_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + def _generate_cpy_struct_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'struct', name) + def _loading_cpy_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + def _loaded_cpy_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + _generate_cpy_union_collecttype = _generate_nothing + def _generate_cpy_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + def _generate_cpy_union_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'union', name) + def _loading_cpy_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + def _loaded_cpy_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('static PyObject *') + prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static Py_ssize_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' (void)self; /* unused */') + prnt(' (void)noarg; /* unused */') + prnt(' return _cffi_get_struct_layout(nums);') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _generate_struct_or_union_method(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, + layoutfuncname)) + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + function = getattr(module, layoutfuncname) + layout = function() + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + _generate_cpy_anonymous_collecttype = _generate_nothing + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _generate_cpy_anonymous_method(self, tp, name): + if not isinstance(tp, model.EnumType): + self._generate_struct_or_union_method(tp, '', name) + + def _loading_cpy_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_cpy_enum(tp, name, module) + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_cpy_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_cpy_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + vartp=None, delayed=True, size_too=False, + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + prnt(' PyObject *o;') + prnt(' int res;') + if not is_int: + prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) + else: + assert category == 'const' + # + if check_value is not None: + self._check_int_constant_value(name, check_value) + # + if not is_int: + if category == 'var': + realexpr = '&' + name + else: + realexpr = name + prnt(' i = (%s);' % (realexpr,)) + prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', + 'variable type'),)) + assert delayed + else: + prnt(' o = _cffi_from_c_int_const(%s);' % name) + prnt(' if (o == NULL)') + prnt(' return -1;') + if size_too: + prnt(' {') + prnt(' PyObject *o1 = o;') + prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' + % (name,)) + prnt(' Py_DECREF(o1);') + prnt(' if (o == NULL)') + prnt(' return -1;') + prnt(' }') + prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) + prnt(' Py_DECREF(o);') + prnt(' if (res < 0)') + prnt(' return -1;') + prnt(' return %s;' % self._chained_list_constants[delayed]) + self._chained_list_constants[delayed] = funcname + '(lib)' + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if not is_int: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + _generate_cpy_constant_method = _generate_nothing + _loading_cpy_constant = _loaded_noop + _loaded_cpy_constant = _loaded_noop + + # ---------- + # enums + + def _check_int_constant_value(self, name, value, err_prefix=''): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % + name) + prnt(' PyErr_Format(_cffi_VerificationError,') + prnt(' "%s%s has the real value %s, not %s",') + prnt(' "%s", "%s", buf, "%d");' % ( + err_prefix, name, value)) + prnt(' return -1;') + prnt(' }') + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator, delayed=False) + return + # + funcname = self._enum_funcname(prefix, name) + prnt = self._prnt + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue, + "enum %s: " % name) + prnt(' return %s;' % self._chained_list_constants[True]) + self._chained_list_constants[True] = funcname + '(lib)' + prnt('}') + prnt() + + _generate_cpy_enum_collecttype = _generate_nothing + _generate_cpy_enum_method = _generate_nothing + + def _loading_cpy_enum(self, tp, name, module): + if tp.partial: + enumvalues = [getattr(module, enumerator) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + + def _loaded_cpy_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + _generate_cpy_macro_collecttype = _generate_nothing + _generate_cpy_macro_method = _generate_nothing + _loading_cpy_macro = _loaded_noop + _loaded_cpy_macro = _loaded_noop + + # ---------- + # global variables + + def _generate_cpy_variable_collecttype(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + else: + tp_ptr = model.PointerType(tp) + self._do_collect_type(tp_ptr) + + def _generate_cpy_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + self._generate_cpy_const(False, name, tp, vartp=tp_ptr, + size_too = tp.length_is_unknown()) + else: + tp_ptr = model.PointerType(tp) + self._generate_cpy_const(False, name, tp_ptr, category='var') + + _generate_cpy_variable_method = _generate_nothing + _loading_cpy_variable = _loaded_noop + + def _loaded_cpy_variable(self, tp, name, module, library): + value = getattr(library, name) + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + assert isinstance(value, tuple) + (value, size) = value + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + ptr = value + delattr(library, name) + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + + # ---------- + + def _generate_setup_custom(self): + prnt = self._prnt + prnt('static int _cffi_setup_custom(PyObject *lib)') + prnt('{') + prnt(' return %s;' % self._chained_list_constants[True]) + prnt('}') + +cffimod_header = r''' +#include +#include + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#if PY_MAJOR_VERSION < 3 +# undef PyCapsule_CheckExact +# undef PyCapsule_GetPointer +# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) +# define PyCapsule_GetPointer(capsule, name) \ + (PyCObject_AsVoidPtr(capsule)) +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int_const(x) \ + (((x) > 0) ? \ + ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ + ((long long)(x) >= (long long)LONG_MIN) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromLongLong((long long)(x))) + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) +#define _CFFI_NUM_EXPORTS 25 + +typedef struct _ctypedescr CTypeDescrObject; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; +static PyObject *_cffi_types, *_cffi_VerificationError; + +static int _cffi_setup_custom(PyObject *lib); /* forward */ + +static PyObject *_cffi_setup(PyObject *self, PyObject *args) +{ + PyObject *library; + int was_alive = (_cffi_types != NULL); + (void)self; /* unused */ + if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, + &library)) + return NULL; + Py_INCREF(_cffi_types); + Py_INCREF(_cffi_VerificationError); + if (_cffi_setup_custom(library) < 0) + return NULL; + return PyBool_FromLong(was_alive); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +static int _cffi_init(void) +{ + PyObject *module, *c_api_object = NULL; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + c_api_object = PyObject_GetAttrString(module, "_C_API"); + if (c_api_object == NULL) + goto failure; + if (!PyCapsule_CheckExact(c_api_object)) { + PyErr_SetNone(PyExc_ImportError); + goto failure; + } + memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), + _CFFI_NUM_EXPORTS * sizeof(void *)); + + Py_DECREF(module); + Py_DECREF(c_api_object); + return 0; + + failure: + Py_XDECREF(module); + Py_XDECREF(c_api_object); + return -1; +} + +#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) + +/**********/ +''' diff --git a/myenv/lib/python3.9/site-packages/cffi/vengine_gen.py b/myenv/lib/python3.9/site-packages/cffi/vengine_gen.py new file mode 100644 index 0000000..2642152 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/vengine_gen.py @@ -0,0 +1,675 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os +import types + +from . import model +from .error import VerificationError + + +class VGenericEngine(object): + _class_key = 'g' + _gen_python_module = False + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self.export_symbols = [] + self._struct_pending_verification = {} + + def patch_extension_kwds(self, kwds): + # add 'export_symbols' to the dictionary. Note that we add the + # list before filling it. When we fill it, it will thus also show + # up in kwds['export_symbols']. + kwds.setdefault('export_symbols', self.export_symbols) + + def find_module(self, module_name, path, so_suffixes): + for so_suffix in so_suffixes: + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + + def collect_types(self): + pass # not needed in the generic engine + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self): + prnt = self._prnt + # first paste some standard set of lines that are mostly '#include' + prnt(cffimod_header) + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + # + # call generate_gen_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate('decl') + # + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + if sys.platform == 'win32': + if sys.version_info >= (3,): + prefix = 'PyInit_' + else: + prefix = 'init' + modname = self.verifier.get_module_name() + prnt("void %s%s(void) { }\n" % (prefix, modname)) + + def load_library(self, flags=0): + # import it with the CFFI backend + backend = self.ffi._backend + # needs to make a path that contains '/', on Posix + filename = os.path.join(os.curdir, self.verifier.modulefilename) + module = backend.load_library(filename, flags) + # + # call loading_gen_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + + # build the FFILibrary class and instance, this is a module subclass + # because modules are expected to have usually-constant-attributes and + # in PyPy this means the JIT is able to treat attributes as constant, + # which we want. + class FFILibrary(types.ModuleType): + _cffi_generic_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + library = FFILibrary("") + # + # finally, call the loaded_gen_xxx() functions. This will set + # up the 'library' object. + self._load(module, 'loaded', library=library) + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_gen_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_gen_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + # typedefs: generates no code so far + + _generate_gen_typedef_decl = _generate_nothing + _loading_gen_typedef = _loaded_noop + _loaded_gen_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_gen_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no _cffi_f_%s wrapper) + self._generate_gen_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + argnames = [] + for i, type in enumerate(tp.args): + indirection = '' + if isinstance(type, model.StructOrUnion): + indirection = '*' + argnames.append('%sx%d' % (indirection, i)) + context = 'argument of %s' % name + arglist = [type.get_c_name(' %s' % arg, context) + for type, arg in zip(tp.args, argnames)] + tpresult = tp.result + if isinstance(tpresult, model.StructOrUnion): + arglist.insert(0, tpresult.get_c_name(' *r', context)) + tpresult = model.void_type + arglist = ', '.join(arglist) or 'void' + wrappername = '_cffi_f_%s' % name + self.export_symbols.append(wrappername) + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) + context = 'result of %s' % name + prnt(tpresult.get_c_name(funcdecl, context)) + prnt('{') + # + if isinstance(tp.result, model.StructOrUnion): + result_code = '*r = ' + elif not isinstance(tp.result, model.VoidType): + result_code = 'return ' + else: + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) + prnt('}') + prnt() + + _loading_gen_function = _loaded_noop + + def _loaded_gen_function(self, tp, name, module, library): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + newfunction = self._load_constant(False, tp, name, module) + else: + indirections = [] + base_tp = tp + if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) + or isinstance(tp.result, model.StructOrUnion)): + indirect_args = [] + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) + indirect_result = tp.result + if isinstance(indirect_result, model.StructOrUnion): + if indirect_result.fldtypes is None: + raise TypeError("'%s' is used as result type, " + "but is opaque" % ( + indirect_result._get_c_name(),)) + indirect_result = model.PointerType(indirect_result) + indirect_args.insert(0, indirect_result) + indirections.insert(0, ("result", indirect_result)) + indirect_result = model.void_type + tp = model.FunctionPtrType(tuple(indirect_args), + indirect_result, tp.ellipsis) + BFunc = self.ffi._get_cached_btype(tp) + wrappername = '_cffi_f_%s' % name + newfunction = module.load_function(BFunc, wrappername) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ, + base_tp) + setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) + + def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): + backend = self.ffi._backend + BType = self.ffi._get_cached_btype(tp) + if i == "result": + ffi = self.ffi + def newfunc(*args): + res = ffi.new(BType) + oldfunc(res, *args) + return res[0] + else: + def newfunc(*args): + args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] + return oldfunc(*args) + newfunc._cffi_base_type = base_tp + return newfunc + + # ---------- + # named structs + + def _generate_gen_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + + def _loading_gen_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + + def _loaded_gen_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_gen_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + + def _loading_gen_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + + def _loaded_gen_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + self.export_symbols.append(layoutfuncname) + prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static intptr_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' return nums[i];') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] + function = module.load_function(BFunc, layoutfuncname) + layout = [] + num = 0 + while True: + x = function(num) + if x < 0: break + layout.append(x) + num += 1 + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_gen_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_gen_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _loading_gen_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_gen_enum(tp, name, module, '') + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_gen_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_gen_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_gen_const(self, is_int, name, tp=None, category='const', + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + self.export_symbols.append(funcname) + if check_value is not None: + assert is_int + assert category == 'const' + prnt('int %s(char *out_error)' % funcname) + prnt('{') + self._check_int_constant_value(name, check_value) + prnt(' return 0;') + prnt('}') + elif is_int: + assert category == 'const' + prnt('int %s(long long *out_value)' % funcname) + prnt('{') + prnt(' *out_value = (long long)(%s);' % (name,)) + prnt(' return (%s) <= 0;' % (name,)) + prnt('}') + else: + assert tp is not None + assert check_value is None + if category == 'var': + ampersand = '&' + else: + ampersand = '' + extra = '' + if category == 'const' and isinstance(tp, model.StructOrUnion): + extra = 'const *' + ampersand = '&' + prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) + prnt('{') + prnt(' return (%s%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_gen_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_gen_const(is_int, name, tp) + + _loading_gen_constant = _loaded_noop + + def _load_constant(self, is_int, tp, name, module, check_value=None): + funcname = '_cffi_const_%s' % name + if check_value is not None: + assert is_int + self._load_known_int_constant(module, funcname) + value = check_value + elif is_int: + BType = self.ffi._typeof_locked("long long*")[0] + BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType) + negative = function(p) + value = int(p[0]) + if value < 0 and not negative: + BLongLong = self.ffi._typeof_locked("long long")[0] + value += (1 << (8*self.ffi.sizeof(BLongLong))) + else: + assert check_value is None + fntypeextra = '(*)(void)' + if isinstance(tp, model.StructOrUnion): + fntypeextra = '*' + fntypeextra + BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] + function = module.load_function(BFunc, funcname) + value = function() + if isinstance(tp, model.StructOrUnion): + value = value[0] + return value + + def _loaded_gen_constant(self, tp, name, module, library): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + value = self._load_constant(is_int, tp, name, module) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # enums + + def _check_int_constant_value(self, name, value): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % + name) + prnt(' sprintf(out_error, "%s has the real value %s, not %s",') + prnt(' "%s", buf, "%d");' % (name[:100], value)) + prnt(' return -1;') + prnt(' }') + + def _load_known_int_constant(self, module, funcname): + BType = self.ffi._typeof_locked("char[]")[0] + BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType, 256) + if function(p) < 0: + error = self.ffi.string(p) + if sys.version_info >= (3,): + error = str(error, 'utf-8') + raise VerificationError(error) + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_gen_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_gen_const(True, enumerator) + return + # + funcname = self._enum_funcname(prefix, name) + self.export_symbols.append(funcname) + prnt = self._prnt + prnt('int %s(char *out_error)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue) + prnt(' return 0;') + prnt('}') + prnt() + + def _loading_gen_enum(self, tp, name, module, prefix='enum'): + if tp.partial: + enumvalues = [self._load_constant(True, tp, enumerator, module) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + else: + funcname = self._enum_funcname(prefix, name) + self._load_known_int_constant(module, funcname) + + def _loaded_gen_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) + + # ---------- + # macros: for now only for integers + + def _generate_gen_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_gen_const(True, name, check_value=check_value) + + _loading_gen_macro = _loaded_noop + + def _loaded_gen_macro(self, tp, name, module, library): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + value = self._load_constant(True, tp, name, module, + check_value=check_value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # global variables + + def _generate_gen_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + if tp.length_is_unknown(): + prnt = self._prnt + funcname = '_cffi_sizeof_%s' % (name,) + self.export_symbols.append(funcname) + prnt("size_t %s(void)" % funcname) + prnt("{") + prnt(" return sizeof(%s);" % (name,)) + prnt("}") + tp_ptr = model.PointerType(tp.item) + self._generate_gen_const(False, name, tp_ptr) + else: + tp_ptr = model.PointerType(tp) + self._generate_gen_const(False, name, tp_ptr, category='var') + + _loading_gen_variable = _loaded_noop + + def _loaded_gen_variable(self, tp, name, module, library): + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + funcname = '_cffi_sizeof_%s' % (name,) + BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] + function = module.load_function(BFunc, funcname) + size = function() + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + tp_ptr = model.PointerType(tp.item) + value = self._load_constant(False, tp_ptr, name, module) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + funcname = '_cffi_var_%s' % name + BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] + function = module.load_function(BFunc, funcname) + ptr = function() + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + +cffimod_header = r''' +#include +#include +#include +#include +#include /* XXX for ssize_t on some platforms */ + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif +''' diff --git a/myenv/lib/python3.9/site-packages/cffi/verifier.py b/myenv/lib/python3.9/site-packages/cffi/verifier.py new file mode 100644 index 0000000..a500c78 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cffi/verifier.py @@ -0,0 +1,307 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os, binascii, shutil, io +from . import __version_verifier_modules__ +from . import ffiplatform +from .error import VerificationError + +if sys.version_info >= (3, 3): + import importlib.machinery + def _extension_suffixes(): + return importlib.machinery.EXTENSION_SUFFIXES[:] +else: + import imp + def _extension_suffixes(): + return [suffix for suffix, _, type in imp.get_suffixes() + if type == imp.C_EXTENSION] + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + + +class Verifier(object): + + def __init__(self, ffi, preamble, tmpdir=None, modulename=None, + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', flags=None, relative_to=None, **kwds): + if ffi._parser._uses_new_feature: + raise VerificationError( + "feature not supported with ffi.verify(), but only " + "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,)) + self.ffi = ffi + self.preamble = preamble + if not modulename: + flattened_kwds = ffiplatform.flatten(kwds) + vengine_class = _locate_engine_class(ffi, force_generic_engine) + self._vengine = vengine_class(self) + self._vengine.patch_extension_kwds(kwds) + self.flags = flags + self.kwds = self.make_relative_to(kwds, relative_to) + # + if modulename: + if tag: + raise TypeError("can't specify both 'modulename' and 'tag'") + else: + key = '\x00'.join(['%d.%d' % sys.version_info[:2], + __version_verifier_modules__, + preamble, flattened_kwds] + + ffi._cdefsources) + if sys.version_info >= (3,): + key = key.encode('utf-8') + k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) + k1 = k1.lstrip('0x').rstrip('L') + k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) + k2 = k2.lstrip('0').rstrip('L') + modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key, + k1, k2) + suffix = _get_so_suffixes()[0] + self.tmpdir = tmpdir or _caller_dir_pycache() + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) + self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) + self.ext_package = ext_package + self._has_source = False + self._has_module = False + + def write_source(self, file=None): + """Write the C source code. It is produced in 'self.sourcefilename', + which can be tweaked beforehand.""" + with self.ffi._lock: + if self._has_source and file is None: + raise VerificationError( + "source code already written") + self._write_source(file) + + def compile_module(self): + """Write the C source code (if not done already) and compile it. + This produces a dynamic link library in 'self.modulefilename'.""" + with self.ffi._lock: + if self._has_module: + raise VerificationError("module already compiled") + if not self._has_source: + self._write_source() + self._compile_module() + + def load_library(self): + """Get a C module from this Verifier instance. + Returns an instance of a FFILibrary class that behaves like the + objects returned by ffi.dlopen(), but that delegates all + operations to the C module. If necessary, the C code is written + and compiled first. + """ + with self.ffi._lock: + if not self._has_module: + self._locate_module() + if not self._has_module: + if not self._has_source: + self._write_source() + self._compile_module() + return self._load_library() + + def get_module_name(self): + basename = os.path.basename(self.modulefilename) + # kill both the .so extension and the other .'s, as introduced + # by Python 3: 'basename.cpython-33m.so' + basename = basename.split('.', 1)[0] + # and the _d added in Python 2 debug builds --- but try to be + # conservative and not kill a legitimate _d + if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'): + basename = basename[:-2] + return basename + + def get_extension(self): + ffiplatform._hack_at_distutils() # backward compatibility hack + if not self._has_source: + with self.ffi._lock: + if not self._has_source: + self._write_source() + sourcename = ffiplatform.maybe_relative_path(self.sourcefilename) + modname = self.get_module_name() + return ffiplatform.get_extension(sourcename, modname, **self.kwds) + + def generates_python_module(self): + return self._vengine._gen_python_module + + def make_relative_to(self, kwds, relative_to): + if relative_to and os.path.dirname(relative_to): + dirname = os.path.dirname(relative_to) + kwds = kwds.copy() + for key in ffiplatform.LIST_OF_FILE_NAMES: + if key in kwds: + lst = kwds[key] + if not isinstance(lst, (list, tuple)): + raise TypeError("keyword '%s' should be a list or tuple" + % (key,)) + lst = [os.path.join(dirname, fn) for fn in lst] + kwds[key] = lst + return kwds + + # ---------- + + def _locate_module(self): + if not os.path.isfile(self.modulefilename): + if self.ext_package: + try: + pkg = __import__(self.ext_package, None, None, ['__doc__']) + except ImportError: + return # cannot import the package itself, give up + # (e.g. it might be called differently before installation) + path = pkg.__path__ + else: + path = None + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffixes()) + if filename is None: + return + self.modulefilename = filename + self._vengine.collect_types() + self._has_module = True + + def _write_source_to(self, file): + self._vengine._f = file + try: + self._vengine.write_source_to_f() + finally: + del self._vengine._f + + def _write_source(self, file=None): + if file is not None: + self._write_source_to(file) + else: + # Write our source file to an in memory file. + f = NativeIO() + self._write_source_to(f) + source_data = f.getvalue() + + # Determine if this matches the current file + if os.path.exists(self.sourcefilename): + with open(self.sourcefilename, "r") as fp: + needs_written = not (fp.read() == source_data) + else: + needs_written = True + + # Actually write the file out if it doesn't match + if needs_written: + _ensure_dir(self.sourcefilename) + with open(self.sourcefilename, "w") as fp: + fp.write(source_data) + + # Set this flag + self._has_source = True + + def _compile_module(self): + # compile this C source + tmpdir = os.path.dirname(self.sourcefilename) + outputfilename = ffiplatform.compile(tmpdir, self.get_extension()) + try: + same = ffiplatform.samefile(outputfilename, self.modulefilename) + except OSError: + same = False + if not same: + _ensure_dir(self.modulefilename) + shutil.move(outputfilename, self.modulefilename) + self._has_module = True + + def _load_library(self): + assert self._has_module + if self.flags is not None: + return self._vengine.load_library(self.flags) + else: + return self._vengine.load_library() + +# ____________________________________________________________ + +_FORCE_GENERIC_ENGINE = False # for tests + +def _locate_engine_class(ffi, force_generic_engine): + if _FORCE_GENERIC_ENGINE: + force_generic_engine = True + if not force_generic_engine: + if '__pypy__' in sys.builtin_module_names: + force_generic_engine = True + else: + try: + import _cffi_backend + except ImportError: + _cffi_backend = '?' + if ffi._backend is not _cffi_backend: + force_generic_engine = True + if force_generic_engine: + from . import vengine_gen + return vengine_gen.VGenericEngine + else: + from . import vengine_cpy + return vengine_cpy.VCPythonEngine + +# ____________________________________________________________ + +_TMPDIR = None + +def _caller_dir_pycache(): + if _TMPDIR: + return _TMPDIR + result = os.environ.get('CFFI_TMPDIR') + if result: + return result + filename = sys._getframe(2).f_code.co_filename + return os.path.abspath(os.path.join(os.path.dirname(filename), + '__pycache__')) + +def set_tmpdir(dirname): + """Set the temporary directory to use instead of __pycache__.""" + global _TMPDIR + _TMPDIR = dirname + +def cleanup_tmpdir(tmpdir=None, keep_so=False): + """Clean up the temporary directory by removing all files in it + called `_cffi_*.{c,so}` as well as the `build` subdirectory.""" + tmpdir = tmpdir or _caller_dir_pycache() + try: + filelist = os.listdir(tmpdir) + except OSError: + return + if keep_so: + suffix = '.c' # only remove .c files + else: + suffix = _get_so_suffixes()[0].lower() + for fn in filelist: + if fn.lower().startswith('_cffi_') and ( + fn.lower().endswith(suffix) or fn.lower().endswith('.c')): + try: + os.unlink(os.path.join(tmpdir, fn)) + except OSError: + pass + clean_dir = [os.path.join(tmpdir, 'build')] + for dir in clean_dir: + try: + for fn in os.listdir(dir): + fn = os.path.join(dir, fn) + if os.path.isdir(fn): + clean_dir.append(fn) + else: + os.unlink(fn) + except OSError: + pass + +def _get_so_suffixes(): + suffixes = _extension_suffixes() + if not suffixes: + # bah, no C_EXTENSION available. Occurs on pypy without cpyext + if sys.platform == 'win32': + suffixes = [".pyd"] + else: + suffixes = [".so"] + + return suffixes + +def _ensure_dir(filename): + dirname = os.path.dirname(filename) + if dirname and not os.path.isdir(dirname): + os.makedirs(dirname) diff --git a/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/LICENSE.rst b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/METADATA b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/METADATA new file mode 100644 index 0000000..8e5dc1e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/METADATA @@ -0,0 +1,111 @@ +Metadata-Version: 2.1 +Name: click +Version: 8.1.3 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Changes, https://click.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/click/ +Project-URL: Issue Tracker, https://github.com/pallets/click/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: colorama ; platform_system == "Windows" +Requires-Dist: importlib-metadata ; python_version < "3.8" + +\$ click\_ +========== + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U click + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + import click + + @click.command() + @click.option("--count", default=1, help="Number of greetings.") + @click.option("--name", prompt="Your name", help="The person to greet.") + def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + + if __name__ == '__main__': + hello() + +.. code-block:: text + + $ python hello.py --count=3 + Your name: Click + Hello, Click! + Hello, Click! + Hello, Click! + + +Donate +------ + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://click.palletsprojects.com/ +- Changes: https://click.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/click/ +- Source Code: https://github.com/pallets/click +- Issue Tracker: https://github.com/pallets/click/issues +- Website: https://palletsprojects.com/p/click +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/RECORD b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/RECORD new file mode 100644 index 0000000..14981e3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/RECORD @@ -0,0 +1,23 @@ +click/__init__.py,sha256=rQBLutqg-z6m8nOzivIfigDn_emijB_dKv9BZ2FNi5s,3138 +click/_compat.py,sha256=JIHLYs7Jzz4KT9t-ds4o4jBzLjnwCiJQKqur-5iwCKI,18810 +click/_termui_impl.py,sha256=qK6Cfy4mRFxvxE8dya8RBhLpSC8HjF-lvBc6aNrPdwg,23451 +click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 +click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 +click/core.py,sha256=mz87bYEKzIoNYEa56BFAiOJnvt1Y0L-i7wD4_ZecieE,112782 +click/decorators.py,sha256=yo3zvzgUm5q7h5CXjyV6q3h_PJAiUaem178zXwdWUFI,16350 +click/exceptions.py,sha256=7gDaLGuFZBeCNwY9ERMsF2-Z3R9Fvq09Zc6IZSKjseo,9167 +click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 +click/globals.py,sha256=TP-qM88STzc7f127h35TD_v920FgfOD2EwzqA0oE8XU,1961 +click/parser.py,sha256=cAEt1uQR8gq3-S9ysqbVU-fdAZNvilxw4ReJ_T1OQMk,19044 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=qOp_BeC9esEOSZKyu5G7RIxEUaLsXUX-mTb7hB1r4QY,18018 +click/termui.py,sha256=ACBQVOvFCTSqtD5VREeCAdRtlHd-Imla-Lte4wSfMjA,28355 +click/testing.py,sha256=ptpMYgRY7dVfE3UDgkgwayu9ePw98sQI3D7zZXiCpj4,16063 +click/types.py,sha256=rEb1aZSQKq3ciCMmjpG2Uva9vk498XRL7ThrcK2GRss,35805 +click/utils.py,sha256=33D6E7poH_nrKB-xr-UyDEXnxOcCiQqxuRLtrqeVv6o,18682 +click-8.1.3.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.1.3.dist-info/METADATA,sha256=tFJIX5lOjx7c5LjZbdTPFVDJSgyv9F74XY0XCPp_gnc,3247 +click-8.1.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +click-8.1.3.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click-8.1.3.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +click-8.1.3.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click-8.1.3.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/myenv/lib/python3.9/site-packages/click/__init__.py b/myenv/lib/python3.9/site-packages/click/__init__.py new file mode 100644 index 0000000..e3ef423 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/__init__.py @@ -0,0 +1,73 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" +from .core import Argument as Argument +from .core import BaseCommand as BaseCommand +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import MultiCommand as MultiCommand +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .parser import OptionParser as OptionParser +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + +__version__ = "8.1.3" diff --git a/myenv/lib/python3.9/site-packages/click/_compat.py b/myenv/lib/python3.9/site-packages/click/_compat.py new file mode 100644 index 0000000..766d286 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/_compat.py @@ -0,0 +1,626 @@ +import codecs +import io +import os +import re +import sys +import typing as t +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +MSYS2 = sys.platform.startswith("win") and ("GCC" in sys.version) +# Determine local App Engine environment, per Google's own suggestion +APP_ENGINE = "APPENGINE_RUNTIME" in os.environ and "Development/" in os.environ.get( + "SERVER_SOFTWARE", "" +) +WIN = sys.platform.startswith("win") and not APP_ENGINE and not MSYS2 +auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def get_filesystem_encoding() -> str: + return sys.getfilesystemencoding() or sys.getdefaultencoding() + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write("") # type: ignore + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO, default: bool = False) -> bool: + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + +def _is_binary_writer(stream: t.IO, default: bool = False) -> bool: + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + +def _find_binary_reader(stream: t.IO) -> t.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO) -> t.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + is_binary: t.Callable[[t.IO, bool], bool], + find_binary: t.Callable[[t.IO], t.Optional[t.BinaryIO]], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: t.Union[str, os.PathLike, int], + mode: str, + encoding: t.Optional[str], + errors: t.Optional[str], +) -> t.IO: + """Handles not passing ``encoding`` and ``errors`` in binary mode.""" + if "b" in mode: + return open(file, mode) + + return open(file, mode, encoding=encoding, errors=errors) + + +def open_stream( + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, +) -> t.Tuple[t.IO, bool]: + binary = "b" in mode + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: t.Optional[int] = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO, af), True + + +class _AtomicFile: + def __init__(self, f: t.IO, tmp_filename: str, real_filename: str) -> None: + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self) -> str: + return self._real_filename + + def close(self, delete: bool = False) -> None: + if self.closed: + return + self._f.close() + os.replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._f, name) + + def __enter__(self) -> "_AtomicFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.close(delete=exc_type is not None) + + def __repr__(self) -> str: + return repr(self._f) + + +def strip_ansi(value: str) -> str: + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream: t.IO) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi( + stream: t.TextIO, color: t.Optional[bool] = None + ) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s): + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or get_filesystem_encoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] + ) -> t.Optional[t.TextIO]: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO], wrapper_func: t.Callable[[], t.TextIO] +) -> t.Callable[[], t.TextIO]: + cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO: + stream = src_func() + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: t.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: t.Mapping[ + str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO] +] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/myenv/lib/python3.9/site-packages/click/_termui_impl.py b/myenv/lib/python3.9/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..4b979bc --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/_termui_impl.py @@ -0,0 +1,717 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" +import contextlib +import math +import os +import sys +import time +import typing as t +from gettext import gettext as _ + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import open_stream +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: t.Optional[t.Iterable[V]], + length: t.Optional[int] = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + label: t.Optional[str] = None, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label = label or "" + if file is None: + file = _default_text_stdout() + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width = width + self.autowidth = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast(t.Iterable[V], range(length)) + self.iter = iter(iterable) + self.length = length + self.pos = 0 + self.avg: t.List[float] = [] + self.start = self.last_eta = time.time() + self.eta_known = False + self.finished = False + self.max_width: t.Optional[int] = None + self.entered = False + self.current_item: t.Optional[V] = None + self.is_hidden = not isatty(self.file) + self._last_line: t.Optional[str] = None + + def __enter__(self) -> "ProgressBar": + self.entered = True + self.render_progress() + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.render_finish() + + def __iter__(self) -> t.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.is_hidden: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + import shutil + + if self.is_hidden: + # Only output the label as it changes if the output is not a + # TTY. Use file=stderr if you expect to be piping stdout. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) # type: ignore + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: t.Optional[V] = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> t.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if self.is_hidden: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + pager_cmd = (os.environ.get("PAGER", None) or "").strip() + if pager_cmd: + if WIN: + return _tempfilepager(generator, pager_cmd, color) + return _pipepager(generator, pager_cmd, color) + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if WIN or sys.platform.startswith("os2"): + return _tempfilepager(generator, "more <", color) + if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0: + return _pipepager(generator, "less", color) + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, "system") and os.system(f'more "{filename}"') == 0: + return _pipepager(generator, "more", color) + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> None: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit("/", 1)[-1].split() + if color is None and cmd_detail[0] == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, env=env) + stdin = t.cast(t.BinaryIO, c.stdin) + encoding = get_best_encoding(stdin) + try: + for text in generator: + if not color: + text = strip_ansi(text) + + stdin.write(text.encode(encoding, "replace")) + except (OSError, KeyboardInterrupt): + pass + else: + stdin.close() + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager( + generator: t.Iterable[str], cmd: str, color: t.Optional[bool] +) -> None: + """Page through text by invoking a program on a temporary file.""" + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + os.system(f'{cmd} "{filename}"') + finally: + os.close(fd) + os.unlink(filename) + + +def _nullpager( + stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool] +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + for editor in "sensible-editor", "vim", "nano": + if os.system(f"which {editor} >/dev/null 2>&1") == 0: + return editor + return "vi" + + def edit_file(self, filename: str) -> None: + import subprocess + + editor = self.get_editor() + environ: t.Optional[t.Dict[str, str]] = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + try: + c = subprocess.Popen(f'{editor} "{filename}"', env=environ, shell=True) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]: + import tempfile + + if not text: + data = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") # type: ignore + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url.replace('"', "")) + args = f'explorer /select,"{url}"' + else: + url = url.replace('"', "") + wait_str = "/WAIT" if wait else "" + args = f'start {wait_str} "" "{url}"' + return os.system(args) + elif CYGWIN: + if locate: + url = os.path.dirname(_unquote_file(url).replace('"', "")) + args = f'cygstart "{url}"' + else: + url = url.replace('"', "") + wait_str = "-w" if wait else "" + args = f'cygstart {wait_str} "{url}"' + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> t.Optional[BaseException]: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if WIN: + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + func: t.Callable[[], str] + + if echo: + func = msvcrt.getwche # type: ignore + else: + func = msvcrt.getwch # type: ignore + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import tty + import termios + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + f: t.Optional[t.TextIO] + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/myenv/lib/python3.9/site-packages/click/_textwrap.py b/myenv/lib/python3.9/site-packages/click/_textwrap.py new file mode 100644 index 0000000..b47dcbd --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/_textwrap.py @@ -0,0 +1,49 @@ +import textwrap +import typing as t +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: t.List[str], + cur_line: t.List[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> t.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/myenv/lib/python3.9/site-packages/click/_winconsole.py b/myenv/lib/python3.9/site-packages/click/_winconsole.py new file mode 100644 index 0000000..6b20df3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/_winconsole.py @@ -0,0 +1,279 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +import io +import sys +import time +import typing as t +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle): + self.handle = handle + + def isatty(self): + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: t.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self): + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> t.Optional[t.TextIO]: + if ( + get_buffer is not None + and encoding in {"utf-16-le", None} + and errors in {"strict", None} + and _is_console(f) + ): + func = _stream_factories.get(f.fileno()) + if func is not None: + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/myenv/lib/python3.9/site-packages/click/core.py b/myenv/lib/python3.9/site-packages/click/core.py new file mode 100644 index 0000000..5abfb0f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/core.py @@ -0,0 +1,2998 @@ +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from contextlib import contextmanager +from contextlib import ExitStack +from functools import partial +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat + +from . import types +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _flag_needs_value +from .parser import OptionParser +from .parser import split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: + import typing_extensions as te + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +V = t.TypeVar("V") + + +def _complete_visible_commands( + ctx: "Context", incomplete: str +) -> t.Iterator[t.Tuple[str, "Command"]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(MultiCommand, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_multicommand( + base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = ( + "It is not possible to add multi commands as children to" + " another multi command that is in chain mode." + ) + else: + hint = ( + "Found a multi command as subcommand to a multi command" + " that is in chain mode. This is not supported." + ) + raise RuntimeError( + f"{hint}. Command {base_command.name!r} is set to chain and" + f" {cmd_name!r} was added as a subcommand but it in itself is a" + f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" + f" within a chained {type(base_command).__name__} named" + f" {base_command.name!r})." + ) + + +def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size))) + + +@contextmanager +def augment_usage_errors( + ctx: "Context", param: t.Optional["Parameter"] = None +) -> t.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: t.Sequence["Parameter"], + declaration_order: t.Sequence["Parameter"], +) -> t.List["Parameter"]: + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + + def sort_key(item: "Parameter") -> t.Tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: t.Type["HelpFormatter"] = HelpFormatter + + def __init__( + self, + command: "Command", + parent: t.Optional["Context"] = None, + info_name: t.Optional[str] = None, + obj: t.Optional[t.Any] = None, + auto_envvar_prefix: t.Optional[str] = None, + default_map: t.Optional[t.Dict[str, t.Any]] = None, + terminal_width: t.Optional[int] = None, + max_content_width: t.Optional[int] = None, + resilient_parsing: bool = False, + allow_extra_args: t.Optional[bool] = None, + allow_interspersed_args: t.Optional[bool] = None, + ignore_unknown_options: t.Optional[bool] = None, + help_option_names: t.Optional[t.List[str]] = None, + token_normalize_func: t.Optional[t.Callable[[str], str]] = None, + color: t.Optional[bool] = None, + show_default: t.Optional[bool] = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: t.Dict[str, t.Any] = {} + #: the leftover arguments. + self.args: t.List[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args: t.List[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: t.Optional[t.Dict[str, t.Any]] = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: t.Optional[str] = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: t.Optional[int] = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: t.Optional[int] = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: t.List[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Optional[ + t.Callable[[str], str] + ] = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: t.Optional[bool] = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: t.Optional[bool] = show_default + + self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: t.Dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> "Context": + self._depth += 1 + push_context(self) + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup: bool = True) -> t.Iterator["Context"]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> t.Dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: t.ContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._exit_stack.close() + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> "Context": + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: t.Type[V]) -> t.Optional[V]: + """Finds the closest object of a given type.""" + node: t.Optional["Context"] = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: t.Type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[False]" = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name) + + if call and callable(value): + return value() + + return value + + return None + + def fail(self, message: str) -> "te.NoReturn": + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> "te.NoReturn": + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> "te.NoReturn": + """Exits the application with a given exit code.""" + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: "Command") -> "Context": + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + def invoke( + __self, # noqa: B902 + __callback: t.Union["Command", t.Callable[..., t.Any]], + *args: t.Any, + **kwargs: t.Any, + ) -> t.Any: + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + """ + if isinstance(__callback, Command): + other_cmd = __callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + __callback = other_cmd.callback + + ctx = __self._make_sub_context(other_cmd) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, param.get_default(ctx) + ) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = __self + + with augment_usage_errors(__self): + with ctx: + return __callback(*args, **kwargs) + + def forward( + __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # noqa: B902 + ) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(__cmd, Command): + raise TypeError("Callback is not a command.") + + for param in __self.params: + if param not in kwargs: + kwargs[param] = __self.params[param] + + return __self.invoke(__cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class BaseCommand: + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: t.Type[Context] = Context + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.Dict[str, t.Any]] = None, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings: t.Dict[str, t.Any] = context_settings + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire structure + below this command. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + :param ctx: A :class:`Context` representing this command. + + .. versionadded:: 8.0 + """ + return {"name": self.name} + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get usage") + + def get_help(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get help") + + def make_context( + self, + info_name: t.Optional[str], + args: t.List[str], + parent: t.Optional[Context] = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class( + self, info_name=info_name, parent=parent, **extra # type: ignore + ) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError("Base commands do not know how to parse arguments.") + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError("Base commands are not invokable by default") + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. Other + command classes will return more completions. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, MultiCommand) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx.protected_args + ) + + return results + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: "te.Literal[True]" = True, + **extra: t.Any, + ) -> "te.NoReturn": + ... + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: + ... + + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt): + echo(file=sys.stderr) + raise Abort() from None + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: t.Optional[str] = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + """ + if complete_var is None: + complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + + :param deprecated: issues a message indicating that + the command is deprecated. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.Dict[str, t.Any]] = None, + callback: t.Optional[t.Callable[..., t.Any]] = None, + params: t.Optional[t.List["Parameter"]] = None, + help: t.Optional[str] = None, + epilog: t.Optional[str] = None, + short_help: t.Optional[str] = None, + options_metavar: t.Optional[str] = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool = False, + ) -> None: + super().__init__(name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params: t.List["Parameter"] = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + info_dict.update( + params=[param.to_info_dict() for param in self.get_params(ctx)], + help=self.help, + epilog=self.epilog, + short_help=self.short_help, + hidden=self.hidden, + deprecated=self.deprecated, + ) + return info_dict + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> t.List["Parameter"]: + rv = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + rv = [*rv, help_option] + + return rv + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> t.List[str]: + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return list(all_names) + + def get_help_option(self, ctx: Context) -> t.Optional["Option"]: + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + + if not help_options or not self.add_help_option: + return None + + def show_help(ctx: Context, param: "Parameter", value: str) -> None: + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + return Option( + help_options, + is_flag=True, + is_eager=True, + expose_value=False, + callback=show_help, + help=_("Show this message and exit."), + ) + + def make_parser(self, ctx: Context) -> OptionParser: + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + text = self.help if self.help is not None else "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + if text: + text = inspect.cleandoc(text).partition("\f")[0] + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + message = _( + "DeprecationWarning: The command {name!r} is deprecated." + ).format(name=self.name) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: The result callback to attach to this multi + command. This can be set or changed later with the + :meth:`result_callback` decorator. + """ + + allow_extra_args = True + allow_interspersed_args = False + + def __init__( + self, + name: t.Optional[str] = None, + invoke_without_command: bool = False, + no_args_is_help: t.Optional[bool] = None, + subcommand_metavar: t.Optional[str] = None, + chain: bool = False, + result_callback: t.Optional[t.Callable[..., t.Any]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "Multi commands in chain mode cannot have" + " optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(__value, *args, **kwargs): # type: ignore + inner = old_callback(__value, *args, **kwargs) # type: ignore + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv + + return decorator + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx.protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx.protected_args, *ctx.args] + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: t.List[str] + ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError + + def list_commands(self, ctx: Context) -> t.List[str]: + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is + the most common way to implement nesting in Click. + + :param name: The name of the group command. + :param commands: A dict mapping names to :class:`Command` objects. + Can also be a list of :class:`Command`, which will use + :attr:`Command.name` to create the dict. + :param attrs: Other command arguments described in + :class:`MultiCommand`, :class:`Command`, and + :class:`BaseCommand`. + + .. versionchanged:: 8.0 + The ``commmands`` argument can be a list of command objects. + """ + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: t.Optional[t.Type[Command]] = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: t.Optional[str] = None, + commands: t.Optional[t.Union[t.Dict[str, Command], t.Sequence[Command]]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: t.Dict[str, Command] = commands + + def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: + ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: + ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + func: t.Optional[t.Callable] = None + + if args and callable(args[0]): + assert ( + len(args) == 1 and not kwargs + ), "Use 'command(**kwargs)(callable)' to provide arguments." + (func,) = args + args = () + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> "Group": + ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]: + ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Optional[t.Callable] = None + + if args and callable(args[0]): + assert ( + len(args) == 1 and not kwargs + ), "Use 'group(**kwargs)(callable)' to provide arguments." + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> "Group": + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> t.List[str]: + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + """ + + def __init__( + self, + name: t.Optional[str] = None, + sources: t.Optional[t.List[MultiCommand]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + #: The list of registered multi commands. + self.sources: t.List[MultiCommand] = sources or [] + + def add_source(self, multi_cmd: MultiCommand) -> None: + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> t.List[str]: + rv: t.Set[str] = set() + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> t.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The later is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + required: bool = False, + default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, + callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, + nargs: t.Optional[int] = None, + multiple: bool = False, + metavar: t.Optional[str] = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, + shell_complete: t.Optional[ + t.Callable[ + [Context, "Parameter", str], + t.Union[t.List["CompletionItem"], t.List[str]], + ] + ] = None, + ) -> None: + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + # Skip no default or callable default. + check_default = default if not callable(default) else None + + if check_default is not None: + if multiple: + try: + # Only check the first value against nargs. + check_default = next(_check_iter(check_default), None) + except TypeError: + raise ValueError( + "'default' must be a list when 'multiple' is true." + ) from None + + # Can be None for multiple with empty default. + if nargs != 1 and check_default is not None: + try: + _check_iter(check_default) + except TypeError: + if multiple: + message = ( + "'default' must be a list of lists when 'multiple' is" + " true and 'nargs' != 1." + ) + else: + message = "'default' must be a list when 'nargs' != 1." + + raise ValueError(message) from None + + if nargs > 1 and len(check_default) != nargs: + subject = "item length" if multiple else "length" + raise ValueError( + f"'default' {subject} must match nargs={nargs}." + ) + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + "default": self.default, + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(self) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is None: + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, t.Any] + ) -> t.Tuple[t.Any, ParameterSource]: + value = opts.get(self.name) # type: ignore + source = ParameterSource.COMMANDLINE + + if value is None: + value = self.value_from_envvar(ctx) + source = ParameterSource.ENVIRONMENT + + if value is None: + value = ctx.lookup_default(self.name) # type: ignore + source = ParameterSource.DEFAULT_MAP + + if value is None: + value = self.get_default(ctx) + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the option's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + return () if self.multiple or self.nargs == -1 else None + + def check_iter(value: t.Any) -> t.Iterator: + try: + return _check_iter(value) + except TypeError: + # This should only happen when passing in args manually, + # the parser should construct an iterable when parsing + # the command line. + raise BadParameter( + _("Value must be an iterable."), ctx=ctx, param=self + ) from None + + if self.nargs == 1 or self.type.is_composite: + convert: t.Callable[[t.Any], t.Any] = partial( + self.type, param=self, ctx=ctx + ) + elif self.nargs == -1: + + def convert(value: t.Any) -> t.Tuple: + return tuple(self.type(x, self, ctx) for x in check_iter(value)) + + else: # nargs > 1 + + def convert(value: t.Any) -> t.Tuple: + value = tuple(check_iter(value)) + + if len(value) != self.nargs: + raise BadParameter( + ngettext( + "Takes {nargs} values but 1 was given.", + "Takes {nargs} values but {len} were given.", + len(value), + ).format(nargs=self.nargs, len=len(value)), + ctx=ctx, + param=self, + ) + + return tuple(self.type(x, self, ctx) for x in value) + + if self.multiple: + return tuple(convert(x) for x in check_iter(value)) + + return convert(value) + + def value_is_missing(self, value: t.Any) -> bool: + if value is None: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + if self.envvar is None: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str] + ) -> t.Tuple[t.Any, t.List[str]]: + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + ctx.set_parameter_source(self.name, source) # type: ignore + + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + + value = None + + if self.expose_value: + ctx.params[self.name] = value # type: ignore + + return value, args + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + pass + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast(t.List["CompletionItem"], results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page. Normally, environment variables are not + shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + + .. versionchanged:: 8.1.0 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1.0 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1.0 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + show_default: t.Union[bool, str, None] = None, + prompt: t.Union[bool, str] = False, + confirmation_prompt: t.Union[bool, str] = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: t.Optional[bool] = None, + flag_value: t.Optional[t.Any] = None, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + help: t.Optional[str] = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + default_is_missing = "default" not in attrs + super().__init__(param_decls, type=type, multiple=multiple, **attrs) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # If prompt is enabled but not required, then the option can be + # used as a flag to indicate using prompt or flag_value. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + if is_flag is None: + if flag_value is not None: + # Implicitly a flag because flag_value was set. + is_flag = True + elif self._flag_needs_value: + # Not a flag, but when used as a flag it shows a prompt. + is_flag = False + else: + # Implicitly a flag because flag options were given. + is_flag = bool(self.secondary_opts) + elif is_flag is False and not self._flag_needs_value: + # Not a flag, and prompt is not enabled, can be used as a + # flag if flag_value is set. + self._flag_needs_value = flag_value is not None + + if is_flag and default_is_missing and not self.required: + self.default: t.Union[t.Any, t.Callable[[], t.Any]] = False + + if flag_value is None: + flag_value = not self.default + + if is_flag and type is None: + # Re-guess the type from the flag value instead of the + # default. + self.type = types.convert_type(None, flag_value) + + self.is_flag: bool = is_flag + self.is_bool_flag = is_flag and isinstance(self.type, types.BoolParamType) + self.flag_value: t.Any = flag_value + + # Counting + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + if __debug__: + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError("'prompt' is not valid for non-boolean flag.") + + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError( + "'prompt' with 'hide_input' is not valid for boolean flag." + ) + + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + if self.multiple and self.is_flag: + raise TypeError("'multiple' is not valid with 'is_flag', use 'count'.") + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + flag_value=self.flag_value, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError("Could not determine name for option") + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: t.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar()}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + extra = [] + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + var_str = ( + envvar + if isinstance(envvar, str) + else ", ".join(str(d) for d in envvar) + ) + extra.append(_("env var: {var}").format(var=var_str)) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or (show_default and (default_value is not None)): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = split_opt( + (self.opts if self.default else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + else: + default_string = str(default_value) + + if default_string: + extra.append(_("default: {default}").format(default=default_string)) + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra.append(range_str) + + if self.required: + extra.append(_("required")) + + if extra: + extra_str = "; ".join(extra) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + # If we're a non boolean flag our default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return param.flag_value # type: ignore + + return None + + return super().get_default(ctx, call=call) + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt( + self.prompt, + default=default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + ) + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is None: + return None + + value_depth = (self.nargs != 1) + bool(self.multiple) + + if value_depth > 0: + rv = self.type.split_envvar_value(rv) + + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + + return rv + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, "Parameter"] + ) -> t.Tuple[t.Any, ParameterSource]: + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option can be + # given as a flag without a value. This is different from None + # to distinguish from the flag not being given at all. + if value is _flag_needs_value: + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + elif ( + self.multiple + and value is not None + and any(v is _flag_needs_value for v in value) + ): + value = [self.flag_value if v is _flag_needs_value else v for v in value] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt if + # prompting is enabled. + elif ( + source in {None, ParameterSource.DEFAULT} + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the parameter constructor. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: t.Sequence[str], + required: t.Optional[bool] = None, + **attrs: t.Any, + ) -> None: + if required is None: + if attrs.get("default") is not None: + required = False + else: + required = attrs.get("nargs", 1) > 0 + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + if __debug__: + if self.default is not None and self.nargs == -1: + raise TypeError("'default' is not supported for nargs=-1.") + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(self) + if not var: + var = self.name.upper() # type: ignore + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Could not determine name for argument") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [self.make_metavar()] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar()}'" + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/myenv/lib/python3.9/site-packages/click/decorators.py b/myenv/lib/python3.9/site-packages/click/decorators.py new file mode 100644 index 0000000..28618dc --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/decorators.py @@ -0,0 +1,497 @@ +import inspect +import types +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +FC = t.TypeVar("FC", bound=t.Union[t.Callable[..., t.Any], Command]) + + +def pass_context(f: F) -> F: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args, **kwargs): # type: ignore + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def pass_obj(f: F) -> F: + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args, **kwargs): # type: ignore + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def make_pass_decorator( + object_type: t.Type, ensure: bool = False +) -> "t.Callable[[F], F]": + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f: F) -> F: + def new_func(*args, **kwargs): # type: ignore + ctx = get_current_context() + + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + f" object of type {object_type.__name__!r}" + " existing." + ) + + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: t.Optional[str] = None +) -> "t.Callable[[F], F]": + """Create a decorator that passes a key from + :attr:`click.Context.meta` as the first argument to the decorated + function. + + :param key: Key in ``Context.meta`` to pass. + :param doc_description: Description of the object being passed, + inserted into the decorator's docstring. Defaults to "the 'key' + key from Context.meta". + + .. versionadded:: 8.0 + """ + + def decorator(f: F) -> F: + def new_func(*args, **kwargs): # type: ignore + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + if doc_description is None: + doc_description = f"the {key!r} key from :attr:`click.Context.meta`" + + decorator.__doc__ = ( + f"Decorator that passes {doc_description} as the first argument" + " to the decorated function." + ) + return decorator + + +CmdType = t.TypeVar("CmdType", bound=Command) + + +@t.overload +def command( + __func: t.Callable[..., t.Any], +) -> Command: + ... + + +@t.overload +def command( + name: t.Optional[str] = None, + **attrs: t.Any, +) -> t.Callable[..., Command]: + ... + + +@t.overload +def command( + name: t.Optional[str] = None, + cls: t.Type[CmdType] = ..., + **attrs: t.Any, +) -> t.Callable[..., CmdType]: + ... + + +def command( + name: t.Union[str, t.Callable[..., t.Any], None] = None, + cls: t.Optional[t.Type[Command]] = None, + **attrs: t.Any, +) -> t.Union[Command, t.Callable[..., Command]]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function with + underscores replaced by dashes. If you want to change that, you can + pass the intended name as the first argument. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name with underscores replaced by dashes. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Optional[t.Callable[..., t.Any]] = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = Command + + def decorator(f: t.Callable[..., t.Any]) -> Command: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + attr_params = attrs.pop("params", None) + params = attr_params if attr_params is not None else [] + + try: + decorator_params = f.__click_params__ # type: ignore + except AttributeError: + pass + else: + del f.__click_params__ # type: ignore + params.extend(reversed(decorator_params)) + + if attrs.get("help") is None: + attrs["help"] = f.__doc__ + + cmd = cls( # type: ignore[misc] + name=name or f.__name__.lower().replace("_", "-"), # type: ignore[arg-type] + callback=f, + params=params, + **attrs, + ) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +@t.overload +def group( + __func: t.Callable[..., t.Any], +) -> Group: + ... + + +@t.overload +def group( + name: t.Optional[str] = None, + **attrs: t.Any, +) -> t.Callable[[F], Group]: + ... + + +def group( + name: t.Union[str, t.Callable[..., t.Any], None] = None, **attrs: t.Any +) -> t.Union[Group, t.Callable[[F], Group]]: + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + """ + if attrs.get("cls") is None: + attrs["cls"] = Group + + if callable(name): + grp: t.Callable[[F], Group] = t.cast(Group, command(**attrs)) + return grp(name) + + return t.cast(Group, command(name, **attrs)) + + +def _param_memo(f: FC, param: Parameter) -> None: + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] # type: ignore + + f.__click_params__.append(param) # type: ignore + + +def argument(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]: + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + """ + + def decorator(f: FC) -> FC: + ArgumentClass = attrs.pop("cls", None) or Argument + _param_memo(f, ArgumentClass(param_decls, **attrs)) + return f + + return decorator + + +def option(*param_decls: str, **attrs: t.Any) -> t.Callable[[FC], FC]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + + def decorator(f: FC) -> FC: + # Issue 926, copy attrs, so pre-defined options can re-use the same cls= + option_attrs = attrs.copy() + OptionClass = option_attrs.pop("cls", None) or Option + _param_memo(f, OptionClass(param_decls, **option_attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", "Do you want to continue?") + kwargs.setdefault("help", "Confirm the action without prompting.") + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: t.Optional[str] = None, + *param_decls: str, + package_name: t.Optional[str] = None, + prog_name: t.Optional[str] = None, + message: t.Optional[str] = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. On Python < 3.8, the ``importlib_metadata`` + backport must be installed. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + metadata: t.Optional[types.ModuleType] + + try: + from importlib import metadata # type: ignore + except ImportError: + # Python < 3.8 + import importlib_metadata as metadata # type: ignore + + try: + version = metadata.version(package_name) # type: ignore + except metadata.PackageNotFoundError: # type: ignore + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + t.cast(str, message) + % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--help`` option which immediately prints the help page + and exits the program. + + This is usually unnecessary, as the ``--help`` option is added to + each command automatically unless ``add_help_option=False`` is + passed. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) diff --git a/myenv/lib/python3.9/site-packages/click/exceptions.py b/myenv/lib/python3.9/site-packages/click/exceptions.py new file mode 100644 index 0000000..9e20b3e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/exceptions.py @@ -0,0 +1,287 @@ +import os +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .utils import echo + +if t.TYPE_CHECKING: + from .core import Context + from .core import Parameter + + +def _join_param_hints( + param_hint: t.Optional[t.Union[t.Sequence[str], str]] +) -> t.Optional[str]: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.Optional[t.IO] = None) -> None: + if file is None: + file = get_text_stderr() + + echo(_("Error: {message}").format(message=self.format_message()), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd = self.ctx.command if self.ctx else None + + def show(self, file: t.Optional[t.IO] = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: t.Optional[str] = None, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + param_type: t.Optional[str] = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: t.Optional[str] = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: t.Optional[str] = None, + possibilities: t.Optional[t.Sequence[str]] = None, + ctx: t.Optional["Context"] = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: t.Optional["Context"] = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename = os.fsdecode(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code: int = 0) -> None: + self.exit_code = code diff --git a/myenv/lib/python3.9/site-packages/click/formatting.py b/myenv/lib/python3.9/site-packages/click/formatting.py new file mode 100644 index 0000000..ddd2a2f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +import typing as t +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: t.Optional[int] = None + + +def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]: + widths: t.Dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: t.Iterable[t.Tuple[str, str]], col_count: int +) -> t.Iterator[t.Tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: t.List[t.Tuple[int, bool, str]] = [] + buf: t.List[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: t.Optional[int] = None, + max_width: t.Optional[int] = None, + ) -> None: + import shutil + + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer: t.List[str] = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage( + self, prog: str, args: str = "", prefix: t.Optional[str] = None + ) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: t.Sequence[t.Tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> t.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> t.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/myenv/lib/python3.9/site-packages/click/globals.py b/myenv/lib/python3.9/site-packages/click/globals.py new file mode 100644 index 0000000..480058f --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/globals.py @@ -0,0 +1,68 @@ +import typing as t +from threading import local + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: "te.Literal[False]" = False) -> "Context": + ... + + +@t.overload +def get_current_context(silent: bool = ...) -> t.Optional["Context"]: + ... + + +def get_current_context(silent: bool = False) -> t.Optional["Context"]: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: "Context") -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/myenv/lib/python3.9/site-packages/click/parser.py b/myenv/lib/python3.9/site-packages/click/parser.py new file mode 100644 index 0000000..2d5a2ed --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/parser.py @@ -0,0 +1,529 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + +# Sentinel value that indicates an option was passed as a flag without a +# value but is not a flag option. Option.consume_value uses this to +# prompt or use the flag_value. +_flag_needs_value = object() + + +def _unpack_args( + args: t.Sequence[str], nargs_spec: t.Sequence[int] +) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] + spos: t.Optional[int] = None + + def _fetch(c: "te.Deque[V]") -> t.Optional[V]: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def split_opt(opt: str) -> t.Tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +def split_arg_string(string: str) -> t.List[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +class Option: + def __init__( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes = set() + + for opt in opts: + prefix, value = split_opt(opt) + if not prefix: + raise ValueError(f"Invalid start character for option ({opt})") + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self) -> bool: + return self.action in ("store", "append") + + def process(self, value: str, state: "ParsingState") -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class Argument: + def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], + state: "ParsingState", + ) -> None: + if self.nargs > 1: + assert value is not None + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + if self.nargs == -1 and self.obj.envvar is not None and value == (): + # Replace empty tuple with None so that a value from the + # environment may be tried. + value = None + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class ParsingState: + def __init__(self, rargs: t.List[str]) -> None: + self.opts: t.Dict[str, t.Any] = {} + self.largs: t.List[str] = [] + self.rargs = rargs + self.order: t.List["CoreParameter"] = [] + + +class OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx: t.Optional["Context"] = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options = False + + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + + self._short_opt: t.Dict[str, Option] = {} + self._long_opt: t.Dict[str, Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: t.List[Argument] = [] + + def add_option( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument( + self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1 + ) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: t.List[str] + ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: t.Optional[str], state: ParsingState + ) -> None: + if opt not in self._long_opt: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we re-combinate the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: Option, state: ParsingState + ) -> t.Any: + nargs = option.nargs + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = _flag_needs_value + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = _flag_needs_value + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) diff --git a/myenv/lib/python3.9/site-packages/click/py.typed b/myenv/lib/python3.9/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/myenv/lib/python3.9/site-packages/click/shell_completion.py b/myenv/lib/python3.9/site-packages/click/shell_completion.py new file mode 100644 index 0000000..c17a8e6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/shell_completion.py @@ -0,0 +1,580 @@ +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import BaseCommand +from .core import Context +from .core import MultiCommand +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .parser import split_arg_string +from .utils import echo + + +def shell_complete( + cli: BaseCommand, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> int: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + if instruction == "source": + echo(comp.source()) + return 0 + + if instruction == "complete": + echo(comp.complete()) + return 0 + + return 1 + + +class CompletionItem: + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: t.Any, + type: str = "plain", + help: t.Optional[str] = None, + **kwargs: t.Any, + ) -> None: + self.value = value + self.type = type + self.help = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +_SOURCE_ZSH = """\ +#compdef %(prog_name)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(prog_name)s] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ +%(complete_var)s=zsh_complete %(prog_name)s)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +compdef %(complete_func)s %(prog_name)s; +""" + +_SOURCE_FISH = """\ +function %(complete_func)s; + set -l response; + + for value in (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ +COMP_CWORD=(commandline -t) %(prog_name)s); + set response $response $value; + end; + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + def __init__( + self, + cli: BaseCommand, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: str, + ) -> None: + self.cli = cli + self.ctx_args = ctx_args + self.prog_name = prog_name + self.complete_var = complete_var + + @property + def func_name(self) -> str: + """The name of the shell function defined by the completion + script. + """ + safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> t.Dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions( + self, args: t.List[str], incomplete: str + ) -> t.List[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + def _check_version(self) -> None: + import subprocess + + output = subprocess.run( + ["bash", "-c", "echo ${BASH_VERSION}"], stdout=subprocess.PIPE + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + raise RuntimeError( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ) + ) + else: + raise RuntimeError( + _("Couldn't detect Bash version, shell completion is not supported.") + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name = "fish" + source_template = _SOURCE_FISH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +_available_shells: t.Dict[str, t.Type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: t.Type[ShellComplete], name: t.Optional[str] = None +) -> None: + """Register a :class:`ShellComplete` subclass under the given name. + The name will be provided by the completion instruction environment + variable during completion. + + :param cls: The completion class that will handle completion for the + shell. + :param name: Name to register the class under. Defaults to the + class's ``name`` attribute. + """ + if name is None: + name = cls.name + + _available_shells[name] = cls + + +def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + value = ctx.params[param.name] + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: BaseCommand, ctx_args: t.Dict[str, t.Any], prog_name: str, args: t.List[str] +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + ctx = cli.make_context(prog_name, args.copy(), **ctx_args) + args = ctx.protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, MultiCommand): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) + args = ctx.protected_args + ctx.args + else: + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + sub_ctx = cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx.protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: t.List[str], incomplete: str +) -> t.Tuple[t.Union[BaseCommand, Parameter], str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/myenv/lib/python3.9/site-packages/click/termui.py b/myenv/lib/python3.9/site-packages/click/termui.py new file mode 100644 index 0000000..bfb2f5a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/termui.py @@ -0,0 +1,787 @@ +import inspect +import io +import itertools +import os +import sys +import typing as t +from gettext import gettext as _ + +from ._compat import isatty +from ._compat import strip_ansi +from ._compat import WIN +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import echo +from .utils import LazyFile + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt: str) -> str: + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool = False, + default: t.Optional[t.Any] = None, + show_choices: bool = True, + type: t.Optional[ParamType] = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name # type: ignore + + return default + + +def prompt( + text: str, + default: t.Optional[t.Any] = None, + hide_input: bool = False, + confirmation_prompt: t.Union[bool, str] = False, + type: t.Optional[t.Union[ParamType, t.Any]] = None, + value_proc: t.Optional[t.Callable[[str], t.Any]] = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(" ") + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) # noqa: B306 + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: t.Optional[bool] = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(" ").lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str], + color: t.Optional[bool] = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast(t.Iterable[str], text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +def progressbar( + iterable: t.Optional[t.Iterable[V]] = None, + length: t.Optional[int] = None, + label: t.Optional[str] = None, + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, +) -> "ProgressBar[V]": + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + Added the ``update_min_steps`` parameter. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. Added the ``update`` method to + the object. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + if WIN: + os.system("cls") + else: + sys.stdout.write("\033[2J\033[1;1H") + + +def _interpret_color( + color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0 +) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bold: t.Optional[bool] = None, + dim: t.Optional[bool] = None, + underline: t.Optional[bool] = None, + overline: t.Optional[bool] = None, + italic: t.Optional[bool] = None, + blink: t.Optional[bool] = None, + reverse: t.Optional[bool] = None, + strikethrough: t.Optional[bool] = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.AnyStr]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +def edit( + text: t.Optional[t.AnyStr] = None, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + filename: t.Optional[str] = None, +) -> t.Optional[t.AnyStr]: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + ed.edit_file(filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Optional[t.Callable[[bool], str]] = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> t.ContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: t.Optional[str] = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/myenv/lib/python3.9/site-packages/click/testing.py b/myenv/lib/python3.9/site-packages/click/testing.py new file mode 100644 index 0000000..e395c2e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/testing.py @@ -0,0 +1,479 @@ +import contextlib +import io +import os +import shlex +import shutil +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from .core import BaseCommand + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> t.List[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> t.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: t.Optional[t.Union[str, bytes, t.IO]], charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast(t.IO, input)) + + if rv is not None: + return rv + + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif isinstance(input, str): + input = input.encode(charset) + + return io.BytesIO(t.cast(bytes, input)) + + +class Result: + """Holds the captured result of an invoked CLI script.""" + + def __init__( + self, + runner: "CliRunner", + stdout_bytes: bytes, + stderr_bytes: t.Optional[bytes], + return_value: t.Any, + exit_code: int, + exception: t.Optional[BaseException], + exc_info: t.Optional[ + t.Tuple[t.Type[BaseException], BaseException, TracebackType] + ] = None, + ): + #: The runner that created the result + self.runner = runner + #: The standard output as bytes. + self.stdout_bytes = stdout_bytes + #: The standard error as bytes, or None if not available + self.stderr_bytes = stderr_bytes + #: The value returned from the invoked command. + #: + #: .. versionadded:: 8.0 + self.return_value = return_value + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happened if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self) -> str: + """The (standard) output as unicode string.""" + return self.stdout + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string.""" + if self.stderr_bytes is None: + raise ValueError("stderr not separately captured") + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param mix_stderr: if this is set to `False`, then stdout and stderr are + preserved as independent streams. This is useful for + Unix-philosophy apps that have predictable stdout and + noisy stderr, such that each may be measured + independently + """ + + def __init__( + self, + charset: str = "utf-8", + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + echo_stdin: bool = False, + mix_stderr: bool = True, + ) -> None: + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + self.mix_stderr = mix_stderr + + def get_default_prog_name(self, cli: "BaseCommand") -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None + ) -> t.Mapping[str, t.Optional[str]]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: t.Optional[t.Union[str, bytes, t.IO]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + color: bool = False, + ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + ``stderr`` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + bytes_output = io.BytesIO() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, bytes_output) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + bytes_output, encoding=self.charset, name="", mode="w" + ) + + bytes_error = None + if self.mix_stderr: + sys.stderr = sys.stdout + else: + bytes_error = io.BytesIO() + sys.stderr = _NamedTextIOWrapper( + bytes_error, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(prompt or "") + val = text_input.readline().rstrip("\r\n") + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + return text_input.readline().rstrip("\r\n") + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (bytes_output, bytes_error) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: "BaseCommand", + args: t.Optional[t.Union[str, t.Sequence[str]]] = None, + input: t.Optional[t.Union[str, bytes, t.IO]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + catch_exceptions: bool = True, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: t.Optional[BaseException] = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + stdout = outstreams[0].getvalue() + if self.mix_stderr: + stderr = None + else: + stderr = outstreams[1].getvalue() # type: ignore + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: t.Optional[t.Union[str, os.PathLike]] = None + ) -> t.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) # type: ignore[type-var] + os.chdir(dt) + + try: + yield t.cast(str, dt) + finally: + os.chdir(cwd) + + if temp_dir is None: + try: + shutil.rmtree(dt) + except OSError: # noqa: B014 + pass diff --git a/myenv/lib/python3.9/site-packages/click/types.py b/myenv/lib/python3.9/site-packages/click/types.py new file mode 100644 index 0000000..b45ee53 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/types.py @@ -0,0 +1,1073 @@ +import os +import stat +import typing as t +from datetime import datetime +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import _get_argv_encoding +from ._compat import get_filesystem_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import LazyFile +from .utils import safecall + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[t.Optional[str]] = None + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: "Parameter") -> t.Optional[str]: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: "Parameter") -> t.Optional[str]: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> t.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> "t.NoReturn": + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name = func.__name__ + self.func = func + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = get_filesystem_encoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +class Choice(ParamType): + """The choice type allows a value to be checked against a fixed set + of supported values. All of these values have to be strings. + + You should only pass a list or tuple of choices. Other iterables + (like generators) may lead to surprising results. + + The resulting value will always be one of the originally passed choices + regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` + being specified. + + See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + """ + + name = "choice" + + def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None: + self.choices = choices + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + choices_str = "|".join(self.choices) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: "Parameter") -> str: + return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + # Match through normalization and case sensitivity + # first do token_normalize_func, then lowercase + # preserve original `value` to produce an accurate message in + # `self.fail` + normed_value = value + normed_choices = {choice: choice for choice in self.choices} + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(value) + normed_choices = { + ctx.token_normalize_func(normed_choice): original + for normed_choice, original in normed_choices.items() + } + + if not self.case_sensitive: + normed_value = normed_value.casefold() + normed_choices = { + normed_choice.casefold(): original + for normed_choice, original in normed_choices.items() + } + + if normed_value in normed_choices: + return normed_choices[normed_value] + + choices_str = ", ".join(map(repr, self.choices)) + self.fail( + ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: t.Optional[t.Sequence[str]] = None): + self.formats = formats or ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[t.Type] + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: "te.Literal[1, -1]", open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + if not open: + return bound + + # Could use Python 3.9's math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if value in {False, True}: + return bool(value) + + norm = value.strip().lower() + + if norm in {"1", "true", "t", "yes", "y", "on"}: + return True + + if norm in {"0", "false", "f", "no", "n", "off"}: + return False + + self.fail( + _("{value!r} is not a valid boolean.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + + name = "filename" + envvar_list_splitter = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: t.Optional[bool] = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: t.Any) -> bool: + if self.lazy is not None: + return self.lazy + if value == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + if hasattr(value, "read") or hasattr(value, "write"): + return value + + lazy = self.resolve_lazy_flag(value) + + if lazy: + f: t.IO = t.cast( + t.IO, + LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ), + ) + + if ctx is not None: + ctx.call_on_close(f.close_intelligently) # type: ignore + + return f + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + + return f + except OSError as e: # noqa: B014 + self.fail(f"'{os.fsdecode(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +class Path(ParamType): + """The ``Path`` type is similar to the :class:`File` type, but + returns the filename instead of an open file. Various checks can be + enabled to validate the type of file and permissions. + + :param exists: The file or directory needs to exist for the value to + be valid. If this is not set to ``True``, and the file does not + exist, then all further checks are silently skipped. + :param file_okay: Allow a file as a value. + :param dir_okay: Allow a directory as a value. + :param readable: if true, a readable check is performed. + :param writable: if true, a writable check is performed. + :param executable: if true, an executable check is performed. + :param resolve_path: Make the value absolute and resolve any + symlinks. A ``~`` is not expanded, as this is supposed to be + done by the shell only. + :param allow_dash: Allow a single dash as a value, which indicates + a standard stream (but does not open it). Use + :func:`~click.open_file` to handle opening this value. + :param path_type: Convert the incoming path value to this type. If + ``None``, keep Python's default, which is ``str``. Useful to + convert to :class:`pathlib.Path`. + + .. versionchanged:: 8.1 + Added the ``executable`` parameter. + + .. versionchanged:: 8.0 + Allow passing ``type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter = os.path.pathsep + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: t.Optional[t.Type] = None, + executable: bool = False, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.readable = readable + self.writable = writable + self.executable = executable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result(self, rv: t.Any) -> t.Any: + if self.type is not None and not isinstance(rv, self.type): + if self.type is str: + rv = os.fsdecode(rv) + elif self.type is bytes: + rv = os.fsencode(rv) + else: + rv = self.type(rv) + + return rv + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + # os.path.realpath doesn't resolve symlinks on Windows + # until Python 3.8. Use pathlib for now. + import pathlib + + rv = os.fsdecode(pathlib.Path(rv).resolve()) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + _("{name} {filename!r} is a file.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} '{filename}' is a directory.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if self.readable and not os.access(rv, os.R_OK): + self.fail( + _("{name} {filename!r} is not readable.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if self.writable and not os.access(rv, os.W_OK): + self.fail( + _("{name} {filename!r} is not writable.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + if self.executable and not os.access(value, os.X_OK): + self.fail( + _("{name} {filename!r} is not executable.").format( + name=self.name.title(), filename=os.fsdecode(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: t.Sequence[t.Union[t.Type, ParamType]]) -> None: + self.types = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/myenv/lib/python3.9/site-packages/click/utils.py b/myenv/lib/python3.9/site-packages/click/utils.py new file mode 100644 index 0000000..8283788 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/click/utils.py @@ -0,0 +1,580 @@ +import os +import re +import sys +import typing as t +from functools import update_wrapper +from types import ModuleType + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import _find_binary_writer +from ._compat import auto_wrap_for_ansi +from ._compat import binary_streams +from ._compat import get_filesystem_encoding +from ._compat import open_stream +from ._compat import should_strip_ansi +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import WIN +from .globals import resolve_color_default + +if t.TYPE_CHECKING: + import typing_extensions as te + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def safecall(func: F) -> F: + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args, **kwargs): # type: ignore + try: + return func(*args, **kwargs) + except Exception: + pass + + return update_wrapper(t.cast(F, wrapper), func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(get_filesystem_encoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return str(value) + + +def make_default_short_help(help: str, max_length: int = 45) -> str: + """Returns a condensed version of help string.""" + # Consider only the first paragraph. + paragraph_end = help.find("\n\n") + + if paragraph_end != -1: + help = help[:paragraph_end] + + # Collapse newlines, tabs, and spaces. + words = help.split() + + if not words: + return "" + + # The first paragraph started with a "no rewrap" marker, ignore it. + if words[0] == "\b": + words = words[1:] + + total_length = 0 + last_index = len(words) - 1 + + for i, word in enumerate(words): + total_length += len(word) + (i > 0) + + if total_length > max_length: # too long, truncate + break + + if word[-1] == ".": # sentence end, truncate without "..." + return " ".join(words[: i + 1]) + + if total_length == max_length and i != last_index: + break # not at sentence end, truncate with "..." + else: + return " ".join(words) # no truncation needed + + # Account for the length of the suffix. + total_length += len("...") + + # remove words until the length is short enough + while i > 0: + total_length -= len(words[i]) + (i > 0) + + if total_length <= max_length: + break + + i -= 1 + + return " ".join(words[:i]) + "..." + + +class LazyFile: + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__( + self, + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, + ): + self.name = filename + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + self._f: t.Optional[t.IO] + + if filename == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self.open(), name) + + def __repr__(self) -> str: + if self._f is not None: + return repr(self._f) + return f"" + + def open(self) -> t.IO: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: # noqa: E402 + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> "LazyFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.close_intelligently() + + def __iter__(self) -> t.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO) -> None: + self._file = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> "KeepOpenFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> t.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.Any]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, (str, bytes, bytearray)): + out: t.Optional[t.Union[str, bytes]] = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: "te.Literal['stdin', 'stdout', 'stderr']", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast(t.IO, LazyFile(filename, mode, encoding, errors, atomic=atomic)) + + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + + if not should_close: + f = t.cast(t.IO, KeepOpenFile(f)) + + return f + + +def format_filename( + filename: t.Union[str, bytes, os.PathLike], shorten: bool = False +) -> str: + """Formats a filename for user display. The main purpose of this + function is to ensure that the filename can be displayed at all. This + will decode the filename to unicode if necessary in a way that it will + not fail. Optionally, it can shorten the filename to not include the + full path to the filename. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + + return os.fsdecode(filename) + + +def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Windows (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Windows (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no affect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class PacifyFlushWrapper: + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + """ + + def __init__(self, wrapped: t.IO) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: t.Optional[str] = None, _main: t.Optional[ModuleType] = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + if getattr(_main, "__package__", None) is None or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: t.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> t.List[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/LICENSE.txt b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/LICENSE.txt new file mode 100644 index 0000000..3105888 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2010 Jonathan Hartley +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holders, nor those of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/METADATA b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/METADATA new file mode 100644 index 0000000..cd93935 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/METADATA @@ -0,0 +1,411 @@ +Metadata-Version: 2.1 +Name: colorama +Version: 0.4.5 +Summary: Cross-platform colored terminal text. +Home-page: https://github.com/tartley/colorama +Author: Jonathan Hartley +Author-email: tartley@tartley.com +Maintainer: Arnon Yaari +License: BSD +Keywords: color colour terminal text ansi windows crossplatform xplatform +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Terminals +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +License-File: LICENSE.txt + +.. image:: https://img.shields.io/pypi/v/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Latest Version + +.. image:: https://img.shields.io/pypi/pyversions/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Supported Python versions + +.. image:: https://github.com/tartley/colorama/actions/workflows/test.yml/badge.svg + :target: https://github.com/tartley/colorama/actions/workflows/test.yml + :alt: Build Status + +Colorama +======== + +Makes ANSI escape character sequences (for producing colored terminal text and +cursor positioning) work under MS Windows. + +.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD + :alt: Donate with Paypal + +`PyPI for releases `_ | +`Github for source `_ | +`Colorama for enterprise on Tidelift `_ + +If you find Colorama useful, please |donate| to the authors. Thank you! + + +Installation +------------ + +Tested on CPython 2.7, 3.5, 3.6, 3.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.6. + +No requirements other than the standard library. + +.. code-block:: bash + + pip install colorama + # or + conda install -c anaconda colorama + + +Description +----------- + +ANSI escape character sequences have long been used to produce colored terminal +text and cursor positioning on Unix and Macs. Colorama makes this work on +Windows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which +would appear as gobbledygook in the output), and converting them into the +appropriate win32 calls to modify the state of the terminal. On other platforms, +Colorama does nothing. + +This has the upshot of providing a simple cross-platform API for printing +colored terminal text from Python, and has the happy side-effect that existing +applications or libraries which use ANSI sequences to produce colored output on +Linux or Macs can now also work on Windows, simply by calling +``colorama.init()``. + +An alternative approach is to install ``ansi.sys`` on Windows machines, which +provides the same behaviour for all applications running in terminals. Colorama +is intended for situations where that isn't easy (e.g., maybe your app doesn't +have an installer.) + +Demo scripts in the source code repository print some colored text using +ANSI sequences. Compare their output under Gnome-terminal's built in ANSI +handling, versus on Windows Command-Prompt using Colorama: + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/ubuntu-demo.png + :width: 661 + :height: 357 + :alt: ANSI sequences on Ubuntu under gnome-terminal. + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/windows-demo.png + :width: 668 + :height: 325 + :alt: Same ANSI sequences on Windows, using Colorama. + +These screenshots show that, on Windows, Colorama does not support ANSI 'dim +text'; it looks the same as 'normal text'. + +Usage +----- + +Initialisation +.............. + +Applications should initialise Colorama using: + +.. code-block:: python + + from colorama import init + init() + +On Windows, calling ``init()`` will filter ANSI escape sequences out of any +text sent to ``stdout`` or ``stderr``, and replace them with equivalent Win32 +calls. + +On other platforms, calling ``init()`` has no effect (unless you request other +optional functionality, see "Init Keyword Args" below; or if output +is redirected). By design, this permits applications to call ``init()`` +unconditionally on all platforms, after which ANSI output should just work. + +On all platforms, if output is redirected, ANSI escape sequences are completely +stripped out. + +To stop using Colorama before your program exits, simply call ``deinit()``. +This will restore ``stdout`` and ``stderr`` to their original values, so that +Colorama is disabled. To resume using Colorama again, call ``reinit()``; it is +cheaper than calling ``init()`` again (but does the same thing). + + +Colored Output +.............. + +Cross-platform printing of colored text can then be done using Colorama's +constant shorthand for ANSI escape sequences. These are deliberately +rudimentary, see below. + +.. code-block:: python + + from colorama import Fore, Back, Style + print(Fore.RED + 'some red text') + print(Back.GREEN + 'and with a green background') + print(Style.DIM + 'and in dim text') + print(Style.RESET_ALL) + print('back to normal now') + +...or simply by manually printing ANSI sequences from your own code: + +.. code-block:: python + + print('\033[31m' + 'some red text') + print('\033[39m') # and reset to default color + +...or, Colorama can be used in conjunction with existing ANSI libraries +such as the venerable `Termcolor `_ +the fabulous `Blessings `_, +or the incredible `_Rich `_. + +If you wish Colorama's Fore, Back and Style constants were more capable, +then consider using one of the above highly capable libraries to generate +colors, etc, and use Colorama just for its primary purpose: to convert +those ANSI sequences to also work on Windows: + +.. code-block:: python + + from colorama import init + from termcolor import colored + + # use Colorama to make Termcolor work on Windows too + init() + + # then use Termcolor for all colored text output + print(colored('Hello, World!', 'green', 'on_red')) + +Available formatting constants are:: + + Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Style: DIM, NORMAL, BRIGHT, RESET_ALL + +``Style.RESET_ALL`` resets foreground, background, and brightness. Colorama will +perform this reset automatically on program exit. + +These are fairly well supported, but not part of the standard:: + + Fore: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + Back: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + + +Cursor Positioning +.................. + +ANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for +an example of how to generate them. + + +Init Keyword Args +................. + +``init()`` accepts some ``**kwargs`` to override default behaviour. + +init(autoreset=False): + If you find yourself repeatedly sending reset sequences to turn off color + changes at the end of every print, then ``init(autoreset=True)`` will + automate that: + + .. code-block:: python + + from colorama import init + init(autoreset=True) + print(Fore.RED + 'some red text') + print('automatically back to default color again') + +init(strip=None): + Pass ``True`` or ``False`` to override whether ANSI codes should be + stripped from the output. The default behaviour is to strip if on Windows + or if output is redirected (not a tty). + +init(convert=None): + Pass ``True`` or ``False`` to override whether to convert ANSI codes in the + output into win32 calls. The default behaviour is to convert if on Windows + and output is to a tty (terminal). + +init(wrap=True): + On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr`` + with proxy objects, which override the ``.write()`` method to do their work. + If this wrapping causes you problems, then this can be disabled by passing + ``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or + ``strip`` or ``convert`` are True. + + When wrapping is disabled, colored printing on non-Windows platforms will + continue to work as normal. To do cross-platform colored output, you can + use Colorama's ``AnsiToWin32`` proxy directly: + + .. code-block:: python + + import sys + from colorama import init, AnsiToWin32 + init(wrap=False) + stream = AnsiToWin32(sys.stderr).stream + + # Python 2 + print >>stream, Fore.BLUE + 'blue text on stderr' + + # Python 3 + print(Fore.BLUE + 'blue text on stderr', file=stream) + + +Recognised ANSI Sequences +......................... + +ANSI sequences generally take the form:: + + ESC [ ; ... + +Where ```` is an integer, and ```` is a single letter. Zero or +more params are passed to a ````. If no params are passed, it is +generally synonymous with passing a single zero. No spaces exist in the +sequence; they have been inserted here simply to read more easily. + +The only ANSI sequences that Colorama converts into win32 calls are:: + + ESC [ 0 m # reset all (colors and brightness) + ESC [ 1 m # bright + ESC [ 2 m # dim (looks same as normal brightness) + ESC [ 22 m # normal brightness + + # FOREGROUND: + ESC [ 30 m # black + ESC [ 31 m # red + ESC [ 32 m # green + ESC [ 33 m # yellow + ESC [ 34 m # blue + ESC [ 35 m # magenta + ESC [ 36 m # cyan + ESC [ 37 m # white + ESC [ 39 m # reset + + # BACKGROUND + ESC [ 40 m # black + ESC [ 41 m # red + ESC [ 42 m # green + ESC [ 43 m # yellow + ESC [ 44 m # blue + ESC [ 45 m # magenta + ESC [ 46 m # cyan + ESC [ 47 m # white + ESC [ 49 m # reset + + # cursor positioning + ESC [ y;x H # position cursor at x across, y down + ESC [ y;x f # position cursor at x across, y down + ESC [ n A # move cursor n lines up + ESC [ n B # move cursor n lines down + ESC [ n C # move cursor n characters forward + ESC [ n D # move cursor n characters backward + + # clear the screen + ESC [ mode J # clear the screen + + # clear the line + ESC [ mode K # clear the line + +Multiple numeric params to the ``'m'`` command can be combined into a single +sequence:: + + ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background + +All other ANSI sequences of the form ``ESC [ ; ... `` +are silently stripped from the output on Windows. + +Any other form of ANSI sequence, such as single-character codes or alternative +initial characters, are not recognised or stripped. It would be cool to add +them though. Let me know if it would be useful for you, via the Issues on +GitHub. + + +Status & Known Problems +----------------------- + +I've personally only tested it on Windows XP (CMD, Console2), Ubuntu +(gnome-terminal, xterm), and OS X. + +Some presumably valid ANSI sequences aren't recognised (see details below), +but to my knowledge nobody has yet complained about this. Puzzling. + +See outstanding issues and wish-list: +https://github.com/tartley/colorama/issues + +If anything doesn't work for you, or doesn't do what you expected or hoped for, +I'd love to hear about it on that issues list, would be delighted by patches, +and would be happy to grant commit access to anyone who submits a working patch +or two. + +If you're hacking on the code, see `README-hacking.md`_. + +.. _README-hacking.md: README-hacking.md + + +License +------- + +Copyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see +LICENSE file. + + +Professional support +-------------------- + +.. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png + :alt: Tidelift + :target: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for colorama is available as part of the + `Tidelift Subscription`_. + 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. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + + +Thanks +------ + +* Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5. +* Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``, + providing a solution to issue #7's setuptools/distutils debate, + and other fixes. +* User 'eryksun', for guidance on correctly instantiating ``ctypes.windll``. +* Matthew McCormick for politely pointing out a longstanding crash on non-Win. +* Ben Hoyt, for a magnificent fix under 64-bit Windows. +* Jesse at Empty Square for submitting a fix for examples in the README. +* User 'jamessp', an observant documentation fix for cursor positioning. +* User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7 + fix. +* Julien Stuyck, for wisely suggesting Python3 compatible updates to README. +* Daniel Griffith for multiple fabulous patches. +* Oscar Lesta for a valuable fix to stop ANSI chars being sent to non-tty + output. +* Roger Binns, for many suggestions, valuable feedback, & bug reports. +* Tim Golden for thought and much appreciated feedback on the initial idea. +* User 'Zearin' for updates to the README file. +* John Szakmeister for adding support for light colors +* Charles Merriam for adding documentation to demos +* Jurko for a fix on 64-bit Windows CPython2.5 w/o ctypes +* Florian Bruhin for a fix when stdout or stderr are None +* Thomas Weininger for fixing ValueError on Windows +* Remi Rampin for better Github integration and fixes to the README file +* Simeon Visser for closing a file handle using 'with' and updating classifiers + to include Python 3.3 and 3.4 +* Andy Neff for fixing RESET of LIGHT_EX colors. +* Jonathan Hartley for the initial idea and implementation. diff --git a/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/RECORD b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/RECORD new file mode 100644 index 0000000..02a3c5e --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/RECORD @@ -0,0 +1,12 @@ +colorama/__init__.py,sha256=ihDoWQOkapwF7sqQ99AoDoEF3vGYm40OtmgW211cLZw,239 +colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522 +colorama/ansitowin32.py,sha256=gGrO7MVtwc-j1Sq3jKfZpERT1JWmYSOsTVDiTnFbZU4,10830 +colorama/initialise.py,sha256=PprovDNxMTrvoNHFcL2NZjpH2XzDc8BLxLxiErfUl4k,1915 +colorama/win32.py,sha256=bJ8Il9jwaBN5BJ8bmN6FoYZ1QYuMKv2j8fGrXh7TJjw,5404 +colorama/winterm.py,sha256=2y_2b7Zsv34feAsP67mLOVc-Bgq51mdYGo571VprlrM,6438 +colorama-0.4.5.dist-info/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 +colorama-0.4.5.dist-info/METADATA,sha256=Kb6MoYzWBmkPhFCf0SW7a-5Eeyssj-szefJmxokQFSU,15128 +colorama-0.4.5.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110 +colorama-0.4.5.dist-info/top_level.txt,sha256=_Kx6-Cni2BT1PEATPhrSRxo0d7kSgfBbHf5o7IF1ABw,9 +colorama-0.4.5.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +colorama-0.4.5.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/WHEEL new file mode 100644 index 0000000..0b18a28 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/top_level.txt new file mode 100644 index 0000000..3fcfb51 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama-0.4.5.dist-info/top_level.txt @@ -0,0 +1 @@ +colorama diff --git a/myenv/lib/python3.9/site-packages/colorama/__init__.py b/myenv/lib/python3.9/site-packages/colorama/__init__.py new file mode 100644 index 0000000..9138a8c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama/__init__.py @@ -0,0 +1,6 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.4.5' diff --git a/myenv/lib/python3.9/site-packages/colorama/ansi.py b/myenv/lib/python3.9/site-packages/colorama/ansi.py new file mode 100644 index 0000000..11ec695 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama/ansi.py @@ -0,0 +1,102 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +''' +This module generates ANSI character codes to printing colors to terminals. +See: http://en.wikipedia.org/wiki/ANSI_escape_code +''' + +CSI = '\033[' +OSC = '\033]' +BEL = '\a' + + +def code_to_chars(code): + return CSI + str(code) + 'm' + +def set_title(title): + return OSC + '2;' + title + BEL + +def clear_screen(mode=2): + return CSI + str(mode) + 'J' + +def clear_line(mode=2): + return CSI + str(mode) + 'K' + + +class AnsiCodes(object): + def __init__(self): + # the subclasses declare class attributes which are numbers. + # Upon instantiation we define instance attributes, which are the same + # as the class attributes but wrapped with the ANSI escape sequence + for name in dir(self): + if not name.startswith('_'): + value = getattr(self, name) + setattr(self, name, code_to_chars(value)) + + +class AnsiCursor(object): + def UP(self, n=1): + return CSI + str(n) + 'A' + def DOWN(self, n=1): + return CSI + str(n) + 'B' + def FORWARD(self, n=1): + return CSI + str(n) + 'C' + def BACK(self, n=1): + return CSI + str(n) + 'D' + def POS(self, x=1, y=1): + return CSI + str(y) + ';' + str(x) + 'H' + + +class AnsiFore(AnsiCodes): + BLACK = 30 + RED = 31 + GREEN = 32 + YELLOW = 33 + BLUE = 34 + MAGENTA = 35 + CYAN = 36 + WHITE = 37 + RESET = 39 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 90 + LIGHTRED_EX = 91 + LIGHTGREEN_EX = 92 + LIGHTYELLOW_EX = 93 + LIGHTBLUE_EX = 94 + LIGHTMAGENTA_EX = 95 + LIGHTCYAN_EX = 96 + LIGHTWHITE_EX = 97 + + +class AnsiBack(AnsiCodes): + BLACK = 40 + RED = 41 + GREEN = 42 + YELLOW = 43 + BLUE = 44 + MAGENTA = 45 + CYAN = 46 + WHITE = 47 + RESET = 49 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 100 + LIGHTRED_EX = 101 + LIGHTGREEN_EX = 102 + LIGHTYELLOW_EX = 103 + LIGHTBLUE_EX = 104 + LIGHTMAGENTA_EX = 105 + LIGHTCYAN_EX = 106 + LIGHTWHITE_EX = 107 + + +class AnsiStyle(AnsiCodes): + BRIGHT = 1 + DIM = 2 + NORMAL = 22 + RESET_ALL = 0 + +Fore = AnsiFore() +Back = AnsiBack() +Style = AnsiStyle() +Cursor = AnsiCursor() diff --git a/myenv/lib/python3.9/site-packages/colorama/ansitowin32.py b/myenv/lib/python3.9/site-packages/colorama/ansitowin32.py new file mode 100644 index 0000000..3db248b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama/ansitowin32.py @@ -0,0 +1,266 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import re +import sys +import os + +from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style, BEL +from .winterm import WinTerm, WinColor, WinStyle +from .win32 import windll, winapi_test + + +winterm = None +if windll is not None: + winterm = WinTerm() + + +class StreamWrapper(object): + ''' + Wraps a stream (such as stdout), acting as a transparent proxy for all + attribute access apart from method 'write()', which is delegated to our + Converter instance. + ''' + def __init__(self, wrapped, converter): + # double-underscore everything to prevent clashes with names of + # attributes on the wrapped stream object. + self.__wrapped = wrapped + self.__convertor = converter + + def __getattr__(self, name): + return getattr(self.__wrapped, name) + + def __enter__(self, *args, **kwargs): + # special method lookup bypasses __getattr__/__getattribute__, see + # https://stackoverflow.com/questions/12632894/why-doesnt-getattr-work-with-exit + # thus, contextlib magic methods are not proxied via __getattr__ + return self.__wrapped.__enter__(*args, **kwargs) + + def __exit__(self, *args, **kwargs): + return self.__wrapped.__exit__(*args, **kwargs) + + def __setstate__(self, state): + self.__dict__ = state + + def __getstate__(self): + return self.__dict__ + + def write(self, text): + self.__convertor.write(text) + + def isatty(self): + stream = self.__wrapped + if 'PYCHARM_HOSTED' in os.environ: + if stream is not None and (stream is sys.__stdout__ or stream is sys.__stderr__): + return True + try: + stream_isatty = stream.isatty + except AttributeError: + return False + else: + return stream_isatty() + + @property + def closed(self): + stream = self.__wrapped + try: + return stream.closed + # AttributeError in the case that the stream doesn't support being closed + # ValueError for the case that the stream has already been detached when atexit runs + except (AttributeError, ValueError): + return True + + +class AnsiToWin32(object): + ''' + Implements a 'write()' method which, on Windows, will strip ANSI character + sequences from the text, and if outputting to a tty, will convert them into + win32 function calls. + ''' + ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer + ANSI_OSC_RE = re.compile('\001?\033\\]([^\a]*)(\a)\002?') # Operating System Command + + def __init__(self, wrapped, convert=None, strip=None, autoreset=False): + # The wrapped stream (normally sys.stdout or sys.stderr) + self.wrapped = wrapped + + # should we reset colors to defaults after every .write() + self.autoreset = autoreset + + # create the proxy wrapping our output stream + self.stream = StreamWrapper(wrapped, self) + + on_windows = os.name == 'nt' + # We test if the WinAPI works, because even if we are on Windows + # we may be using a terminal that doesn't support the WinAPI + # (e.g. Cygwin Terminal). In this case it's up to the terminal + # to support the ANSI codes. + conversion_supported = on_windows and winapi_test() + + # should we strip ANSI sequences from our output? + if strip is None: + strip = conversion_supported or (not self.stream.closed and not self.stream.isatty()) + self.strip = strip + + # should we should convert ANSI sequences into win32 calls? + if convert is None: + convert = conversion_supported and not self.stream.closed and self.stream.isatty() + self.convert = convert + + # dict of ansi codes to win32 functions and parameters + self.win32_calls = self.get_win32_calls() + + # are we wrapping stderr? + self.on_stderr = self.wrapped is sys.stderr + + def should_wrap(self): + ''' + True if this class is actually needed. If false, then the output + stream will not be affected, nor will win32 calls be issued, so + wrapping stdout is not actually required. This will generally be + False on non-Windows platforms, unless optional functionality like + autoreset has been requested using kwargs to init() + ''' + return self.convert or self.strip or self.autoreset + + def get_win32_calls(self): + if self.convert and winterm: + return { + AnsiStyle.RESET_ALL: (winterm.reset_all, ), + AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), + AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), + AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), + AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), + AnsiFore.RED: (winterm.fore, WinColor.RED), + AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), + AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), + AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), + AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), + AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), + AnsiFore.WHITE: (winterm.fore, WinColor.GREY), + AnsiFore.RESET: (winterm.fore, ), + AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), + AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), + AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), + AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), + AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), + AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), + AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), + AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), + AnsiBack.BLACK: (winterm.back, WinColor.BLACK), + AnsiBack.RED: (winterm.back, WinColor.RED), + AnsiBack.GREEN: (winterm.back, WinColor.GREEN), + AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), + AnsiBack.BLUE: (winterm.back, WinColor.BLUE), + AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), + AnsiBack.CYAN: (winterm.back, WinColor.CYAN), + AnsiBack.WHITE: (winterm.back, WinColor.GREY), + AnsiBack.RESET: (winterm.back, ), + AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), + AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), + AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), + AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), + AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), + AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), + AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), + AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), + } + return dict() + + def write(self, text): + if self.strip or self.convert: + self.write_and_convert(text) + else: + self.wrapped.write(text) + self.wrapped.flush() + if self.autoreset: + self.reset_all() + + + def reset_all(self): + if self.convert: + self.call_win32('m', (0,)) + elif not self.strip and not self.stream.closed: + self.wrapped.write(Style.RESET_ALL) + + + def write_and_convert(self, text): + ''' + Write the given text to our wrapped stream, stripping any ANSI + sequences from the text, and optionally converting them into win32 + calls. + ''' + cursor = 0 + text = self.convert_osc(text) + for match in self.ANSI_CSI_RE.finditer(text): + start, end = match.span() + self.write_plain_text(text, cursor, start) + self.convert_ansi(*match.groups()) + cursor = end + self.write_plain_text(text, cursor, len(text)) + + + def write_plain_text(self, text, start, end): + if start < end: + self.wrapped.write(text[start:end]) + self.wrapped.flush() + + + def convert_ansi(self, paramstring, command): + if self.convert: + params = self.extract_params(command, paramstring) + self.call_win32(command, params) + + + def extract_params(self, command, paramstring): + if command in 'Hf': + params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) + while len(params) < 2: + # defaults: + params = params + (1,) + else: + params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) + if len(params) == 0: + # defaults: + if command in 'JKm': + params = (0,) + elif command in 'ABCD': + params = (1,) + + return params + + + def call_win32(self, command, params): + if command == 'm': + for param in params: + if param in self.win32_calls: + func_args = self.win32_calls[param] + func = func_args[0] + args = func_args[1:] + kwargs = dict(on_stderr=self.on_stderr) + func(*args, **kwargs) + elif command in 'J': + winterm.erase_screen(params[0], on_stderr=self.on_stderr) + elif command in 'K': + winterm.erase_line(params[0], on_stderr=self.on_stderr) + elif command in 'Hf': # cursor position - absolute + winterm.set_cursor_position(params, on_stderr=self.on_stderr) + elif command in 'ABCD': # cursor position - relative + n = params[0] + # A - up, B - down, C - forward, D - back + x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] + winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) + + + def convert_osc(self, text): + for match in self.ANSI_OSC_RE.finditer(text): + start, end = match.span() + text = text[:start] + text[end:] + paramstring, command = match.groups() + if command == BEL: + if paramstring.count(";") == 1: + params = paramstring.split(";") + # 0 - change title and icon (we will only change title) + # 1 - change icon (we don't support this) + # 2 - change title + if params[0] in '02': + winterm.set_title(params[1]) + return text diff --git a/myenv/lib/python3.9/site-packages/colorama/initialise.py b/myenv/lib/python3.9/site-packages/colorama/initialise.py new file mode 100644 index 0000000..430d066 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama/initialise.py @@ -0,0 +1,80 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import atexit +import contextlib +import sys + +from .ansitowin32 import AnsiToWin32 + + +orig_stdout = None +orig_stderr = None + +wrapped_stdout = None +wrapped_stderr = None + +atexit_done = False + + +def reset_all(): + if AnsiToWin32 is not None: # Issue #74: objects might become None at exit + AnsiToWin32(orig_stdout).reset_all() + + +def init(autoreset=False, convert=None, strip=None, wrap=True): + + if not wrap and any([autoreset, convert, strip]): + raise ValueError('wrap=False conflicts with any other arg=True') + + global wrapped_stdout, wrapped_stderr + global orig_stdout, orig_stderr + + orig_stdout = sys.stdout + orig_stderr = sys.stderr + + if sys.stdout is None: + wrapped_stdout = None + else: + sys.stdout = wrapped_stdout = \ + wrap_stream(orig_stdout, convert, strip, autoreset, wrap) + if sys.stderr is None: + wrapped_stderr = None + else: + sys.stderr = wrapped_stderr = \ + wrap_stream(orig_stderr, convert, strip, autoreset, wrap) + + global atexit_done + if not atexit_done: + atexit.register(reset_all) + atexit_done = True + + +def deinit(): + if orig_stdout is not None: + sys.stdout = orig_stdout + if orig_stderr is not None: + sys.stderr = orig_stderr + + +@contextlib.contextmanager +def colorama_text(*args, **kwargs): + init(*args, **kwargs) + try: + yield + finally: + deinit() + + +def reinit(): + if wrapped_stdout is not None: + sys.stdout = wrapped_stdout + if wrapped_stderr is not None: + sys.stderr = wrapped_stderr + + +def wrap_stream(stream, convert, strip, autoreset, wrap): + if wrap: + wrapper = AnsiToWin32(stream, + convert=convert, strip=strip, autoreset=autoreset) + if wrapper.should_wrap(): + stream = wrapper.stream + return stream diff --git a/myenv/lib/python3.9/site-packages/colorama/win32.py b/myenv/lib/python3.9/site-packages/colorama/win32.py new file mode 100644 index 0000000..c2d8360 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama/win32.py @@ -0,0 +1,152 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +try: + import ctypes + from ctypes import LibraryLoader + windll = LibraryLoader(ctypes.WinDLL) + from ctypes import wintypes +except (AttributeError, ImportError): + windll = None + SetConsoleTextAttribute = lambda *_: None + winapi_test = lambda *_: None +else: + from ctypes import byref, Structure, c_char, POINTER + + COORD = wintypes._COORD + + class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + def __str__(self): + return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( + self.dwSize.Y, self.dwSize.X + , self.dwCursorPosition.Y, self.dwCursorPosition.X + , self.wAttributes + , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right + , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X + ) + + _GetStdHandle = windll.kernel32.GetStdHandle + _GetStdHandle.argtypes = [ + wintypes.DWORD, + ] + _GetStdHandle.restype = wintypes.HANDLE + + _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo + _GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + POINTER(CONSOLE_SCREEN_BUFFER_INFO), + ] + _GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute + _SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + ] + _SetConsoleTextAttribute.restype = wintypes.BOOL + + _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition + _SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + COORD, + ] + _SetConsoleCursorPosition.restype = wintypes.BOOL + + _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA + _FillConsoleOutputCharacterA.argtypes = [ + wintypes.HANDLE, + c_char, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputCharacterA.restype = wintypes.BOOL + + _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute + _FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputAttribute.restype = wintypes.BOOL + + _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW + _SetConsoleTitleW.argtypes = [ + wintypes.LPCWSTR + ] + _SetConsoleTitleW.restype = wintypes.BOOL + + def _winapi_test(handle): + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return bool(success) + + def winapi_test(): + return any(_winapi_test(h) for h in + (_GetStdHandle(STDOUT), _GetStdHandle(STDERR))) + + def GetConsoleScreenBufferInfo(stream_id=STDOUT): + handle = _GetStdHandle(stream_id) + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return csbi + + def SetConsoleTextAttribute(stream_id, attrs): + handle = _GetStdHandle(stream_id) + return _SetConsoleTextAttribute(handle, attrs) + + def SetConsoleCursorPosition(stream_id, position, adjust=True): + position = COORD(*position) + # If the position is out of range, do nothing. + if position.Y <= 0 or position.X <= 0: + return + # Adjust for Windows' SetConsoleCursorPosition: + # 1. being 0-based, while ANSI is 1-based. + # 2. expecting (x,y), while ANSI uses (y,x). + adjusted_position = COORD(position.Y - 1, position.X - 1) + if adjust: + # Adjust for viewport's scroll position + sr = GetConsoleScreenBufferInfo(STDOUT).srWindow + adjusted_position.Y += sr.Top + adjusted_position.X += sr.Left + # Resume normal processing + handle = _GetStdHandle(stream_id) + return _SetConsoleCursorPosition(handle, adjusted_position) + + def FillConsoleOutputCharacter(stream_id, char, length, start): + handle = _GetStdHandle(stream_id) + char = c_char(char.encode()) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + success = _FillConsoleOutputCharacterA( + handle, char, length, start, byref(num_written)) + return num_written.value + + def FillConsoleOutputAttribute(stream_id, attr, length, start): + ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' + handle = _GetStdHandle(stream_id) + attribute = wintypes.WORD(attr) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + return _FillConsoleOutputAttribute( + handle, attribute, length, start, byref(num_written)) + + def SetConsoleTitle(title): + return _SetConsoleTitleW(title) diff --git a/myenv/lib/python3.9/site-packages/colorama/winterm.py b/myenv/lib/python3.9/site-packages/colorama/winterm.py new file mode 100644 index 0000000..0fdb4ec --- /dev/null +++ b/myenv/lib/python3.9/site-packages/colorama/winterm.py @@ -0,0 +1,169 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from . import win32 + + +# from wincon.h +class WinColor(object): + BLACK = 0 + BLUE = 1 + GREEN = 2 + CYAN = 3 + RED = 4 + MAGENTA = 5 + YELLOW = 6 + GREY = 7 + +# from wincon.h +class WinStyle(object): + NORMAL = 0x00 # dim text, dim background + BRIGHT = 0x08 # bright text, dim background + BRIGHT_BACKGROUND = 0x80 # dim text, bright background + +class WinTerm(object): + + def __init__(self): + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self.set_attrs(self._default) + self._default_fore = self._fore + self._default_back = self._back + self._default_style = self._style + # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. + # So that LIGHT_EX colors and BRIGHT style do not clobber each other, + # we track them separately, since LIGHT_EX is overwritten by Fore/Back + # and BRIGHT is overwritten by Style codes. + self._light = 0 + + def get_attrs(self): + return self._fore + self._back * 16 + (self._style | self._light) + + def set_attrs(self, value): + self._fore = value & 7 + self._back = (value >> 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + self._light = 0 + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + elif mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + elif mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/INSTALLER b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/INSTALLER new file mode 100644 index 0000000..2f9ab90 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/INSTALLER @@ -0,0 +1 @@ +Poetry 1.6.1 \ No newline at end of file diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE new file mode 100644 index 0000000..0707425 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE @@ -0,0 +1,6 @@ +This software is made available under the terms of *either* of the licenses +found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made +under the terms of *both* these licenses. + +The code used in the OS random engine is derived from CPython, and is licensed +under the terms of the PSF License Agreement. diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.APACHE b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.APACHE new file mode 100644 index 0000000..62589ed --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.APACHE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.BSD b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.BSD new file mode 100644 index 0000000..ec1a29d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.BSD @@ -0,0 +1,27 @@ +Copyright (c) Individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of PyCA Cryptography nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.PSF b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.PSF new file mode 100644 index 0000000..4d3a4f5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/LICENSE.PSF @@ -0,0 +1,41 @@ +1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and + the Individual or Organization ("Licensee") accessing and otherwise using Python + 2.7.12 software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python 2.7.12 alone or in any derivative + version, provided, however, that PSF's License Agreement and PSF's notice of + copyright, i.e., "Copyright © 2001-2016 Python Software Foundation; All Rights + Reserved" are retained in Python 2.7.12 alone or in any derivative version + prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or + incorporates Python 2.7.12 or any part thereof, and wants to make the + derivative work available to others as provided herein, then Licensee hereby + agrees to include in any such work a brief summary of the changes made to Python + 2.7.12. + +4. PSF is making Python 2.7.12 available to Licensee on an "AS IS" basis. + PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF + EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE + USE OF PYTHON 2.7.12 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.12 + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.12, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of + its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship + of agency, partnership, or joint venture between PSF and Licensee. This License + Agreement does not grant permission to use PSF trademarks or trade name in a + trademark sense to endorse or promote products or services of Licensee, or any + third party. + +8. By copying, installing or otherwise using Python 2.7.12, Licensee agrees + to be bound by the terms and conditions of this License Agreement. diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/METADATA b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/METADATA new file mode 100644 index 0000000..9ed7d6c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/METADATA @@ -0,0 +1,138 @@ +Metadata-Version: 2.1 +Name: cryptography +Version: 37.0.4 +Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. +Home-page: https://github.com/pyca/cryptography +Author: The Python Cryptographic Authority and individual contributors +Author-email: cryptography-dev@python.org +License: BSD-3-Clause OR Apache-2.0 +Project-URL: Documentation, https://cryptography.io/ +Project-URL: Source, https://github.com/pyca/cryptography/ +Project-URL: Issues, https://github.com/pyca/cryptography/issues +Project-URL: Changelog, https://cryptography.io/en/latest/changelog/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: License :: OSI Approved :: BSD License +Classifier: Natural Language :: English +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: POSIX +Classifier: Operating System :: POSIX :: BSD +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Security :: Cryptography +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: LICENSE.APACHE +License-File: LICENSE.BSD +License-File: LICENSE.PSF +Requires-Dist: cffi (>=1.12) +Provides-Extra: docs +Requires-Dist: sphinx (!=1.8.0,!=3.1.0,!=3.1.1,>=1.6.5) ; extra == 'docs' +Requires-Dist: sphinx-rtd-theme ; extra == 'docs' +Provides-Extra: docstest +Requires-Dist: pyenchant (>=1.6.11) ; extra == 'docstest' +Requires-Dist: twine (>=1.12.0) ; extra == 'docstest' +Requires-Dist: sphinxcontrib-spelling (>=4.0.1) ; extra == 'docstest' +Provides-Extra: pep8test +Requires-Dist: black ; extra == 'pep8test' +Requires-Dist: flake8 ; extra == 'pep8test' +Requires-Dist: flake8-import-order ; extra == 'pep8test' +Requires-Dist: pep8-naming ; extra == 'pep8test' +Provides-Extra: sdist +Requires-Dist: setuptools-rust (>=0.11.4) ; extra == 'sdist' +Provides-Extra: ssh +Requires-Dist: bcrypt (>=3.1.5) ; extra == 'ssh' +Provides-Extra: test +Requires-Dist: pytest (>=6.2.0) ; extra == 'test' +Requires-Dist: pytest-benchmark ; extra == 'test' +Requires-Dist: pytest-cov ; extra == 'test' +Requires-Dist: pytest-subtests ; extra == 'test' +Requires-Dist: pytest-xdist ; extra == 'test' +Requires-Dist: pretend ; extra == 'test' +Requires-Dist: iso8601 ; extra == 'test' +Requires-Dist: pytz ; extra == 'test' +Requires-Dist: hypothesis (!=3.79.2,>=1.11.4) ; extra == 'test' + +pyca/cryptography +================= + +.. image:: https://img.shields.io/pypi/v/cryptography.svg + :target: https://pypi.org/project/cryptography/ + :alt: Latest Version + +.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest + :target: https://cryptography.io + :alt: Latest Docs + +.. image:: https://github.com/pyca/cryptography/workflows/CI/badge.svg?branch=main + :target: https://github.com/pyca/cryptography/actions?query=workflow%3ACI+branch%3Amain + +.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=main + :target: https://codecov.io/github/pyca/cryptography?branch=main + + +``cryptography`` is a package which provides cryptographic recipes and +primitives to Python developers. Our goal is for it to be your "cryptographic +standard library". It supports Python 3.6+ and PyPy3 7.2+. + +``cryptography`` includes both high level recipes and low level interfaces to +common cryptographic algorithms such as symmetric ciphers, message digests, and +key derivation functions. For example, to encrypt something with +``cryptography``'s high level symmetric encryption recipe: + +.. code-block:: pycon + + >>> from cryptography.fernet import Fernet + >>> # Put this somewhere safe! + >>> key = Fernet.generate_key() + >>> f = Fernet(key) + >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") + >>> token + '...' + >>> f.decrypt(token) + 'A really secret message. Not for prying eyes.' + +You can find more information in the `documentation`_. + +You can install ``cryptography`` with: + +.. code-block:: console + + $ pip install cryptography + +For full details see `the installation documentation`_. + +Discussion +~~~~~~~~~~ + +If you run into bugs, you can file them in our `issue tracker`_. + +We maintain a `cryptography-dev`_ mailing list for development discussion. + +You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get +involved. + +Security +~~~~~~~~ + +Need to report a security issue? Please consult our `security reporting`_ +documentation. + + +.. _`documentation`: https://cryptography.io/ +.. _`the installation documentation`: https://cryptography.io/en/latest/installation/ +.. _`issue tracker`: https://github.com/pyca/cryptography/issues +.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev +.. _`security reporting`: https://cryptography.io/en/latest/security/ diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/RECORD b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/RECORD new file mode 100644 index 0000000..c09d990 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/RECORD @@ -0,0 +1,99 @@ +cryptography/__about__.py,sha256=--Ir4xTpXvJIAKXDX9hap3KQf2E9--cHRoaKB-fb_cY,417 +cryptography/__init__.py,sha256=j08JCN_u_m8eL-zxbXRxgsriW6Oe29oSSo_e2hyyasg,748 +cryptography/exceptions.py,sha256=sN_VVTF_LuKMM6R-lIASFFuzAmz1uZ2Qbcdko9WyS64,1471 +cryptography/fernet.py,sha256=W1NZKgmIxX-iMJr6GW-vm-j4BkYACKxHjrq4cbIZMaw,6604 +cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +cryptography/utils.py,sha256=v3zj8FS2bHYAmH__CECwfa0flmFCQnGrxZBRQcDys1A,5627 +cryptography/hazmat/__init__.py,sha256=OYlvgprzULzZlsf3yYTsd6VUVyQmpsbHjgJdNnsyRwE,418 +cryptography/hazmat/_oid.py,sha256=CrOgnohV6ckWZU7ZFUYvgf_Gj8npC7LhJfzBB6wLHYc,15440 +cryptography/hazmat/backends/__init__.py,sha256=bgrjB1SX2vXX-rmfG7A4PqGkq-isqQVXGaZtjWHAgj0,324 +cryptography/hazmat/backends/openssl/__init__.py,sha256=7rpz1Z3eV9vZy_d2iLrwC8Oz0vEruDFrjJlc6W2ZDXA,271 +cryptography/hazmat/backends/openssl/aead.py,sha256=1GASyrJPO8a-mDPTT7VJZXPb_0zEdrkW-Wu_rxV-6RQ,8442 +cryptography/hazmat/backends/openssl/backend.py,sha256=XBpLgVxVYvXwmkdcCwd0bVQWK0EBTHTbCFDsLGsBbBg,96584 +cryptography/hazmat/backends/openssl/ciphers.py,sha256=n3rrPQZi1blJBKqIWeMG6-U6YTvEb8rXGQKn8i-kFog,10342 +cryptography/hazmat/backends/openssl/cmac.py,sha256=K5-S0H72KHZH-WPAcHL5jCtcNyoBZSMe7VmxGn8_VWA,3005 +cryptography/hazmat/backends/openssl/decode_asn1.py,sha256=nSqtgO5MJVf_UUkvw9tez10zhGnsGHq24OP1X2GKOe4,1113 +cryptography/hazmat/backends/openssl/dh.py,sha256=9fwPordToELTkeJ-c7TuO9NiE1vfUBejk2QEUZbvo4s,12230 +cryptography/hazmat/backends/openssl/dsa.py,sha256=awfP80ykAfb4C_I-aOo-PnGU1DF6uf8bnEi-jld18ec,8888 +cryptography/hazmat/backends/openssl/ec.py,sha256=kgxwW508FTXDwGG-7pSywBLlICZKKfo4bcTHnNpsvJY,11103 +cryptography/hazmat/backends/openssl/ed25519.py,sha256=irHT-jSbpTNMMHqw5T885uzAi3Syf3kaaHuTnKgQPSg,5920 +cryptography/hazmat/backends/openssl/ed448.py,sha256=K8HDEiXl98QGJ-4llT4SVZf5-xe8aCuci00DkZf0lhw,5874 +cryptography/hazmat/backends/openssl/encode_asn1.py,sha256=4RUYVTpkYh6J1BnmYdr3G8xv4X1H-K2k2-fQoIDkpHI,570 +cryptography/hazmat/backends/openssl/hashes.py,sha256=3L5bkCOo2LbRSVNGLca_9rpCZ2zb8ISBrMLtts1BkEw,3241 +cryptography/hazmat/backends/openssl/hmac.py,sha256=9RX8bo9ywJievoodxjmqCXmD2iUWyH2jBmw78Hb-pOY,3095 +cryptography/hazmat/backends/openssl/poly1305.py,sha256=_qyGCXNaQVCFpa1qjb_9UtsI6lmnki_15Jbc5vihbeE,2514 +cryptography/hazmat/backends/openssl/rsa.py,sha256=KK97C_jBJEUGfKfJK7E8QZ-uZb6DTJjX6dLOuVbqTI8,20720 +cryptography/hazmat/backends/openssl/utils.py,sha256=7Ara81KkY0QCLPqW6kUG9dEsp52cZ3kOUJczwEpecJ0,1977 +cryptography/hazmat/backends/openssl/x25519.py,sha256=oA_ao4o27ki_OAx0UXNeI2ItZ84Xg_li7It1DxFlrZ0,4753 +cryptography/hazmat/backends/openssl/x448.py,sha256=a_zgqGUpGFvyKEoKRR1vgNdD_gk1gxGYpBp1a6x9HuE,4338 +cryptography/hazmat/backends/openssl/x509.py,sha256=WUoRC6UDM9FkOdn6xR5Mk-v_WCq7eJryenGN9ni8L-A,1452 +cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/bindings/_openssl.abi3.so,sha256=8iHtYijm7UPnTTJ2C0n5tOrVDan81I-HEF9oR2SvVyM,6023128 +cryptography/hazmat/bindings/_rust.abi3.so,sha256=OmU1FnjADpbk4-CDvbk2G63VxB6MbrYeivWX_IBBNz0,2004592 +cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=ga5QLYp8MmumQB-Rp4TGHq_NAqONcXTrLm2712TZ9Ms,103 +cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=Hovrt8dXZ9p8BKHaroPYmunu1VtDuirslJnE4jTG28s,411 +cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=jATWMh1yz5JpnnT7A10_sbY-ja5zARnOpZaToLqm43Y,768 +cryptography/hazmat/bindings/_rust/x509.pyi,sha256=YdnUA9uu60WhQP5QihTgo2pBrT49wxYtayCZ4trgZAg,1497 +cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/bindings/openssl/_conditional.py,sha256=K0JIsYkDBifV-x5WDeq9M1Hofr6HW667rDFlhDEiIMQ,10078 +cryptography/hazmat/bindings/openssl/binding.py,sha256=hWWp-N_JMUuYaNuRHgpadEEdVJsL-wAhdQpTj-Pi0Vc,8044 +cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/primitives/_asymmetric.py,sha256=nVJwmxkakirAXfFp410pC4kY_CinzN5FSJwhEn2IE34,485 +cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=zd7N8rBYWaf8tPM7GDtZ9vUgarK_P0_PUNCFi3A0u0c,1016 +cryptography/hazmat/primitives/_serialization.py,sha256=OC_uXC5cNHucoOkHuTsZbfcQ9bvZs1cq7b18TcJu4Es,1341 +cryptography/hazmat/primitives/cmac.py,sha256=ODkc7EonY1cRxyJ0SYOuwtiYQv6B0ZPxJQm3rXxfXd4,2037 +cryptography/hazmat/primitives/constant_time.py,sha256=6bkW00QjhKusdgsQbexXhMlGX0XRN59XNmxWS2W38NA,387 +cryptography/hazmat/primitives/hashes.py,sha256=cpaYjgkazlq7Xw0MVoR3cp17mD0TgyEvhZQbyoAWHzU,5996 +cryptography/hazmat/primitives/hmac.py,sha256=M_sa4smPIkO8ra17Xl_cM0daRhGCozUu_8gnHePEIb0,2131 +cryptography/hazmat/primitives/keywrap.py,sha256=TWqyG9K7k-Ymq4kcIw7u3NIKUPVDtv6bimwxIJYTe20,5643 +cryptography/hazmat/primitives/padding.py,sha256=xruasOE5Cd8KEQ-yp9W6v9WKPvKH-GudHCPKQ7A8HfI,6207 +cryptography/hazmat/primitives/poly1305.py,sha256=QvxPMrqjgKJt0mOZSeZKk4NcxsNCd2kgfI-X1CmyUW4,1837 +cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 +cryptography/hazmat/primitives/asymmetric/dh.py,sha256=pjjgKFcn2bCAaL_5zr0ygwXM8pHJFyAO6koJFkzhQb8,6604 +cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=dIo6lYiHWRWUCxwejAi01w1-3jjmzEuJovqaVqDO3_g,7870 +cryptography/hazmat/primitives/asymmetric/ec.py,sha256=wX8wH9bD7g7-YxmINam_s9cPc9RUPrui2QdIKg6Q3Nc,14468 +cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=1qOl1UWV_-cXKHhwlFSyPBdhpx2HMDRukkI6eI5i8vM,2728 +cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=oR-j4jGcWUnGxWi1GygHxVZbgkSOKHsR6y1E3Lf6wYM,2647 +cryptography/hazmat/primitives/asymmetric/padding.py,sha256=EkKuY9e6UFqSuQ0LvyKYKl_L19tOfNCTlHWEiKgHeUc,2690 +cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=GiCIuBuJdpeew-yJ7mnTF4KFH_FUJaut1r-d6TRs31s,11322 +cryptography/hazmat/primitives/asymmetric/types.py,sha256=VidxjUWPOMB8q8vGiaXMhY715Zw8U9Vd4_rkqjOagRE,1814 +cryptography/hazmat/primitives/asymmetric/utils.py,sha256=5hD4KjfMbmozeFq08PLVunHr4FgeVzV1NkKalECM26s,756 +cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=-nbaGlgT1sufO9Ic-urwKDql8Da0U3GL6hZJIMqHgVc,2588 +cryptography/hazmat/primitives/asymmetric/x448.py,sha256=V3lxb1VOiRTa3bzVUC3uZat2ogfExUOdktCIGUUMZ2Y,2556 +cryptography/hazmat/primitives/ciphers/__init__.py,sha256=Qp78Y3PDSRfwp7DDa3pezlLrED_QFhic_LvDw4LM9ZQ,646 +cryptography/hazmat/primitives/ciphers/aead.py,sha256=QnJD2doZ8XdpCIrDwqJBNgaw2eG9Tx4FWirIP159MAg,11488 +cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=GoM_c2LNonci43B06g0e9zXW6PfBh_uAFiZhIxrQ_x4,4677 +cryptography/hazmat/primitives/ciphers/base.py,sha256=AiCYCzXbSZ9wQbXWMYc60IKmzqz5619YdaaF0zVr4rY,8251 +cryptography/hazmat/primitives/ciphers/modes.py,sha256=Pb2h2X0HUVfM6xKdSZjCgCsUcCQ32mDTSTRQQl4-1Gs,7988 +cryptography/hazmat/primitives/kdf/__init__.py,sha256=DcZhzfLG8d8IYBH771lGTVU5S87OQDpu3nrfOwZnsmA,715 +cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=5YXw8cLZCBYT6rVDGS5URQEeFiPW-ZRBRcPdZQIxTMA,3772 +cryptography/hazmat/primitives/kdf/hkdf.py,sha256=LlDQbCvlNzuLa_UJXrkG5fXGjAjor5Wunv2378TBmms,3031 +cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=QmgJw2_l0D21DEMMfuNQ6e1IaLV3bjwOzMJEAXhpOVs,7699 +cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=wEMH4CJfPccCg9apQLXyWUWBrZLTpYLLnoZEnzvaHQo,2032 +cryptography/hazmat/primitives/kdf/scrypt.py,sha256=JvX_cD0o0Op5EcFNeZhr-vI5sYv_LdnJ6kNEbW3u5ow,2228 +cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=JsdrJhw2IJVYkl8JIWUN66h7DrKZM2RoQ_tw_iKAvdI,2018 +cryptography/hazmat/primitives/serialization/__init__.py,sha256=RALEthF7wRjlMyTvSq09XmKQey74tsSdDCCsDaD6yQU,1129 +cryptography/hazmat/primitives/serialization/base.py,sha256=yw8_yzIvruT6fmS-KrTmIXbAF00rItH48WXTPOSLdJ4,1761 +cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=tHQlCKOY0EfOBBiqR_et4TgcDY_OAtRENC69arjvyLU,6481 +cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=LnISP-1SEDXCpsoEbR0EfuIlWm8eJAgWupt0gvHyyIU,5870 +cryptography/hazmat/primitives/serialization/ssh.py,sha256=Bp4M8yFrLnw9Oj3jCbttewovymCX_OGzBg5GBw4RPpA,23923 +cryptography/hazmat/primitives/twofactor/__init__.py,sha256=ZHo4zwWidFP2RWFl8luiNuYkVMZPghzx54izPNSCtD4,222 +cryptography/hazmat/primitives/twofactor/hotp.py,sha256=v4wkTbdc1E53POx6pdNnEUBvANbmt4f6scQSsTgABeU,2989 +cryptography/hazmat/primitives/twofactor/totp.py,sha256=bIIxOI-LcLGNahB5kN7A_TwEyYMTsLjHd8eJc4b2cLg,1449 +cryptography/x509/__init__.py,sha256=yC0TbuvPmWL1U4rEY-0m46SayuxCfPVNFWjJJdi5lY0,7654 +cryptography/x509/base.py,sha256=FNBVG8ACCBZLF5TXlq1vjEPWtlR5YZ1Bs25AIxEHI34,33747 +cryptography/x509/certificate_transparency.py,sha256=Elm_-GGA6k9zrcm5KYVY5uTirDsvGc_BUuTLR7Hu-K4,1119 +cryptography/x509/extensions.py,sha256=LFy1jgd_0Z_P-lE2-07nZGJmsFh_1cOOTAl9ejyXFHQ,64999 +cryptography/x509/general_name.py,sha256=S_kJd4ZsNGrMfi2osfFJEWqPxy3oPCAWpLb91yhxzPs,7896 +cryptography/x509/name.py,sha256=EOtO9CscxrfsxhO6GTEfVhiZo3_EE7qGIFfv1eeI4-U,14200 +cryptography/x509/ocsp.py,sha256=OQKsqW_Y4mWY53UT_JG79RJR19xt53Q-iQSSw4m0kZM,16691 +cryptography/x509/oid.py,sha256=CLIlQwzE3PQXMvkKep4JbzVUaRDl_stwcX_U6-s2cNw,794 +cryptography-37.0.4.dist-info/LICENSE,sha256=Q9rSzHUqtyHNmp827OcPtTq3cTVR8tPYaU2OjFoG1uI,323 +cryptography-37.0.4.dist-info/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 +cryptography-37.0.4.dist-info/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 +cryptography-37.0.4.dist-info/LICENSE.PSF,sha256=aT7ApmKzn5laTyUrA6YiKUVHDBtvEsoCkY5O_g32S58,2415 +cryptography-37.0.4.dist-info/METADATA,sha256=xTRAAMAb3cHqW1cXChdK9TXOWG2ghhz-sdfmRXvXrqU,5434 +cryptography-37.0.4.dist-info/WHEEL,sha256=MfjkjXwqeYlORnFhJNWi-eFW4jhozqV8XXeu9PzVv9Y,110 +cryptography-37.0.4.dist-info/top_level.txt,sha256=zYbdX67v4JFZPfsaNue7ZV4-mgoRqYCAhMsNgt22LqA,22 +cryptography-37.0.4.dist-info/INSTALLER,sha256=gRgfSaB7mbFTKnL6UjSYEdWrvm1o583nO6nktg_YuCc,12 +cryptography-37.0.4.dist-info/RECORD,, diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/WHEEL b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/WHEEL new file mode 100644 index 0000000..fd41c07 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: false +Tag: cp36-abi3-macosx_10_10_x86_64 + diff --git a/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/top_level.txt b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/top_level.txt new file mode 100644 index 0000000..f512e40 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography-37.0.4.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_openssl +cryptography diff --git a/myenv/lib/python3.9/site-packages/cryptography/__about__.py b/myenv/lib/python3.9/site-packages/cryptography/__about__.py new file mode 100644 index 0000000..399beb6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/__about__.py @@ -0,0 +1,15 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +__all__ = [ + "__version__", + "__author__", + "__copyright__", +] + +__version__ = "37.0.4" + +__author__ = "The Python Cryptographic Authority and individual contributors" +__copyright__ = "Copyright 2013-2022 {}".format(__author__) diff --git a/myenv/lib/python3.9/site-packages/cryptography/__init__.py b/myenv/lib/python3.9/site-packages/cryptography/__init__.py new file mode 100644 index 0000000..599bf51 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/__init__.py @@ -0,0 +1,29 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import sys +import warnings + +from cryptography.__about__ import ( + __author__, + __copyright__, + __version__, +) +from cryptography.utils import CryptographyDeprecationWarning + + +__all__ = [ + "__version__", + "__author__", + "__copyright__", +] + +if sys.version_info[:2] == (3, 6): + warnings.warn( + "Python 3.6 is no longer supported by the Python core team. " + "Therefore, support for it is deprecated in cryptography and will be" + " removed in a future release.", + CryptographyDeprecationWarning, + stacklevel=2, + ) diff --git a/myenv/lib/python3.9/site-packages/cryptography/exceptions.py b/myenv/lib/python3.9/site-packages/cryptography/exceptions.py new file mode 100644 index 0000000..a315703 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/exceptions.py @@ -0,0 +1,68 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography import utils + +if typing.TYPE_CHECKING: + from cryptography.hazmat.bindings.openssl.binding import ( + _OpenSSLErrorWithText, + ) + + +class _Reasons(utils.Enum): + BACKEND_MISSING_INTERFACE = 0 + UNSUPPORTED_HASH = 1 + UNSUPPORTED_CIPHER = 2 + UNSUPPORTED_PADDING = 3 + UNSUPPORTED_MGF = 4 + UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5 + UNSUPPORTED_ELLIPTIC_CURVE = 6 + UNSUPPORTED_SERIALIZATION = 7 + UNSUPPORTED_X509 = 8 + UNSUPPORTED_EXCHANGE_ALGORITHM = 9 + UNSUPPORTED_DIFFIE_HELLMAN = 10 + UNSUPPORTED_MAC = 11 + + +class UnsupportedAlgorithm(Exception): + def __init__( + self, message: str, reason: typing.Optional[_Reasons] = None + ) -> None: + super(UnsupportedAlgorithm, self).__init__(message) + self._reason = reason + + +class AlreadyFinalized(Exception): + pass + + +class AlreadyUpdated(Exception): + pass + + +class NotYetFinalized(Exception): + pass + + +class InvalidTag(Exception): + pass + + +class InvalidSignature(Exception): + pass + + +class InternalError(Exception): + def __init__( + self, msg: str, err_code: typing.List["_OpenSSLErrorWithText"] + ) -> None: + super(InternalError, self).__init__(msg) + self.err_code = err_code + + +class InvalidKey(Exception): + pass diff --git a/myenv/lib/python3.9/site-packages/cryptography/fernet.py b/myenv/lib/python3.9/site-packages/cryptography/fernet.py new file mode 100644 index 0000000..9c5a3d7 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/fernet.py @@ -0,0 +1,212 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import base64 +import binascii +import os +import time +import typing + +from cryptography import utils +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import hashes, padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.hmac import HMAC + + +class InvalidToken(Exception): + pass + + +_MAX_CLOCK_SKEW = 60 + + +class Fernet: + def __init__( + self, + key: typing.Union[bytes, str], + backend: typing.Any = None, + ): + try: + key = base64.urlsafe_b64decode(key) + except binascii.Error as exc: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) from exc + if len(key) != 32: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) + + self._signing_key = key[:16] + self._encryption_key = key[16:] + + @classmethod + def generate_key(cls) -> bytes: + return base64.urlsafe_b64encode(os.urandom(32)) + + def encrypt(self, data: bytes) -> bytes: + return self.encrypt_at_time(data, int(time.time())) + + def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: + iv = os.urandom(16) + return self._encrypt_from_parts(data, current_time, iv) + + def _encrypt_from_parts( + self, data: bytes, current_time: int, iv: bytes + ) -> bytes: + utils._check_bytes("data", data) + + padder = padding.PKCS7(algorithms.AES.block_size).padder() + padded_data = padder.update(data) + padder.finalize() + encryptor = Cipher( + algorithms.AES(self._encryption_key), + modes.CBC(iv), + ).encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + + basic_parts = ( + b"\x80" + + current_time.to_bytes(length=8, byteorder="big") + + iv + + ciphertext + ) + + h = HMAC(self._signing_key, hashes.SHA256()) + h.update(basic_parts) + hmac = h.finalize() + return base64.urlsafe_b64encode(basic_parts + hmac) + + def decrypt(self, token: bytes, ttl: typing.Optional[int] = None) -> bytes: + timestamp, data = Fernet._get_unverified_token_data(token) + if ttl is None: + time_info = None + else: + time_info = (ttl, int(time.time())) + return self._decrypt_data(data, timestamp, time_info) + + def decrypt_at_time( + self, token: bytes, ttl: int, current_time: int + ) -> bytes: + if ttl is None: + raise ValueError( + "decrypt_at_time() can only be used with a non-None ttl" + ) + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, (ttl, current_time)) + + def extract_timestamp(self, token: bytes) -> int: + timestamp, data = Fernet._get_unverified_token_data(token) + # Verify the token was not tampered with. + self._verify_signature(data) + return timestamp + + @staticmethod + def _get_unverified_token_data(token: bytes) -> typing.Tuple[int, bytes]: + utils._check_bytes("token", token) + try: + data = base64.urlsafe_b64decode(token) + except (TypeError, binascii.Error): + raise InvalidToken + + if not data or data[0] != 0x80: + raise InvalidToken + + if len(data) < 9: + raise InvalidToken + + timestamp = int.from_bytes(data[1:9], byteorder="big") + return timestamp, data + + def _verify_signature(self, data: bytes) -> None: + h = HMAC(self._signing_key, hashes.SHA256()) + h.update(data[:-32]) + try: + h.verify(data[-32:]) + except InvalidSignature: + raise InvalidToken + + def _decrypt_data( + self, + data: bytes, + timestamp: int, + time_info: typing.Optional[typing.Tuple[int, int]], + ) -> bytes: + if time_info is not None: + ttl, current_time = time_info + if timestamp + ttl < current_time: + raise InvalidToken + + if current_time + _MAX_CLOCK_SKEW < timestamp: + raise InvalidToken + + self._verify_signature(data) + + iv = data[9:25] + ciphertext = data[25:-32] + decryptor = Cipher( + algorithms.AES(self._encryption_key), modes.CBC(iv) + ).decryptor() + plaintext_padded = decryptor.update(ciphertext) + try: + plaintext_padded += decryptor.finalize() + except ValueError: + raise InvalidToken + unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() + + unpadded = unpadder.update(plaintext_padded) + try: + unpadded += unpadder.finalize() + except ValueError: + raise InvalidToken + return unpadded + + +class MultiFernet: + def __init__(self, fernets: typing.Iterable[Fernet]): + fernets = list(fernets) + if not fernets: + raise ValueError( + "MultiFernet requires at least one Fernet instance" + ) + self._fernets = fernets + + def encrypt(self, msg: bytes) -> bytes: + return self.encrypt_at_time(msg, int(time.time())) + + def encrypt_at_time(self, msg: bytes, current_time: int) -> bytes: + return self._fernets[0].encrypt_at_time(msg, current_time) + + def rotate(self, msg: bytes) -> bytes: + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + p = f._decrypt_data(data, timestamp, None) + break + except InvalidToken: + pass + else: + raise InvalidToken + + iv = os.urandom(16) + return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) + + def decrypt(self, msg: bytes, ttl: typing.Optional[int] = None) -> bytes: + for f in self._fernets: + try: + return f.decrypt(msg, ttl) + except InvalidToken: + pass + raise InvalidToken + + def decrypt_at_time( + self, msg: bytes, ttl: int, current_time: int + ) -> bytes: + for f in self._fernets: + try: + return f.decrypt_at_time(msg, ttl, current_time) + except InvalidToken: + pass + raise InvalidToken diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/__init__.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/__init__.py new file mode 100644 index 0000000..007694b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/__init__.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +Hazardous Materials + +This is a "Hazardous Materials" module. You should ONLY use it if you're +100% absolutely sure that you know what you're doing because this module +is full of land mines, dragons, and dinosaurs with laser guns. +""" diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/_oid.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/_oid.py new file mode 100644 index 0000000..da3668b --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/_oid.py @@ -0,0 +1,345 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import hashes + + +class ObjectIdentifier: + def __init__(self, dotted_string: str) -> None: + self._dotted_string = dotted_string + + nodes = self._dotted_string.split(".") + intnodes = [] + + # There must be at least 2 nodes, the first node must be 0..2, and + # if less than 2, the second node cannot have a value outside the + # range 0..39. All nodes must be integers. + for node in nodes: + try: + node_value = int(node, 10) + except ValueError: + raise ValueError( + f"Malformed OID: {dotted_string} (non-integer nodes)" + ) + if node_value < 0: + raise ValueError( + f"Malformed OID: {dotted_string} (negative-integer nodes)" + ) + intnodes.append(node_value) + + if len(nodes) < 2: + raise ValueError( + f"Malformed OID: {dotted_string} " + "(insufficient number of nodes)" + ) + + if intnodes[0] > 2: + raise ValueError( + f"Malformed OID: {dotted_string} " + "(first node outside valid range)" + ) + + if intnodes[0] < 2 and intnodes[1] >= 40: + raise ValueError( + f"Malformed OID: {dotted_string} " + "(second node outside valid range)" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ObjectIdentifier): + return NotImplemented + + return self.dotted_string == other.dotted_string + + def __repr__(self) -> str: + return "".format( + self.dotted_string, self._name + ) + + def __hash__(self) -> int: + return hash(self.dotted_string) + + @property + def _name(self) -> str: + return _OID_NAMES.get(self, "Unknown OID") + + @property + def dotted_string(self) -> str: + return self._dotted_string + + +class ExtensionOID: + SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") + SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") + KEY_USAGE = ObjectIdentifier("2.5.29.15") + SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") + ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") + BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") + NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") + CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") + CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") + POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") + AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") + POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") + EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") + FRESHEST_CRL = ObjectIdentifier("2.5.29.46") + INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") + ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28") + AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") + SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") + OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") + TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") + CRL_NUMBER = ObjectIdentifier("2.5.29.20") + DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") + PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier( + "1.3.6.1.4.1.11129.2.4.2" + ) + PRECERT_POISON = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") + SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") + + +class OCSPExtensionOID: + NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") + + +class CRLEntryExtensionOID: + CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") + CRL_REASON = ObjectIdentifier("2.5.29.21") + INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") + + +class NameOID: + COMMON_NAME = ObjectIdentifier("2.5.4.3") + COUNTRY_NAME = ObjectIdentifier("2.5.4.6") + LOCALITY_NAME = ObjectIdentifier("2.5.4.7") + STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") + STREET_ADDRESS = ObjectIdentifier("2.5.4.9") + ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") + ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") + SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") + SURNAME = ObjectIdentifier("2.5.4.4") + GIVEN_NAME = ObjectIdentifier("2.5.4.42") + TITLE = ObjectIdentifier("2.5.4.12") + GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") + X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") + DN_QUALIFIER = ObjectIdentifier("2.5.4.46") + PSEUDONYM = ObjectIdentifier("2.5.4.65") + USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") + DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") + EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") + JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") + JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") + JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( + "1.3.6.1.4.1.311.60.2.1.2" + ) + BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") + POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") + POSTAL_CODE = ObjectIdentifier("2.5.4.17") + INN = ObjectIdentifier("1.2.643.3.131.1.1") + OGRN = ObjectIdentifier("1.2.643.100.1") + SNILS = ObjectIdentifier("1.2.643.100.3") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + +class SignatureAlgorithmOID: + RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") + RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") + # This is an alternate OID for RSA with SHA1 that is occasionally seen + _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") + RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") + RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11") + RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12") + RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") + RSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.13") + RSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.14") + RSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.15") + RSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.16") + RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") + ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") + ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") + ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") + ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") + ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") + ECDSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.9") + ECDSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.10") + ECDSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.11") + ECDSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.12") + DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") + DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") + DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") + DSA_WITH_SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.3.3") + DSA_WITH_SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.3.4") + ED25519 = ObjectIdentifier("1.3.101.112") + ED448 = ObjectIdentifier("1.3.101.113") + GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") + GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") + GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") + + +_SIG_OIDS_TO_HASH: typing.Dict[ + ObjectIdentifier, typing.Optional[hashes.HashAlgorithm] +] = { + SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), + SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ED25519: None, + SignatureAlgorithmOID.ED448: None, + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, +} + + +class ExtendedKeyUsageOID: + SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") + CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") + CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") + EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") + TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") + OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") + ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") + SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") + KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") + IPSEC_IKE = ObjectIdentifier("1.3.6.1.5.5.7.3.17") + + +class AuthorityInformationAccessOID: + CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") + OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") + + +class SubjectInformationAccessOID: + CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") + + +class CertificatePoliciesOID: + CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") + CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") + ANY_POLICY = ObjectIdentifier("2.5.29.32.0") + + +class AttributeOID: + CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + +_OID_NAMES = { + NameOID.COMMON_NAME: "commonName", + NameOID.COUNTRY_NAME: "countryName", + NameOID.LOCALITY_NAME: "localityName", + NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", + NameOID.STREET_ADDRESS: "streetAddress", + NameOID.ORGANIZATION_NAME: "organizationName", + NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", + NameOID.SERIAL_NUMBER: "serialNumber", + NameOID.SURNAME: "surname", + NameOID.GIVEN_NAME: "givenName", + NameOID.TITLE: "title", + NameOID.GENERATION_QUALIFIER: "generationQualifier", + NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", + NameOID.DN_QUALIFIER: "dnQualifier", + NameOID.PSEUDONYM: "pseudonym", + NameOID.USER_ID: "userID", + NameOID.DOMAIN_COMPONENT: "domainComponent", + NameOID.EMAIL_ADDRESS: "emailAddress", + NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", + NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( + "jurisdictionStateOrProvinceName" + ), + NameOID.BUSINESS_CATEGORY: "businessCategory", + NameOID.POSTAL_ADDRESS: "postalAddress", + NameOID.POSTAL_CODE: "postalCode", + NameOID.INN: "INN", + NameOID.OGRN: "OGRN", + NameOID.SNILS: "SNILS", + NameOID.UNSTRUCTURED_NAME: "unstructuredName", + SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", + SignatureAlgorithmOID.RSASSA_PSS: "RSASSA-PSS", + SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", + SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", + SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", + SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", + SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", + SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", + SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", + SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", + SignatureAlgorithmOID.ED25519: "ed25519", + SignatureAlgorithmOID.ED448: "ed448", + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( + "GOST R 34.11-94 with GOST R 34.10-2001" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" + ), + ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", + ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", + ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", + ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", + ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", + ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", + ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", + ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", + ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", + ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", + ExtensionOID.KEY_USAGE: "keyUsage", + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", + ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", + ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.PRECERT_POISON: "ctPoison", + CRLEntryExtensionOID.CRL_REASON: "cRLReason", + CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", + CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", + ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", + ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", + ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", + ExtensionOID.POLICY_MAPPINGS: "policyMappings", + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", + ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", + ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", + ExtensionOID.FRESHEST_CRL: "freshestCRL", + ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", + ExtensionOID.ISSUING_DISTRIBUTION_POINT: ("issuingDistributionPoint"), + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", + ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", + ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", + ExtensionOID.CRL_NUMBER: "cRLNumber", + ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", + ExtensionOID.TLS_FEATURE: "TLSFeature", + AuthorityInformationAccessOID.OCSP: "OCSP", + AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", + SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", + CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", + CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", + OCSPExtensionOID.NONCE: "OCSPNonce", + AttributeOID.CHALLENGE_PASSWORD: "challengePassword", +} diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py new file mode 100644 index 0000000..3926f85 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/__init__.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from typing import Any + + +def default_backend() -> Any: + from cryptography.hazmat.backends.openssl.backend import backend + + return backend diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py new file mode 100644 index 0000000..31fd17c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/__init__.py @@ -0,0 +1,9 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography.hazmat.backends.openssl.backend import backend + + +__all__ = ["backend"] diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/aead.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/aead.py new file mode 100644 index 0000000..f7914af --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/aead.py @@ -0,0 +1,251 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import InvalidTag + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + from cryptography.hazmat.primitives.ciphers.aead import ( + AESCCM, + AESGCM, + AESOCB3, + AESSIV, + ChaCha20Poly1305, + ) + + _AEAD_TYPES = typing.Union[ + AESCCM, AESGCM, AESOCB3, AESSIV, ChaCha20Poly1305 + ] + +_ENCRYPT = 1 +_DECRYPT = 0 + + +def _aead_cipher_name(cipher: "_AEAD_TYPES") -> bytes: + from cryptography.hazmat.primitives.ciphers.aead import ( + AESCCM, + AESGCM, + AESOCB3, + AESSIV, + ChaCha20Poly1305, + ) + + if isinstance(cipher, ChaCha20Poly1305): + return b"chacha20-poly1305" + elif isinstance(cipher, AESCCM): + return f"aes-{len(cipher._key) * 8}-ccm".encode("ascii") + elif isinstance(cipher, AESOCB3): + return f"aes-{len(cipher._key) * 8}-ocb".encode("ascii") + elif isinstance(cipher, AESSIV): + return f"aes-{len(cipher._key) * 8 // 2}-siv".encode("ascii") + else: + assert isinstance(cipher, AESGCM) + return f"aes-{len(cipher._key) * 8}-gcm".encode("ascii") + + +def _evp_cipher(cipher_name: bytes, backend: "Backend"): + if cipher_name.endswith(b"-siv"): + evp_cipher = backend._lib.EVP_CIPHER_fetch( + backend._ffi.NULL, + cipher_name, + backend._ffi.NULL, + ) + backend.openssl_assert(evp_cipher != backend._ffi.NULL) + evp_cipher = backend._ffi.gc(evp_cipher, backend._lib.EVP_CIPHER_free) + else: + evp_cipher = backend._lib.EVP_get_cipherbyname(cipher_name) + backend.openssl_assert(evp_cipher != backend._ffi.NULL) + + return evp_cipher + + +def _aead_setup( + backend: "Backend", + cipher_name: bytes, + key: bytes, + nonce: bytes, + tag: typing.Optional[bytes], + tag_len: int, + operation: int, +): + evp_cipher = _evp_cipher(cipher_name, backend) + ctx = backend._lib.EVP_CIPHER_CTX_new() + ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free) + res = backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + int(operation == _ENCRYPT), + ) + backend.openssl_assert(res != 0) + res = backend._lib.EVP_CIPHER_CTX_set_key_length(ctx, len(key)) + backend.openssl_assert(res != 0) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(nonce), + backend._ffi.NULL, + ) + backend.openssl_assert(res != 0) + if operation == _DECRYPT: + assert tag is not None + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag + ) + backend.openssl_assert(res != 0) + elif cipher_name.endswith(b"-ccm"): + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL + ) + backend.openssl_assert(res != 0) + + nonce_ptr = backend._ffi.from_buffer(nonce) + key_ptr = backend._ffi.from_buffer(key) + res = backend._lib.EVP_CipherInit_ex( + ctx, + backend._ffi.NULL, + backend._ffi.NULL, + key_ptr, + nonce_ptr, + int(operation == _ENCRYPT), + ) + backend.openssl_assert(res != 0) + return ctx + + +def _set_length(backend: "Backend", ctx, data_len: int) -> None: + intptr = backend._ffi.new("int *") + res = backend._lib.EVP_CipherUpdate( + ctx, backend._ffi.NULL, intptr, backend._ffi.NULL, data_len + ) + backend.openssl_assert(res != 0) + + +def _process_aad(backend: "Backend", ctx, associated_data: bytes) -> None: + outlen = backend._ffi.new("int *") + res = backend._lib.EVP_CipherUpdate( + ctx, backend._ffi.NULL, outlen, associated_data, len(associated_data) + ) + backend.openssl_assert(res != 0) + + +def _process_data(backend: "Backend", ctx, data: bytes) -> bytes: + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data)) + if res == 0: + # AES SIV can error here if the data is invalid on decrypt + backend._consume_errors() + raise InvalidTag + return backend._ffi.buffer(buf, outlen[0])[:] + + +def _encrypt( + backend: "Backend", + cipher: "_AEAD_TYPES", + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, +) -> bytes: + from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESSIV + + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, cipher_name, cipher._key, nonce, None, tag_length, _ENCRYPT + ) + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + for ad in associated_data: + _process_aad(backend, ctx, ad) + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + # All AEADs we support besides OCB are streaming so they return nothing + # in finalization. OCB can return up to (16 byte block - 1) bytes so + # we need a buffer here too. + buf = backend._ffi.new("unsigned char[]", 16) + res = backend._lib.EVP_CipherFinal_ex(ctx, buf, outlen) + backend.openssl_assert(res != 0) + processed_data += backend._ffi.buffer(buf, outlen[0])[:] + tag_buf = backend._ffi.new("unsigned char[]", tag_length) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_GET_TAG, tag_length, tag_buf + ) + backend.openssl_assert(res != 0) + tag = backend._ffi.buffer(tag_buf)[:] + + if isinstance(cipher, AESSIV): + # RFC 5297 defines the output as IV || C, where the tag we generate is + # the "IV" and C is the ciphertext. This is the opposite of our + # other AEADs, which are Ciphertext || Tag + backend.openssl_assert(len(tag) == 16) + return tag + processed_data + else: + return processed_data + tag + + +def _decrypt( + backend: "Backend", + cipher: "_AEAD_TYPES", + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, +) -> bytes: + from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESSIV + + if len(data) < tag_length: + raise InvalidTag + + if isinstance(cipher, AESSIV): + # RFC 5297 defines the output as IV || C, where the tag we generate is + # the "IV" and C is the ciphertext. This is the opposite of our + # other AEADs, which are Ciphertext || Tag + tag = data[:tag_length] + data = data[tag_length:] + else: + tag = data[-tag_length:] + data = data[:-tag_length] + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, cipher_name, cipher._key, nonce, tag, tag_length, _DECRYPT + ) + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + for ad in associated_data: + _process_aad(backend, ctx, ad) + # CCM has a different error path if the tag doesn't match. Errors are + # raised in Update and Final is irrelevant. + if isinstance(cipher, AESCCM): + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data)) + if res != 1: + backend._consume_errors() + raise InvalidTag + + processed_data = backend._ffi.buffer(buf, outlen[0])[:] + else: + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + # OCB can return up to 15 bytes (16 byte block - 1) in finalization + buf = backend._ffi.new("unsigned char[]", 16) + res = backend._lib.EVP_CipherFinal_ex(ctx, buf, outlen) + processed_data += backend._ffi.buffer(buf, outlen[0])[:] + if res == 0: + backend._consume_errors() + raise InvalidTag + + return processed_data diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py new file mode 100644 index 0000000..42fb446 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py @@ -0,0 +1,2537 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import collections +import contextlib +import itertools +import typing +import warnings +from contextlib import contextmanager + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.backends.openssl import aead +from cryptography.hazmat.backends.openssl.ciphers import _CipherContext +from cryptography.hazmat.backends.openssl.cmac import _CMACContext +from cryptography.hazmat.backends.openssl.dh import ( + _DHParameters, + _DHPrivateKey, + _DHPublicKey, + _dh_params_dup, +) +from cryptography.hazmat.backends.openssl.dsa import ( + _DSAParameters, + _DSAPrivateKey, + _DSAPublicKey, +) +from cryptography.hazmat.backends.openssl.ec import ( + _EllipticCurvePrivateKey, + _EllipticCurvePublicKey, +) +from cryptography.hazmat.backends.openssl.ed25519 import ( + _Ed25519PrivateKey, + _Ed25519PublicKey, +) +from cryptography.hazmat.backends.openssl.ed448 import ( + _ED448_KEY_SIZE, + _Ed448PrivateKey, + _Ed448PublicKey, +) +from cryptography.hazmat.backends.openssl.hashes import _HashContext +from cryptography.hazmat.backends.openssl.hmac import _HMACContext +from cryptography.hazmat.backends.openssl.poly1305 import ( + _POLY1305_KEY_SIZE, + _Poly1305Context, +) +from cryptography.hazmat.backends.openssl.rsa import ( + _RSAPrivateKey, + _RSAPublicKey, +) +from cryptography.hazmat.backends.openssl.x25519 import ( + _X25519PrivateKey, + _X25519PublicKey, +) +from cryptography.hazmat.backends.openssl.x448 import ( + _X448PrivateKey, + _X448PublicKey, +) +from cryptography.hazmat.bindings._rust import ( + x509 as rust_x509, +) +from cryptography.hazmat.bindings.openssl import binding +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding +from cryptography.hazmat.primitives.asymmetric import ( + dh, + dsa, + ec, + ed25519, + ed448, + rsa, + x25519, + x448, +) +from cryptography.hazmat.primitives.asymmetric.padding import ( + MGF1, + OAEP, + PKCS1v15, + PSS, +) +from cryptography.hazmat.primitives.asymmetric.types import ( + CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES, + PRIVATE_KEY_TYPES, + PUBLIC_KEY_TYPES, +) +from cryptography.hazmat.primitives.ciphers import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) +from cryptography.hazmat.primitives.ciphers.algorithms import ( + AES, + ARC4, + Camellia, + ChaCha20, + SM4, + TripleDES, + _BlowfishInternal, + _CAST5Internal, + _IDEAInternal, + _SEEDInternal, +) +from cryptography.hazmat.primitives.ciphers.modes import ( + CBC, + CFB, + CFB8, + CTR, + ECB, + GCM, + Mode, + OFB, + XTS, +) +from cryptography.hazmat.primitives.kdf import scrypt +from cryptography.hazmat.primitives.serialization import pkcs7, ssh +from cryptography.hazmat.primitives.serialization.pkcs12 import ( + PKCS12Certificate, + PKCS12KeyAndCertificates, + _ALLOWED_PKCS12_TYPES, + _PKCS12_CAS_TYPES, +) + + +_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) + + +# Not actually supported, just used as a marker for some serialization tests. +class _RC2: + pass + + +class Backend: + """ + OpenSSL API binding interfaces. + """ + + name = "openssl" + + # FIPS has opinions about acceptable algorithms and key sizes, but the + # disallowed algorithms are still present in OpenSSL. They just error if + # you try to use them. To avoid that we allowlist the algorithms in + # FIPS 140-3. This isn't ideal, but FIPS 140-3 is trash so here we are. + _fips_aead = { + b"aes-128-ccm", + b"aes-192-ccm", + b"aes-256-ccm", + b"aes-128-gcm", + b"aes-192-gcm", + b"aes-256-gcm", + } + # TripleDES encryption is disallowed/deprecated throughout 2023 in + # FIPS 140-3. To keep it simple we denylist any use of TripleDES (TDEA). + _fips_ciphers = (AES,) + # Sometimes SHA1 is still permissible. That logic is contained + # within the various *_supported methods. + _fips_hashes = ( + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA512_224, + hashes.SHA512_256, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, + hashes.SHAKE128, + hashes.SHAKE256, + ) + _fips_ecdh_curves = ( + ec.SECP224R1, + ec.SECP256R1, + ec.SECP384R1, + ec.SECP521R1, + ) + _fips_rsa_min_key_size = 2048 + _fips_rsa_min_public_exponent = 65537 + _fips_dsa_min_modulus = 1 << 2048 + _fips_dh_min_key_size = 2048 + _fips_dh_min_modulus = 1 << _fips_dh_min_key_size + + def __init__(self): + self._binding = binding.Binding() + self._ffi = self._binding.ffi + self._lib = self._binding.lib + self._rsa_skip_check_key = False + self._fips_enabled = self._is_fips_enabled() + + self._cipher_registry = {} + self._register_default_ciphers() + if self._fips_enabled and self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + warnings.warn( + "OpenSSL FIPS mode is enabled. Can't enable DRBG fork safety.", + UserWarning, + ) + else: + self.activate_osrandom_engine() + self._dh_types = [self._lib.EVP_PKEY_DH] + if self._lib.Cryptography_HAS_EVP_PKEY_DHX: + self._dh_types.append(self._lib.EVP_PKEY_DHX) + + def __repr__(self) -> str: + return "".format( + self.openssl_version_text(), self._fips_enabled + ) + + def openssl_assert( + self, + ok: bool, + errors: typing.Optional[typing.List[binding._OpenSSLError]] = None, + ) -> None: + return binding._openssl_assert(self._lib, ok, errors=errors) + + def _is_fips_enabled(self) -> bool: + if self._lib.Cryptography_HAS_300_FIPS: + mode = self._lib.EVP_default_properties_is_fips_enabled( + self._ffi.NULL + ) + else: + mode = getattr(self._lib, "FIPS_mode", lambda: 0)() + + if mode == 0: + # OpenSSL without FIPS pushes an error on the error stack + self._lib.ERR_clear_error() + return bool(mode) + + def _enable_fips(self) -> None: + # This function enables FIPS mode for OpenSSL 3.0.0 on installs that + # have the FIPS provider installed properly. + self._binding._enable_fips() + assert self._is_fips_enabled() + self._fips_enabled = self._is_fips_enabled() + + def activate_builtin_random(self) -> None: + if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + # Obtain a new structural reference. + e = self._lib.ENGINE_get_default_RAND() + if e != self._ffi.NULL: + self._lib.ENGINE_unregister_RAND(e) + # Reset the RNG to use the built-in. + res = self._lib.RAND_set_rand_method(self._ffi.NULL) + self.openssl_assert(res == 1) + # decrement the structural reference from get_default_RAND + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + @contextlib.contextmanager + def _get_osurandom_engine(self): + # Fetches an engine by id and returns it. This creates a structural + # reference. + e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) + self.openssl_assert(e != self._ffi.NULL) + # Initialize the engine for use. This adds a functional reference. + res = self._lib.ENGINE_init(e) + self.openssl_assert(res == 1) + + try: + yield e + finally: + # Decrement the structural ref incremented by ENGINE_by_id. + res = self._lib.ENGINE_free(e) + self.openssl_assert(res == 1) + # Decrement the functional ref incremented by ENGINE_init. + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + def activate_osrandom_engine(self) -> None: + if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + # Unregister and free the current engine. + self.activate_builtin_random() + with self._get_osurandom_engine() as e: + # Set the engine as the default RAND provider. + res = self._lib.ENGINE_set_default_RAND(e) + self.openssl_assert(res == 1) + # Reset the RNG to use the engine + res = self._lib.RAND_set_rand_method(self._ffi.NULL) + self.openssl_assert(res == 1) + + def osrandom_engine_implementation(self) -> str: + buf = self._ffi.new("char[]", 64) + with self._get_osurandom_engine() as e: + res = self._lib.ENGINE_ctrl_cmd( + e, b"get_implementation", len(buf), buf, self._ffi.NULL, 0 + ) + self.openssl_assert(res > 0) + return self._ffi.string(buf).decode("ascii") + + def openssl_version_text(self) -> str: + """ + Friendly string name of the loaded OpenSSL library. This is not + necessarily the same version as it was compiled against. + + Example: OpenSSL 1.1.1d 10 Sep 2019 + """ + return self._ffi.string( + self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION) + ).decode("ascii") + + def openssl_version_number(self) -> int: + return self._lib.OpenSSL_version_num() + + def create_hmac_ctx( + self, key: bytes, algorithm: hashes.HashAlgorithm + ) -> _HMACContext: + return _HMACContext(self, key, algorithm) + + def _evp_md_from_algorithm(self, algorithm: hashes.HashAlgorithm): + if algorithm.name == "blake2b" or algorithm.name == "blake2s": + alg = "{}{}".format( + algorithm.name, algorithm.digest_size * 8 + ).encode("ascii") + else: + alg = algorithm.name.encode("ascii") + + evp_md = self._lib.EVP_get_digestbyname(alg) + return evp_md + + def _evp_md_non_null_from_algorithm(self, algorithm: hashes.HashAlgorithm): + evp_md = self._evp_md_from_algorithm(algorithm) + self.openssl_assert(evp_md != self._ffi.NULL) + return evp_md + + def hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if self._fips_enabled and not isinstance(algorithm, self._fips_hashes): + return False + + evp_md = self._evp_md_from_algorithm(algorithm) + return evp_md != self._ffi.NULL + + def signature_hash_supported( + self, algorithm: hashes.HashAlgorithm + ) -> bool: + # Dedicated check for hashing algorithm use in message digest for + # signatures, e.g. RSA PKCS#1 v1.5 SHA1 (sha1WithRSAEncryption). + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return False + return self.hash_supported(algorithm) + + def scrypt_supported(self) -> bool: + if self._fips_enabled: + return False + else: + return self._lib.Cryptography_HAS_SCRYPT == 1 + + def hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + # FIPS mode still allows SHA1 for HMAC + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return True + + return self.hash_supported(algorithm) + + def create_hash_ctx( + self, algorithm: hashes.HashAlgorithm + ) -> hashes.HashContext: + return _HashContext(self, algorithm) + + def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool: + if self._fips_enabled: + # FIPS mode requires AES. TripleDES is disallowed/deprecated in + # FIPS 140-3. + if not isinstance(cipher, self._fips_ciphers): + return False + + try: + adapter = self._cipher_registry[type(cipher), type(mode)] + except KeyError: + return False + evp_cipher = adapter(self, cipher, mode) + return self._ffi.NULL != evp_cipher + + def register_cipher_adapter(self, cipher_cls, mode_cls, adapter): + if (cipher_cls, mode_cls) in self._cipher_registry: + raise ValueError( + "Duplicate registration for: {} {}.".format( + cipher_cls, mode_cls + ) + ) + self._cipher_registry[cipher_cls, mode_cls] = adapter + + def _register_default_ciphers(self) -> None: + for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8, GCM]: + self.register_cipher_adapter( + AES, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"), + ) + for mode_cls in [CBC, CTR, ECB, OFB, CFB]: + self.register_cipher_adapter( + Camellia, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"), + ) + for mode_cls in [CBC, CFB, CFB8, OFB]: + self.register_cipher_adapter( + TripleDES, mode_cls, GetCipherByName("des-ede3-{mode.name}") + ) + self.register_cipher_adapter( + TripleDES, ECB, GetCipherByName("des-ede3") + ) + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + _BlowfishInternal, mode_cls, GetCipherByName("bf-{mode.name}") + ) + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + _SEEDInternal, mode_cls, GetCipherByName("seed-{mode.name}") + ) + for cipher_cls, mode_cls in itertools.product( + [_CAST5Internal, _IDEAInternal], + [CBC, OFB, CFB, ECB], + ): + self.register_cipher_adapter( + cipher_cls, + mode_cls, + GetCipherByName("{cipher.name}-{mode.name}"), + ) + self.register_cipher_adapter(ARC4, type(None), GetCipherByName("rc4")) + # We don't actually support RC2, this is just used by some tests. + self.register_cipher_adapter(_RC2, type(None), GetCipherByName("rc2")) + self.register_cipher_adapter( + ChaCha20, type(None), GetCipherByName("chacha20") + ) + self.register_cipher_adapter(AES, XTS, _get_xts_cipher) + for mode_cls in [ECB, CBC, OFB, CFB, CTR]: + self.register_cipher_adapter( + SM4, mode_cls, GetCipherByName("sm4-{mode.name}") + ) + + def create_symmetric_encryption_ctx( + self, cipher: CipherAlgorithm, mode: Mode + ) -> _CipherContext: + return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) + + def create_symmetric_decryption_ctx( + self, cipher: CipherAlgorithm, mode: Mode + ) -> _CipherContext: + return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT) + + def pbkdf2_hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + return self.hmac_supported(algorithm) + + def derive_pbkdf2_hmac( + self, + algorithm: hashes.HashAlgorithm, + length: int, + salt: bytes, + iterations: int, + key_material: bytes, + ) -> bytes: + buf = self._ffi.new("unsigned char[]", length) + evp_md = self._evp_md_non_null_from_algorithm(algorithm) + key_material_ptr = self._ffi.from_buffer(key_material) + res = self._lib.PKCS5_PBKDF2_HMAC( + key_material_ptr, + len(key_material), + salt, + len(salt), + iterations, + evp_md, + length, + buf, + ) + self.openssl_assert(res == 1) + return self._ffi.buffer(buf)[:] + + def _consume_errors(self) -> typing.List[binding._OpenSSLError]: + return binding._consume_errors(self._lib) + + def _consume_errors_with_text( + self, + ) -> typing.List[binding._OpenSSLErrorWithText]: + return binding._consume_errors_with_text(self._lib) + + def _bn_to_int(self, bn) -> int: + assert bn != self._ffi.NULL + self.openssl_assert(not self._lib.BN_is_negative(bn)) + + bn_num_bytes = self._lib.BN_num_bytes(bn) + bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) + bin_len = self._lib.BN_bn2bin(bn, bin_ptr) + # A zero length means the BN has value 0 + self.openssl_assert(bin_len >= 0) + val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + return val + + def _int_to_bn(self, num: int, bn=None): + """ + Converts a python integer to a BIGNUM. The returned BIGNUM will not + be garbage collected (to support adding them to structs that take + ownership of the object). Be sure to register it for GC if it will + be discarded after use. + """ + assert bn is None or bn != self._ffi.NULL + + if bn is None: + bn = self._ffi.NULL + + binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") + bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn) + self.openssl_assert(bn_ptr != self._ffi.NULL) + return bn_ptr + + def generate_rsa_private_key( + self, public_exponent: int, key_size: int + ) -> rsa.RSAPrivateKey: + rsa._verify_rsa_parameters(public_exponent, key_size) + + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + + bn = self._int_to_bn(public_exponent) + bn = self._ffi.gc(bn, self._lib.BN_free) + + res = self._lib.RSA_generate_key_ex( + rsa_cdata, key_size, bn, self._ffi.NULL + ) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPrivateKey( + self, rsa_cdata, evp_pkey, self._rsa_skip_check_key + ) + + def generate_rsa_parameters_supported( + self, public_exponent: int, key_size: int + ) -> bool: + return ( + public_exponent >= 3 + and public_exponent & 1 != 0 + and key_size >= 512 + ) + + def load_rsa_private_numbers( + self, numbers: rsa.RSAPrivateNumbers + ) -> rsa.RSAPrivateKey: + rsa._check_private_key_components( + numbers.p, + numbers.q, + numbers.d, + numbers.dmp1, + numbers.dmq1, + numbers.iqmp, + numbers.public_numbers.e, + numbers.public_numbers.n, + ) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + d = self._int_to_bn(numbers.d) + dmp1 = self._int_to_bn(numbers.dmp1) + dmq1 = self._int_to_bn(numbers.dmq1) + iqmp = self._int_to_bn(numbers.iqmp) + e = self._int_to_bn(numbers.public_numbers.e) + n = self._int_to_bn(numbers.public_numbers.n) + res = self._lib.RSA_set0_factors(rsa_cdata, p, q) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, d) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_crt_params(rsa_cdata, dmp1, dmq1, iqmp) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPrivateKey( + self, rsa_cdata, evp_pkey, self._rsa_skip_check_key + ) + + def load_rsa_public_numbers( + self, numbers: rsa.RSAPublicNumbers + ) -> rsa.RSAPublicKey: + rsa._check_public_key_components(numbers.e, numbers.n) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + e = self._int_to_bn(numbers.e) + n = self._int_to_bn(numbers.n) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, self._ffi.NULL) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + + def _create_evp_pkey_gc(self): + evp_pkey = self._lib.EVP_PKEY_new() + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return evp_pkey + + def _rsa_cdata_to_evp_pkey(self, rsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _bytes_to_bio(self, data: bytes): + """ + Return a _MemoryBIO namedtuple of (BIO, char*). + + The char* is the storage for the BIO and it must stay alive until the + BIO is finished with. + """ + data_ptr = self._ffi.from_buffer(data) + bio = self._lib.BIO_new_mem_buf(data_ptr, len(data)) + self.openssl_assert(bio != self._ffi.NULL) + + return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr) + + def _create_mem_bio_gc(self): + """ + Creates an empty memory BIO. + """ + bio_method = self._lib.BIO_s_mem() + self.openssl_assert(bio_method != self._ffi.NULL) + bio = self._lib.BIO_new(bio_method) + self.openssl_assert(bio != self._ffi.NULL) + bio = self._ffi.gc(bio, self._lib.BIO_free) + return bio + + def _read_mem_bio(self, bio) -> bytes: + """ + Reads a memory BIO. This only works on memory BIOs. + """ + buf = self._ffi.new("char **") + buf_len = self._lib.BIO_get_mem_data(bio, buf) + self.openssl_assert(buf_len > 0) + self.openssl_assert(buf[0] != self._ffi.NULL) + bio_data = self._ffi.buffer(buf[0], buf_len)[:] + return bio_data + + def _evp_pkey_to_private_key(self, evp_pkey) -> PRIVATE_KEY_TYPES: + """ + Return the appropriate type of PrivateKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPrivateKey( + self, rsa_cdata, evp_pkey, self._rsa_skip_check_key + ) + elif ( + key_type == self._lib.EVP_PKEY_RSA_PSS + and not self._lib.CRYPTOGRAPHY_IS_LIBRESSL + and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + and not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E + ): + # At the moment the way we handle RSA PSS keys is to strip the + # PSS constraints from them and treat them as normal RSA keys + # Unfortunately the RSA * itself tracks this data so we need to + # extract, serialize, and reload it without the constraints. + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + bio = self._create_mem_bio_gc() + res = self._lib.i2d_RSAPrivateKey_bio(bio, rsa_cdata) + self.openssl_assert(res == 1) + return self.load_der_private_key( + self._read_mem_bio(bio), password=None + ) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPrivateKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 + return _X448PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 + return _X25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_ED448 is not present in OpenSSL < 1.1.1 + return _Ed448PrivateKey(self, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _evp_pkey_to_public_key(self, evp_pkey) -> PUBLIC_KEY_TYPES: + """ + Return the appropriate type of PublicKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + if ec_cdata == self._ffi.NULL: + errors = self._consume_errors_with_text() + raise ValueError("Unable to load EC key", errors) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPublicKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 + return _X448PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 + return _X25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.1 + return _Ed448PublicKey(self, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _oaep_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + return isinstance( + algorithm, + ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ), + ) + + def rsa_padding_supported(self, padding: AsymmetricPadding) -> bool: + if isinstance(padding, PKCS1v15): + return True + elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): + # SHA1 is permissible in MGF1 in FIPS even when SHA1 is blocked + # as signature algorithm. + if self._fips_enabled and isinstance( + padding._mgf._algorithm, hashes.SHA1 + ): + return True + else: + return self.hash_supported(padding._mgf._algorithm) + elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): + return self._oaep_hash_supported( + padding._mgf._algorithm + ) and self._oaep_hash_supported(padding._algorithm) + else: + return False + + def generate_dsa_parameters(self, key_size: int) -> dsa.DSAParameters: + if key_size not in (1024, 2048, 3072, 4096): + raise ValueError( + "Key size must be 1024, 2048, 3072, or 4096 bits." + ) + + ctx = self._lib.DSA_new() + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + + res = self._lib.DSA_generate_parameters_ex( + ctx, + key_size, + self._ffi.NULL, + 0, + self._ffi.NULL, + self._ffi.NULL, + self._ffi.NULL, + ) + + self.openssl_assert(res == 1) + + return _DSAParameters(self, ctx) + + def generate_dsa_private_key( + self, parameters: dsa.DSAParameters + ) -> dsa.DSAPrivateKey: + ctx = self._lib.DSAparams_dup( + parameters._dsa_cdata # type: ignore[attr-defined] + ) + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + self._lib.DSA_generate_key(ctx) + evp_pkey = self._dsa_cdata_to_evp_pkey(ctx) + + return _DSAPrivateKey(self, ctx, evp_pkey) + + def generate_dsa_private_key_and_parameters( + self, key_size: int + ) -> dsa.DSAPrivateKey: + parameters = self.generate_dsa_parameters(key_size) + return self.generate_dsa_private_key(parameters) + + def _dsa_cdata_set_values(self, dsa_cdata, p, q, g, pub_key, priv_key): + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + res = self._lib.DSA_set0_key(dsa_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + def load_dsa_private_numbers( + self, numbers: dsa.DSAPrivateNumbers + ) -> dsa.DSAPrivateKey: + dsa._check_dsa_private_numbers(numbers) + parameter_numbers = numbers.public_numbers.parameter_numbers + + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(parameter_numbers.p) + q = self._int_to_bn(parameter_numbers.q) + g = self._int_to_bn(parameter_numbers.g) + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + + def load_dsa_public_numbers( + self, numbers: dsa.DSAPublicNumbers + ) -> dsa.DSAPublicKey: + dsa._check_dsa_parameters(numbers.parameter_numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.parameter_numbers.p) + q = self._int_to_bn(numbers.parameter_numbers.q) + g = self._int_to_bn(numbers.parameter_numbers.g) + pub_key = self._int_to_bn(numbers.y) + priv_key = self._ffi.NULL + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + + def load_dsa_parameter_numbers( + self, numbers: dsa.DSAParameterNumbers + ) -> dsa.DSAParameters: + dsa._check_dsa_parameters(numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + g = self._int_to_bn(numbers.g) + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DSAParameters(self, dsa_cdata) + + def _dsa_cdata_to_evp_pkey(self, dsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DSA(evp_pkey, dsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def dsa_supported(self) -> bool: + return not self._fips_enabled + + def dsa_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if not self.dsa_supported(): + return False + return self.signature_hash_supported(algorithm) + + def cmac_algorithm_supported(self, algorithm) -> bool: + return self.cipher_supported( + algorithm, CBC(b"\x00" * algorithm.block_size) + ) + + def create_cmac_ctx(self, algorithm: BlockCipherAlgorithm) -> _CMACContext: + return _CMACContext(self, algorithm) + + def load_pem_private_key( + self, data: bytes, password: typing.Optional[bytes] + ) -> PRIVATE_KEY_TYPES: + return self._load_key( + self._lib.PEM_read_bio_PrivateKey, + self._evp_pkey_to_private_key, + data, + password, + ) + + def load_pem_public_key(self, data: bytes) -> PUBLIC_KEY_TYPES: + mem_bio = self._bytes_to_bio(data) + # In OpenSSL 3.0.x the PEM_read_bio_PUBKEY function will invoke + # the default password callback if you pass an encrypted private + # key. This is very, very, very bad as the default callback can + # trigger an interactive console prompt, which will hang the + # Python process. We therefore provide our own callback to + # catch this and error out properly. + userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") + evp_pkey = self._lib.PEM_read_bio_PUBKEY( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_pem_parameters(self, data: bytes) -> dh.DHParameters: + mem_bio = self._bytes_to_bio(data) + # only DH is supported currently + dh_cdata = self._lib.PEM_read_bio_DHparams( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + else: + self._handle_key_loading_error() + + def load_der_private_key( + self, data: bytes, password: typing.Optional[bytes] + ) -> PRIVATE_KEY_TYPES: + # OpenSSL has a function called d2i_AutoPrivateKey that in theory + # handles this automatically, however it doesn't handle encrypted + # private keys. Instead we try to load the key two different ways. + # First we'll try to load it as a traditional key. + bio_data = self._bytes_to_bio(data) + key = self._evp_pkey_from_der_traditional_key(bio_data, password) + if key: + return self._evp_pkey_to_private_key(key) + else: + # Finally we try to load it with the method that handles encrypted + # PKCS8 properly. + return self._load_key( + self._lib.d2i_PKCS8PrivateKey_bio, + self._evp_pkey_to_private_key, + data, + password, + ) + + def _evp_pkey_from_der_traditional_key(self, bio_data, password): + key = self._lib.d2i_PrivateKey_bio(bio_data.bio, self._ffi.NULL) + if key != self._ffi.NULL: + # In OpenSSL 3.0.0-alpha15 there exist scenarios where the key will + # successfully load but errors are still put on the stack. Tracked + # as https://github.com/openssl/openssl/issues/14996 + self._consume_errors() + + key = self._ffi.gc(key, self._lib.EVP_PKEY_free) + if password is not None: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + return key + else: + self._consume_errors() + return None + + def load_der_public_key(self, data: bytes) -> PUBLIC_KEY_TYPES: + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.d2i_PUBKEY_bio(mem_bio.bio, self._ffi.NULL) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.d2i_RSAPublicKey_bio( + mem_bio.bio, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_der_parameters(self, data: bytes) -> dh.DHParameters: + mem_bio = self._bytes_to_bio(data) + dh_cdata = self._lib.d2i_DHparams_bio(mem_bio.bio, self._ffi.NULL) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + elif self._lib.Cryptography_HAS_EVP_PKEY_DHX: + # We check to see if the is dhx. + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + dh_cdata = self._lib.Cryptography_d2i_DHxparams_bio( + mem_bio.bio, self._ffi.NULL + ) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + + self._handle_key_loading_error() + + def _cert2ossl(self, cert: x509.Certificate) -> typing.Any: + data = cert.public_bytes(serialization.Encoding.DER) + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) + self.openssl_assert(x509 != self._ffi.NULL) + x509 = self._ffi.gc(x509, self._lib.X509_free) + return x509 + + def _ossl2cert(self, x509: typing.Any) -> x509.Certificate: + bio = self._create_mem_bio_gc() + res = self._lib.i2d_X509_bio(bio, x509) + self.openssl_assert(res == 1) + return rust_x509.load_der_x509_certificate(self._read_mem_bio(bio)) + + def _csr2ossl(self, csr: x509.CertificateSigningRequest) -> typing.Any: + data = csr.public_bytes(serialization.Encoding.DER) + mem_bio = self._bytes_to_bio(data) + x509_req = self._lib.d2i_X509_REQ_bio(mem_bio.bio, self._ffi.NULL) + self.openssl_assert(x509_req != self._ffi.NULL) + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + return x509_req + + def _ossl2csr( + self, x509_req: typing.Any + ) -> x509.CertificateSigningRequest: + bio = self._create_mem_bio_gc() + res = self._lib.i2d_X509_REQ_bio(bio, x509_req) + self.openssl_assert(res == 1) + return rust_x509.load_der_x509_csr(self._read_mem_bio(bio)) + + def _crl2ossl(self, crl: x509.CertificateRevocationList) -> typing.Any: + data = crl.public_bytes(serialization.Encoding.DER) + mem_bio = self._bytes_to_bio(data) + x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL) + self.openssl_assert(x509_crl != self._ffi.NULL) + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) + return x509_crl + + def _ossl2crl( + self, x509_crl: typing.Any + ) -> x509.CertificateRevocationList: + bio = self._create_mem_bio_gc() + res = self._lib.i2d_X509_CRL_bio(bio, x509_crl) + self.openssl_assert(res == 1) + return rust_x509.load_der_x509_crl(self._read_mem_bio(bio)) + + def _crl_is_signature_valid( + self, + crl: x509.CertificateRevocationList, + public_key: CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES, + ) -> bool: + if not isinstance( + public_key, + ( + _DSAPublicKey, + _RSAPublicKey, + _EllipticCurvePublicKey, + ), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " or EllipticCurvePublicKey." + ) + x509_crl = self._crl2ossl(crl) + res = self._lib.X509_CRL_verify(x509_crl, public_key._evp_pkey) + + if res != 1: + self._consume_errors() + return False + + return True + + def _csr_is_signature_valid( + self, csr: x509.CertificateSigningRequest + ) -> bool: + x509_req = self._csr2ossl(csr) + pkey = self._lib.X509_REQ_get_pubkey(x509_req) + self.openssl_assert(pkey != self._ffi.NULL) + pkey = self._ffi.gc(pkey, self._lib.EVP_PKEY_free) + res = self._lib.X509_REQ_verify(x509_req, pkey) + + if res != 1: + self._consume_errors() + return False + + return True + + def _check_keys_correspond(self, key1, key2): + if self._lib.EVP_PKEY_cmp(key1._evp_pkey, key2._evp_pkey) != 1: + raise ValueError("Keys do not correspond") + + def _load_key(self, openssl_read_func, convert_func, data, password): + mem_bio = self._bytes_to_bio(data) + + userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") + if password is not None: + utils._check_byteslike("password", password) + password_ptr = self._ffi.from_buffer(password) + userdata.password = password_ptr + userdata.length = len(password) + + evp_pkey = openssl_read_func( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + + if evp_pkey == self._ffi.NULL: + if userdata.error != 0: + self._consume_errors() + if userdata.error == -1: + raise TypeError( + "Password was not given but private key is encrypted" + ) + else: + assert userdata.error == -2 + raise ValueError( + "Passwords longer than {} bytes are not supported " + "by this backend.".format(userdata.maxsize - 1) + ) + else: + self._handle_key_loading_error() + + # In OpenSSL 3.0.0-alpha15 there exist scenarios where the key will + # successfully load but errors are still put on the stack. Tracked + # as https://github.com/openssl/openssl/issues/14996 + self._consume_errors() + + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + if password is not None and userdata.called == 0: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + assert ( + password is not None and userdata.called == 1 + ) or password is None + + return convert_func(evp_pkey) + + def _handle_key_loading_error(self) -> typing.NoReturn: + errors = self._consume_errors() + + if not errors: + raise ValueError( + "Could not deserialize key data. The data may be in an " + "incorrect format or it may be encrypted with an unsupported " + "algorithm." + ) + + elif ( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT + ) + or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PKCS12, + self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR, + ) + or ( + self._lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + self._lib.ERR_LIB_PROV, + self._lib.PROV_R_BAD_DECRYPT, + ) + ) + ): + raise ValueError("Bad decrypt. Incorrect password?") + + elif any( + error._lib_reason_match( + self._lib.ERR_LIB_EVP, + self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM, + ) + for error in errors + ): + raise ValueError("Unsupported public key algorithm.") + + else: + errors_with_text = binding._errors_with_text(errors) + raise ValueError( + "Could not deserialize key data. The data may be in an " + "incorrect format, it may be encrypted with an unsupported " + "algorithm, or it may be an unsupported key type (e.g. EC " + "curves with explicit parameters).", + errors_with_text, + ) + + def elliptic_curve_supported(self, curve: ec.EllipticCurve) -> bool: + try: + curve_nid = self._elliptic_curve_to_nid(curve) + except UnsupportedAlgorithm: + curve_nid = self._lib.NID_undef + + group = self._lib.EC_GROUP_new_by_curve_name(curve_nid) + + if group == self._ffi.NULL: + self._consume_errors() + return False + else: + self.openssl_assert(curve_nid != self._lib.NID_undef) + self._lib.EC_GROUP_free(group) + return True + + def elliptic_curve_signature_algorithm_supported( + self, + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, + curve: ec.EllipticCurve, + ) -> bool: + # We only support ECDSA right now. + if not isinstance(signature_algorithm, ec.ECDSA): + return False + + return self.elliptic_curve_supported(curve) + + def generate_elliptic_curve_private_key( + self, curve: ec.EllipticCurve + ) -> ec.EllipticCurvePrivateKey: + """ + Generate a new private key on the named curve. + """ + + if self.elliptic_curve_supported(curve): + ec_cdata = self._ec_key_new_by_curve(curve) + + res = self._lib.EC_KEY_generate_key(ec_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + else: + raise UnsupportedAlgorithm( + "Backend object does not support {}.".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + + def load_elliptic_curve_private_numbers( + self, numbers: ec.EllipticCurvePrivateNumbers + ) -> ec.EllipticCurvePrivateKey: + public = numbers.public_numbers + + ec_cdata = self._ec_key_new_by_curve(public.curve) + + private_value = self._ffi.gc( + self._int_to_bn(numbers.private_value), self._lib.BN_clear_free + ) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private_value) + if res != 1: + self._consume_errors() + raise ValueError("Invalid EC key.") + + self._ec_key_set_public_key_affine_coordinates( + ec_cdata, public.x, public.y + ) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def load_elliptic_curve_public_numbers( + self, numbers: ec.EllipticCurvePublicNumbers + ) -> ec.EllipticCurvePublicKey: + ec_cdata = self._ec_key_new_by_curve(numbers.curve) + self._ec_key_set_public_key_affine_coordinates( + ec_cdata, numbers.x, numbers.y + ) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def load_elliptic_curve_public_bytes( + self, curve: ec.EllipticCurve, point_bytes: bytes + ) -> ec.EllipticCurvePublicKey: + ec_cdata = self._ec_key_new_by_curve(curve) + group = self._lib.EC_KEY_get0_group(ec_cdata) + self.openssl_assert(group != self._ffi.NULL) + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_oct2point( + group, point, point_bytes, len(point_bytes), bn_ctx + ) + if res != 1: + self._consume_errors() + raise ValueError("Invalid public bytes for the given curve") + + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def derive_elliptic_curve_private_key( + self, private_value: int, curve: ec.EllipticCurve + ) -> ec.EllipticCurvePrivateKey: + ec_cdata = self._ec_key_new_by_curve(curve) + + get_func, group = self._ec_key_determine_group_get_func(ec_cdata) + + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + + value = self._int_to_bn(private_value) + value = self._ffi.gc(value, self._lib.BN_clear_free) + + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_mul( + group, point, value, self._ffi.NULL, self._ffi.NULL, bn_ctx + ) + self.openssl_assert(res == 1) + + bn_x = self._lib.BN_CTX_get(bn_ctx) + bn_y = self._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + if res != 1: + self._consume_errors() + raise ValueError("Unable to derive key from private_value") + + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + private = self._int_to_bn(private_value) + private = self._ffi.gc(private, self._lib.BN_clear_free) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def _ec_key_new_by_curve(self, curve: ec.EllipticCurve): + curve_nid = self._elliptic_curve_to_nid(curve) + return self._ec_key_new_by_curve_nid(curve_nid) + + def _ec_key_new_by_curve_nid(self, curve_nid: int): + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + return self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + def elliptic_curve_exchange_algorithm_supported( + self, algorithm: ec.ECDH, curve: ec.EllipticCurve + ) -> bool: + if self._fips_enabled and not isinstance( + curve, self._fips_ecdh_curves + ): + return False + + return self.elliptic_curve_supported(curve) and isinstance( + algorithm, ec.ECDH + ) + + def _ec_cdata_to_evp_pkey(self, ec_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_EC_KEY(evp_pkey, ec_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _elliptic_curve_to_nid(self, curve: ec.EllipticCurve) -> int: + """ + Get the NID for a curve name. + """ + + curve_aliases = {"secp192r1": "prime192v1", "secp256r1": "prime256v1"} + + curve_name = curve_aliases.get(curve.name, curve.name) + + curve_nid = self._lib.OBJ_sn2nid(curve_name.encode()) + if curve_nid == self._lib.NID_undef: + raise UnsupportedAlgorithm( + "{} is not a supported elliptic curve".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + return curve_nid + + @contextmanager + def _tmp_bn_ctx(self): + bn_ctx = self._lib.BN_CTX_new() + self.openssl_assert(bn_ctx != self._ffi.NULL) + bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free) + self._lib.BN_CTX_start(bn_ctx) + try: + yield bn_ctx + finally: + self._lib.BN_CTX_end(bn_ctx) + + def _ec_key_determine_group_get_func(self, ctx): + """ + Given an EC_KEY determine the group and what function is required to + get point coordinates. + """ + self.openssl_assert(ctx != self._ffi.NULL) + + nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field") + self.openssl_assert(nid_two_field != self._lib.NID_undef) + + group = self._lib.EC_KEY_get0_group(ctx) + self.openssl_assert(group != self._ffi.NULL) + + method = self._lib.EC_GROUP_method_of(group) + self.openssl_assert(method != self._ffi.NULL) + + nid = self._lib.EC_METHOD_get_field_type(method) + self.openssl_assert(nid != self._lib.NID_undef) + + if nid == nid_two_field and self._lib.Cryptography_HAS_EC2M: + get_func = self._lib.EC_POINT_get_affine_coordinates_GF2m + else: + get_func = self._lib.EC_POINT_get_affine_coordinates_GFp + + assert get_func + + return get_func, group + + def _ec_key_set_public_key_affine_coordinates(self, ctx, x: int, y: int): + """ + Sets the public key point in the EC_KEY context to the affine x and y + values. + """ + + if x < 0 or y < 0: + raise ValueError( + "Invalid EC key. Both x and y must be non-negative." + ) + + x = self._ffi.gc(self._int_to_bn(x), self._lib.BN_free) + y = self._ffi.gc(self._int_to_bn(y), self._lib.BN_free) + res = self._lib.EC_KEY_set_public_key_affine_coordinates(ctx, x, y) + if res != 1: + self._consume_errors() + raise ValueError("Invalid EC key.") + + def _private_key_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + key, + evp_pkey, + cdata, + ) -> bytes: + # validate argument types + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + if not isinstance(format, serialization.PrivateFormat): + raise TypeError( + "format must be an item from the PrivateFormat enum" + ) + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Encryption algorithm must be a KeySerializationEncryption " + "instance" + ) + + # validate password + if isinstance(encryption_algorithm, serialization.NoEncryption): + password = b"" + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): + password = encryption_algorithm.password + if len(password) > 1023: + raise ValueError( + "Passwords longer than 1023 bytes are not supported by " + "this backend" + ) + else: + raise ValueError("Unsupported encryption type") + + # PKCS8 + PEM/DER + if format is serialization.PrivateFormat.PKCS8: + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_PKCS8PrivateKey_bio + else: + raise ValueError("Unsupported encoding for PKCS8") + return self._private_key_bytes_via_bio( + write_bio, evp_pkey, password + ) + + # TraditionalOpenSSL + PEM/DER + if format is serialization.PrivateFormat.TraditionalOpenSSL: + if self._fips_enabled and not isinstance( + encryption_algorithm, serialization.NoEncryption + ): + raise ValueError( + "Encrypted traditional OpenSSL format is not " + "supported in FIPS mode." + ) + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if encoding is serialization.Encoding.PEM: + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.PEM_write_bio_RSAPrivateKey + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.PEM_write_bio_DSAPrivateKey + elif key_type == self._lib.EVP_PKEY_EC: + write_bio = self._lib.PEM_write_bio_ECPrivateKey + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._private_key_bytes_via_bio( + write_bio, cdata, password + ) + + if encoding is serialization.Encoding.DER: + if password: + raise ValueError( + "Encryption is not supported for DER encoded " + "traditional OpenSSL keys" + ) + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.i2d_RSAPrivateKey_bio + elif key_type == self._lib.EVP_PKEY_EC: + write_bio = self._lib.i2d_ECPrivateKey_bio + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.i2d_DSAPrivateKey_bio + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._bio_func_output(write_bio, cdata) + + raise ValueError("Unsupported encoding for TraditionalOpenSSL") + + # OpenSSH + PEM + if format is serialization.PrivateFormat.OpenSSH: + if encoding is serialization.Encoding.PEM: + return ssh.serialize_ssh_private_key(key, password) + + raise ValueError( + "OpenSSH private key format can only be used" + " with PEM encoding" + ) + + # Anything that key-specific code was supposed to handle earlier, + # like Raw. + raise ValueError("format is invalid with this key") + + def _private_key_bytes_via_bio(self, write_bio, evp_pkey, password): + if not password: + evp_cipher = self._ffi.NULL + else: + # This is a curated value that we will update over time. + evp_cipher = self._lib.EVP_get_cipherbyname(b"aes-256-cbc") + + return self._bio_func_output( + write_bio, + evp_pkey, + evp_cipher, + password, + len(password), + self._ffi.NULL, + self._ffi.NULL, + ) + + def _bio_func_output(self, write_bio, *args): + bio = self._create_mem_bio_gc() + res = write_bio(bio, *args) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def _public_key_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + key, + evp_pkey, + cdata, + ) -> bytes: + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + if not isinstance(format, serialization.PublicFormat): + raise TypeError( + "format must be an item from the PublicFormat enum" + ) + + # SubjectPublicKeyInfo + PEM/DER + if format is serialization.PublicFormat.SubjectPublicKeyInfo: + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_PUBKEY + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_PUBKEY_bio + else: + raise ValueError( + "SubjectPublicKeyInfo works only with PEM or DER encoding" + ) + return self._bio_func_output(write_bio, evp_pkey) + + # PKCS1 + PEM/DER + if format is serialization.PublicFormat.PKCS1: + # Only RSA is supported here. + key_type = self._lib.EVP_PKEY_id(evp_pkey) + if key_type != self._lib.EVP_PKEY_RSA: + raise ValueError("PKCS1 format is supported only for RSA keys") + + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_RSAPublicKey + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_RSAPublicKey_bio + else: + raise ValueError("PKCS1 works only with PEM or DER encoding") + return self._bio_func_output(write_bio, cdata) + + # OpenSSH + OpenSSH + if format is serialization.PublicFormat.OpenSSH: + if encoding is serialization.Encoding.OpenSSH: + return ssh.serialize_ssh_public_key(key) + + raise ValueError( + "OpenSSH format must be used with OpenSSH encoding" + ) + + # Anything that key-specific code was supposed to handle earlier, + # like Raw, CompressedPoint, UncompressedPoint + raise ValueError("format is invalid with this key") + + def dh_supported(self) -> bool: + return not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + + def generate_dh_parameters( + self, generator: int, key_size: int + ) -> dh.DHParameters: + if key_size < dh._MIN_MODULUS_SIZE: + raise ValueError( + "DH key_size must be at least {} bits".format( + dh._MIN_MODULUS_SIZE + ) + ) + + if generator not in (2, 5): + raise ValueError("DH generator must be 2 or 5") + + dh_param_cdata = self._lib.DH_new() + self.openssl_assert(dh_param_cdata != self._ffi.NULL) + dh_param_cdata = self._ffi.gc(dh_param_cdata, self._lib.DH_free) + + res = self._lib.DH_generate_parameters_ex( + dh_param_cdata, key_size, generator, self._ffi.NULL + ) + self.openssl_assert(res == 1) + + return _DHParameters(self, dh_param_cdata) + + def _dh_cdata_to_evp_pkey(self, dh_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DH(evp_pkey, dh_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def generate_dh_private_key( + self, parameters: dh.DHParameters + ) -> dh.DHPrivateKey: + dh_key_cdata = _dh_params_dup( + parameters._dh_cdata, self # type: ignore[attr-defined] + ) + + res = self._lib.DH_generate_key(dh_key_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_key_cdata) + + return _DHPrivateKey(self, dh_key_cdata, evp_pkey) + + def generate_dh_private_key_and_parameters( + self, generator: int, key_size: int + ) -> dh.DHPrivateKey: + return self.generate_dh_private_key( + self.generate_dh_parameters(generator, key_size) + ) + + def load_dh_private_numbers( + self, numbers: dh.DHPrivateNumbers + ) -> dh.DHPrivateKey: + parameter_numbers = numbers.public_numbers.parameter_numbers + + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.Cryptography_DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + # DH_check will return DH_NOT_SUITABLE_GENERATOR if p % 24 does not + # equal 11 when the generator is 2 (a quadratic nonresidue). + # We want to ignore that error because p % 24 == 23 is also fine. + # Specifically, g is then a quadratic residue. Within the context of + # Diffie-Hellman this means it can only generate half the possible + # values. That sounds bad, but quadratic nonresidues leak a bit of + # the key to the attacker in exchange for having the full key space + # available. See: https://crypto.stackexchange.com/questions/12961 + if codes[0] != 0 and not ( + parameter_numbers.g == 2 + and codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0 + ): + raise ValueError("DH private numbers did not pass safety checks.") + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPrivateKey(self, dh_cdata, evp_pkey) + + def load_dh_public_numbers( + self, numbers: dh.DHPublicNumbers + ) -> dh.DHPublicKey: + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + parameter_numbers = numbers.parameter_numbers + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.y) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPublicKey(self, dh_cdata, evp_pkey) + + def load_dh_parameter_numbers( + self, numbers: dh.DHParameterNumbers + ) -> dh.DHParameters: + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(numbers.p) + g = self._int_to_bn(numbers.g) + + if numbers.q is not None: + q = self._int_to_bn(numbers.q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DHParameters(self, dh_cdata) + + def dh_parameters_supported( + self, p: int, g: int, q: typing.Optional[int] = None + ) -> bool: + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(p) + g = self._int_to_bn(g) + + if q is not None: + q = self._int_to_bn(q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.Cryptography_DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + return codes[0] == 0 + + def dh_x942_serialization_supported(self) -> bool: + return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 + + def x25519_load_public_bytes(self, data: bytes) -> x25519.X25519PublicKey: + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_public_key + if len(data) != 32: + raise ValueError("An X25519 public key is 32 bytes long") + + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set_type(evp_pkey, self._lib.NID_X25519) + self.openssl_assert(res == 1) + res = self._lib.EVP_PKEY_set1_tls_encodedpoint( + evp_pkey, data, len(data) + ) + self.openssl_assert(res == 1) + return _X25519PublicKey(self, evp_pkey) + + def x25519_load_private_bytes( + self, data: bytes + ) -> x25519.X25519PrivateKey: + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_private_key and drop the + # zeroed_bytearray garbage. + # OpenSSL only has facilities for loading PKCS8 formatted private + # keys using the algorithm identifiers specified in + # https://tools.ietf.org/html/draft-ietf-curdle-pkix-09. + # This is the standard PKCS8 prefix for a 32 byte X25519 key. + # The form is: + # 0:d=0 hl=2 l= 46 cons: SEQUENCE + # 2:d=1 hl=2 l= 1 prim: INTEGER :00 + # 5:d=1 hl=2 l= 5 cons: SEQUENCE + # 7:d=2 hl=2 l= 3 prim: OBJECT :1.3.101.110 + # 12:d=1 hl=2 l= 34 prim: OCTET STRING (the key) + # Of course there's a bit more complexity. In reality OCTET STRING + # contains an OCTET STRING of length 32! So the last two bytes here + # are \x04\x20, which is an OCTET STRING of length 32. + if len(data) != 32: + raise ValueError("An X25519 private key is 32 bytes long") + + pkcs8_prefix = b'0.\x02\x01\x000\x05\x06\x03+en\x04"\x04 ' + with self._zeroed_bytearray(48) as ba: + ba[0:16] = pkcs8_prefix + ba[16:] = data + bio = self._bytes_to_bio(ba) + evp_pkey = self._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL) + + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + self.openssl_assert( + self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_X25519 + ) + return _X25519PrivateKey(self, evp_pkey) + + def _evp_pkey_keygen_gc(self, nid): + evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL) + self.openssl_assert(evp_pkey_ctx != self._ffi.NULL) + evp_pkey_ctx = self._ffi.gc(evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free) + res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx) + self.openssl_assert(res == 1) + evp_ppkey = self._ffi.new("EVP_PKEY **") + res = self._lib.EVP_PKEY_keygen(evp_pkey_ctx, evp_ppkey) + self.openssl_assert(res == 1) + self.openssl_assert(evp_ppkey[0] != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free) + return evp_pkey + + def x25519_generate_key(self) -> x25519.X25519PrivateKey: + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X25519) + return _X25519PrivateKey(self, evp_pkey) + + def x25519_supported(self) -> bool: + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_IS_LIBRESSL + + def x448_load_public_bytes(self, data: bytes) -> x448.X448PublicKey: + if len(data) != 56: + raise ValueError("An X448 public key is 56 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_X448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PublicKey(self, evp_pkey) + + def x448_load_private_bytes(self, data: bytes) -> x448.X448PrivateKey: + if len(data) != 56: + raise ValueError("An X448 private key is 56 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_X448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PrivateKey(self, evp_pkey) + + def x448_generate_key(self) -> x448.X448PrivateKey: + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X448) + return _X448PrivateKey(self, evp_pkey) + + def x448_supported(self) -> bool: + if self._fips_enabled: + return False + return ( + not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 + and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + ) + + def ed25519_supported(self) -> bool: + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + + def ed25519_load_public_bytes( + self, data: bytes + ) -> ed25519.Ed25519PublicKey: + utils._check_bytes("data", data) + + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 public key is 32 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED25519, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PublicKey(self, evp_pkey) + + def ed25519_load_private_bytes( + self, data: bytes + ) -> ed25519.Ed25519PrivateKey: + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 private key is 32 bytes long") + + utils._check_byteslike("data", data) + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PrivateKey(self, evp_pkey) + + def ed25519_generate_key(self) -> ed25519.Ed25519PrivateKey: + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519) + return _Ed25519PrivateKey(self, evp_pkey) + + def ed448_supported(self) -> bool: + if self._fips_enabled: + return False + return ( + not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + ) + + def ed448_load_public_bytes(self, data: bytes) -> ed448.Ed448PublicKey: + utils._check_bytes("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 public key is 57 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PublicKey(self, evp_pkey) + + def ed448_load_private_bytes(self, data: bytes) -> ed448.Ed448PrivateKey: + utils._check_byteslike("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 private key is 57 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PrivateKey(self, evp_pkey) + + def ed448_generate_key(self) -> ed448.Ed448PrivateKey: + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448) + return _Ed448PrivateKey(self, evp_pkey) + + def derive_scrypt( + self, + key_material: bytes, + salt: bytes, + length: int, + n: int, + r: int, + p: int, + ) -> bytes: + buf = self._ffi.new("unsigned char[]", length) + key_material_ptr = self._ffi.from_buffer(key_material) + res = self._lib.EVP_PBE_scrypt( + key_material_ptr, + len(key_material), + salt, + len(salt), + n, + r, + p, + scrypt._MEM_LIMIT, + buf, + length, + ) + if res != 1: + errors = self._consume_errors_with_text() + # memory required formula explained here: + # https://blog.filippo.io/the-scrypt-parameters/ + min_memory = 128 * n * r // (1024**2) + raise MemoryError( + "Not enough memory to derive key. These parameters require" + " {} MB of memory.".format(min_memory), + errors, + ) + return self._ffi.buffer(buf)[:] + + def aead_cipher_supported(self, cipher) -> bool: + cipher_name = aead._aead_cipher_name(cipher) + if self._fips_enabled and cipher_name not in self._fips_aead: + return False + # SIV isn't loaded through get_cipherbyname but instead a new fetch API + # only available in 3.0+. But if we know we're on 3.0+ then we know + # it's supported. + if cipher_name.endswith(b"-siv"): + return self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER == 1 + else: + return ( + self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL + ) + + @contextlib.contextmanager + def _zeroed_bytearray(self, length: int) -> typing.Iterator[bytearray]: + """ + This method creates a bytearray, which we copy data into (hopefully + also from a mutable buffer that can be dynamically erased!), and then + zero when we're done. + """ + ba = bytearray(length) + try: + yield ba + finally: + self._zero_data(ba, length) + + def _zero_data(self, data, length: int) -> None: + # We clear things this way because at the moment we're not + # sure of a better way that can guarantee it overwrites the + # memory of a bytearray and doesn't just replace the underlying char *. + for i in range(length): + data[i] = 0 + + @contextlib.contextmanager + def _zeroed_null_terminated_buf(self, data): + """ + This method takes bytes, which can be a bytestring or a mutable + buffer like a bytearray, and yields a null-terminated version of that + data. This is required because PKCS12_parse doesn't take a length with + its password char * and ffi.from_buffer doesn't provide null + termination. So, to support zeroing the data via bytearray we + need to build this ridiculous construct that copies the memory, but + zeroes it after use. + """ + if data is None: + yield self._ffi.NULL + else: + data_len = len(data) + buf = self._ffi.new("char[]", data_len + 1) + self._ffi.memmove(buf, data, data_len) + try: + yield buf + finally: + # Cast to a uint8_t * so we can assign by integer + self._zero_data(self._ffi.cast("uint8_t *", buf), data_len) + + def load_key_and_certificates_from_pkcs12( + self, data: bytes, password: typing.Optional[bytes] + ) -> typing.Tuple[ + typing.Optional[PRIVATE_KEY_TYPES], + typing.Optional[x509.Certificate], + typing.List[x509.Certificate], + ]: + pkcs12 = self.load_pkcs12(data, password) + return ( + pkcs12.key, + pkcs12.cert.certificate if pkcs12.cert else None, + [cert.certificate for cert in pkcs12.additional_certs], + ) + + def load_pkcs12( + self, data: bytes, password: typing.Optional[bytes] + ) -> PKCS12KeyAndCertificates: + if password is not None: + utils._check_byteslike("password", password) + + bio = self._bytes_to_bio(data) + p12 = self._lib.d2i_PKCS12_bio(bio.bio, self._ffi.NULL) + if p12 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Could not deserialize PKCS12 data") + + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + evp_pkey_ptr = self._ffi.new("EVP_PKEY **") + x509_ptr = self._ffi.new("X509 **") + sk_x509_ptr = self._ffi.new("Cryptography_STACK_OF_X509 **") + with self._zeroed_null_terminated_buf(password) as password_buf: + res = self._lib.PKCS12_parse( + p12, password_buf, evp_pkey_ptr, x509_ptr, sk_x509_ptr + ) + + # Workaround for + # https://github.com/libressl-portable/portable/issues/659 + if self._lib.CRYPTOGRAPHY_LIBRESSL_LESS_THAN_340: + self._consume_errors() + + if res == 0: + self._consume_errors() + raise ValueError("Invalid password or PKCS12 data") + + cert = None + key = None + additional_certificates = [] + + if evp_pkey_ptr[0] != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey_ptr[0], self._lib.EVP_PKEY_free) + key = self._evp_pkey_to_private_key(evp_pkey) + + if x509_ptr[0] != self._ffi.NULL: + x509 = self._ffi.gc(x509_ptr[0], self._lib.X509_free) + cert_obj = self._ossl2cert(x509) + name = None + maybe_name = self._lib.X509_alias_get0(x509, self._ffi.NULL) + if maybe_name != self._ffi.NULL: + name = self._ffi.string(maybe_name) + cert = PKCS12Certificate(cert_obj, name) + + if sk_x509_ptr[0] != self._ffi.NULL: + sk_x509 = self._ffi.gc(sk_x509_ptr[0], self._lib.sk_X509_free) + num = self._lib.sk_X509_num(sk_x509_ptr[0]) + + # In OpenSSL < 3.0.0 PKCS12 parsing reverses the order of the + # certificates. + indices: typing.Iterable[int] + if ( + self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER + or self._lib.CRYPTOGRAPHY_IS_BORINGSSL + ): + indices = range(num) + else: + indices = reversed(range(num)) + + for i in indices: + x509 = self._lib.sk_X509_value(sk_x509, i) + self.openssl_assert(x509 != self._ffi.NULL) + x509 = self._ffi.gc(x509, self._lib.X509_free) + addl_cert = self._ossl2cert(x509) + addl_name = None + maybe_name = self._lib.X509_alias_get0(x509, self._ffi.NULL) + if maybe_name != self._ffi.NULL: + addl_name = self._ffi.string(maybe_name) + additional_certificates.append( + PKCS12Certificate(addl_cert, addl_name) + ) + + return PKCS12KeyAndCertificates(key, cert, additional_certificates) + + def serialize_key_and_certificates_to_pkcs12( + self, + name: typing.Optional[bytes], + key: typing.Optional[_ALLOWED_PKCS12_TYPES], + cert: typing.Optional[x509.Certificate], + cas: typing.Optional[typing.List[_PKCS12_CAS_TYPES]], + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + password = None + if name is not None: + utils._check_bytes("name", name) + + if isinstance(encryption_algorithm, serialization.NoEncryption): + nid_cert = -1 + nid_key = -1 + pkcs12_iter = 0 + mac_iter = 0 + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): + # PKCS12 encryption is hopeless trash and can never be fixed. + # This is the least terrible option. + nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + # At least we can set this higher than OpenSSL's default + pkcs12_iter = 20000 + # mac_iter chosen for compatibility reasons, see: + # https://www.openssl.org/docs/man1.1.1/man3/PKCS12_create.html + # Did we mention how lousy PKCS12 encryption is? + mac_iter = 1 + password = encryption_algorithm.password + else: + raise ValueError("Unsupported key encryption type") + + if cas is None or len(cas) == 0: + sk_x509 = self._ffi.NULL + else: + sk_x509 = self._lib.sk_X509_new_null() + sk_x509 = self._ffi.gc(sk_x509, self._lib.sk_X509_free) + + # This list is to keep the x509 values alive until end of function + ossl_cas = [] + for ca in cas: + if isinstance(ca, PKCS12Certificate): + ca_alias = ca.friendly_name + ossl_ca = self._cert2ossl(ca.certificate) + with self._zeroed_null_terminated_buf( + ca_alias + ) as ca_name_buf: + res = self._lib.X509_alias_set1( + ossl_ca, ca_name_buf, -1 + ) + self.openssl_assert(res == 1) + else: + ossl_ca = self._cert2ossl(ca) + ossl_cas.append(ossl_ca) + res = self._lib.sk_X509_push(sk_x509, ossl_ca) + backend.openssl_assert(res >= 1) + + with self._zeroed_null_terminated_buf(password) as password_buf: + with self._zeroed_null_terminated_buf(name) as name_buf: + ossl_cert = self._cert2ossl(cert) if cert else self._ffi.NULL + if key is not None: + evp_pkey = key._evp_pkey # type: ignore[union-attr] + else: + evp_pkey = self._ffi.NULL + + p12 = self._lib.PKCS12_create( + password_buf, + name_buf, + evp_pkey, + ossl_cert, + sk_x509, + nid_key, + nid_cert, + pkcs12_iter, + mac_iter, + 0, + ) + + self.openssl_assert(p12 != self._ffi.NULL) + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + + bio = self._create_mem_bio_gc() + res = self._lib.i2d_PKCS12_bio(bio, p12) + self.openssl_assert(res > 0) + return self._read_mem_bio(bio) + + def poly1305_supported(self) -> bool: + if self._fips_enabled: + return False + return self._lib.Cryptography_HAS_POLY1305 == 1 + + def create_poly1305_ctx(self, key: bytes) -> _Poly1305Context: + utils._check_byteslike("key", key) + if len(key) != _POLY1305_KEY_SIZE: + raise ValueError("A poly1305 key is 32 bytes long") + + return _Poly1305Context(self, key) + + def pkcs7_supported(self) -> bool: + return not self._lib.CRYPTOGRAPHY_IS_BORINGSSL + + def load_pem_pkcs7_certificates( + self, data: bytes + ) -> typing.List[x509.Certificate]: + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.PEM_read_bio_PKCS7( + bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def load_der_pkcs7_certificates( + self, data: bytes + ) -> typing.List[x509.Certificate]: + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.d2i_PKCS7_bio(bio.bio, self._ffi.NULL) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def _load_pkcs7_certificates(self, p7): + nid = self._lib.OBJ_obj2nid(p7.type) + self.openssl_assert(nid != self._lib.NID_undef) + if nid != self._lib.NID_pkcs7_signed: + raise UnsupportedAlgorithm( + "Only basic signed structures are currently supported. NID" + " for this data was {}".format(nid), + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + sk_x509 = p7.d.sign.cert + num = self._lib.sk_X509_num(sk_x509) + certs = [] + for i in range(num): + x509 = self._lib.sk_X509_value(sk_x509, i) + self.openssl_assert(x509 != self._ffi.NULL) + res = self._lib.X509_up_ref(x509) + # When OpenSSL is less than 1.1.0 up_ref returns the current + # refcount. On 1.1.0+ it returns 1 for success. + self.openssl_assert(res >= 1) + x509 = self._ffi.gc(x509, self._lib.X509_free) + cert = self._ossl2cert(x509) + certs.append(cert) + + return certs + + def pkcs7_serialize_certificates( + self, + certs: typing.List[x509.Certificate], + encoding: serialization.Encoding, + ): + certs = list(certs) + if not certs or not all( + isinstance(cert, x509.Certificate) for cert in certs + ): + raise TypeError("certs must be a list of certs with length >= 1") + + if encoding not in ( + serialization.Encoding.PEM, + serialization.Encoding.DER, + ): + raise TypeError("encoding must DER or PEM from the Encoding enum") + + certs_sk = self._lib.sk_X509_new_null() + certs_sk = self._ffi.gc(certs_sk, self._lib.sk_X509_free) + # This list is to keep the x509 values alive until end of function + ossl_certs = [] + for cert in certs: + ossl_cert = self._cert2ossl(cert) + ossl_certs.append(ossl_cert) + res = self._lib.sk_X509_push(certs_sk, ossl_cert) + self.openssl_assert(res >= 1) + # We use PKCS7_sign here because it creates the PKCS7 and PKCS7_SIGNED + # structures for us rather than requiring manual assignment. + p7 = self._lib.PKCS7_sign( + self._ffi.NULL, + self._ffi.NULL, + certs_sk, + self._ffi.NULL, + self._lib.PKCS7_PARTIAL, + ) + bio_out = self._create_mem_bio_gc() + if encoding is serialization.Encoding.PEM: + res = self._lib.PEM_write_bio_PKCS7_stream( + bio_out, p7, self._ffi.NULL, 0 + ) + else: + assert encoding is serialization.Encoding.DER + res = self._lib.i2d_PKCS7_bio(bio_out, p7) + + self.openssl_assert(res == 1) + return self._read_mem_bio(bio_out) + + def pkcs7_sign( + self, + builder: pkcs7.PKCS7SignatureBuilder, + encoding: serialization.Encoding, + options: typing.List[pkcs7.PKCS7Options], + ) -> bytes: + assert builder._data is not None + bio = self._bytes_to_bio(builder._data) + init_flags = self._lib.PKCS7_PARTIAL + final_flags = 0 + + if len(builder._additional_certs) == 0: + certs = self._ffi.NULL + else: + certs = self._lib.sk_X509_new_null() + certs = self._ffi.gc(certs, self._lib.sk_X509_free) + # This list is to keep the x509 values alive until end of function + ossl_certs = [] + for cert in builder._additional_certs: + ossl_cert = self._cert2ossl(cert) + ossl_certs.append(ossl_cert) + res = self._lib.sk_X509_push(certs, ossl_cert) + self.openssl_assert(res >= 1) + + if pkcs7.PKCS7Options.DetachedSignature in options: + # Don't embed the data in the PKCS7 structure + init_flags |= self._lib.PKCS7_DETACHED + final_flags |= self._lib.PKCS7_DETACHED + + # This just inits a structure for us. However, there + # are flags we need to set, joy. + p7 = self._lib.PKCS7_sign( + self._ffi.NULL, + self._ffi.NULL, + certs, + self._ffi.NULL, + init_flags, + ) + self.openssl_assert(p7 != self._ffi.NULL) + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + signer_flags = 0 + # These flags are configurable on a per-signature basis + # but we've deliberately chosen to make the API only allow + # setting it across all signatures for now. + if pkcs7.PKCS7Options.NoCapabilities in options: + signer_flags |= self._lib.PKCS7_NOSMIMECAP + elif pkcs7.PKCS7Options.NoAttributes in options: + signer_flags |= self._lib.PKCS7_NOATTR + + if pkcs7.PKCS7Options.NoCerts in options: + signer_flags |= self._lib.PKCS7_NOCERTS + + for certificate, private_key, hash_algorithm in builder._signers: + ossl_cert = self._cert2ossl(certificate) + md = self._evp_md_non_null_from_algorithm(hash_algorithm) + p7signerinfo = self._lib.PKCS7_sign_add_signer( + p7, + ossl_cert, + private_key._evp_pkey, # type: ignore[union-attr] + md, + signer_flags, + ) + self.openssl_assert(p7signerinfo != self._ffi.NULL) + + for option in options: + # DetachedSignature, NoCapabilities, and NoAttributes are already + # handled so we just need to check these last two options. + if option is pkcs7.PKCS7Options.Text: + final_flags |= self._lib.PKCS7_TEXT + elif option is pkcs7.PKCS7Options.Binary: + final_flags |= self._lib.PKCS7_BINARY + + bio_out = self._create_mem_bio_gc() + if encoding is serialization.Encoding.SMIME: + # This finalizes the structure + res = self._lib.SMIME_write_PKCS7( + bio_out, p7, bio.bio, final_flags + ) + elif encoding is serialization.Encoding.PEM: + res = self._lib.PKCS7_final(p7, bio.bio, final_flags) + self.openssl_assert(res == 1) + res = self._lib.PEM_write_bio_PKCS7_stream( + bio_out, p7, bio.bio, final_flags + ) + else: + assert encoding is serialization.Encoding.DER + # We need to call finalize here becauase i2d_PKCS7_bio does not + # finalize. + res = self._lib.PKCS7_final(p7, bio.bio, final_flags) + self.openssl_assert(res == 1) + # OpenSSL 3.0 leaves a random bio error on the stack: + # https://github.com/openssl/openssl/issues/16681 + if self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: + self._consume_errors() + res = self._lib.i2d_PKCS7_bio(bio_out, p7) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio_out) + + +class GetCipherByName: + def __init__(self, fmt: str): + self._fmt = fmt + + def __call__(self, backend: Backend, cipher: CipherAlgorithm, mode: Mode): + cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +def _get_xts_cipher(backend: Backend, cipher: AES, mode): + cipher_name = "aes-{}-xts".format(cipher.key_size // 2) + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +backend = Backend() diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ciphers.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ciphers.py new file mode 100644 index 0000000..1058de9 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ciphers.py @@ -0,0 +1,282 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import ciphers +from cryptography.hazmat.primitives.ciphers import algorithms, modes + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _CipherContext: + _ENCRYPT = 1 + _DECRYPT = 0 + _MAX_CHUNK_SIZE = 2**30 - 1 + + def __init__( + self, backend: "Backend", cipher, mode, operation: int + ) -> None: + self._backend = backend + self._cipher = cipher + self._mode = mode + self._operation = operation + self._tag: typing.Optional[bytes] = None + + if isinstance(self._cipher, ciphers.BlockCipherAlgorithm): + self._block_size_bytes = self._cipher.block_size // 8 + else: + self._block_size_bytes = 1 + + ctx = self._backend._lib.EVP_CIPHER_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_CIPHER_CTX_free + ) + + registry = self._backend._cipher_registry + try: + adapter = registry[type(cipher), type(mode)] + except KeyError: + raise UnsupportedAlgorithm( + "cipher {} in {} mode is not supported " + "by this backend.".format( + cipher.name, mode.name if mode else mode + ), + _Reasons.UNSUPPORTED_CIPHER, + ) + + evp_cipher = adapter(self._backend, cipher, mode) + if evp_cipher == self._backend._ffi.NULL: + msg = "cipher {0.name} ".format(cipher) + if mode is not None: + msg += "in {0.name} mode ".format(mode) + msg += ( + "is not supported by this backend (Your version of OpenSSL " + "may be too old. Current version: {}.)" + ).format(self._backend.openssl_version_text()) + raise UnsupportedAlgorithm(msg, _Reasons.UNSUPPORTED_CIPHER) + + if isinstance(mode, modes.ModeWithInitializationVector): + iv_nonce = self._backend._ffi.from_buffer( + mode.initialization_vector + ) + elif isinstance(mode, modes.ModeWithTweak): + iv_nonce = self._backend._ffi.from_buffer(mode.tweak) + elif isinstance(mode, modes.ModeWithNonce): + iv_nonce = self._backend._ffi.from_buffer(mode.nonce) + elif isinstance(cipher, algorithms.ChaCha20): + iv_nonce = self._backend._ffi.from_buffer(cipher.nonce) + else: + iv_nonce = self._backend._ffi.NULL + # begin init with cipher and operation type + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + operation, + ) + self._backend.openssl_assert(res != 0) + # set the key length to handle variable key ciphers + res = self._backend._lib.EVP_CIPHER_CTX_set_key_length( + ctx, len(cipher.key) + ) + self._backend.openssl_assert(res != 0) + if isinstance(mode, modes.GCM): + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(iv_nonce), + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res != 0) + if mode.tag is not None: + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_TAG, + len(mode.tag), + mode.tag, + ) + self._backend.openssl_assert(res != 0) + self._tag = mode.tag + + # pass key/iv + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.from_buffer(cipher.key), + iv_nonce, + operation, + ) + + # Check for XTS mode duplicate keys error + errors = self._backend._consume_errors() + lib = self._backend._lib + if res == 0 and ( + ( + lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER + and errors[0]._lib_reason_match( + lib.ERR_LIB_EVP, lib.EVP_R_XTS_DUPLICATED_KEYS + ) + ) + or ( + lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + lib.ERR_LIB_PROV, lib.PROV_R_XTS_DUPLICATED_KEYS + ) + ) + ): + raise ValueError("In XTS mode duplicated keys are not allowed") + + self._backend.openssl_assert(res != 0, errors=errors) + + # We purposely disable padding here as it's handled higher up in the + # API. + self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + self._ctx = ctx + + def update(self, data: bytes) -> bytes: + buf = bytearray(len(data) + self._block_size_bytes - 1) + n = self.update_into(data, buf) + return bytes(buf[:n]) + + def update_into(self, data: bytes, buf: bytes) -> int: + total_data_len = len(data) + if len(buf) < (total_data_len + self._block_size_bytes - 1): + raise ValueError( + "buffer must be at least {} bytes for this " + "payload".format(len(data) + self._block_size_bytes - 1) + ) + + data_processed = 0 + total_out = 0 + outlen = self._backend._ffi.new("int *") + baseoutbuf = self._backend._ffi.from_buffer(buf) + baseinbuf = self._backend._ffi.from_buffer(data) + + while data_processed != total_data_len: + outbuf = baseoutbuf + total_out + inbuf = baseinbuf + data_processed + inlen = min(self._MAX_CHUNK_SIZE, total_data_len - data_processed) + + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, outbuf, outlen, inbuf, inlen + ) + if res == 0 and isinstance(self._mode, modes.XTS): + self._backend._consume_errors() + raise ValueError( + "In XTS mode you must supply at least a full block in the " + "first update call. For AES this is 16 bytes." + ) + else: + self._backend.openssl_assert(res != 0) + data_processed += inlen + total_out += outlen[0] + + return total_out + + def finalize(self) -> bytes: + if ( + self._operation == self._DECRYPT + and isinstance(self._mode, modes.ModeWithAuthenticationTag) + and self.tag is None + ): + raise ValueError( + "Authentication tag must be provided when decrypting." + ) + + buf = self._backend._ffi.new("unsigned char[]", self._block_size_bytes) + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen) + if res == 0: + errors = self._backend._consume_errors() + + if not errors and isinstance(self._mode, modes.GCM): + raise InvalidTag + + lib = self._backend._lib + self._backend.openssl_assert( + errors[0]._lib_reason_match( + lib.ERR_LIB_EVP, + lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + ) + or ( + lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + lib.ERR_LIB_PROV, + lib.PROV_R_WRONG_FINAL_BLOCK_LENGTH, + ) + ) + or ( + lib.CRYPTOGRAPHY_IS_BORINGSSL + and errors[0].reason + == lib.CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH + ), + errors=errors, + ) + raise ValueError( + "The length of the provided data is not a multiple of " + "the block length." + ) + + if ( + isinstance(self._mode, modes.GCM) + and self._operation == self._ENCRYPT + ): + tag_buf = self._backend._ffi.new( + "unsigned char[]", self._block_size_bytes + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, + self._backend._lib.EVP_CTRL_AEAD_GET_TAG, + self._block_size_bytes, + tag_buf, + ) + self._backend.openssl_assert(res != 0) + self._tag = self._backend._ffi.buffer(tag_buf)[:] + + res = self._backend._lib.EVP_CIPHER_CTX_reset(self._ctx) + self._backend.openssl_assert(res == 1) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def finalize_with_tag(self, tag: bytes) -> bytes: + tag_len = len(tag) + if tag_len < self._mode._min_tag_length: + raise ValueError( + "Authentication tag must be {} bytes or longer.".format( + self._mode._min_tag_length + ) + ) + elif tag_len > self._block_size_bytes: + raise ValueError( + "Authentication tag cannot be more than {} bytes.".format( + self._block_size_bytes + ) + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag + ) + self._backend.openssl_assert(res != 0) + self._tag = tag + return self.finalize() + + def authenticate_additional_data(self, data: bytes) -> None: + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, + self._backend._ffi.NULL, + outlen, + self._backend._ffi.from_buffer(data), + len(data), + ) + self._backend.openssl_assert(res != 0) + + @property + def tag(self) -> typing.Optional[bytes]: + return self._tag diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/cmac.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/cmac.py new file mode 100644 index 0000000..35f50c5 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/cmac.py @@ -0,0 +1,87 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.ciphers.modes import CBC + +if typing.TYPE_CHECKING: + from cryptography.hazmat.primitives import ciphers + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _CMACContext: + def __init__( + self, + backend: "Backend", + algorithm: "ciphers.BlockCipherAlgorithm", + ctx=None, + ) -> None: + if not backend.cmac_algorithm_supported(algorithm): + raise UnsupportedAlgorithm( + "This backend does not support CMAC.", + _Reasons.UNSUPPORTED_CIPHER, + ) + + self._backend = backend + self._key = algorithm.key + self._algorithm = algorithm + self._output_length = algorithm.block_size // 8 + + if ctx is None: + registry = self._backend._cipher_registry + adapter = registry[type(algorithm), CBC] + + evp_cipher = adapter(self._backend, algorithm, CBC) + + ctx = self._backend._lib.CMAC_CTX_new() + + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free) + + key_ptr = self._backend._ffi.from_buffer(self._key) + res = self._backend._lib.CMAC_Init( + ctx, + key_ptr, + len(self._key), + evp_cipher, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res == 1) + + self._ctx = ctx + + def update(self, data: bytes) -> None: + res = self._backend._lib.CMAC_Update(self._ctx, data, len(data)) + self._backend.openssl_assert(res == 1) + + def finalize(self) -> bytes: + buf = self._backend._ffi.new("unsigned char[]", self._output_length) + length = self._backend._ffi.new("size_t *", self._output_length) + res = self._backend._lib.CMAC_Final(self._ctx, buf, length) + self._backend.openssl_assert(res == 1) + + self._ctx = None + + return self._backend._ffi.buffer(buf)[:] + + def copy(self) -> "_CMACContext": + copied_ctx = self._backend._lib.CMAC_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.CMAC_CTX_free + ) + res = self._backend._lib.CMAC_CTX_copy(copied_ctx, self._ctx) + self._backend.openssl_assert(res == 1) + return _CMACContext(self._backend, self._algorithm, ctx=copied_ctx) + + def verify(self, signature: bytes) -> None: + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py new file mode 100644 index 0000000..df91d6d --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -0,0 +1,31 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography import x509 + +# CRLReason ::= ENUMERATED { +# unspecified (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# -- value 7 is not used +# removeFromCRL (8), +# privilegeWithdrawn (9), +# aACompromise (10) } +_CRL_ENTRY_REASON_ENUM_TO_CODE = { + x509.ReasonFlags.unspecified: 0, + x509.ReasonFlags.key_compromise: 1, + x509.ReasonFlags.ca_compromise: 2, + x509.ReasonFlags.affiliation_changed: 3, + x509.ReasonFlags.superseded: 4, + x509.ReasonFlags.cessation_of_operation: 5, + x509.ReasonFlags.certificate_hold: 6, + x509.ReasonFlags.remove_from_crl: 8, + x509.ReasonFlags.privilege_withdrawn: 9, + x509.ReasonFlags.aa_compromise: 10, +} diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dh.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dh.py new file mode 100644 index 0000000..70364a3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dh.py @@ -0,0 +1,318 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import dh + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _dh_params_dup(dh_cdata, backend: "Backend"): + lib = backend._lib + ffi = backend._ffi + + param_cdata = lib.DHparams_dup(dh_cdata) + backend.openssl_assert(param_cdata != ffi.NULL) + param_cdata = ffi.gc(param_cdata, lib.DH_free) + if lib.CRYPTOGRAPHY_IS_LIBRESSL: + # In libressl DHparams_dup don't copy q + q = ffi.new("BIGNUM **") + lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL) + q_dup = lib.BN_dup(q[0]) + res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL) + backend.openssl_assert(res == 1) + + return param_cdata + + +def _dh_cdata_to_parameters(dh_cdata, backend: "Backend") -> "_DHParameters": + param_cdata = _dh_params_dup(dh_cdata, backend) + return _DHParameters(backend, param_cdata) + + +class _DHParameters(dh.DHParameters): + def __init__(self, backend: "Backend", dh_cdata): + self._backend = backend + self._dh_cdata = dh_cdata + + def parameter_numbers(self) -> dh.DHParameterNumbers: + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + q_val: typing.Optional[int] + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + return dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ) + + def generate_private_key(self) -> dh.DHPrivateKey: + return self._backend.generate_dh_private_key(self) + + def parameter_bytes( + self, + encoding: serialization.Encoding, + format: serialization.ParameterFormat, + ) -> bytes: + if encoding is serialization.Encoding.OpenSSH: + raise TypeError("OpenSSH encoding is not supported") + + if format is not serialization.ParameterFormat.PKCS3: + raise ValueError("Only PKCS3 serialization is supported") + + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, self._backend._ffi.NULL, q, self._backend._ffi.NULL + ) + if ( + q[0] != self._backend._ffi.NULL + and not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX + ): + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + if encoding is serialization.Encoding.PEM: + if q[0] != self._backend._ffi.NULL: + write_bio = self._backend._lib.PEM_write_bio_DHxparams + else: + write_bio = self._backend._lib.PEM_write_bio_DHparams + elif encoding is serialization.Encoding.DER: + if q[0] != self._backend._ffi.NULL: + write_bio = self._backend._lib.Cryptography_i2d_DHxparams_bio + else: + write_bio = self._backend._lib.i2d_DHparams_bio + else: + raise TypeError("encoding must be an item from the Encoding enum") + + bio = self._backend._create_mem_bio_gc() + res = write_bio(bio, self._dh_cdata) + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + +def _get_dh_num_bits(backend, dh_cdata) -> int: + p = backend._ffi.new("BIGNUM **") + backend._lib.DH_get0_pqg(dh_cdata, p, backend._ffi.NULL, backend._ffi.NULL) + backend.openssl_assert(p[0] != backend._ffi.NULL) + return backend._lib.BN_num_bits(p[0]) + + +class _DHPrivateKey(dh.DHPrivateKey): + def __init__(self, backend: "Backend", dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bytes = self._backend._lib.DH_size(dh_cdata) + + @property + def key_size(self) -> int: + return _get_dh_num_bits(self._backend, self._dh_cdata) + + def private_numbers(self) -> dh.DHPrivateNumbers: + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dh.DHPrivateNumbers( + public_numbers=dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ), + y=self._backend._bn_to_int(pub_key[0]), + ), + x=self._backend._bn_to_int(priv_key[0]), + ) + + def exchange(self, peer_public_key: dh.DHPublicKey) -> bytes: + if not isinstance(peer_public_key, _DHPublicKey): + raise TypeError("peer_public_key must be a DHPublicKey") + + ctx = self._backend._lib.EVP_PKEY_CTX_new( + self._evp_pkey, self._backend._ffi.NULL + ) + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.EVP_PKEY_CTX_free) + res = self._backend._lib.EVP_PKEY_derive_init(ctx) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_PKEY_derive_set_peer( + ctx, peer_public_key._evp_pkey + ) + # Invalid kex errors here in OpenSSL 3.0 because checks were moved + # to EVP_PKEY_derive_set_peer + self._exchange_assert(res == 1) + keylen = self._backend._ffi.new("size_t *") + res = self._backend._lib.EVP_PKEY_derive( + ctx, self._backend._ffi.NULL, keylen + ) + # Invalid kex errors here in OpenSSL < 3 + self._exchange_assert(res == 1) + self._backend.openssl_assert(keylen[0] > 0) + buf = self._backend._ffi.new("unsigned char[]", keylen[0]) + res = self._backend._lib.EVP_PKEY_derive(ctx, buf, keylen) + self._backend.openssl_assert(res == 1) + + key = self._backend._ffi.buffer(buf, keylen[0])[:] + pad = self._key_size_bytes - len(key) + + if pad > 0: + key = (b"\x00" * pad) + key + + return key + + def _exchange_assert(self, ok: bool) -> None: + if not ok: + errors_with_text = self._backend._consume_errors_with_text() + raise ValueError( + "Error computing shared key.", + errors_with_text, + ) + + def public_key(self) -> dh.DHPublicKey: + dh_cdata = _dh_params_dup(self._dh_cdata, self._backend) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key( + self._dh_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + self._backend.openssl_assert(pub_key_dup != self._backend._ffi.NULL) + + res = self._backend._lib.DH_set0_key( + dh_cdata, pub_key_dup, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dh_cdata_to_evp_pkey(dh_cdata) + return _DHPublicKey(self._backend, dh_cdata, evp_pkey) + + def parameters(self) -> dh.DHParameters: + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if format is not serialization.PrivateFormat.PKCS8: + raise ValueError( + "DH private keys support only PKCS8 serialization" + ) + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL, + ) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._dh_cdata, + ) + + +class _DHPublicKey(dh.DHPublicKey): + def __init__(self, backend: "Backend", dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bits = _get_dh_num_bits(self._backend, self._dh_cdata) + + @property + def key_size(self) -> int: + return self._key_size_bits + + def public_numbers(self) -> dh.DHPublicNumbers: + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key( + self._dh_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ), + y=self._backend._bn_to_int(pub_key[0]), + ) + + def parameters(self) -> dh.DHParameters: + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if format is not serialization.PublicFormat.SubjectPublicKeyInfo: + raise ValueError( + "DH public keys support only " + "SubjectPublicKeyInfo serialization" + ) + + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL, + ) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dsa.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dsa.py new file mode 100644 index 0000000..8634b72 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/dsa.py @@ -0,0 +1,239 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + utils as asym_utils, +) + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _dsa_sig_sign( + backend: "Backend", private_key: "_DSAPrivateKey", data: bytes +) -> bytes: + sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata) + sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len) + buflen = backend._ffi.new("unsigned int *") + + # The first parameter passed to DSA_sign is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_sign( + 0, data, len(data), sig_buf, buflen, private_key._dsa_cdata + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(buflen[0]) + + return backend._ffi.buffer(sig_buf)[: buflen[0]] + + +def _dsa_sig_verify( + backend: "Backend", + public_key: "_DSAPublicKey", + signature: bytes, + data: bytes, +) -> None: + # The first parameter passed to DSA_verify is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_verify( + 0, data, len(data), signature, len(signature), public_key._dsa_cdata + ) + + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +class _DSAParameters(dsa.DSAParameters): + def __init__(self, backend: "Backend", dsa_cdata): + self._backend = backend + self._dsa_cdata = dsa_cdata + + def parameter_numbers(self) -> dsa.DSAParameterNumbers: + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + return dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ) + + def generate_private_key(self) -> dsa.DSAPrivateKey: + return self._backend.generate_dsa_private_key(self) + + +class _DSAPrivateKey(dsa.DSAPrivateKey): + _key_size: int + + def __init__(self, backend: "Backend", dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + @property + def key_size(self) -> int: + return self._key_size + + def private_numbers(self) -> dsa.DSAPrivateNumbers: + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dsa.DSAPrivateNumbers( + public_numbers=dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ), + y=self._backend._bn_to_int(pub_key[0]), + ), + x=self._backend._bn_to_int(priv_key[0]), + ) + + def public_key(self) -> dsa.DSAPublicKey: + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + res = self._backend._lib.DSA_set0_key( + dsa_cdata, pub_key_dup, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata) + return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey) + + def parameters(self) -> dsa.DSAParameters: + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._dsa_cdata, + ) + + def sign( + self, + data: bytes, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> bytes: + data, _ = _calculate_digest_and_algorithm(data, algorithm) + return _dsa_sig_sign(self._backend, self, data) + + +class _DSAPublicKey(dsa.DSAPublicKey): + _key_size: int + + def __init__(self, backend: "Backend", dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + @property + def key_size(self) -> int: + return self._key_size + + def public_numbers(self) -> dsa.DSAPublicNumbers: + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ), + y=self._backend._bn_to_int(pub_key[0]), + ) + + def parameters(self) -> dsa.DSAParameters: + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def verify( + self, + signature: bytes, + data: bytes, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> None: + data, _ = _calculate_digest_and_algorithm(data, algorithm) + return _dsa_sig_verify(self._backend, self, signature, data) diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ec.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ec.py new file mode 100644 index 0000000..9bc6dd3 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ec.py @@ -0,0 +1,315 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, + _evp_pkey_derive, +) +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _check_signature_algorithm( + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, +) -> None: + if not isinstance(signature_algorithm, ec.ECDSA): + raise UnsupportedAlgorithm( + "Unsupported elliptic curve signature algorithm.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + +def _ec_key_curve_sn(backend: "Backend", ec_key) -> str: + group = backend._lib.EC_KEY_get0_group(ec_key) + backend.openssl_assert(group != backend._ffi.NULL) + + nid = backend._lib.EC_GROUP_get_curve_name(group) + # The following check is to find EC keys with unnamed curves and raise + # an error for now. + if nid == backend._lib.NID_undef: + raise ValueError( + "ECDSA keys with explicit parameters are unsupported at this time" + ) + + # This is like the above check, but it also catches the case where you + # explicitly encoded a curve with the same parameters as a named curve. + # Don't do that. + if ( + not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + and backend._lib.EC_GROUP_get_asn1_flag(group) == 0 + ): + raise ValueError( + "ECDSA keys with explicit parameters are unsupported at this time" + ) + + curve_name = backend._lib.OBJ_nid2sn(nid) + backend.openssl_assert(curve_name != backend._ffi.NULL) + + sn = backend._ffi.string(curve_name).decode("ascii") + return sn + + +def _mark_asn1_named_ec_curve(backend: "Backend", ec_cdata): + """ + Set the named curve flag on the EC_KEY. This causes OpenSSL to + serialize EC keys along with their curve OID which makes + deserialization easier. + """ + + backend._lib.EC_KEY_set_asn1_flag( + ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE + ) + + +def _check_key_infinity(backend: "Backend", ec_cdata) -> None: + point = backend._lib.EC_KEY_get0_public_key(ec_cdata) + backend.openssl_assert(point != backend._ffi.NULL) + group = backend._lib.EC_KEY_get0_group(ec_cdata) + backend.openssl_assert(group != backend._ffi.NULL) + if backend._lib.EC_POINT_is_at_infinity(group, point): + raise ValueError( + "Cannot load an EC public key where the point is at infinity" + ) + + +def _sn_to_elliptic_curve(backend: "Backend", sn: str) -> ec.EllipticCurve: + try: + return ec._CURVE_TYPES[sn]() + except KeyError: + raise UnsupportedAlgorithm( + "{} is not a supported elliptic curve".format(sn), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + + +def _ecdsa_sig_sign( + backend: "Backend", private_key: "_EllipticCurvePrivateKey", data: bytes +) -> bytes: + max_size = backend._lib.ECDSA_size(private_key._ec_key) + backend.openssl_assert(max_size > 0) + + sigbuf = backend._ffi.new("unsigned char[]", max_size) + siglen_ptr = backend._ffi.new("unsigned int[]", 1) + res = backend._lib.ECDSA_sign( + 0, data, len(data), sigbuf, siglen_ptr, private_key._ec_key + ) + backend.openssl_assert(res == 1) + return backend._ffi.buffer(sigbuf)[: siglen_ptr[0]] + + +def _ecdsa_sig_verify( + backend: "Backend", + public_key: "_EllipticCurvePublicKey", + signature: bytes, + data: bytes, +) -> None: + res = backend._lib.ECDSA_verify( + 0, data, len(data), signature, len(signature), public_key._ec_key + ) + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +class _EllipticCurvePrivateKey(ec.EllipticCurvePrivateKey): + def __init__(self, backend: "Backend", ec_key_cdata, evp_pkey): + self._backend = backend + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + _check_key_infinity(backend, ec_key_cdata) + + @property + def curve(self) -> ec.EllipticCurve: + return self._curve + + @property + def key_size(self) -> int: + return self.curve.key_size + + def exchange( + self, algorithm: ec.ECDH, peer_public_key: ec.EllipticCurvePublicKey + ) -> bytes: + if not ( + self._backend.elliptic_curve_exchange_algorithm_supported( + algorithm, self.curve + ) + ): + raise UnsupportedAlgorithm( + "This backend does not support the ECDH algorithm.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + if peer_public_key.curve.name != self.curve.name: + raise ValueError( + "peer_public_key and self are not on the same curve" + ) + + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) + + def public_key(self) -> ec.EllipticCurvePublicKey: + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + + curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group) + public_ec_key = self._backend._ec_key_new_by_curve_nid(curve_nid) + + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point) + self._backend.openssl_assert(res == 1) + + evp_pkey = self._backend._ec_cdata_to_evp_pkey(public_ec_key) + + return _EllipticCurvePublicKey(self._backend, public_ec_key, evp_pkey) + + def private_numbers(self) -> ec.EllipticCurvePrivateNumbers: + bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key) + private_value = self._backend._bn_to_int(bn) + return ec.EllipticCurvePrivateNumbers( + private_value=private_value, + public_numbers=self.public_key().public_numbers(), + ) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._ec_key, + ) + + def sign( + self, + data: bytes, + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, + ) -> bytes: + _check_signature_algorithm(signature_algorithm) + data, _ = _calculate_digest_and_algorithm( + data, + signature_algorithm.algorithm, + ) + return _ecdsa_sig_sign(self._backend, self, data) + + +class _EllipticCurvePublicKey(ec.EllipticCurvePublicKey): + def __init__(self, backend: "Backend", ec_key_cdata, evp_pkey): + self._backend = backend + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + _check_key_infinity(backend, ec_key_cdata) + + @property + def curve(self) -> ec.EllipticCurve: + return self._curve + + @property + def key_size(self) -> int: + return self.curve.key_size + + def public_numbers(self) -> ec.EllipticCurvePublicNumbers: + get_func, group = self._backend._ec_key_determine_group_get_func( + self._ec_key + ) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + with self._backend._tmp_bn_ctx() as bn_ctx: + bn_x = self._backend._lib.BN_CTX_get(bn_ctx) + bn_y = self._backend._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + self._backend.openssl_assert(res == 1) + + x = self._backend._bn_to_int(bn_x) + y = self._backend._bn_to_int(bn_y) + + return ec.EllipticCurvePublicNumbers(x=x, y=y, curve=self._curve) + + def _encode_point(self, format: serialization.PublicFormat) -> bytes: + if format is serialization.PublicFormat.CompressedPoint: + conversion = self._backend._lib.POINT_CONVERSION_COMPRESSED + else: + assert format is serialization.PublicFormat.UncompressedPoint + conversion = self._backend._lib.POINT_CONVERSION_UNCOMPRESSED + + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + with self._backend._tmp_bn_ctx() as bn_ctx: + buflen = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, self._backend._ffi.NULL, 0, bn_ctx + ) + self._backend.openssl_assert(buflen > 0) + buf = self._backend._ffi.new("char[]", buflen) + res = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, buf, buflen, bn_ctx + ) + self._backend.openssl_assert(buflen == res) + + return self._backend._ffi.buffer(buf)[:] + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.X962 + or format is serialization.PublicFormat.CompressedPoint + or format is serialization.PublicFormat.UncompressedPoint + ): + if encoding is not serialization.Encoding.X962 or format not in ( + serialization.PublicFormat.CompressedPoint, + serialization.PublicFormat.UncompressedPoint, + ): + raise ValueError( + "X962 encoding must be used with CompressedPoint or " + "UncompressedPoint format" + ) + + return self._encode_point(format) + else: + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def verify( + self, + signature: bytes, + data: bytes, + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, + ) -> None: + _check_signature_algorithm(signature_algorithm) + data, _ = _calculate_digest_and_algorithm( + data, + signature_algorithm.algorithm, + ) + _ecdsa_sig_verify(self._backend, self, signature, data) diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed25519.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed25519.py new file mode 100644 index 0000000..5cfdffb --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed25519.py @@ -0,0 +1,155 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import exceptions +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, + Ed25519PublicKey, + _ED25519_KEY_SIZE, + _ED25519_SIG_SIZE, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _Ed25519PublicKey(Ed25519PublicKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] + + def verify(self, signature: bytes, data: bytes) -> None: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +class _Ed25519PrivateKey(Ed25519PrivateKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self) -> Ed25519PublicKey: + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed25519_load_public_bytes(public_bytes) + + def sign(self, data: bytes) -> bytes: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed448.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed448.py new file mode 100644 index 0000000..dad93c6 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/ed448.py @@ -0,0 +1,156 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography import exceptions +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, + Ed448PublicKey, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + +_ED448_KEY_SIZE = 57 +_ED448_SIG_SIZE = 114 + + +class _Ed448PublicKey(Ed448PublicKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] + + def verify(self, signature: bytes, data: bytes) -> None: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +class _Ed448PrivateKey(Ed448PrivateKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self) -> Ed448PublicKey: + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed448_load_public_bytes(public_bytes) + + def sign(self, data: bytes) -> bytes: + evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py new file mode 100644 index 0000000..2f29d71 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -0,0 +1,18 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +from cryptography import x509 + + +_CRLREASONFLAGS = { + x509.ReasonFlags.key_compromise: 1, + x509.ReasonFlags.ca_compromise: 2, + x509.ReasonFlags.affiliation_changed: 3, + x509.ReasonFlags.superseded: 4, + x509.ReasonFlags.cessation_of_operation: 5, + x509.ReasonFlags.certificate_hold: 6, + x509.ReasonFlags.privilege_withdrawn: 7, + x509.ReasonFlags.aa_compromise: 8, +} diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hashes.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hashes.py new file mode 100644 index 0000000..278b381 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hashes.py @@ -0,0 +1,87 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import hashes + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _HashContext(hashes.HashContext): + def __init__( + self, backend: "Backend", algorithm: hashes.HashAlgorithm, ctx=None + ) -> None: + self._algorithm = algorithm + + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.EVP_MD_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_MD_CTX_free + ) + evp_md = self._backend._evp_md_from_algorithm(algorithm) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{} is not a supported hash on this backend.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + res = self._backend._lib.EVP_DigestInit_ex( + ctx, evp_md, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm + + def copy(self) -> "_HashContext": + copied_ctx = self._backend._lib.EVP_MD_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) + + def update(self, data: bytes) -> None: + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.EVP_DigestUpdate( + self._ctx, data_ptr, len(data) + ) + self._backend.openssl_assert(res != 0) + + def finalize(self) -> bytes: + if isinstance(self.algorithm, hashes.ExtendableOutputFunction): + # extendable output functions use a different finalize + return self._finalize_xof() + else: + buf = self._backend._ffi.new( + "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE + ) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert( + outlen[0] == self.algorithm.digest_size + ) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def _finalize_xof(self) -> bytes: + buf = self._backend._ffi.new( + "unsigned char[]", self.algorithm.digest_size + ) + res = self._backend._lib.EVP_DigestFinalXOF( + self._ctx, buf, self.algorithm.digest_size + ) + self._backend.openssl_assert(res != 0) + return self._backend._ffi.buffer(buf)[: self.algorithm.digest_size] diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hmac.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hmac.py new file mode 100644 index 0000000..5fd5407 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hmac.py @@ -0,0 +1,85 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import constant_time, hashes + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _HMACContext(hashes.HashContext): + def __init__( + self, + backend: "Backend", + key: bytes, + algorithm: hashes.HashAlgorithm, + ctx=None, + ): + self._algorithm = algorithm + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.HMAC_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.HMAC_CTX_free) + evp_md = self._backend._evp_md_from_algorithm(algorithm) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{} is not a supported hash on this backend".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + key_ptr = self._backend._ffi.from_buffer(key) + res = self._backend._lib.HMAC_Init_ex( + ctx, key_ptr, len(key), evp_md, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + self._key = key + + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm + + def copy(self) -> "_HMACContext": + copied_ctx = self._backend._lib.HMAC_CTX_new() + self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.HMAC_CTX_free + ) + res = self._backend._lib.HMAC_CTX_copy(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HMACContext( + self._backend, self._key, self.algorithm, ctx=copied_ctx + ) + + def update(self, data: bytes) -> None: + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.HMAC_Update(self._ctx, data_ptr, len(data)) + self._backend.openssl_assert(res != 0) + + def finalize(self) -> bytes: + buf = self._backend._ffi.new( + "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE + ) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.HMAC_Final(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def verify(self, signature: bytes) -> None: + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/poly1305.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/poly1305.py new file mode 100644 index 0000000..dd6d376 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/poly1305.py @@ -0,0 +1,68 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import constant_time + + +_POLY1305_TAG_SIZE = 16 +_POLY1305_KEY_SIZE = 32 + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +class _Poly1305Context: + def __init__(self, backend: "Backend", key: bytes) -> None: + self._backend = backend + + key_ptr = self._backend._ffi.from_buffer(key) + # This function copies the key into OpenSSL-owned memory so we don't + # need to retain it ourselves + evp_pkey = self._backend._lib.EVP_PKEY_new_raw_private_key( + self._backend._lib.NID_poly1305, + self._backend._ffi.NULL, + key_ptr, + len(key), + ) + self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) + self._evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + ctx = self._backend._lib.EVP_MD_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + self._ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + self._ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + + def update(self, data: bytes) -> None: + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.EVP_DigestSignUpdate( + self._ctx, data_ptr, len(data) + ) + self._backend.openssl_assert(res != 0) + + def finalize(self) -> bytes: + buf = self._backend._ffi.new("unsigned char[]", _POLY1305_TAG_SIZE) + outlen = self._backend._ffi.new("size_t *", _POLY1305_TAG_SIZE) + res = self._backend._lib.EVP_DigestSignFinal(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == _POLY1305_TAG_SIZE) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def verify(self, tag: bytes) -> None: + mac = self.finalize() + if not constant_time.bytes_eq(mac, tag): + raise InvalidSignature("Value did not match computed tag.") diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/rsa.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/rsa.py new file mode 100644 index 0000000..20b643c --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/rsa.py @@ -0,0 +1,567 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import typing + +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ( + utils as asym_utils, +) +from cryptography.hazmat.primitives.asymmetric.padding import ( + AsymmetricPadding, + MGF1, + OAEP, + PKCS1v15, + PSS, + _Auto, + _DigestLength, + _MaxLength, + calculate_max_pss_salt_length, +) +from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKey, + RSAPrivateNumbers, + RSAPublicKey, + RSAPublicNumbers, +) + + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _get_rsa_pss_salt_length( + backend: "Backend", + pss: PSS, + key: typing.Union[RSAPrivateKey, RSAPublicKey], + hash_algorithm: hashes.HashAlgorithm, +) -> int: + salt = pss._salt_length + + if isinstance(salt, _MaxLength): + return calculate_max_pss_salt_length(key, hash_algorithm) + elif isinstance(salt, _DigestLength): + return hash_algorithm.digest_size + elif isinstance(salt, _Auto): + if isinstance(key, RSAPrivateKey): + raise ValueError( + "PSS salt length can only be set to AUTO when verifying" + ) + return backend._lib.RSA_PSS_SALTLEN_AUTO + else: + return salt + + +def _enc_dec_rsa( + backend: "Backend", + key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + data: bytes, + padding: AsymmetricPadding, +) -> bytes: + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Padding must be an instance of AsymmetricPadding.") + + if isinstance(padding, PKCS1v15): + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, OAEP): + padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING + + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF, + ) + + if not backend.rsa_padding_supported(padding): + raise UnsupportedAlgorithm( + "This combination of padding and hash algorithm is not " + "supported by this backend.", + _Reasons.UNSUPPORTED_PADDING, + ) + + else: + raise UnsupportedAlgorithm( + "{} is not supported by this backend.".format(padding.name), + _Reasons.UNSUPPORTED_PADDING, + ) + + return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding) + + +def _enc_dec_rsa_pkey_ctx( + backend: "Backend", + key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + data: bytes, + padding_enum: int, + padding: AsymmetricPadding, +) -> bytes: + init: typing.Callable[[typing.Any], int] + crypt: typing.Callable[[typing.Any, typing.Any, int, bytes, int], int] + if isinstance(key, _RSAPublicKey): + init = backend._lib.EVP_PKEY_encrypt_init + crypt = backend._lib.EVP_PKEY_encrypt + else: + init = backend._lib.EVP_PKEY_decrypt_init + crypt = backend._lib.EVP_PKEY_decrypt + + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init(pkey_ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) + backend.openssl_assert(res > 0) + buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(buf_size > 0) + if isinstance(padding, OAEP): + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + oaep_md = backend._evp_md_non_null_from_algorithm(padding._algorithm) + res = backend._lib.EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, oaep_md) + backend.openssl_assert(res > 0) + + if ( + isinstance(padding, OAEP) + and padding._label is not None + and len(padding._label) > 0 + ): + # set0_rsa_oaep_label takes ownership of the char * so we need to + # copy it into some new memory + labelptr = backend._lib.OPENSSL_malloc(len(padding._label)) + backend.openssl_assert(labelptr != backend._ffi.NULL) + backend._ffi.memmove(labelptr, padding._label, len(padding._label)) + res = backend._lib.EVP_PKEY_CTX_set0_rsa_oaep_label( + pkey_ctx, labelptr, len(padding._label) + ) + backend.openssl_assert(res == 1) + + outlen = backend._ffi.new("size_t *", buf_size) + buf = backend._ffi.new("unsigned char[]", buf_size) + # Everything from this line onwards is written with the goal of being as + # constant-time as is practical given the constraints of Python and our + # API. See Bleichenbacher's '98 attack on RSA, and its many many variants. + # As such, you should not attempt to change this (particularly to "clean it + # up") without understanding why it was written this way (see + # Chesterton's Fence), and without measuring to verify you have not + # introduced observable time differences. + res = crypt(pkey_ctx, buf, outlen, data, len(data)) + resbuf = backend._ffi.buffer(buf)[: outlen[0]] + backend._lib.ERR_clear_error() + if res <= 0: + raise ValueError("Encryption/decryption failed.") + return resbuf + + +def _rsa_sig_determine_padding( + backend: "Backend", + key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], +) -> int: + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Expected provider of AsymmetricPadding.") + + pkey_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(pkey_size > 0) + + if isinstance(padding, PKCS1v15): + # Hash algorithm is ignored for PKCS1v15-padding, may be None. + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, PSS): + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF, + ) + + # PSS padding requires a hash algorithm + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + # Size of key in bytes - 2 is the maximum + # PSS signature length (salt length is checked later) + if pkey_size - algorithm.digest_size - 2 < 0: + raise ValueError( + "Digest too large for key size. Use a larger " + "key or different digest." + ) + + padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING + else: + raise UnsupportedAlgorithm( + "{} is not supported by this backend.".format(padding.name), + _Reasons.UNSUPPORTED_PADDING, + ) + + return padding_enum + + +# Hash algorithm can be absent (None) to initialize the context without setting +# any message digest algorithm. This is currently only valid for the PKCS1v15 +# padding type, where it means that the signature data is encoded/decoded +# as provided, without being wrapped in a DigestInfo structure. +def _rsa_sig_setup( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], + key: typing.Union["_RSAPublicKey", "_RSAPrivateKey"], + init_func: typing.Callable[[typing.Any], int], +): + padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm) + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init_func(pkey_ctx) + if res != 1: + errors = backend._consume_errors() + raise ValueError("Unable to sign/verify with this key", errors) + + if algorithm is not None: + evp_md = backend._evp_md_non_null_from_algorithm(algorithm) + res = backend._lib.EVP_PKEY_CTX_set_signature_md(pkey_ctx, evp_md) + if res <= 0: + backend._consume_errors() + raise UnsupportedAlgorithm( + "{} is not supported by this backend for RSA signing.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) + if res <= 0: + backend._consume_errors() + raise UnsupportedAlgorithm( + "{} is not supported for the RSA signature operation.".format( + padding.name + ), + _Reasons.UNSUPPORTED_PADDING, + ) + if isinstance(padding, PSS): + assert isinstance(algorithm, hashes.HashAlgorithm) + res = backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen( + pkey_ctx, + _get_rsa_pss_salt_length(backend, padding, key, algorithm), + ) + backend.openssl_assert(res > 0) + + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + + return pkey_ctx + + +def _rsa_sig_sign( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: hashes.HashAlgorithm, + private_key: "_RSAPrivateKey", + data: bytes, +) -> bytes: + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + private_key, + backend._lib.EVP_PKEY_sign_init, + ) + buflen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_sign( + pkey_ctx, backend._ffi.NULL, buflen, data, len(data) + ) + backend.openssl_assert(res == 1) + buf = backend._ffi.new("unsigned char[]", buflen[0]) + res = backend._lib.EVP_PKEY_sign(pkey_ctx, buf, buflen, data, len(data)) + if res != 1: + errors = backend._consume_errors_with_text() + raise ValueError( + "Digest or salt length too long for key size. Use a larger key " + "or shorter salt length if you are specifying a PSS salt", + errors, + ) + + return backend._ffi.buffer(buf)[:] + + +def _rsa_sig_verify( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: hashes.HashAlgorithm, + public_key: "_RSAPublicKey", + signature: bytes, + data: bytes, +) -> None: + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + public_key, + backend._lib.EVP_PKEY_verify_init, + ) + res = backend._lib.EVP_PKEY_verify( + pkey_ctx, signature, len(signature), data, len(data) + ) + # The previous call can return negative numbers in the event of an + # error. This is not a signature failure but we need to fail if it + # occurs. + backend.openssl_assert(res >= 0) + if res == 0: + backend._consume_errors() + raise InvalidSignature + + +def _rsa_sig_recover( + backend: "Backend", + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], + public_key: "_RSAPublicKey", + signature: bytes, +) -> bytes: + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + public_key, + backend._lib.EVP_PKEY_verify_recover_init, + ) + + # Attempt to keep the rest of the code in this function as constant/time + # as possible. See the comment in _enc_dec_rsa_pkey_ctx. Note that the + # buflen parameter is used even though its value may be undefined in the + # error case. Due to the tolerant nature of Python slicing this does not + # trigger any exceptions. + maxlen = backend._lib.EVP_PKEY_size(public_key._evp_pkey) + backend.openssl_assert(maxlen > 0) + buf = backend._ffi.new("unsigned char[]", maxlen) + buflen = backend._ffi.new("size_t *", maxlen) + res = backend._lib.EVP_PKEY_verify_recover( + pkey_ctx, buf, buflen, signature, len(signature) + ) + resbuf = backend._ffi.buffer(buf)[: buflen[0]] + backend._lib.ERR_clear_error() + # Assume that all parameter errors are handled during the setup phase and + # any error here is due to invalid signature. + if res != 1: + raise InvalidSignature + return resbuf + + +class _RSAPrivateKey(RSAPrivateKey): + _evp_pkey: object + _rsa_cdata: object + _key_size: int + + def __init__( + self, backend: "Backend", rsa_cdata, evp_pkey, _skip_check_key: bool + ): + res: int + # RSA_check_key is slower in OpenSSL 3.0.0 due to improved + # primality checking. In normal use this is unlikely to be a problem + # since users don't load new keys constantly, but for TESTING we've + # added an init arg that allows skipping the checks. You should not + # use this in production code unless you understand the consequences. + if not _skip_check_key: + res = backend._lib.RSA_check_key(rsa_cdata) + if res != 1: + errors = backend._consume_errors_with_text() + raise ValueError("Invalid private key", errors) + # 2 is prime and passes an RSA key check, so we also check + # if p and q are odd just to be safe. + p = backend._ffi.new("BIGNUM **") + q = backend._ffi.new("BIGNUM **") + backend._lib.RSA_get0_factors(rsa_cdata, p, q) + backend.openssl_assert(p[0] != backend._ffi.NULL) + backend.openssl_assert(q[0] != backend._ffi.NULL) + p_odd = backend._lib.BN_is_odd(p[0]) + q_odd = backend._lib.BN_is_odd(q[0]) + if p_odd != 1 or q_odd != 1: + errors = backend._consume_errors_with_text() + raise ValueError("Invalid private key", errors) + + # Blinding is on by default in many versions of OpenSSL, but let's + # just be conservative here. + res = backend._lib.RSA_blinding_on(rsa_cdata, backend._ffi.NULL) + backend.openssl_assert(res == 1) + + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + @property + def key_size(self) -> int: + return self._key_size + + def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes: + key_size_bytes = (self.key_size + 7) // 8 + if key_size_bytes != len(ciphertext): + raise ValueError("Ciphertext length must be equal to key size.") + + return _enc_dec_rsa(self._backend, self, ciphertext, padding) + + def public_key(self) -> RSAPublicKey: + ctx = self._backend._lib.RSAPublicKey_dup(self._rsa_cdata) + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free) + evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx) + return _RSAPublicKey(self._backend, ctx, evp_pkey) + + def private_numbers(self) -> RSAPrivateNumbers: + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + d = self._backend._ffi.new("BIGNUM **") + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + dmp1 = self._backend._ffi.new("BIGNUM **") + dmq1 = self._backend._ffi.new("BIGNUM **") + iqmp = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key(self._rsa_cdata, n, e, d) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(d[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_factors(self._rsa_cdata, p, q) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_crt_params( + self._rsa_cdata, dmp1, dmq1, iqmp + ) + self._backend.openssl_assert(dmp1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(dmq1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(iqmp[0] != self._backend._ffi.NULL) + return RSAPrivateNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + d=self._backend._bn_to_int(d[0]), + dmp1=self._backend._bn_to_int(dmp1[0]), + dmq1=self._backend._bn_to_int(dmq1[0]), + iqmp=self._backend._bn_to_int(iqmp[0]), + public_numbers=RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ), + ) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._rsa_cdata, + ) + + def sign( + self, + data: bytes, + padding: AsymmetricPadding, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> bytes: + data, algorithm = _calculate_digest_and_algorithm(data, algorithm) + return _rsa_sig_sign(self._backend, padding, algorithm, self, data) + + +class _RSAPublicKey(RSAPublicKey): + _evp_pkey: object + _rsa_cdata: object + _key_size: int + + def __init__(self, backend: "Backend", rsa_cdata, evp_pkey): + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + @property + def key_size(self) -> int: + return self._key_size + + def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: + return _enc_dec_rsa(self._backend, self, plaintext, padding) + + def public_numbers(self) -> RSAPublicNumbers: + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, n, e, self._backend._ffi.NULL + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + return RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ) + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, self._rsa_cdata + ) + + def verify( + self, + signature: bytes, + data: bytes, + padding: AsymmetricPadding, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ) -> None: + data, algorithm = _calculate_digest_and_algorithm(data, algorithm) + _rsa_sig_verify( + self._backend, padding, algorithm, self, signature, data + ) + + def recover_data_from_signature( + self, + signature: bytes, + padding: AsymmetricPadding, + algorithm: typing.Optional[hashes.HashAlgorithm], + ) -> bytes: + if isinstance(algorithm, asym_utils.Prehashed): + raise TypeError( + "Prehashed is only supported in the sign and verify methods. " + "It cannot be used with recover_data_from_signature." + ) + return _rsa_sig_recover( + self._backend, padding, algorithm, self, signature + ) diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/utils.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/utils.py new file mode 100644 index 0000000..3a70a58 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/utils.py @@ -0,0 +1,52 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.utils import Prehashed + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +def _evp_pkey_derive(backend: "Backend", evp_pkey, peer_public_key) -> bytes: + ctx = backend._lib.EVP_PKEY_CTX_new(evp_pkey, backend._ffi.NULL) + backend.openssl_assert(ctx != backend._ffi.NULL) + ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free) + res = backend._lib.EVP_PKEY_derive_init(ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_derive_set_peer(ctx, peer_public_key._evp_pkey) + backend.openssl_assert(res == 1) + keylen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_derive(ctx, backend._ffi.NULL, keylen) + backend.openssl_assert(res == 1) + backend.openssl_assert(keylen[0] > 0) + buf = backend._ffi.new("unsigned char[]", keylen[0]) + res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen) + if res != 1: + errors_with_text = backend._consume_errors_with_text() + raise ValueError("Error computing shared key.", errors_with_text) + + return backend._ffi.buffer(buf, keylen[0])[:] + + +def _calculate_digest_and_algorithm( + data: bytes, + algorithm: typing.Union[Prehashed, hashes.HashAlgorithm], +) -> typing.Tuple[bytes, hashes.HashAlgorithm]: + if not isinstance(algorithm, Prehashed): + hash_ctx = hashes.Hash(algorithm) + hash_ctx.update(data) + data = hash_ctx.finalize() + else: + algorithm = algorithm._algorithm + + if len(data) != algorithm.digest_size: + raise ValueError( + "The provided data must be the same length as the hash " + "algorithm's digest size." + ) + + return (data, algorithm) diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x25519.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x25519.py new file mode 100644 index 0000000..f68501a --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x25519.py @@ -0,0 +1,132 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PrivateKey, + X25519PublicKey, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + + +_X25519_KEY_SIZE = 32 + + +class _X25519PublicKey(X25519PublicKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self) -> bytes: + ucharpp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.EVP_PKEY_get1_tls_encodedpoint( + self._evp_pkey, ucharpp + ) + self._backend.openssl_assert(res == 32) + self._backend.openssl_assert(ucharpp[0] != self._backend._ffi.NULL) + data = self._backend._ffi.gc( + ucharpp[0], self._backend._lib.OPENSSL_free + ) + return self._backend._ffi.buffer(data, res)[:] + + +class _X25519PrivateKey(X25519PrivateKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self) -> X25519PublicKey: + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_PUBKEY_bio(bio, self._evp_pkey) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._lib.d2i_PUBKEY_bio( + bio, self._backend._ffi.NULL + ) + self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) + evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + return _X25519PublicKey(self._backend, evp_pkey) + + def exchange(self, peer_public_key: X25519PublicKey) -> bytes: + if not isinstance(peer_public_key, X25519PublicKey): + raise TypeError("peer_public_key must be X25519PublicKey.") + + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self) -> bytes: + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_private_key + # The trick we use here is serializing to a PKCS8 key and just + # using the last 32 bytes, which is the key itself. + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_PKCS8PrivateKey_bio( + bio, + self._evp_pkey, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + 0, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res == 1) + pkcs8 = self._backend._read_mem_bio(bio) + self._backend.openssl_assert(len(pkcs8) == 48) + return pkcs8[-_X25519_KEY_SIZE:] diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x448.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x448.py new file mode 100644 index 0000000..f45db56 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x448.py @@ -0,0 +1,117 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.x448 import ( + X448PrivateKey, + X448PublicKey, +) + +if typing.TYPE_CHECKING: + from cryptography.hazmat.backends.openssl.backend import Backend + +_X448_KEY_SIZE = 56 + + +class _X448PublicKey(X448PublicKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PublicFormat, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] + + +class _X448PrivateKey(X448PrivateKey): + def __init__(self, backend: "Backend", evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self) -> X448PublicKey: + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.x448_load_public_bytes(public_bytes) + + def exchange(self, peer_public_key: X448PublicKey) -> bytes: + if not isinstance(peer_public_key, X448PublicKey): + raise TypeError("peer_public_key must be X448PublicKey.") + + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) + + def private_bytes( + self, + encoding: serialization.Encoding, + format: serialization.PrivateFormat, + encryption_algorithm: serialization.KeySerializationEncryption, + ) -> bytes: + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self) -> bytes: + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x509.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x509.py new file mode 100644 index 0000000..aa4ed10 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/x509.py @@ -0,0 +1,45 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +import warnings + +from cryptography import utils, x509 + + +# This exists for pyOpenSSL compatibility and SHOULD NOT BE USED +# WE WILL REMOVE THIS VERY SOON. +def _Certificate(backend, x509) -> x509.Certificate: # noqa: N802 + warnings.warn( + "This version of cryptography contains a temporary pyOpenSSL " + "fallback path. Upgrade pyOpenSSL now.", + utils.DeprecatedIn35, + ) + return backend._ossl2cert(x509) + + +# This exists for pyOpenSSL compatibility and SHOULD NOT BE USED +# WE WILL REMOVE THIS VERY SOON. +def _CertificateSigningRequest( # noqa: N802 + backend, x509_req +) -> x509.CertificateSigningRequest: + warnings.warn( + "This version of cryptography contains a temporary pyOpenSSL " + "fallback path. Upgrade pyOpenSSL now.", + utils.DeprecatedIn35, + ) + return backend._ossl2csr(x509_req) + + +# This exists for pyOpenSSL compatibility and SHOULD NOT BE USED +# WE WILL REMOVE THIS VERY SOON. +def _CertificateRevocationList( # noqa: N802 + backend, x509_crl +) -> x509.CertificateRevocationList: + warnings.warn( + "This version of cryptography contains a temporary pyOpenSSL " + "fallback path. Upgrade pyOpenSSL now.", + utils.DeprecatedIn35, + ) + return backend._ossl2crl(x509_crl) diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py b/myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py new file mode 100644 index 0000000..b509336 --- /dev/null +++ b/myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/__init__.py @@ -0,0 +1,3 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. diff --git a/myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_openssl.abi3.so b/myenv/lib/python3.9/site-packages/cryptography/hazmat/bindings/_openssl.abi3.so new file mode 100755 index 0000000000000000000000000000000000000000..dcb10a059ea276aa82ca2ee95d773080c25b447d GIT binary patch literal 6023128 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 z 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ℜ&&pKAZgaWr`BWa9bU-ZN{on0*+Wo(k|P~AQe zUoZ1+t-f!E+y%GPJ?!`QBt^jXmvLb2;fv}XPF-h3fr2T_R(87O*-0)?SC{UEg#j}% zy^Ij(9G6MTFo(p8;z-a1pKEHWzKdkYR)7xFrI<3{htxNg^U%NZxIk%uR`_8RF_H)R z+G=IBIyt}5G-6>>>3Yl3&xBnfZyDcMV?aW)eUr1etuxo7k%;FJ)mzhky=-xmgR~lo zFb8S)5DzA8wv|ijwJ3z#54s1j_;zK`Zu;YHTX)%+RZ2{b`1ZDpv|DCK($uxv5V3gC z1Ai9m&3e~V zHTr%5`nCK!jGqP;3 z0ydN$F|zc6IB}6IViW$TN-LWeeSJ0RS6(?pgLp9E@V+%hzd<4BK@Ma&qZ=#Snf*v9 zV>17cZ158#u^)rdCgUr#vfXkE_a@%B-;}gSpgwC>OvLMrKdJatkfP zPEWqzwe{9Ai#}*Ucr2!+SkQ=IgOMc+0oGs>ejmu4xA)8qu$|rQg4{8DxAr2;39`=A zsJhLBrR(`Mnje&Ppo&HKuagW~1=pbaeD}1dM>8ZxT*FZ$vQa22?k0Io(z2;@!56gJs|bfZ_6i9AS{aeXi$^1Z}cA`{IoesB_sRI^-FPrfDT@pKhZ=u`-gUW zZHidFE0I_0^npUq#bVTXxeH7)`uvY9+VR@q&77vz!vcSR&wZ1I?%D7Oc#n7{d57}$qV$iv^~;M4&W7@nz-aZPh$ zT0yJd{5puk01@uF))4#w>Dxc*2u>A(pQu1E>dW^nA+bvn1C}6rB#?|zfZpY0A*p@7 zAck{9&9v5y-q4kJ9KGRXC@6$f2?YC^5hFza(1`7%iR_U4LR){3N zad+hb9UrgavfT+-kc_J|mxg#D9GC@WLy&U=lFf`z@Jv>NF!{G~gbGz#4A8eT7uUSg z3ve(xnY(8rAuLP%T@j{-m-Uf>`!^+5p<8j%ztFU`f2}I4-c3thiICAkS={~%Ea5ni zUYsXbX>z;=m;Rh#$TdzniFai54E>egcLvb-U&7By|nK4eB(;tS@ z;RhC&+DB?q`3IvjMl#0ijW}NC?xmuE2wMqS_ikPY-N6b$l9>?1gf=>KZJ2_39CJC( z0**atf;Vl1v}A3MaF25F=8SdeF-Q2KVmvD({OWDtZP%}1ugv1qLD{Hsd#2;# zX7>BPRs6vDW}%HEMw-sTE)gQomV4Yjt^~Vr|kB(H=LW#PC=I9F#i+5RPKmB(# zw$6Twbmi|FZHfJf#}?+V4c{dJAQ1Q1r_AdlP1{k=b*O}P0joQ7s%fuGgZ$j2v>Q@( zA((q}7gPwL4+A|8nTd*bq76hWs5f;YnI}!)=+^ze5T73YF6)EL=hP7@zyvR0Ie4^X zE4b7u_$S3u!Ha(D6A2-oTMpumzzHvzj22nigbo$g?-GOAFPH^F7dCL0kM|@OnbJa=p zOT@&SN(QS<^-Fa(nPQ^-WukTiiLJCn-S>Ea0Z?WK+~>;EXdjz)qSuKas}5aLwj9g9 zV7(-ppPC>$)y2wzy^>i%4|dC^JL@hZ2a+vycFe1sxW>>^%dfheN1>f|`;FcfH1ss` zlUuY4Pmn@~p0sBH3A)2yhNT008x7rQ7w~Lpsid%|k>EG}wy;GKSfYWGI*Se@tp!8( z8JYw5Mcqqqzie8okYAFmr$ReBZW$soxVpgnpE zQHd84(#sd6_wouo^8MoXxm;kRbY?BsQB!+e+?$tSQ)YzxNPAh>njggr8EO9fXbZch zHNT6!T-lnhv6q(C{CHlP8lDC<*G_@3fnw~uC*z8LfPK~U!eXVx0kiT>FBAo9M!{hh zRajxM%C0Xg6E5|I6+*XQ08+QZ@;V%9Ae{9o7U8Q(8<8K7C|Wa`e+~y2E&Re5d)-2n zpznL5oq7&^lvL;wy}p6-Vgqy+fULgi_={W&Kxo~UR-81q)$H{1hYe>Z83~&jT6WLn zuK^0Jxr846ec{3%AS}~zD|y00k=`(XdLP!5m!Nm+DjY)hOhe0utGQBYG>qM)D>f(5 zb9lxSaJ(E4l@D};)njS686ufX@XKy9BPBuD~_9Ast!uz;RQc3I$wemYjL$yDjZK!R?So+J>GLKv$iZ?Y}vs1455Put!YnHA@*v`4;{rv4+ zxn>DL!gh3brM!)DI~Z^8$Tb5{vEy=iAF{1~9i0|`P(|?tO7=!yG@g9k-st9qx+Sd- zg`G$X4VGvIZw+`H$xBhB8MmW$Xqmv~jDX4QT=T_bhs*ROHEYp%!NnzB+)@rXC?REs;bMurmDI z+#=2Qyu!Rxl|;Id-W);A{teU8;ULwtLWH54%pid^b#c;z-%7aQ2JQnBuec2RCuEHb z33nM)IG}M}MViM*W7}Gr8b%{!E-pj8w;8C&o2oFgBF9zacoQNzu_Q$@1Q?@v&C44P z5(6B>q_2!4oBD^Y>qh`cMgU{ZFmkl^I#@9lr@c_{Jcb;t42$PC$LVk6jMGo0Ksa4LH2*eaip{^`tb`sn zvM^dk$2~^nm0`izBZiZqf{Yiuc2FGozE+X#J|?=xex3OPRTlpW_6E%aOFcza0Ou?N zZ+&ZSQORYSq^-Ak-P-!IuVoSXVglLW8DlGtUE%xmrxmFBl}?}p8e^NcZj5Q(7;}I^W9X-{F(!U9 zX^eMN;5!#QsG>5^7;3$WYQEZ^G)C{U*=l}}Y_TyWt1SK%@_M5&1ZzNJ7+SKh%q=QW zY>b9itufZH*j?t1r>Jt2GD>QVp_imF1ZrSooP1%@7$2{|@`40bwlOYgq%nq9^iYwx zqA^rRShT%0hTg3)9_JZHkq3D-!PI=Gy$z5AH=mgh`{%#O)=eh~tZq>f$V|tp)Q)am zT@siEH5XAZrEW>OfFcE{gCr#hK1Sow@f#VSobZpsvP3$0Wny4`SGM%CDSeO_Fm#4` zG_5#V70)%dt3(ZU($-B2-;0RY$3J@>#9UUvQ944jU$G7waOF^H&Bwnd4n;x zsJO@tUw_58VL3!9bHi$KL~c-0;|9HyZWK`0z@9o69QLiip-8s!q-c<&-gaKnKHK0x zvRvBdlG3Pes^`)F=o7Mcm>w9d$Ctq}_!mnu7>?4Y$eGM%O84PAn%NxmfPkhsg{wbf zjir%2ETXq19se`i+Pm@H&K$0A1y!ctkz5TEjVKFNYvwrEzBY0CAb*JLgRvP^c~)w3 zH=CGBh5rVZLHVS#Y;AFS5w^Motj$o6pT*_FrGhw*1(iK@&oMru%=#5?#MrQFWYl8y zZQnBkN%XeluBV<^GmQ$3fX#iXU9ld)7phXh3bFYtMq75ByTmrSl_x# zq-k9&wr(woGiUh3V0vqD24Ced0r5GJ0R8LCe~>3=OQzPuS4v4{VYX|cSbdqHY>HjU zI$yE6r5x1MFmCr;^A`l9Xd`Bna2#tCGBf5nHigBr_=2%(`Dt&oS)tPSrcmTwm46za80rpSa_mx@qLy4#>55?k18BObprb$LtYu6YV z_FD^&S?*8k^WRtUi8-f$z(BHyR<7HR7kY&i7EtiJu5LofCXL1`OXD-Z+h{{?1YT4u zvnp%4b`>D^H7gna>=uWJPOG(3lFG2Uh9m}a(H@mR*pOJ$uB~w4J4q71DO&3V-uH^8 z!ho0>06yBYgXB~7$mP{dW9t=+U6Ka+<9AK>zj0e8%qvNxe2x50)#FX_-Q)Sbs(j~@ zlzdISwN3rCZ<1$`=b5ZLhmxmhg&3Efvsvs;^&DF&hv|owBYbWnl=pgC)yt1aOeV@A z0_x60hj7wMF6H7iV6E0KU=(!}969X*HklS9yCR(4TWg?PaiAr%4OOv>Q2Phk$~hx6 za}cIrK;8I4AD(dcH0#4!_GXr8*H{$HGQ+W3b@<~S4hKCqr7E{=y1Oa0uhpjZYPXEd zz@S~;sOJwou0CFuP-*)TEhNJkP|PopWr?G4evAR z7QVwVt|gp!L3!Ql42RyUwXDMIwc%SSc^bOfZTy9sUt+ugg|0AJQ)#!`bcJ)Usxks} z7%py}?aSq#hI(ciCqp+-8UMJO?GIyZf2_KTuL#ywnjfdf^-KJXp;JQA-`wdWb+OpX zeqqF74?nGopXM3b&le`0Va;m&=DU=jX@!1ZNV_LzNy7 zDSkkmJM#|`C|ta-#OZ+VCs?6;@bAsezc;=}R;4WiE|-7rQx)a!3vl|n&@32T$YbUI zb2paa^PPk@txy2C{wyt?J~+~O>obJm9772#R&P@b*<8^V5)9HS{IBTy7Kzt3c!s|J$=|B)mz9t5dXBG$XN~Lh|DGARU8eiU$le2eT9|7y z1{T%}C53vYa=#wkLBod~2~RVe?ir3D1KZe8eduk8J->Dcc@r+t22py`*{djGfM^+U zo{5$oCb;dVQxwaT2VnUM3mbcj==_*@=3`y1-WPd~|?ZsaWf8+QYO*36^ z+cbiO0>p0UU@2lbOA&3YGjExWJ&L7>8|#bJb<~j*jc8D3YY^Zc9>(`n&o|M4NT&ML zdwH@;e11}_-Y0%r+L4uM@7eVrfow_AHk@Qdw2;;YQ98rH5>HJHZM=SzSB_B^=d1Z^ z?ysS|Fn-Cqt@OB?RTHzSQYTZ=c)=9sO6}Lw^@;2qFkuT!cr0^jm~hJ% ztT8$WIo?AylwwF>_9cXV*+ZXCLW`5mAS9g2F>!}Be{`4z_N=L>l7OGt0vD)=BR%U4 zNmdn1EHOuTOsirt`H1;~$9z4_GrtXlmltN<0?={cifV6;IFWJU*}40obup`5EdHGi zYJ3XH>NDCyw=ahZp|Kv?ACg)bjdt?TKP90oM|nth5>l?x2R-H=Dy^p<-hg~ahWl3={iynxpOXmGH(kSZWIyH zlz+&itR;db8694NY7z%mJy>I`w=jZTl}Q{Y5BFz+$X;dlH!o;dx+6`T%gc&Nhgnii z#MkxqRo7S+%NaJ?z-$#ZyN-+2Ewni4PuLd-DJCI>*^QAa<^qVAZB&A)&YXb#q{r-1j!D??BOWt6jX{XujUi#StC3@p6BW$n4o%W- z)bWB%{8#=pZ9Q!?wrf<8QoTQ$Mz#50F_@f1Z4dLWaYVyAL-%g9<@XI zwbsAZ>Bn{}n3N6MBh%Ex_aJ0+IDWO(v~>j07ORs*P21@4#l(K_D7qG_<6=45rZ33x z2QUir*M;iuhF#{PZt`V4#&O69fUv4?q(!l-1^cy&vNVY>{&F-m-vMLJMkK3 z+t6xf!S-G4(lq1(UVci@UEc3SYUt|<`*#{|bkWwIJOkWrB{J-~ac6fZL54TtI**LN z#$ugKG!LGzXVEIggsq;JFK*q3YGLkZ>k z|Ke`?h;OQC3s2pv4kOEJU0dl1gbBVdQYC7Rnb@Y6_ZO40eBMd-*G463&^D0it;yN5 z3Z0a7^j_A`QSD}rR^HSmq$^2A3u(P*22d61U#7Npt8LuB74IjP&X#d2#W?^?i&2Z& z${1;!(A=5RW~#FKbqcO%&=-znDT*q`{XPe&yvb)-bC3E8&5adE&E4`8f9PS zWsef1=@n%^>1D4JUnblAzH4Q}XTCM@WtcU*_Nytz{Q1Kr$Z&J+qkgdf|SzEM*pEjfCOb z!bFg0t-CA|>|hnL9gn7l%jk#ia_Y2&`yrdgp#AQyp)TyFIEk2W**A<%rwW@k$7UVv z6?Un><|)VK3W!H3ZQ)#lB{g#DpO@p0#J&p+E%HZl@Le@!V(#N8w}k_}^mdA1f3T9c zVWT6wS4mRFF{Cz~X-NJ0%OE9f3&uH8NL>i&$|UM`q=qL*$-)YtMvyu}NZEIxp;1WP zdM70&Eqo;dLnPL=0(;5UmJxoEd;?KpX@76S@7kw13kswQcj)5Ko#IdLd#^CP z3J>ux^ji^(sJZi`9~Gzm{T|TQ_CV0LAkhER9W`Yt?`P;6;cge4?>d|g#*H46)oheO z`yL%WZE$h!Bl73JBHZ8jy5auR$>9EL$NdO6G+Y4P%k+Jmq#!)Z5pD~?I-{G9i&GC1 zf`3tvTZ={CpSEQX{JsFYKs!(rP!laS5S{zJ9Hyu)w%faxl@cO5LjN6-?4&x+Q-v#T zsBsnCLQnJJ=Qw>HTSoDxc<~lQ@$Xmh1!~H?xWr}-eI#<`@9@ym}XUt@#^CD}G&ck1%RlVTI?KCjcqe zZYIKZRV$3ReP>sjBvv}}OUQ=w@$>Ee38`qFycs_`&DcqRa5Q@z%eQ1f8z>a@ebLq} z#V7d9wLii^ua^7|_1?TU8TQ4cp+z;lx?K{kiDa%luM9FxaHpGPxX7OAK{*{HE*NI+ zn5lS)(ueBYg_;<)2zK`gAWAo|sZy?{2Qz~S~0^uyqY<;j8O)0uQAzO1f*5i%U5)rqFmSlNKZ;%iu(E~ zw0W9-g3n+Jma^5_p;VVmFf~hI+F%F@zu_axW+?m$dD7yb@L7D9vCp=b697|&(JP^R zqkTE$FN*_~1ue4}HvP%x;hPexbYvEX_a=)5O912Tl#PBH6eM|-`Qc3K1x%URyk4S` zbztws&XKY0#GIv@vG{QF4X^A*I-k@~p+j|IeA7?l+@Hqr&0^MsP8+G5St|MLVFOXY zXWymAm-*~^FT+@L5TBK15$ou%Ay88#&@o;v8|LDsqL|c$5_8$uNYru;HTc!N8ZR(r#PvPuke6^$}$oJl?!?uZJ?@uaHWgn z#Fzp{s1_ExV725n)|92IWKCI3jvZ-$_c2jDi@zBx6IAnCHrc1=OC~ZgF?$Q+f@Xi^ z%h;p$8Ac~&_49ke={rgZep=s!`A>(1e8yb}S^K{xIuV{vqrwlC)+piV>}XRyZ|mtZ zhj~u3YBB5-CNoIxdps7AJGOv4qyD}#)m6A1Xd0)8I~DQo7h;6p%A=)~m~J!xegc|d zo^W;RMDKCrTc&&uD4*e##eX0@dKp9mATu!M_lA{-IL_ZD<>;`)T8(>tCqx8$@1r-}J1wxHuUJ4ky!}(}l%587LxWCu@Mc%(_r*rRlO_kQ<4atiP^AW>Z?AKg-r74jZUowhYcMsoC zQLXtatq|`%(s!YT1u;A=xluDND)es8W?k&&n=s;(E5~M`_{mFE30smxw#cWP&8Dly z`Yg7VDO$C{S@4R>lg1UooV53+)u6@WXxRMu48|P*2jfdJ82=Yl5R5Gdj9I9Yl@i2T46Y#Ix19?x#0;2gMp&=31Gc{m7Ff44Cxc6A32=oXvNC z+-$68qKK7oBTqbR!lD9@vbYp%01V45ssO+ZRuKR@@UsA(BR%Fhb9d2Oelbr6q3l@a z9+C+gwqN%8)d*@9Tsri^{ug;<&qa9Kc$NjsXElR}Yb}^NLGw@^ehPXI-VEVnrvn2T z;!AmIq9VR~8Un7Sf=nQ!+y(6|MHQ@iP}dBd(pP0eO>l>Q+?YDlc+GwmDWZkyEiakI zk9gbWhySG2*w3OLwwLe|Zq+75HnJ$lMDsMT2^W6RnE%+>Fya0-f{gt!9U$13?|wFm6YPz$lrv`NA8cd1qs%0%?Vc3c`8$GFzM&_ zDAjn%Ofx42qF<7O1P76Tihmz!lri`Y|qT5MGJ3(`>SZH zu$nQWHUBihYKC-+k0(=$vD1cUc<^Tk><8ckZjRu)%GcR5WxDdO<`8otb$LUg^MoH> zE;>IX%Bf3Ti)7mfcp!C0-7Bd(;C#9Ct>nH14pI(qi}?C-9b3lt#M-j6#NO~13&r&c zXJm)#(g8bsn{@7G(NZRr;-sfP$8ZGg@w`eFW5X{du}z)B5v0BBPFx$VPGZHRmRIN0 zhIMl0b~s>)DVQ^pgi#m>wmE1^)@K;y6Di{x!{mjnEDr~dAEQkwA`Qddm(>iRkJgAj zcG6UGgdS%{z0oznlU2tUkl)t>(iDq3>|S|^S9z{!`WP3^uWJ0`u-rY5==kQwcxjG< zMAMG23KPRTS}9#kK@JaSuQI-mNwZ~)dl&`D_2}~SqO9N7rufGtT=eN4kY%b9ug)=F z49#D+3RtU6{WPt1h*b3O1}eJdB-V7y#+0jHxl5;6A0*0Fh3dK*C!@XWX+Y$OadKFD z?ao!^@};X~B-LXGHZMh8rC-70CJY%JabeQ@Wy{1UTAcLoEJ~iClF#sx@ohw>$(uNB zbKu>ZE%7UFSz_Wy;aHXPX_a%qTB~8Nn@PQ(Pgz0H>5eR;+ST&2L{6?lyT zBef|$8QW7Ab@4p4^Ml>@73X_9T~+h8_(A&8Kwd~Zu6fIxT5g#M!t2Yz>uFZTohKT4 zlBQYbO|yAsc;bg|gBcifelgd4JZ(uGR? zO(nnccZOj{)V{1`4mP;frX4m5vo_^5x>PCH^|l>Bo^i`87p08kZRrq$V9mLUiu#_4 zdgb?Nb8e-;1_l1f13N(KUo#0jSAoAIFiOZFcdYt(`Q(1#A^f9sS^3i5=yZtJ@Ws2P z&=B$r(^J-MkTysqE#97gv1bUWaY)5({Zod80GO}uzdOR_mg^V zHht!P^Jgv}D)scZKOmuB7N4g73I6>59sc5>FiQHL*VpV^X8+QJTDPr)Q9bJFW&4*R z9#F);pEVhPk#5o!3Vcw3&nwW3TgeuElh?(mtC0w#++O@!9Q!FmOE`FKHR@TE=e6m0 ztv>#aKUCAlt;54W7y<8DZ2@sylp!_T^;uJNzYXB_8V7qm?_tX9ta5z|F{rlpe6GCb zzM(1?^EvL*gx|gt~n};-p#~--a9hrX(kvaP07Ze+4RS#>7_!nLO(*ktLUGD z^}RBEld%pun*;dpuG=I~rK#9Kh_OP}7`@vdhr!A4C}%1sBcfE*wkGq{r&YaU`#X5-J|%=km#W!qL2&C<#I z5S9=}9!ZyA6D-5>Frb(Awjxqc=LyuLHvu)lJejp;w%wxZ>DW-osyK5*|07=$Gq5M*Cs7-+8JtNJU3Ef?idcDoA4-($0cpQ(eqV zf^>~Rn%RfJxW59zgvGX{dz2s?2ZTZcqD&_^aL`ql*+Kf{;R)Ez+}+AE|9&dw*24|q z+v_OiYmQ0}?_m z^Rmi%q8|<%U(@gOJmSPupV55NHzS$yqiM4FBG51q&bUq8h+)PA(?JUQ{b5$4iK@}g zLa8`*ifS|$f)1+D^P*;Ao7h(!#Mo1Xn3Yt6HGkIao}bQ$AW0l1|H^ba)?8~@Y%y~5 z*#M+#u5`|DtAYY&_O!YS_m3*mCmpXVfzrOaGT~>D_wX1kP{wN>G4R15;1xIJs&Zx$ zH7Nf*)N1z`LD|!x94{#O3MjF?sszPMOin;sxk(A=HO<&7C`ogg4+!i~6yI7AI2;Wl zZ#6+`799vA8$+eN%;qos9Hx3g5Shk69;v{!Bl!;YK6f+(!q|tn`ob50OZW0dG`8H? zt9kk-spf%R%{=enM-Z`0tTTv#SnpI>Jp7+8w6ci|Zb5YIq!LvGKjzpFj|vOj|iUh*vRwz8O9eap7eIUj;pC zlJRvA{jOB{Lo|S8={G0o&$cGSC_26feVk@}$$Hyz*iNRs8bH{fyU;3PuC$xuxUn3` zrJ*=cCvL*>5>1kvL$aZrE^D2aVK{7=yU;G^)86#rc1qi}25@~ts$Loiys%z?t?8bcI zdMyh@=({MYvx>Q8Rp}r{eYt|7lhK~~xwT{JhvCLixQz>Eu%2F7ha8y-vmdtv_2VWy z84B^wi?xM?q)#GeB zshujII6o9-KOLUGWFS80S-Qu!&~jIIir6kfY?p$e5?K8+rzv%T0AR{;Zsce>dl$Gz z3nGq}n$49v(?rJeS(19H_HEZvNO-=W6D2+;)398+&epS&=#@k(akzjLRX-ynHnp|5 zTVj`Fxd#iN#9mSEzY@$6zNzhu>P)##(-^w}4P@L5EaWu`7c@MWeWTq0#;Tjn8 zW-EE^AX5PgBx*m^GK{^P_i+BStZo!l!2cdxo_Qam#Oyn1muL=J^Dx@)9)l_Pqbm5T zikG_AGPQkFns$Y68SMkaHUsy zO|#?fy;i=W&YnomdtdTdsGS&@f~Yn1(!6nDJc~Bvch%9GU^mNDTbZf$ZDewdf3J^0 zj!RX~L(~r1vQwP2lLCLBzA;5It_=f%{{8CuSu|%;{=^;J%Q|)E7K;oPv|1@h3cV1d!6H;-1`Egx z4%I3~QjXVYXw3Ft?H_7?hR zb}kHSI;x}TD4(r!Ho4ZzF}@R@v?Sw}Z0{+EBVs|bB#@zfUX zksN!+Cs40%0440q@D*JiC|yi!-T$re*8OKwZqangF^;^R=g_u)h3@~KPnWvC27-QT z09S6*f-hIqHSmr`^r#7Hf7H7n3Y-k9qWmT&@x0`RmF!a;{`T5m8$UNTn8WjX85K>@ zP7i&!9ur_A^}U^v*T+JM+1GsC8lJ;F`(-J4gqjTUJ`N?RH9i*YSUg4`^JDL%%ECsT z!;JgQSTa7_7CF zulqF7MYu<6qFsUt+^8^ zsKKonFn6;&_QN(ju407d?)Z%KnhWu{foJ-$m8o}fn)?3>JAD?Y2t0-n1mU+)2; z7FQg>VwvWy#TrIc*r(o5Qn50<`o!1QqF1j0C+gMgz2S~LO6chxqE|ovgz428lv(tk z>g4NGKJ1CUl@d--ujYTMq*s@zu+1*PZHwsNQLpmT4AGPamdebER5m{SY6AsRQQeDX z37tb5q-omH-}$-GI;4LsO2;rWE6*`Qp zvpWd!We3c6{Nv*$uh&0{ygsiQ`MQ7e99ocLNnRVV?iSy%`jZ*oF&dLyj2)O>tELOI z$G_>dVbOgxYP>+dsRb&}Ed?@qVe3=3@?iOs!e_cS{tY$$MQ^-SjaQX5E(X!~g*0Bg z7`+Wgd;~PCB|1r4cQ@bhO6s5K+s;3V5Qi+ALk3gH%{47B^Q9m z{IK1=RPzZfd9ARos@&;S3SstH$VS;U*ce{hjawaCUJsYd+zK;)z32$9a;ml_95ut` z3!J}6-J-I(;WaoCKJqaW&&}n1D_hu-!^VL7&o2YlvO**N?vHS4#DG5z__ZD%rMgboc_pvj>AUxnla7+r zVSQ?%$RUXy#xJ)MhV-uOejO(?tS0YCNp(K~@e@w9j-uU1>dKY~lUdgH+pDPxB~S^* zI>KOTJhSMihx*wGEDB&ZdW)9h4^KOQOoJ^#(E+?m4x@9+0eMIowPcpVlkRjSfuHg{ zfbT+-1y1^!7rwq#4Xd$jJ3p_(hsW1IfqsJMsg6^tFY!Gn`PDhjhsbX|wWXO3+X5Y% zjy4Vws*~0`MUc?zD;{Ye^2Q6x9#j{1;FS%8I*neIarj|P#XCqH#t{+##WB1N+iPKm-v#xG`Z zC|BOqf-%--WGJgyspx+$XzK9x1_pZ}*n)10^97pi$5Ix;AqAM>U9j|xjWe&w1~ahO z_<{yxN;=7X4;i+UsN z;h&xzlW~p~r*pO9rlTm@sLSz(4yi4~@*7C}|> zXFde1F3Mdm&)ui=ooQ}VUuf(S9G_7>?OtfK-<>Vd$Fs#MIA+^M-u#y{!&^jh|lrQg$dXG{`rk-rbsw;5gJ zb`-y4030MH{rwygI2bo@fGuL zS$rgrwsGiXjWvRFe1h513)kS?(Xp3zMR!K)d%kXf=P(kTD(TL-d_i}9yq5*S*ugdN zgfA^ton9S&`@Ps-C40S?#tZxj{ds(DWldhTR|6&P!j&G_#1ETDSe9VNP@`n>#>Y{uI;N0Rw!t`BW=Z|k%NvJFP^H@%l?IN%WvPCC z#Lv$vpPz2bswyYT@W6}?~)otTyQxTF{wlx9@imZbLJFH*HvT3VB^+6_$ zB)4dVlnnw(pDk|SZ|9iA=yGz_%D^y%2yO+Qo*g_2daaj+?-1aj9m_|e9j$_puUo}) z*a)o|q8&5#ps+ceTu<1_ux3#pefbQkau^=Ht!!wV9j_SuHr4L&)kNF2%@V6U=17r5 zN*d|u#CsWWo!kGMmMUK6>P7A?nOEeNK$>gmN2aFK8g-a`2jWM7h?WU6lx#(!WdEKa zC8MEoBrD~=V*XNo$MvfRwwr#vfKdsA-DUc9RpYzWul$I*Gygx-k06AcseMTZRML-e zlA+y6=}y`7V+wIc1^qbj!=@iM?u>ri?fUTw&*4v_E9l25J|60mB+B%o={p(yND`0n z@8JANvOUT4q0F{^%{*-`aEs-rDxR%J`#=^GnjibUA0+pzO#h0`YUgq*>ltGy8&46G zTG=qvxnb4LfgazSHo>ZKV3<|=59Fd&Y;D8N6<_98X_2&I8C}ov2ybn|xxLX!ue|D> zU3hro&9;BR_dR$t^Uj?)X(P{lS-2&QTxHc_BN(g~nmR|ka?K%BQwHi#E_<1>vgWSM zKCtA?;cYL~FcE&~@akDPm0DV%RHn#_YS_s-tE|NjXIsQFDD=#&ENX?KnFO=qZztAK zwke%=&i3aE2HWG9AdLqIF3)w*4jj8iwpMJ%a57MLe#Fi+;p@uo7ntXRmB#Z2hKc6| zsV;aBD3)&?W)y0`?8}lh%34l+SnGd%j>SM+1c(ZiH?LWj$_G}ie0dv0>zd zmaT{k`qF&6J*E9X0LQbL`7pocF4SmD&CFeS?Y|pYoW=`}G?W!6Y^d6F_O^fy_gUjH zqu<%Ql=oUl!7cWESJ{FW*V=ZCR>JAKSik@Lj`aI4sfB#qi9CnDa@1nUFMN+LL=9)| zD!*U{ppBx?!ZQS6NB_cB|jDUv-%A z@Yd+JFX75tqN&F5UGpLE{g&$F>oyj?KZM;Sw&wW)Tekq;q6Th2=H%(?hc&M-$Xit} z`NQy8TUB>X(?Xr{FPr?YKID2#!Fq}(mU?y6IdXnx(Rzy?wXWSaOow(}ZwdS)J|n_& zZ`XxEq=WkWm-Vj64F5odc7sL$mZ-r|H&w?3xor{)qjxf~)QikcC$oX)umJK)WNJ_j znY$yas6BuFAYz%#>u|&MsrI<}(HJ0We`?csDu(^xS8vJ-ukC!BhO|5h9>rgo(E^LB z!YEFyz|Ip=a6Za5&h!B;w4d>kxtfRBq@2^u_Ue*0s7Tz{VE@JVAX%b5)P;S_HOzg` zN39j}L3i#6;j)zB{M!>|ih~;c!`eL1tnFz+7C0PhO_X~e z?ci2KmY??frp^%;Tv_IU`iFWTmHJGDQW+2QEG&*5D4dn`dG3K?i;!Zv+Mo46M0acR zKuNyhUHTu5v0SGgJ3r%ekn_8qbYAi9r_ zG^7S#Qwl9SNlN z3N1R_QM{h#uvr<3(REz1V~XM#6j~^k7&gqHsH>Z>5dYnEyhP11*Kvp19^yI+;J&tsV0u$Fw$WYJT;{<0SkRJJwNdly(}zGhbL-kO<~ay2(MPFv)7cWLh4^bF14 zP>0+_fd(%k66>p4u)(a{!t~B+hS$`(oLUPn%`Mb%Lp^o?Mn{fJUrRjDxxcBi7Uknl zQ+0UmOP0hZyW66L95Ii)B*##|ag<2xL{$dq{MSa{sb9TM)|HiH0|G|QouX~B-@OR`g zg#YIu6y3Cttj;Belug%7Oy`$qik-pxU*~ymPg=&rc-Z!TI3_BdfS35UG5<~fE^*Xa zjzRzGZSekfaiudL=KtCia>9?Of87Os!ZFw4__niEZ_BmtI(uVUFD*75OrcC~;?+U1 zPN+H5vdR6Wh)0pgw*I+aiXA4A+xJ{gf9T?wluoMZRofV=_uCRye?yh>bw}|WW+8$S zt8e5Bsy>X~U#9A$Mw5JQTyObK{qWS$@QwN0;ZDq+glT zxu$Kjb^xg}I^!=veU9@L=^E-h5XMU;Q^>1dI0|HJDkd9`m*VR|>(9f54#TvespElg z?-Z*KhH3q9w8}6Ka}i7{??Fj_p#LbnZ+H&)eoC26l8>*RZSZO{@H8JaXez6%X_&0uJ0zai6eAk_S7ap~C z{vCj$f4BU*`K(I(J30D`I2}HbF3jvR>yLccD;EHtWKg^HH%v1Lrt{%8+TCeOQ{mnk zR2Zd^3jdDh@IPB+RXB!NBe!O>`#Q|GQPZ4_DZiW(KdY%`OYGUQH(!!7NIh=91 z#gEbKY&*3qMF7?ky+#zZ@-Wehbi5-;T>84+iIVw$r9CP;g zDqGlR_cp29krrWE;~O8}-W;E=fqjD7(XVMbeVmGE@?!=QtN##oUtq7oUcu(deZaqkH~734%8+;YtCY*`gPatHm1g(hl| zNyLS6%i(FJ%*=I12M?R8iehf!pu6Gt4V%O9Nh*GWIId~Z{T=;6IFFX(f}c45Y^m<;1k%Rvnflm^*R`$DvjbZF5w^G$A(iH+ zZ6@~cT4UG0H-lZLfGASm0i?rkVdD^~A0houHXIzN(wNe6WNb3L19xP++1$!thc&JG zfmk8jbPF}h7qFP?Yo|aOUo_Z!C`PY?*>>pfXkNwaeT*=et@3<)S?0nWM6_=&f9}2V z5659-*T+9xjZsd-6XU1UKb&;#ySHzTo@VgM`~#Qky=U~EO-#Q&^xk~<+UY(2oOe&} zv!@QFcgCu@rcHKd;ZytjN)cPD(bC&N8j&?d9nJS?i4j*8-h#4qQCv!=k&XVg`rpiw zA|mQvRBuVVa=Bf<;`aEXn_KtT=Y4b!i$3#p`|}*`<{bM{_kbt`bo{DjnV`i%Fw2}elW+ggotv-f-?v*vb8vxwwmi;Gu z^Rg{uC|ZHsnjn7*1`djsML| z9P^>iZ)zOvuZE)pPBJ*J@*GZs(Jc4#g>AKwxsG%jo~ zpYXngr1Z2x=al=nz7BIc7YkP#J}Dv zAD_B45&S#}{ve$*teE>wtr8af`^vhJxKi2SB_as01UBfBilZsO>(ZDQeT z?=wb!V`CWIp-P;8!gF{V0hAaW{rNYf=i=3M9KW7`|BAq~x+T1M1J#o)6eQ_TZC`0N z;^=)VF4D5E=}mm+Os#M}=j6EFmh>{K6Y*^C9FE;(%wYvoi4$5U8xHR@1{2Ao9ICaR zVwwDc#l^PJL65%C*XB1pIC>c|`u+oq2ue}r#HpW(e!FtqeTl;8in)-F-A+C%1?6qyCWzd7=mffg%iqv zXeuzaOjvi>vHYCT(*HC5)U-GA-|)os;v_l0rbMiR>rOvjsPJXLe*yN@p}Jl^1y#Zxm@^}3{Mn>t5)Wo%h| zK~kotW6IKsYnV#`#w=5n3W0{F17T}2Hql>joI>h7&9B~tCh;?V6j2PNFk$K4YP_KvZhbyvs1dj5?mu*1f z<5ezS_Y}|Jxe?jM|Hu~_KU$4%K;x)jZ|GRF#h^H8V+Zz40h{2!W(wGxGGH-IdY^#Z zA?rQxI=VJ^Wwx1tsb<87#7aNDA+ZTvvI&LnfsvUAewvx@%C0lp!GM5p{rln)=XT*{ zgI-H`H7Sybi@KRSNc|dBUfzUEV7z~<^GEd@UL{a3Bo zKONJp<~eMLkV>9EhFC2~sQBRsF#MPkGs;7y8gWd-wb#Iqc^LIsNvy;2?H9?d@|6_= z)0Sf4_|%ME>i8&vqD3r1&=?kVABlh0AVw7ZGXDpSaVJZ8;$J$c%WIxhm<*NoS1-A`J zF;f+Wc}SEbaje_S5X;-N@^GewGGv_Wuaw*JDr5?CIx*wQQ{pBntEQ9JsHT0T&N&r_ z2n8_|UlyJjnbqZHQx}!7D5sD8PuWOBll;`vXUylc-teii&(D`W*Ymk2Y*+Sqkv`i> z$cvkJ4EueT-`2B%ApC(#Xkd|#MuWZ2vR7{}`!A9FQWhxefjqY%@%33@`l4Fuke)B)f%;fh!`)!o! zG2xf5Tgh{n!NK{Z4j7f{ZD}B>vv8!rA?mpFYN}KSHe|d!KQiI-M>fq^rG*?cESA*E z4|I;`*(>o>q`S2&ecIfPDYNlZt&`l!PU^^;DO*0X5!Dp9xu}i*;4eN5QN=f8;_rVW;bd#rNgV93R=8%y z8jE?)<^ML0eM-P3E`T2=;GZo69!=IGu(9|fx9#)7W}7mEo4FsDx81M*a>0P%`!xso zr+)$RH3wNOkZ(hW3BmA1xrFaG1o9ApoNA!JQVhb<2}^tm`qnO8O5Su{(9o2>e>5M% zTi3Y4*&R20*UP5yR=>uktU~c^qwYAN@-IiFh3D|)GE_8R1eH~gT)Yp_n%b7yW83Nd zlhs~l(%w(X@TujyEJ`>#`97oUdp+OfnZjYo_fz=p!Ng1fp46FF{YjnIsuqbF zB)XW?@xgbBE+%yxHIl*;M~)81c4Xs>Rc{&bC%y^s!yyaNw(=Y#pOPGIcH&=yBgMsr zS5y9ku9SNCu7rtizluV^Kux7b&ujwQrp}hR_@LQMomcp-q`clv>MSShPABYIi8i5c zQpd+LWOW=rvUU>xsn3wpIV+N5rgCRPPFpqD1x&N^h~}xXY!XKGCzlczS${&k)d)(X z7_2GZLeV?*COm)3HV|XVA5QrPv)op`W9CRc(t|hJJ#iJmE`HmB>Ye^^#!_|o<0hPl zv)J}1A5u?D^QDuq0Hv#^wa`Da=?^?tV;s5lTkHSRO@CCW7%~RC|H_6qalc4@#E8cC zEdGBV99fU~w!`+d`VE=!S1JDg!v7)upKS2T;(zAbEV6bN>^TYz=rmaL(J=2A|`fYmGqoIvXA)(SNaS>vP6J-K39T=V&y>CSQ?Uge3Q(5k|tQocvbjoeMe@#4lQOS!18)d znbAo)C^7@q=fZ_w*~R_TJMV^JV4RK@eSe?xCw7&IKBv#fetCVSt5^%iTo7AGZa<0I z+bWU8^^&zIztz_wkTB=GAvMvn5;sco{T1eS)AOm)`CSu$Uq|@CR7{O%hXrczp697! z!Z+t{1}Ou7KZe z8T>w!;CIX*{Imn)7Sg!40Ptr3TzDwRhObVGize;LdYkw*kAAmP(v6myKA3G`$NeIh zwmF-kug5b^xf(FK;Lz{nLNVaT)@T<2rBuj$k=DKU{YTRH{EA2?> z+uzTFEn5f8-lDnyWfnxmT;MoNTR>j8mqcOPlHuV{QgYT^tRYv&#~@z#YMTLc*4;a> zf7LzenBnSgY@J!cm1N<|`aijMOD)gF6_WseeTSOMY^pYy+uc&IwQDUuV*j&r(&BJZ zuw*^Se3o0UlE0bE$NEdNF-YQgWLZgsVx2q)F)fV7o8YN$;-yn+RXJC)=&6YvTa8o@ zSzRH0Wk?MY?E>wGI0&UR7STam z&!s2SPU<|No@i5ejjmbrEMc@F%<3dRr%1D2G&cmD@0=Vy6we9ty`|yC!=y4xJ94jg z=3XawI^#HbvsNJx?T?=2GS`wa=;E_%wubnY5yPq;Oju9KpD^F>7v4C%i6iU7H(9PH{k+VAT?>l9h0(CJlpV>=SlS96 zSshC99S!MvhiuR?SZA8qvA?Mdw@v(~{@lmI10u0AH%5#u(*tyXbIcfn%m2yS!!^a_(Qykh}CPUpJTMaPvR~4cQg7S)N-Z zaK$Zgp6)K^7@*(()c}nYpoI?T5CQsP8K8c?U}T<0FB3qIU^yfZ{Cora?E+{Qh&BjD zr+(__vgFdBE=r+Sxp|2c=1~kKYOw7I4Q;FG^fpjF%+a}G73eG#CR{ zUqI(@&?)|jz92j>kwk$Vd5w7OBx5OUG6K$T{t=;@Tsv=gd+2fnpxB?oT(0^QH#pUr zSu|u8{l$1wEo6S<$m}j;4lYCHCP!uo3@aXEZJOPs=efobgw{^P7~xmyCw89DfF{c{ zjKRbdCRztP3KN6w)`nZD&P{;D^M-&yRp@eb;zC6W6@G@ctLDe4Y2^4||Ls*q!NIRW z!5^H0GkFf}u(`y}KRE?!AglO8T!78?$c!k0R_DPl8ZC@O+4$`V==_vRI0#@;zIpB> z?4&aNFn NcdZCPQh%+%XMI9D&2O!DR#`XoZ#r)_zLK~>gYYfb9foXm(Y9P26isd z$wF^69iir~+$AQYW~#Kd)S_ncTPUV5DDKUVFw7x03$jcjdUSyxca}l!)K+`{!^ z;i8^Mz;PlwS0BxrIiJvj=1R23P|XzAJKTJp=hMp?A>USB=x1kRBUWk<*hFup;n`&U zPZ*6jrGEdMsCz7;>9_S=+!ZyyEcD5P25d9VxGrt~Zx&dYexlZ7F- zZ({iN`>8UQN({~h&KDuA@5jIRDLPd(vrp6a6h5IQ_nPOxXBvxPyoC zRXxWPjX6IfqFdBJmqAmP@f==)X(i^wK5#s0U3?u+X08&JBptMLRuC_HZ0x1Taxjsq zmXb2(yF*D)H|IE{L8gkGYjY>q_$?K*8?3iMCEKwvqb842Xea6Fm)V>1t>qHKzJHJ~ z0YxpNoDz%&KmHRu80S2AfamZ$ycxoSFQ7HW0RqoKr~4SRw!&y2b{994_y$owQ_^sI zv2BSDJ>i)HOUC1M;D%*?Hgsx*4ns(ZrD!ghVfoPsQvRPXnQHx2*xkwd9qvTyp6@#giF@a6>P z%{DK?n|%=B5K-L~i8!L)`qzO%zq9&WEi4T`G5qs`W;ZJd2HSrEQG1#p2 z@nRi&_V=B67^8gY%AJF#{v?S0UF4a4zf-Tn zvKAvrDQ&n*y3*;H?oj8VD6;^|j`xZiL)P2J z*r2oXjs21C_PqDb={9K)iSH!%4>1BGkiIyL(NgB0z~H0g`A+(SvHXAfVY!?OEPssW z@MlC(VtEIM!16C52fI$BwPhwU!(^)`A!`qGw{%!12$rRanAj1ltIJ?%MHsNQ7A$Ql zbpkU&vPdA#3HQeyzWxA7!hX#i*Mq27~E=-ixLgO9%LDb6PKQX!T{Q*Q_~+NwK5h*gVz- z-OnNmy(=Zm{d_YY@6V;`#90Lrhz#&@4D_@X3N~j3`?GS(nX*ALE&XV4^n_HaD(XUH z$B{_?4({6+Rp2#Rz)M7f;^pS?wyoa>rw3D99Fmv!YK_$$58~_>FgVnS?`-#AlFyv| z9Gv}SIQw~;TU?v7&nb)}OQ{f>(H?7?LD13z_r7348u2_r+FV%X>yF?#9E9*nLW(|a z5t2(pJdDD=Mmp>A|B`gN)|ShXCcfZJ{FJ=+qAk3Mzbbp*|6;ZYR8k^6F4II8z;c%D zLYt>_Np&%j-SEN2B~a5q;5u(m$f{u!v}S00=6R!WCn2z{BXF(|IH?SQNaODzJfU$% zX>DioJX)IT9-zxTKv!$a94wPobYT0skjA`lipE4~)IZhRy!Bby+{xQ~ljra%%qa0S z+P>3ivv@PW{JL|GmMlZ@K?ifX!0hH=ekm~5mx1|)^KM6hQGYTcQ9Q`78#GwF6dfJJ z!wOEO4q7x!+`&K?14wD5F)JZ!!Xxij>KxXulppl|vOrZk24GKpJc@piBpDZDWeJEYiz)pBAR0*7+zKLnx%Vh*UV(rLt|ZrmDc>F z&sy^kPjux8Nk z=6T*)Pm3Ciy43naI!_;{X{QfStNY(IGyk4G?ZlJ2@V1tEEQpu`)%DAgPV0%N+Y{UQ zK}Y%YXF%Cj#OCW>tNa=`-VN)0Iwk$Tk#Um*?e2s+(H<`(7HtQD^6N#N{nYgnOhTt(01Z*;*-?8w?AXp zJ@GWyjdJV`5q6uEVHX$OU4pQZJ6##5*rK?2@A52~o35U*vo{a(;$XNkTPcOU$fn1A zJ0_Qo2Rx_KL%+B+aJXQGE?GHz7$TGD#e{3M7oxcp(U7$jv{^(Z8+n(9)c{0$(Txt^^C@()03k_794YJ4#E2HEk|IiKMBT~A)L2JL?8XqrS z0Uy7O4MNI?f=O5ke@jyC2L+^j0L(2a!~?<@&_Bx1&yBIkQ+`j3zd7O%yCM{2$Z1kx z)|k%5t?V2PJ=JzFcdU1|sboF}gLxWoe(@P#5Z~1z^!ca_>cfJ}eDi(b4}0p=gQc-) zIcrXV6AX^Eg1^>;mW6jVb5@7mZl(P&_EgIss7D6zb^^YNX=9dEZGZzBH3ML#T9cgs zU^S0vn#y>RgWSgFYU9*N?bF7qV}Ap$e&D?N5PS>s;9-eZR|5lHZAtgBd)7S`;H7-s zs8;@}DIZiVT44~Y1@T7?@ll?`!DSFnrw$O8Ad=z)l*cUB><)uiuhZf!)Fl`jpS!Q7 zT{JK_9Br+5Xvl;z8onDN;J&(7C);NpX52Qm=b!lnD8!! zIeZss49l!ZUn#2vs@kwX)M%GNm=gHCH%h2^`B@s%_s!B;q+TGW9~$gKuYDNcgNFqs zVsu=^iSO+#{lv=lTUi!D+rjxR_@E_B!hxYldId^xm;XY};7!`4!ALs)n0B?cmcZ$G zk;h^~QQm_F2Yg7;&m*Ugxo++5pZKkl4)HJBrDdUL35OkG8+<8-d+fLQ4x`>4GJjf{ z|NK9Xhdxhc&=}K+i(bokD1Il|g+22THxH`TZ&oCq!&vGJWrj@~ndlo(DEnER)r208 z=4P|%fjm)hFJQ#O{;lkWR@Rv~Tj`p(J#)4iGsUxD%j1#Rj6G&$#$dg^783(;$$uMy zJ@7BtkL<9d@z>V-E`5@|aGI=RbhKRy^gK3Xei$wXGq zn#m1zG=k5oorjVYxeeI^J!{4Au%XNmy+-cUPeAT;C--fh!|z~2iQMQikNOQ=e>d7p zx;`EBvVUPg0BS?nm~xsIUWv<9+D``C)|N}qY-{chPg-+(sJS+8F0ba!Dr+w0`(9Qe zVWIqZ*=Vnn@4KX`_-(bm+!h7Xk`U>I5hp_}kH(13E9{qTTV^J1&_MP6GgOrEYFQLw zvvZc8&n(Tj@&(8|akw7ZG#puCg>waq^Z)vhxy4qX%1<&EKvX(kv z9)4>RS}MMP@QM%cpNxI@y-Tql8kMDs0`<&n6zKi_;R<_ceaNiIgpL9;^(14ak&GEE z=V|j8P?u(22g`Qh^BFr}nmX=rrex*foO!L zs^W?gWur@!d15l5%s*UVFHK|DMvbfMJJR&0=LXYs>SIRJZI3|Htxi*oXj%oWLumRE zVzV1?hSIdB$T6DI|3syI$9%*9rPF)_{&F?K)nc-;^}uWW-L~rFS@dlWXlLdAOy%fN zdx>oRobjGIW}0uq2r^Ue*@GC81GDka*sbGvgS}!kBs<&oCBtYgXE$)fCbt!E3;mwo zz=Bs5_p;I~NafsN99$^gg$PRneh^cxlkfQ!R)}jW0Pg3{xF5a@ueeS_tkV*=20esN zk?J%OEDdq*BPOU34g`mp2OG58jqIYHE2x8iNho{F;Eg_=B%7{uq#{tHmird7>SmU)asv= zdvRjA4IBAbT9;)@xfgBP=SAX1qDkBH*4px78iCoBhM`=CCdufjJ&!dn`-AHQfuzPQ ztdYpGO?-gdwP})8hd4yzLFh3a?6VvmjF#KZ*FDK|xB$VFL>fKct1u?v!Eb40S?jG47B!kw8jao-yyORTG7lMl|f5)BDJ>Mjiy}+daQ%~u>wD~S_`F+^)6%6~dUYmGq@AyT6xJ)W_&mFBb2d}%+x1&JP)Z$4>C&ZkO`r@sRb zkf82ps{-evpz~pZ92u|qIej!gM<+i!8%H~%rv)x_$?OL5BRh8$X@bUm9i&>Pc{TQ3 zjH7$(#;Z?iG7I9ip1-j%zxM9HdLy2ABz#Z59VgF}2 zE7EG24b>!?@&f~Ac81~LJDTUVg`H|HInF!WT;`hcYOS=e5UtTM8(dZz4(Qa$lNw8z z;Z`1~xSF18dv-ihIsPG2(HkB_j#J$pov;)+u3VOt<6J03MNdMw#TVr*LGd0ifSl^$ z4Gs}%ELwPs^-r;Kp$pbG8CP=Ul~P5 z^1Zlgsd^WD>`KXRIKHf~%4y$3XO3c3X#SS$y59UdC zD8!Mwk+=I&W7xC@AWvsWW4!i&)bK0FE-C(RoxHv1B{t6sybosJ4UL>GNj!V`rfyApoI6%S^8eM7I|dXd9^cnPq(9CoW1=6V8-XVct*v#($orCeVtouGYR+NU%%*maX1djf4Oyot8L0|(nV zF~L4s-f5*Cec#kF_R?7$3re4;WuI7w!uj_oY0C!{C33&k^@! z(m5Sb@}XTVP9BJtrxy1ClnK=S<9)P!YhEG{W>{nZL8`lHc_R~$3XAT50erlJJ~Prj zvK4vOWJ+Z(p`&juS8)eT#GW1ydx2uMMGOWW%>4U1Bfzin`*8m0+fVrYZT@A;=(~Oo zuB+eg_Fn?0X2-^4Kh~JUeku-t7G;e(j6RdC@AkrQOna_r7-r}bO-VA@jQuBV=4#GZ=lIxRALOCtv@*m=)mo?siH!dk?t=_ zw`-*9qsmEsA8{XZ7?w*SuYBa}szXFkd=$l+MS zDYlo6fMVbtV%s%gYqWygs?D;^*_2}B=XApCU8+CTu0cKs<}94R@38HGwzHzz%MMuMh}ehh zt#4i+df>dvgcNnIR9zd(z3s$w|6T+8AJ)R*z;VWS6)`vQ&ofqasl7~wJ-Na@Zlhxg zP5lbl_ea01E4P(JwRcH=d^`UgEn7A^xd;b_%od=w;xT|0kU4Mb_e7e~NO}eA(F~TA zTVOq1`mR2{ONaAHc9VFF>-CirvGw{JtC4u8Vt(`O^sD4nm9m;%OZ(9*U=qb%5j44$ zYvmQAh4)j(P99b#$?P9VzCXbnlD;qCJI9o+sqtXynfpyWs_sWUz9PKyb(``WPC{); z>hUMO;Dmo)D5=L8gW3@it`?`pmJTj&>0EE=%KKgh9j;~K*H z=jO*si=T-K6bnzA7xJH{Oh>MZ7yL8*o>wAz4y}p3npu4(WR*Xzfb4cuD<&5+L_Jju z$G=jPC~BiPJw#loup-wtN`}YWx}c-*yiNjY!xI89aT*sj5i%xxD9estMIDYRXGHEc zrboo+eufz4n#$O+08Zpq`d959fci43dnbC=BAkyHWSej%u(24SSM4dMw9sB->OIZ5+atODb`t)`kL}vQBT-&GP0R zt0h&o$nQ;L5J{ay{xm1dG_Gl zkdC?*-QR(-(RWA^i34|CPG(vdqIL06G0tnu7VJ)Jatp`qya*Q0Jpq9v^!@szn)4 z_L-l!z7EN&-(WT&&SH+NdR&FAwmLrLvoj#LZ!Lx73(_6F(y+-y(DgjRj~+Tv15XCQ zmg(8So@Au3mnPb4io5YWUVhWoay|XRoA1g@D|LzaMgCE6p8x69AG#cUl}<5I~93Hl(mxmuu(6-B#*!nUv zq`N5G3_T_T|I?wMV5nQA%ZcpZ-_o#j3)zVHb{4eitqs0LF}q8mp^H(^1b&Clkdu3A>UKfK)!CPJCN@|$Q^(WEM{d; z)uJfhMR%9vdl-ciGo}okiKkcMsfUb`Ouj~ayC02;vJMBOn=#;`cjW4`D#6BO!NefvXs`p0lO$NolPxi+M-ap)FFSV4$w_V`8spd%yss)go_zhZ z)OcRg*{eBjYwS)77$N@z?F(=0Vn+2w#Z{LoJ+Fk4Ux(QSW$Ne&^qA}m| zTl6{U+e;C2JfwIrl^5Qi7OwCXlB}#{!@le-{75b6v|>8Ji#&%ne^H@@uhByBQ-C(< zMG1jD1tdPbhbj`OE+&(NCkfBWi z*jwNhRDoJm@vlNqLk~irQZ$O8&vjX|^Q_qyh_>X3=c(CKGtIut2g(-E*#&^?HDt$)4J_2`3i;?m zC4l|jr<{)Z4SH6YgxLmQ`$)oUk#M+^;3(VPkglewlR5sv&y3!-+JJWXp-KzVRdEX{ zBYUMGYYf07Rin8C$|ur9C5Fy2Z1Q+_F?5!&(MlY>^_w`mG|&&5L0sk5Gz)5aLI;uv zsmTJpvAf@jPChA?{9sDRe&el%eHd0U zA;`IJ{DkV7d`x@j9WJh@aSuiM{HJM->=V_;>9wpHcW8%N7@PRwxNZzP`F7kLmbS3_ z1b~)|R3^XJAo~=LW`@S(T;}kh*UVZq3_hP@uJFp_i)4Vv2w9}*h?Sk`popK>U8G>f zU`BUNezNgK0`gH42}QWzgYsPnY6K@{mS#q_FiM_Y%|ykH4xl^+M}BLHuOwYQtxcME zm!!BUa}S?-YzZfa;A<^qzh)}Dh&8}Ok*kj7R#AUCD+N*WOAptiC6BoBBn$5 z+%-MPbkB!sF1Z<9p^Bz^K5zDJ_zc!wu7TpDjRKGSYg9i~|0#58IjKynl4d^sWg;vY zs~fTZ25RvkfsUttL>piHg*PW>-V3bWwsC{P-v_-wB)2`LDJe%=+m~3uR9o37ezsS$ zax=@zl_7R2<%|z%yt8Un?skTOw~I0`dv)fAIrYw&;wI?*bSZmLK2{Z{<^h zcEn7|($_SDNk>MHH8T&g%F19g)-sUcpC*F#)LTzfXn=|u2dedGwXXgy=bgo}_>win zCM#hes>KnNkm5+xN_D7n`1s%KG0_QBV=Jf3Pt5338;-~3%#U3;ITGpgxtdM>JO38& zFGo}V!ZiPif1lww`KRxC*7xLH@>}oT&A+5xDZ8JZ$5zXh;Uxd86l0#qM}t(4d`dA* z5`UhYl-BumEN-DFY?N%xj`YAA812)b2f1w+NV3if+bFx*2js+dRmBDs@er@UzXBn9 zoQwpho>oYXlPOTlT8vrc<}OPqKcmjtnd_q8J~gD@dOq1DZYzL5_k!B+CI#bVhkis9 z=TwH*!Km0_&`K{~)XT5wrA_*^%jyu$D>GX_=&N!01GeK(Mo~j<{GZX6*?i&9!bs-v zl7YnRLqy9|-Ramo;Ac~ejntXmPQ~h_2UGOR+|yWpSkg!>Q%J6((u*-A%(kh78Q3cg z+p-GD?BWdoX&nCX3pd~&Wm3bpKO(1zaJ&-~FHZZt3APu?dr|tGygENENAHUaWV`5Q zj^DtV-l8HC|2bt~5z4wIJkCxN>w?CX-Squkvhp9aoY)ufVIcf&Keb}IN8@nt>_hA0 zDIWcCCr&wY6_Ug)@@<7aSO`ybyx2J7;=%)rt(aP_O=voGFv`OTl^SV@kqR~Q|rYqH|3<<+^YUSNE#!h zmW)Jga6-O9Y2nV6zPNsLc?d7>X!)$A3i=S9bfho*Qrg?GoUvMXg93n{)8__!L9vdG zRVu%Ql&3Nv${npJc8S%hd$HFIpYEe#MtfauhIe-YOc7znGWGE>I>LO=k!~^m8ifbmANNQS#&8g`>v7u&&MA=+GsuKniq1Hy9cC)= zk}du!Uy9}}y?<2$9j`}3SHXxcQepo2e;A9j6^2_#)!P={S98fsz5t%l*ydO3F*DT% zmgB+}=lo|)@qB%8e%E<<@q4tH*wuu6F}_~Cyh_+w6j&TjL8ZFXrEy#P(j$xvvuxk_ z34N-E65*$#wkC{mplXnFT*G%Zie=r}p$weUI`>zAesR#hiw6C^jo;_-&-6u}6UHe| zU;aDwuMOxEizK*#(GV~X8^TBVA#3QzA6lZT(y?`M?zdHSqkhuAZ3SqerirSszcZXk zG4JQed@<(!PT@-^i7d?cE&K& z9hHEx;h)#d*7=g^2;t0sKIxbSK-2ZBLcDn+2CgOJ5NRW0(%T5cd zlnYbozojDo!r*y3D`fg2DJnOU?W6=;l9>Bp2`B3Z7ye!AgRZgU zW%t!eUaCO8?m?czb=Ou%EpGecQu6Z9LD2RTw4SRC+F643KMrl0piM4=rgR@uT900r zLi6k~OVF^h+Ywy-h&Zf^zehlGJF!Jed{-JirS=kk;P#l1iasc(&4Kx_dbRgSx5wc+ zLOe{lrE}V8Kehjp6MJjx%j|et9JuygSpot1rXifK|42eOwN)U5EAST$k|xkYk`rvU zrG->wmeAi5DLif;ymaQUsTi#!DwmZ0ai(+{9-hg|(EMwQ>=w96cqaPL9~t{!y$beA zlMv?negyk}jacaBamFcTq9-Af7}VQhLzH)cDZQ39--l)<=f9YNX8Oq%yx`pW!VzyO z{eNF+dSy`PSIXD7txEYTe@4WEY0gf5d=Z0S%=1w1!jxWjK5iz|V<}X?_%~quV=P)Q z4;2me8nXYMf7Z2uwiPkfkh_S>vs9xtk&36=wESPJN_(C>q@7{mSUx6`nJj}w#Fm`2 zG^$5r-4>Dk#StVyy7{#LO#SHIYr>u5>*@T7g-(z>TczB3ct|#oE+{X4*1x68l#@ET zt8%etc*a)G!&dFdi*VX@vV#g!Wk@~^BH_S!rUom2h#J_Imwa6v<-;RaRZxQ*x#mo5Oa@n7!#Bm9UUU=K<$@G}_-t%w!vT_;CVGdrK zxfRPa*0xfwD2?Y*&Tz+DtaY}!whM)BRZY264BJx-z0pwFXcvgiCelw2H!9h0vNOyq zgO~NP8&fk<=JsW>*_Zo?Y6s_fItIP_Ill>_hpq=HzYl%DjKfCsZXdTr1k)kE;jVFj ztPNL=UQiJ+o--PSvsCa`Rv5F%$QLiFFv_BTJ>l5tPEE zdN>!Yi}bf149qk#7TVMSruZJ^zXxKFH8j5iONyIYA%_tT;YZPzY{oZZ^=1&@gwU#= z(V2A8tp2f@V$J9I_xt!e#^WXWeeiNb2`Baa1CyUlZ@=;59fyg7a48-y2o5{S%kyar z-&}iyT-xQu*lHiWZ%{L{;z(*x15Ru@Ua4I?S`FsM{`_*f?1y;{2X13s7B<_iC6XZQ zue{v)Y%7Hp?Pe9~I(ZITUs<8ge(#4APR@8&PqhvZ4|b=0rdU(|SZn$undisuEEF^& z5ndDuUa)MwHjcm0>+Doc$)2Z~O_D>V*wy9pBWe9cK9sz5nok*0ze(lF;R`NydL8Sl zT&4Pz?;{!7zRFdqPo%I;_^Vv0e%mUn61*l9$z0uop!+b+rYQLlzuM%GDlCHRDgP8* z$l%L-w_D$elS#=oJye{zA`E1@QISciI7{k(Ow%{uS3dbFxV0 zV3Ev7bCM3$H@wW8ka*8^p)cw%^TF?EJ(?TH&0>3rO{H>3iO&6{B*E}EGM<>${ zF=L>2REcW`{ZB`(ORbvgg;B92KF#L5=6b6bvvGX&Zw8nVU%*@s?K0(3N%0Ymtx{ z=qDI_HpQLS`OV+buZ)crISNKB(N!8}I=h=VcMUA>W<|viEPn=|;t%y7XmfnyXxlHM z?d8}pNe!+J9~o9|QUS!ts(lpyd1oeRRrZkPb%2#4X*xlw!7>kRhD(m0HnaJ){B@+U?+cDinKZ7<#L}0V=WXeM zsk_bxvsq{&o&Oyj21I>ja>Qssx@R?`l~Y-d>u0C|D%Gg01jX90Xlxfhi&rUT}?O z*&m8N+*nBHr2GeUkg}EdUr!o|99BFA)N&4Q!ppUASPi z6Jz~{D8@*4&kNs*E2Ft5kY;F7G6SD@~s^ZgLq8}w!&=)&*e>m-T6?)Np z)!<)*+5RPeROK;x^c)s`e(VdEnh4H+qXLvKQnZ+9tS_wYt59sbit#VDDA@V2vw^!1 zrPX;+s>7*qStGqMU!qO(vDBFI@MvPpr6j$WBSyeD(K|W(H46HB64-`mNw|@?jkz+TEE;tggq2Z3% zIlQ#uzOdcms{Dvgd|Q`W<>vc1CqH7__*-&vpGT0xC4)KxEkE|-9oA_dqY$0v&VN)8 z$w<&BGLLPNb_m_n{Mu#*Fml-Z`(E?HN;O|W*|Ng)#1a8ncBS9tAT}@TPHdqSVwY>O z@Fp7b4LfN!&yVdr597V`w-pd-lKrbD#XmI@3vlj9-oUvpTxdL>@OlN378taoe^)fOpLZx*IFz^kUIEHk!kT|c z?4QdWLNuRj1t~ueP(pzy(W-y7|g<@=_AF$OFDbPU+ z48F@cy#+5Z=?av@cotZ}HnpsQc{DJuX{y>1TTz*UfYN-@RfIyVJ6+OBM2pEVOjbFa z=qzx2*FA4rs%pN^I;XX&%dD6R&P@tNf8me>PPC9|&>-BbdVcJ_GwF1n{Y?ekT8+q( zKynq&)YTwtQc|~b+WfF}rHY!uiO}oL2KwKgssQ~*6mqtC5Hbv|%;IF6?Q1SkFN7(x z=s^mtvV)kQdGWZbB+8&4IgRF}bPS?^)9Fn7^n_mv?((1E2 ziVtRAUe9?QdU;#=Qi2*2o{JE!Oy5uI)>`z-(J#uQ;e4nnek1vuAG^U>(Eg8KSD^hm z3iATu^O)r)ocJ`0l^_3fMXB_3jYd1blr09{gQzCO3p7XBo=A`9AA56-@bb zVaCdybtY(?SP88`UUtUPR_fzu=YA9$aarcyC3Kd1_*ct2{nNMA{LYrq_w4WFS+EAf zOTIlpoj>v~6Q2=8E3?OPfD0dF#^JxN-=CS5Dy1H>`H?Ze(|xeSYwTxe3+$z;gG$px z_P5O}#NQ3P#I*1HU30bleil8KI3~YM`SK&SioZ?WwRCGlZv}Y|Vyw-$$9yCBtY)L< zlW0FSds<+BDk_hTatg_z5AH0x(ND)C6f1L7#JedTrisjiL=68AFi*$z8G-Kag3}HQnF#? z8gYWH0Ua~HjnXuAju;cM>TF(Zw^}Pv)9D|R#hBsX-|bsfvuT=tY>>RgSOtUF+_ve% zht@6C$|duC1(A2|8Ot8kp6{UWc!QwhYDzUfx+sJutK=dVemrhP#y?xEwcI` zn%1|w9m41S@Sip5c@nh-PyPAkmvqQX`F@=Ih&|skdS1=1A3eKQpa&mN6}}7N73g`k zzY;xHEPb!!v;BI~bKLzyG}7A?-f0V&0atGblx|V9(-|C_`{18 z=^4-Kq55{(dq&TNo$E)>z4s2KN6tKKQJJ2zU#LXS;}5)7^11oa^`qz2g+uAtQuG`M z;uZAm>gOxbGxj~B=h=?+qi6dH^lT-1z5?PE=y~+HO7vX2qpPc zcMqjU$-b~*WqOYLeI@xkz4*PN=jw~skDh1Q=Qmj2G@J?hfOrM@bpEaqJ^R0B^gKFq z{pi`W0zF#j6TS%I73jIQuM#~!U-Vwd=dJejqi6h`L*?^9(er%}uRzbM&s3sk^Y@IN z-PeKht$$zi_`9d~Rc1YbH>iK_Sw?Su#FRn5TL%69`JmsA5BmL&vft~f zFO}@U`0uUgf$Bm!~CeEZ>*S zrI20I9>-x5()j>e^)_TZT#|cP$MWe}0+@WO!U5#ggfcg_QU1BkW{x}2=6mvivi_}j z#l&AUDqlu^RP#9T@;sHb*%Nk)DIiFHbIDgW+Z^|((~d3F=_5JV$9#dtd{og%3h_MP zvP|aZN%HZT{1Sgy?K1Vy&HTnDgpqw)>u-B3aa*v&?J^+8#BD)|Ta8|l-)-94reu8a zHU0x7$|cf3Z?_&U*&ysuw@npkFB<9bCBHqszU$L`4i}wm%OP9NWjUnHsO9Ts@f_T*b^#wmVUm!lN@YmJ`MlMjW!CPUqJplhaq8HFXX{MH7+RgBlX&J7K-WGQs_}M+sG!2y zKeFgsrm3_oBVG2AC{*+(Cfiv3|9|~X?1QbLmIBDX)tYvry4ev*X@Bhy|7H}w z{k7>6t(GFsYm?sI8}(XSTkZC6e)#sOKJm|7iu=C;zYE^=eKu5^RQjPR zwgPB%@qB-QEX&qsDFtJY*y%ifGiJ5s(RNQfc0zOfE#w?}%dKJ9&9 zGuaQBw1xL|r&*WS@=J7yVQP^s!E?Cw^lX>7p6V>#saO9=7T!OZfb?}oY(Tn?H}nNN zenQJe8*1_sybv9yiu(q8YV2f7&_}Cn9l~n&SgM#Fd=Nj=GjhFl=a;d?u77Y=eZYZ= zRilmZEWdKY(5{)TFyU0A=>TTP7JblZI$yJ84?}BdA6TSm;+IM^(a>rv`DD#?nSSR- zjQT}3KF^P6F8jT%@m-~O^U<$be74Txlfm)krq?I&T{?bF$DdDf>{eFWOY?Jd2HE{M z9?y$ z7KY8vQrxT42lKnr2elto;BbehqEh_! zqH}t+FY4#~i?9DDId3kt%VqJs;wxq% zMEF?pmFUB2;ti-6GI0q#5RlQ6!~+wv@m^VcC2Pq3L-t7cf+6RIZ#VM!=2auSNl;|f z0ePZu!IL8*XEAC&DsX-MSlJR8R!WH2T?z9S0by$WZ(omOFP)P+%9!@_BK+NEr+f-17 z>fpvQQ>J;$*W0MZexXPccatJXA*h)YlDK@CmcD>cxb`pQdSe(W&a|_I>=(fP{6X;% zub6~ISpwStpROBlezc##yRegB|JN=cBkV{g{6THTc+1j~$TIJ(a$HxV#_$PdPzoRrdcwFycgb@#PBnep^hI`|*lM3J48#TDgw@h_JPx;h|Loq%{w=XR+Q_j^uhDTrZ(yT#tx+& zT=c|L={EitX`ut-!tPTxOc$Hmi*IqDp(#hSOqS~#Jibo#gY{2%B-Z6}wIJiNwEOLB z4cnlw7yegRfSXHEGfBbu;Eu2-9DO1vn1)0_94sj6F&5D~-Pf z83xOgbe7=&`rNm86RYRj`ZredQ3#JwDp@@Cm|BcRe>Wce9N{hW(mL)Eu14MfCmqNl z37pxRLpTq>&id@J7Mj#TVdJarsixW+Z)){=&jvlIzd@%;T{8NcF=>DFqnx!68d&hf z{ovSDfCS?*v$uy~MWOuI#}2^e6mA4x3YCqshcJ@JwbXnzzc3(w7dp|G_1D)_KI^1E z->9TNKK3yU1F7s)ap7p}dvc*i8Ao<>Il(sRTmcRi77gcJ`1u7-3{X27LqAa2HQo8WCxg+B<5yNr&q(5rI6PqNZrYq-i<1rvVO7z|-+U6+X7n>Y`gyrMn>Oh8wS#^?H0bwV2K}zPp&Z`+gMOb@_B&%QZS5bV zd{S6{M_517XE`A_m(2-n^?8#-EyWgHBwpp~w&OWmgM>c3!}yuC)tyydsyx1)ob>lW{UaU*9&g298-!re zRt$Q|tnLSJeM4-5?tQZI)&shI0AsG=B7ITDi(CS^`lw_t4Pp+YSQ*WKP95 znapeg6I(0pcPRbfC=2fh&aT!~Z?0qg*DhjTn1yZP7J z^eJ)-7h4K_KL|p|%>ui0N)~KCUjTbR2CTTup|QIwFHd4+w(45KEJK42sb-K% z;nJI$OVm?_l$qJgTh;^-Je07y;YcI)r=JI_6{?l5yPM~*R~c3>@&&B^2M#2}?#(NU zlI=e<*3)5!A$BXfzfh(rNl4y$%f98A$H~%|BpyudY2xonXE#SIE zQ;%T}icFQABcB*ck!M5MOj(JU?acDXR@RQT-n+27&Tm{nbBGOY;lz2t@rk`*Z*(W? z)UxCKF^PT)UoIzef0pads1$AO;vl1!tLkLVW9+mkw)tt|V(pK3yXd3r#1VRt&wG)b zyhu8f&bHr>v~SyT0sH5p=)F7AUij9EO7>*w5hmdR#TGRPt$bZS&tVdhFR631C(BXN zM8X?Wm}havFBSNAMb)R*+?XXX#>)urg`9s9RMrO=m1fX9NzHSlwA54ZGk*_4cR z@fd?A<{)2pNnAbKWfA8S=17L z)Q1l-_oyF!x`mIftkP(B^huCfxTi3_Qap;M>*(cPdO1Tc2Ze{u@BD~=T$7FG)-}Jp z7$u|`^tF^#@G)QD6UWBjkx5Z>8(m=G?Sy`Sa|0rni1-_#lIl|48CDLnK@La4?s!>(=kfu|Ij<41iUMXBp<#F|UC6Bj`T|aq@_x%eM<*{b|yO+n= zKN%{I{D}SEGkP~&PkImY{S6iAt@%IDdm)EdXL?;6k4<^c=-vL9^^@;$zF(jsy*u9c z?&aJ0AExk1fcg^ro8^OmB= z#iHe#`t0M3r2==tgW=0Ru}yvHYKrJ@vmG?`Cz@}fXD@Hn&RqRZPAR+w1RG@Kt-j31^2P=}SQCU812hst z$fBkzlCvRHPQgSH@wgw9w@4`}`9s;5=pShJiO+zda0oX)B2y1PBdmei9$lc$UVJfkb;qpvD#z3E)?0Yu|6(4+rVaRMIJg2A zlx5}rnKQ(~p&)jPBlb6*!*>qJBBt06#NGtk;<=EQp|^qYgXLRw9-1{PwIG}&w&ePR zcK56lnXz2Rgi$|^dh&6#hKSp`O^A{2hZ2N<8c%ZC0s zzDYFLL`!?jeIhKmzCu&SEXgd9A@#fU8=g$x(5e-pRNJ~uQt8PC$@|VkmaHT+fKlqp zTXpTc{^xHEY}kY7$9^w2Rf(UIDGGXx>J1SWX$HOrrqB#&ikR!RNZR1JI)V7$ zMu4ohMV$mb1hR&%aNNKRnT$HqYYgI721Zk7cQ<9imyeh6$aN!?Zlv-_nhX0MWQzOI zLr~n8gjK%oP@cm>6SImNdsHLculTTWouP*jwLr4)9(-n9$KKn($5~Z*{DC$Q5SXB?b`>NlV9SdZ zp;{<~R5CDVqvfRnDpIHvP*z#BT9rb}WZF!pQ>qdzickfltDtqIB@~*bg(U%534)jf z)QDw$Myp0d2rJV6_jm4n-ex9|b@#LV{Qv*$r<3P-?%R2}=bn4+xo=d~x%>@Q&oZuE zMH%5Doa=ZGCZ%ZecK?@PWsb-c8z|NcA`|^rv-Mx)nVT=B^mV^Uo!n{!J$ix> zbl*E6Xq6+VMFf42s*MTqisq+K8J^}(pXZ>0PkA8BEj*y3xG886PQ9^`~ zpiL6y+*PE;iO|HU>fuBCttI&6b7o(8Ms!5TM%}BQ)D1!%l$t>Sj`t^PlxTp7$u;`7JU z2)=`6Lt2OE+lJ_vtU{kZ&akbV0JfiS*uF{FUP(pA73#Ise?mft?R6w3fmV|Q?Df-C z9Bz0sB##FhI^5bDP0a>hbU-=;WRU~X!+Y@BdO*4Wf)*P>i=9EDO}axOXzrO9L3W2# zvcyS1I3Zma2y}icqYm1t6hX&_1y>Rb!2`ZCcjhVc`fq#2%e3>=5Tg6gDpMsc@)9RC zuN;+9O#{KDB2n&Cj<%%K!3x_g>4vP|6e3W)5Ugi@YCb}9<Sb!+=pEFczEj4Xz4@$ZLdl$Pn#(uH0d2YzA4rHo~W=xryHv$ zk*Mc=VqAG*2k*gmse+i*UZAI_t%h3J8%SOglGSk_R>!H~baeiY>p$H(OvgWYQNxaJ z^$d``K!~;9rH+qdX+EX(rp}}K3B{VIzE!bf_;+o7*^Od@AAGtV$0B>i`t#JfP&~)e zY4Bz-OaYg0Lm`G#aU^kl!Dq1alm1h$-(8*u!aS*-R?RZFQmba8o;JNlCi20DBNbHuKgZ6<0b=$< zo?m-jzyF&$l=w&$@FFEb~2Y~w_F=Y&1m63f4r{?^3>%UXPKG^LbY^~EEb0#t zdS~6CR<8~!J6vIZcG&VyRtmMnV46}?*?LiXg8!}1WA=v57xSK+kPQtg#oSmAZJ-qG z2r(v_s2*^%X~HMpfhN?@8BO>b-h-QtsiO%GdVAcpUt-L#mF=vMXyOzxDCl>WkPqtB z^}4pkPw%jZn{ZoOP$Z6t=KfL4WLVWtEcnAU>6qByP02(nGU3~&v#p}NQpzOC!cN>F z#}Ue^w+?UV4tV|#R30-HYek&4qXe14WQWv%n{;uGBx22M7zC}blQnB8oFWEXg~_9E zi6MPyjGtRusrjBrriOTpw#}Jw)ghHn=uiqx(wUeHIW*mTk@F9-Gty>-v;tp@;zC4; zj1>$!ZIGatxQH)-U%cfp>|edCglj+iVhYN!(uW|}ig)x6=+l<&hKD>4(iW1gkncuS z>ZQxhqW^*m?RUgU{wS2M7IItDar<&TW&IBJpn)Frl$jj4Yfa+(YKcC-Cd|_L1Iv$j zXPgoD`#n4RD<5`sB>}X$O17V=Vf%4}i;khlba$1t!%?8h!V?%)2nmH{%yDK<<#r&z z%huPTd@bbDs3(LmgAL7v2|hYk%1yQi_D?jY!;nD5nHhKVF*N3zi4WfR15+BV*37KU zMRIzIFQBj09X0G)RkI&PHizQe62hq_Vy~1~qj;v$3C8?N%8#=Hk|QlQ10U{rQN!0w zWQb`o*AlnqWdEKl&*Xa1q*%njv7sV0>DXq9B#=xxqFQ)LVv{AuHe#qRWJ|jJ<|FXZ zw}_}e@cljQF4@<|^t$zgOnHR&ZPHJK(;sTzexoOtjHLUI^&V~41}@W=Ye~M=Re7p) z)J0V5VHh-8t;?jI`8I0(w`32F_`W&v*0}-M$BE4^UJr2@-dI@(YT30enN~@! z&1`JQZ5^7#wQIEzjPADnvYGvZxxM;FPtY`Gf+&&~r&;Sl?;ag`w?Q8*0no=t5JmD* z%yK#c1IpjxZUmaKkgDR0-%|GWt-+*2c2b|6a=wG%wp@N2{F%G969B|Ej~UxEM(pTO z&+aPFA@w|wI1S+?3V}qS)V`KY*y}SJ_u2ob{?6-g#axAvu6=#y zgr-t+4$BMT|2lUma5-Kl6VQsn*1G0+B?XGyeZ1(zVAbiCodpnY})gwH4!= zB#?8X0E92IF?&O1WBc{Usv2%uPE(S3nIw}2-f&;`dVV)BIJ#Y*ec5N-W7s{q-Q#XO z+|8A}>KPl$XSJH54p%dvL^OW5j71E$F3}=}lzuNa?tjEg8z6<_y{VLOsxPBT*%#Zj zBDlIGno=I9jR=+UfT_jN5;V!CmYmg15JmD5n!9N|@V^KBSzF8OhV<4wafU?>lhR!X z7>4YzmuyUw^#CZRly!BT6Pr-hbz&3Bx+XSO*40rc>sE>X zM1XWQON0VYgL+Vd(V-GG8q}Z;)R@+NA{72NX>Hymv`*M1v`*S3v>vcaXl>agv>v=m zXq~)EXgy+=&^mRO(0a@+p>_H$q4oG(LTl?Tp|#D?O5dvPm@BR6@9eGWy4%>_h`Ye< zZg|=Kc`GpDP7X46L5EJ2dKCUQJ9NZ%7tl&m-37FwmUaQHsNh{dE8Wd5pp~w57to3s zu?uL$WZDI^Vjk`SS}}!p0j-$*yMR`PIJR51|9hFL`$FW(4xPCDkw0G!b9~&%h|qNuJIw1PXo{TX^-35c z(#<2>UN4uMN4VWQQlljR?idNuk@;TiAIOs%Iv+HNBh2Bf<%aDy#?u@@OuhNG&8O8% zo~nqDExm@`XbC`Xj09su#?vdKz>TL@>Lmc~7zv_C>gDKcFWW_6)X|!1xf_)5?b)=8 zoA`K!%hNh5X)Pa3gfc+$E@_oSugT82_n3)OQibz;W=di!WVlX6md z1W&MpWhB$VsX(~WkR6%Z<+i3K1S#<6ZT4k*ab~$_&I%%C4WhPZX8AsNx5%`HTP%n1 zN~UhHbP{I^A~PFX*_W+ZHD9Z7sHWALqM92mMQY-$ZW)utEJF+RM}=J@%4zI?{Wnqo zJ4}I(_GL)lr+)kYSLuT}sdm;Mi+sPP7t`&mPHaNtYhq)OuZ~K$vpTVf#$6|N44{d2 zmd;qYV2loFJ>p36dL7bw)4Zc4fJI{@7$eeY-djh9d#k}6Edg-HNRW>FzYfXfk9Cro z@2zUOpOaWiO80YgcD>DhK6`ZbR+|7%H;!tJpKcs=ViR&&6B{><>Zo+%s1uuL9Cc#H z0GenV)fwrJ*IR!qiHi)EWQR1}bx47l$&5&M0wVM71Dj5lZlOXNxeydK3i6ASt!qs#jTuYw3@N!v1*3 z@ydGO)vgEL!}Y+c>4D!PhRq+pl+*cl4q-ji)Hwax+@a1Kl1G)-R$D5%w$4-0i4`Kg zX5;8udnXY$HsHDvp2|HI;8>=;0a9RujC zqXF&9-YV0q&t1(OP2?x1?!EPvo;=N!8t;2YYlGHX)tSbBdY;Xiu3{_p$NA0ScMQLY z{GP*P{3*Y?`2B%xVE@MNJN&x%X(U)dWIL9#!?Q~hPX}gu>6NpK za~ZU-=CH_FE5*43v~JdSWqVoU#aOMqyR=uaeH|}~SlgFfDH8eY<#RR9)w$vWeo@lu z%*MSiAtx2vX)Vej&)+kKsnJIt25$E z+Et)eviPi+T?yN0SfOn>BrnMP_H~(!v-chLYl8-3kr|Z8tP5AIt*dm>#Pf?+;!t^s zHpigJ>=KBQMN0e2uCA6p8e_O1Zgs8v)rn2;wI((eh3crZ{MCs~$X}h7g zwG8)lpFa*Ax9?OdWiJGNM5|yqPu>>6mKFz_a?KRzH`E_aaX`id$@X*HT`sd~PvCIb zQH}=@R56P|_0-{ayU|l+*Y{-~C6dE+ zoGSaX|FyF3u(BIpH?@^Y0z3!^xKbKJWQp3={PE40&$?DovccaapP4sb}^Bt1*52P^fsSuI>QvzzYS zNZo;S+}X#m2yweoj?1;M+MkQv#$~tb*v0`$xxA>mY_2GONyiSrFKY;m)WS zJWCLUfB@k8U7HCA;Oa0Tz8%EJWuGi&xm!+&JQ@{%hz_{5D5v0D=`y1yHy?s_=2MYgM5oOSMHK0qP|Qt;D!Eye%-}Q>(d>5H0F+?Q z=a7=5G}lPFulU_Et2Tud;pmrKyUPCy#DrADLOk~aV^n?}As(i96P9G0&RjF)vHa!HIQozxMrO;9f^?kEw_IK_Tv{w!YR0e0nqosFccI>x*Nw zf4c?!OlNOvSa?bj%#cMIa1VT*I=B5<)Io7uFqy+`{ASH?zwn%tez#uDRh$X#AT2uI zi~pT=9SY?mttOO%cGk$My^#zu45IH5JiDI~!IR0*%OR^G#vkB(RIi3)rMZJM-qqZh z-I6J*4}fIp^XqyES&`kcj(upRT+ShmQhVu*2UhGOiN;t7EybWy0T!3(8Q+v2**jC1 zXn^ccSIV@0d!V9i#7?(GL7%3MNifdNdRG4u>SxB0P*KYHwqUzM2VFa{n-L1q5Ke8p z(jgbzC;T}x`o+pO1n4U+I20c^a+&ZPM0^@%N%RNoP^PO98r8{g@cy%nNR{Kxs6CVz zTgC0wIAwQx^~dsZoIC7vc(LN7XnDK)zN#C|!= zm$Jvr-)D;5ILKDAUaC~whY}Nle!Eh1wcQxnOO$6R0lQ~9CXqM}7?6k+m#{v6fI?h6m#R2s|Q{1wk77eXXInS4`tD)VeVj+Tuf5;cYfcYFGbLt{kiE61TycE^QwS-Zz_) zkp0T%JRsLfQhC2MO5WFoc~9_pQQ|aj3OiB(@kCm`H8v!oFS|}iG6qGX@l8qB)N57YtnQa$282pw~;7h#+3vexCs zqb^GgH*)W$D1o^&F0)wyFQd#Qqm=n9wx5+b$t4&PrMdZg$+lg!Ku9_>DaG=mEiFEy z^0c44aD2liZ9WYi__S?0?y)yfeUUb`%EP3|mz-L5 zLWqVK)DYlW9o3^7rgRc8>Ucf}vN#*@_I8x9Z(f!63y|Ar-0C>1QP*0sthLiF{Ba(b zZ`Y}0+fcA3+<)7zjRp!QdQHV01EcpaNI60o@$Zu;ef`qK*EJyQnN@QESyFPOhI@cd z76x_LrZWev`zTMlegsaaZ3kakSj)C+NocaPbnzMo;X;G3#vou0b_k*`>I@a7ttmmy z6}2AN+FE&prE#*$^^8r?nUY*0FzrC)dbe_IquwfS4k1Rg&d7FWI@(+jt_sT2g6GLJ zN14j1>{08Fsx&1~YBz3cNNyaQWP{m`Y+ULjQ2C-tJxis&!ud%dFfBQC5#}cfXy6FYL|!U-i*M2}ZOVut-_>0ZYFIEN?{(;mfja?vtmfSG$#w zi#5sl1hX)wvKCOxRj810IXC98k8sRUd7Wo^ye*hoGS<2Q2*>@}CSr}9k_>tTX%>Sj z&r`rr_X9vJYXDsMNv$>aEF>oQA>Iz>7Cgith0$}yTl}5i*ARRwOjIz3hS$NB>s0iQ zIRyVJM&i()43!~CJ9iv6n=bOYR;-cEBXY4c0-|Ylfx^v1SJ&Y+#1~IB$IOtSKbFFs zZy47K$4`+|Wd=?!&ymV;BI4mc?1zJ5<`d5z&(&>^rDM-{56=1He(q4A7E<;2LxmoF zhQ#R;_t>15vNwmfOcs33#iNu>Zxx9BK4D4$KZfl97wzHr{spDQfa`0JX4s-XWPOja z%9IIC`X^CKatod|Mg|b zvL_h~J0qo_X!~@Eev7im*%EwMlxQ?np7w18szVLln*ch+2KQDy z`&y?GDijs#jINgO{EhJbpW3qtmXO$raW;>9IzqKc^LIB;b0 z+gGU})8h_Roacj_OrbD+SGVkqE&?_)D$G}Q3#}w~0C&HNDdzUE27aCy9nP;5ntDG( zgk+EZL@i261_6%?*GUd4A-`xJ&|2j{c_iEI3-#UPY?-wlV<=qbUZ)3JPmwBEOw_`4 z8v2ymy92y+wdWqc&j3-_U8e%kPPD^kB;)0lkDowG+xJhuI9_MKCeKs(Qv|t!3pj2ajLuT1$^y+6Hjm;xD0z?AUuLEGq?dyXN(+}FIK*>r!Upcj6 zWt^0TT1xwRzK3#C`uQC4pM$w^O?DoKMfSVM{>l|}91(sRLy70G1xDfnVx*L6yC}cf z^ENcz))_jw!&YaBofsib6C@mo3Vu6{l1=jK=eNT(gsXIiNT3dXn6+9baG}QQK~zLa z|1!>BIBe&21NvU;yT!9%T|0Zoj1X$(xXsCCeyR!3-X zp)n2Tc2-V@Q8pyJHy^w=)A44pO-115&j)id9i>#jX$-{_@NND;YroDTEKmE)@6k}- zASihDQgoUb!UeBKIQW+cQv17@DsX|U^q%EuCo12!_zqUC3{^W--ee_919Z95^X=C0 zfr=ngI6hKR8~n&pZ;FcloQuK6Mp`&J=_7m_eZ4m16;__U-XoXr;SM;7R#qU*gY(b`v;%Hv70pTCYBjxfzM`6!z--5)M<pY}accst6lx51OTN&^M) z!nt(2jNh8E_#bfTUU1^y@6zq1O2%^Og7N^@m# z-jZ>77ykJxB5w+SAV8+7BOnYci?BDb1RR zyRGwiK%n`FL*{QiKNWz#wK1#(OM$;N70~-<<+>`HNOa^9ipX?amMG}Rf(30-kUx_j z!?hWn?n@9I?ome~gxEo3?Lt!~K_0Ky&4DzHl2;3!1NQDWqnB2MQKvVY*9KO#z_| z6*^^K3ybI(cSJ7TJQ8OVm<55^Z1grMwYQ-m3mYWr!f~<3SWNYc7x|*S z=A`eINo(WR+qQ#?4O5%I#RSL=Q?F6P93lA!(ImJ|~S#77)8((w& z?UqYbKzUj#z?|)P!8`*-Bd}V;pyGV#pP7s3btLLxz(t0M!IBdjg17&oj*IB~L$Qk} zbV(22*Sedl!nh%%j6BajTBFW^=2xC}+f$$Ct!*vcm@QJCxXnL;X;)r-&d z__R2epMdeOn9xk+(%2$|byFf2Mpo$6id;rX0c;KBZ|Z`!VsBL+vY?oKjN6)kWyQ-E zq0x4J2v@! zrvb@o@_>?ca{9{vlq>C@E8;6Doyy2B7o9#@QyEi3|D8XNQ*xA65OMveZX*9xc*jEG z65~h)|3Q2s0Tz>MIPPfJfyxCwz@>!nFs1R)bXu<)sUDq5N&O#a0U$v21y@jAbW50B z>au%x=iLoCE2L7DRlCw!U2uSPpg}KkK&!F4cyMmH_A&f6%CsK4!+B1^`vcPI2!>gE z7cYPw(Y(JEOKq20cSmYps!a9)5v?^T_8`TAzU)ibEO%sIQrD^uGSbjkd5E1jUpDu0 zgHLh8-MYu8*tOms<#jxQUn8x$h}y=3eT4@J6GD~e8DJdsTwmcPACN0=9_Dq^Zj>I3 zz*7Xcym>%DEu;^gCaABl)~C*I7AR`PhCmja@87#^}EK2CIcqmTBT~X$>K1e7?2dMRG-aCwQO%ywpS?IKe=oc<+26W|HP{L6{P9e zk2El>gZJQ2s*x7wE6Gn8eS>aqi}R}XnrXn#6xpYXBG~(b(8s1)!leM-26N7$<8Z&I;EPLPlT}L6R@S?h1aICbBok_T$=uhIXYbB0G`~(gt^J$8iGf`+nc>ThVmZ{lW{29 z!BD-xp^BB+u~e{Zs-ol5?iFuLhpq6yF+-beQ7GOatGdIYBjm$L41Xt|U9iry;KWZp z%Ewv7${wFOyV##))lEF_!Un`P+lgfEbjJQRQOT-_Hrp;h zsEki*Q+Az0a=vNlj$x35p{`qY(=<%FQs9#u<1^^D%fRqr;TW_?J{Xs|O2Z}NbjgR& zSIQ=F+&8D#mIsYzNBkJ7uXj|R%6o7MH4&RPc{0KAZLlKb_+uny_=A+(LL^BGQvqx6 zTkPe@V&Pz^GiyEtyO0VE6g=~0tmDm=WP^+EQe0cf@*}{rOYO};r%G4*@x8Z+h?a~6 z`#FR^|1b#O;t*cLd+=qdFGko`)BXvBO)%$tOy#1^eYv3CPbo^MD@xyFXP(Iir)3LldjPc0E zFf4fX0jtXM2jI+ujx$&A9$XH`f*A)V2PK~(oceqQo&}p-w!@U|M=skb%9bTt%uqiH z=_N-+-A=H~W&6`ZWP8MAYgRVZPn^xyLs8kTB^zRDRaxd8o*W`ZSv||}SHMn;W7uT; z8gDNw_Cnwt#7$e+ohuZbx{$SR#${;;2RPY?Ngs<_^DvNP@rru-)D(&=O89Uo8ai2g(l;XP;C6!A5W%|>clT7j>xMbM+qA)Gk3JVwDpCiz4{sWI)6-X)<5aO#I3n< zW0o>(P)cX%*G#0BXoddnY&@wd0Vrx4ojkbOaWXexS6%Q*kaAPhc3})v2ZzmUAjFotD1@Emb?@TiwL(%YQlsHC|UASS?^Q& z^S$G)y^~gpXTP|$TY1^mS6E`{g!#44Z`KFHTnp0Q%=avQMnUlo=aNNZ6S{PLg=>hS zEHKpD42#Z`=gDz{JBXlCS*W*_%8GBxe6K7hJ#P?G%M%ZM@c4$=<;GVsFN9kAz--ad zNqk>nHGf^XdYfU0WXc-5>^>6kv$|XO+m>nT?NKd2{J6KBAgV8Xx40*gs3J$cuX6!0R_mqm41a2A-#xR; z?Dsmv4L%SP_j-s6f$Tmuk6!>gSDSTNX=dq9L_tkG?3P(}qayx`jLU2^{^dtnIJA%a z(f1XZtJO07cd_s(vB9MNEd={--auDTom(A+#ckZ!Q|uB)b89+RHVzo$jKlYJ*jL!7 z(hUByrK=V$h&s$bsJ!A<&8=IK+!|ll-oE0)vO_s56?(0}4TeamtDCQ#bZXb}%x~6T z^nlcQ$%2Z72MMaYEeaTCS_6kD!LB|`7SxO?tMCz(e7v&ZqT+9{a2bEmRlj-0>8iAg z$|9HED}9EGs^NgNiz=GmZ%J6bC`ol8!GB_*S$7FVwGLdh1;y&D!qouRa+# zPPbO4XGIg1bpizDG>evJ-lW!eWdw%F+YSK7{<9FCtsktxZ;vQrH9U`>hsYHo+k#Uu z+8uJ~`R;Ii;^_GO;srQutGKH1YXv{8kMOpJ41M~`Av%r$KjLTfx|>@^6Aq%J*SzhD z8B}V2lEu921}d*0+*wG6+M8AYsIQ;{(^^S1SVx;JksY|*H0YgZ8pT-$J-_|I%*F{? zNBi)77W*|~ndnE1u6=%SP@LQEmK0d;r%dH(Q*W_^pCF+(tR9rmVaQ!brHqZqf1YHR zoa``pYXTETk9Ki6bnZFQ6yH81@eGJehU65m)n94m#0jkp!PHx^z|0`i001G``6@y` z^7Z|y?kDBGPRTD`nT5fYPD?uNU;DA{PUk&1?425FQy0$aKT%U9QahJe5kk3Juhf4#e}mp0!}>RUU_GAzx|2Wg9^~p_ zea}`B*ML6vKsF(LTY1gppdEtYrK~iO)*Ny)v~$3CZr-PM2l6uld5HtLL?C|x17jn& zakqWcsm-Yi@;3*V&kP9dIQrcaSA`0OkS zOmFpQk@3HT$Z)=yf%gcv=RRbX8~QAGl!+CZZk2;O8ZS&W`KetWqQeKQZRPu@NX_%E z78thB>qe+^S-P>QdNgd{TIrk?6y3q5c+}noJ0j+3&6}-#jP@0X_L07 zb$0QA*~R;FedFDYlYMOmYxb`p_zQpJ6BdjVV-_9e^B!1L$YF!$N z_fZCU{VvLO6p88LvIcc38luVRrds``2>PH$@nrPRF3oMu79Zg;sjYax!Ly5J9^3?P zXQ+Olsq}C9Q%tr6aL1QHJ z0 z{8|+rtu9Q;N9sON%be){{ruCY_ldfJesmw{5u@f;OaeUY_x6J12>h5a_^l@VOi{%6 zhy9Dhzm6i9E)G(AsphCQP9xndbAwyj&vc6G@X%E;4r%_$dcb^(+ee~xa0rjJ4(nE` z))PeZ=l`f-`pBDdQ;Rv8VrbvEc*T@jr@krsY#si@{C|bdT(|z}>re46UH?iK^Uru| z^*<>|e6s$l@+)0Bf4Y1zF&*#ZE5+PY`7T~6FLkMk)qjj%Q>h_|VPqe>{=qqNZ6UUu z0}*RSqI@@2b|GMr`+0|?38zRo$_6GnrF%s&|j5UD$q8Sg}ctA5!E}i zpmMGJvt9XDseG-LmYu0 z7EJ)7rlWf$Hof?#hNVG><6Gre4u?dSO^ z)qXFuhh)lKl$5$wYdi`4>hzmy!+r!KUFeMh*ue^g`4~{D3$M=nFesewtZ5%9UHCuW zKIYVEAA|It5)^Sa+>2Ff(cKZts4OI3uVEWdMH;iu{DCq1io0R<2OYC_@*X@%CB)43 zZQv|w0A^boaQkMgjn$EgQQH8%vpQ{Hzvm?t4<_2cgPNBAlcSP_15q2e>0b=rAKeAM z3mm@h6~0HL@bzur78*<_9JlzgObM{PC)EbZ?E`89585Eme2>V&fNua7(*Q31uQ!0) z{Op50c|m0YEmy|DYz^Q|xR`;2o{Q_zKn*g?az}x={&P-JK_}&JZ27&%$?y8zIh&d}@U?UK!R0V5iQBm{JvL;6S| zeX~P)mXI#Nte7cYK=*J+o05JZEud3F0hM4n@T(3|5*_;JG_w=T`JDd5GE#3$jZXGa zWKNF0L^d+Iy+;aCq&qQ145g{LPRblj%ipx+~w*n9x656%JWEpR2K-plfF39NerURb-q_w-Pf*?A~&b{MSE&;bd= z?vwZq0bmSL>)IJ=3lz|!A#_@P?;egxUFFA^?!Z)BkAB%b=L%!Y#R56x1yVeToOWq{ zOHv*|8L&b*5Cv$)AQYRIzGKxrc>|35i(_1t_h1{N}3%|=(w z5N^kwovxg}@*bR!D#we>ozzNL&Us1X zo+LySnoxAFb!D}wti4=W=c}x5rpofdabTjXdtjPzT4&B}FFugpwv*PKe}NwBrXm55f#5`ho$u zOcCRR0(E5Pfk11d1jD=?N{$H-gohH?igYKc{lxXBC8TOR6Yg({hchYn$f=%}^+zYI z$dLJNH~q88(Dr|UzsEZM?)L-u`%d^C*Oga2o8>~r|6;l)5JjWvj5!J7=>rCF3hlsq zGSst&vegVvKFJjZi1z?uG{6YODACNioJCiXBhnkbt+$G)i4A(@lyRn1U8msDqo4x; z13k-xlKQ2{Ex28?{BA{^;XpEN50I&!aCk)i&KB=C!`e4bVp*--AN~y8GuS?~N_5jy za5nn(ze6)&J2{ix#6c5eroYP5#$OHppTdBvS*;@{Xhl=4G(f7C@?LZ!hpPTe_=Jl! zn5(zWZ-~-I{04eP)I-5~=fiDD(&YU&Q$0O4TnxXn+_7J#!=(7xZaLS4WDUm&k`wyge+tuGly!#+U4>X6}&0*hILl6?dCkL?R_U7&6B5qLOwfyB_Q8 zgcO?uqYXwI>o^InLWSgmCcdF%6-n?LLsZgrk&@uZAJc4V%KSEqM|#9tsj90Z-yP1O z)c7`?-l~rD=Z%_P@;Ge!p%RttI<%2+moD-2(VDTz+dPV z!DM$`A03`SkD6m}GPi|E$+-2fQ{plm(;R~X$4{5WI<&jQaAQh`*T+Mp z+%ZDgW)-L?o#>QQh|d4({ePv_W74r<|K)U3)aVt$+ z8;me2mhc{2dsDKBdt+yU^g&pO*Fdm*^gDTK4XUe(CaU5CjuomUT$S+5jH1FDEJN@n z=7r!|NW95Ue;E48QC3v9k_~AS0&z>dbdAu?Go)sxl%m!h!L$$MLbN=ueRb+ zhf0xB8*FV-qD0fKX$JfLD3XO}{vc-{LjH&TDO>N~F@v%V6Mu?Jsr797C<}3d0U*|{ zzL9a2Ip9~BY}lVoCLkgpg@1m>RBP}4+5^ZP5&?$0vtUt<9dC0w9*wuCDY)iWu*JIn zNKEB=^i7X6xn{Bt&`k8y_ay(Vr@mYKx1Jo}Fj=2Pd+>FH`_hB2sqRY;zNWh`9y*z? zeV|93Z15#5(X%$=))2BXz6BgBMI(gmkoo&AlUWnb@O}S<31-;&MTcbg!&79iL9Mgd zwN_TZAasbQHB!IKo;g|eSO)**l!>JXB?zQU0S;E~p>HIgDT9hrkBfs~ibB&8WgYGk zpjFMsm~I%Rh!GvF;f|s??AI!kS-<;&6YW)ztuRy#oy*gYK|-5V!O8MW--L@n<=V{m zT^63rbM1>07z{X}NWoY7IBoFo^OlaXV+|6{-+1}&@O=O%x6ZTnW!6Q4*ktC!{6wAn z7r*@c;eHsma0lYTN!*Y9HAFcn@4=oYNgFke^s$(d)t$Lhnc6Kk9;MInzE9~PpMmOr zdT_XloM52}Y)Fz2`rnMdn#1wud&zaIbG^!zI4VH2oatm7Vb9g<` zii>y;@;5lGh`1od-ItKI=VJb3+J?8Z@Wfp*yp~OuNRzLtC4`3c)f)EK@`pI#P0qgu zq>Q>*Oi5eI5X{s0mufPrv_N&~;vp??&Xi@?BJ6nMC1&n~sSPNT(&9&p+-<;VPPgPl z)r*xcxMDfQ%w)VjcxmL=2Dil4AKONAlVO#bEixT$!L~(u>Ei7He8?zC-v0Ge$2YMC|8{CSkCg}TumF&i;7ZNPv z?~CTdar13gUrNzILw-Nl#9=C^Hu;O>URI5&O$NV0*J<^%BF($NO2oo^V$9dfsWlh5 zIe5=x0zT&Umxlptd7(!xsHQ9kQXN8SIznhS5MuF{KHbr;ytt&s^Of3CWQ(ynF6Axw z1Vjlvn$Dnv?2Qapq8TCUy~fjf1$TYbxc&5vaJ$=ad)7^G`y^^X+-9Oj?dMAr*>e$p z676R_6;f#zthawrweTqA(M2+REy#-$%yUJrP|-cE=>On72)>rANEJ$BoUg)ob+iTB z!9F?1G$$#4vJbjRx7tH!I&A|GR^Ohmu(g3nHj@?)lEQiUAbq0D%PJSHR9-Y#5n#1XCY3-#?wGD$=rB+ z5!z##3;cW5BVex;7qjt#<#_XiaCzFJ-(bm*no97s*CvRg7B*R#YvAR}vmt z+3KsEO+Vy^2k9|O%#Tn$oc*a4G~Oi9I?ET5pwGy@8c%XkUKQ~H#x}leqf6gfR&wiQt z&raqKZaH47c^ilBLQCgo4)Pdfx03HqmhM=Om5`aTc^*Tf%#;mUw4a%Bn>Nj4rrfLz z3z;cjUuzHBc9fY?);5F8l)?ay*~RjZJqiJjT(LZCk1jdAbHxn})&w^<@#yHybjZfa zOfJkLGBdeskS2F6v9GTiq{%n0wXfUO+haqoJ#1SK7`9Rj7|yZBZS(AL^JVrpcS&Z- z+|`*W?Q1hrIODifFvz8{Am>UBozezFuC!UG&Mp;(^e7gz#4%UgtWBw4Y}-$ZT`l_J zFq~Xz+J4)#x8d#dC@2mVL&>Tu4&=(^X3N1CyUgZH)?oLwj-LvFeLBrdx_Hn=sd9l} zoRu-^+wEGh!UutyD>ZK1T5r#UMJ~Npb;6#B2Y+)c$9g2kPr0Q#E`~~}qpz@@2WBG*y0A{K!ZLoHT`F6yQo(YSH(Rdq1|`jv zyObH4dwFm!&Q1Da4j_<8VV&fgRa$AYOFiw&U!@CLjTsl@Ca_Aku!HpaXMSBB+rl?S zm|Rt4GNelm5}R0vW2eMHPx2@{C_quMC#u*k75m3mv6lRe%3j_u?9#YW!t6s&gxT4u zq7n^@XvqkHRBfkiI8S8S#VPOZ2qX!GN}r8`<>o+kEJhuz?8Btz?e`?A-8 z7-rK=?jetwdc{unxyC)#iXRlyA5W9@uV6t)Uw-j*dvYQ)eV{vW8$Owt=0=w4u*lV^ zo;1fHc~|X801)-i^(1V~Q@QzI&&=|fltELlfbzbN=_|ai+7*3Bc<9M>Hc&Xm%8q-U zHl?B!bOu+wCT-)9u%Yr93N(|l9u<{;#l$fvy+eq9v8;BQ51KQ}w;Gg!zUg$XnUKIL z+WcI%#H-0@DYyo5P2Cj#7^WCMS_-W*u`-%QOCclBQZ$d2!gJhA{a?`5Gd+v@f`Nye zL(A4qe>8j3-kF~EzIaX{2P;dW zxmb9YLaQX8nV?Vtl&Dq$lmei7lp1oGExoX~yRyYlF_;Y&Q!MPmGYQkeyA)alQ|3?z zQ;BL}n!!{mxCaIt0N)b>l*J+XEcE!~J zVg>L?o=Jcf-lfngfc*r80F|hgLZtwpdpLmdJ^50F|f~pi%%(4-^qPf!Z6Ubv9eL z{QiYW?sbUQ7WdlC>ttSCpZ#%nFjP0jEV%7MxE;&xA{Uy#+u016wyiFjfsu0ON@Z8x z1_xoYU~;H}N~mf!=?3#WI@(4A-W>?shRSTfSN@SsD!=%eahXCX=GurB##nDOK36O^ zP`Zx8D>U&kb1lg-%a5?cE~-o6xzYy9rRqBwE2!D5pkWFMxoOcg8c!+UrXJ5^nj4YB_WvJ}nC5?(jbtxQFELR$p0b)W_EV>32r2rK@B2?V|OU8`m^&vRB zp7k^6r}j`kG2n_;tgNr6m!78Ut?a>{NH5j!yIYVWe)sZaL_Ww%nn;W4QaD6ft~8PB zi3y3c=o%uG0wVQ@h)nW(jp8Fz*79Yj+{#ND6^rUpIH*{zG%Bl!2~n}=8dQ`5RP=~Y zNp=Qfa2plI`aXs_HA4LvjGoFGOtI0qy-08)5|{90B(CHoO`=70DI5|lSDM7jhzUuw z=o%800uuFzNKA73Y{f^Y%;U>Yxs;bQDi+nHa8R*aX;kJA6QW|#HK-^BsOS-)@-n$C z12%XR>$ry7d%@_+VQ%Ox9XQ#5m=2ukUZn%4yH}Yot-MMf&*qub#}?kD&?M$!V7z;%!&sMJtkKq?QgY@$@W+|0#Rk2yB5Ma^hS=)GIL8m=NO14hX0D6Lh1JhXZFYQy%gH- zn!FZayOAE_Gcr{r^%Q3yExlKcIDF)*j|RbO z`Ca+@ojWi1!_J*w<9GG&&Yf$R1eXioyBH0B+J(PoMjZTkELi&Q;_?1xUw#=sVu|TG zc<>kCm+*LA;^8Z-8jqvk&wR?(Lgg^-YJ^qq3fJ=~|9&cKSMKJQ`SZ@5M-q2EzfZvL z|KNA*Gdp*lMfv^wzDGU$;eYY>W)JIX|2(A*>@aRDydEOoovZ>qXovefk$4ZolFzUB z_=Smdf92ig>;FGGzcPX>VknO1R=D=diWxAg}oP@7=6mkSl$kS|wioNMI+ zB6V)Mjr^hsmXAK{y!%TiHL;#+n9BvU(1Yb;k#}DXcPXJV;bj&lus?NnnN>ZS26>9b zfJyZQ@;fUhQKUP;$Pa}q^hiS4w>QAYm6_#=F|~;g564(Tx6;U=$2)dqf3$#t$;@#5 zM{D)`dz&p6)5@0V4ccScmvM*Mn9kM>q=@ou&VevyyG2YrK z`{yiSmgjVId+>n~mJpWM@l#A5jydhqw(8<-BCP z2+3C7A4g@!A$+mMqLVfMB8FrOhjOL;a>a*Olu8eMLg$30N=qUUbkt8o z8jOg+ryjldar1Pq{PMtr)16!3wDE zEVW<9)#}gx5zA6REB0wFWjoxdgmXJMl5lq8Kq?tbvJL2+4V{ILlfkXp&oAzHZRWaO z7qr46v~ujT0y00_!D6V_X8ak&9r<3gREL7^Yik@prY0Q@M5`q#y;!)IOa#uzcDQ@$ zcrO+{OrSq&m$dpSxrAMMKkEJ|1EslZ^8eXjTMRSV2RLhU4OE^@B*Vwm!O*|a)?_QY zAdVBwF3E2;$;gx)^FlGnFJ2M}#}b$ch6qKovH5s?8mcq0OEN2MDVBW}Z5qjAxWs*x zEX+~XmyL_!QY_>}UbUlo565=TF0tA)xU1Bx!MK;^h06|6FSW08$8iSJvB8wp-!}0e zDH|%^p}rXa7*m&2)Cc4juc3JDVyZ3&pU|4%8BXk|Ddj>+iA9qNU%g~Hg`8BU5JfV! zXbAqfUO@*?kW%;&#p=p>VdNRTN=t|xtzk%89SF0!rxF^RTCe=OiE$MmijDP^?*Sr4 z9#LdraBH1%5o|AeYajsG3;tuI4lm9jYh`0trjv#-YUP{t%Fqr3s}&9jbG5>WiLi!1 z4vwBf;V8G^8|p0~utW|_ut4xH3xWfp&E-}xb@F5_6!n6D3GoyK&sI z9ddBax*w2RGX=3cv%(cS!J}EZ)un9Q@cgk2)tD)fs-$uie?o%no(9U^w?vK*h5^XW zOe9;SNmo|NYwb?bB=Ij$}D>;Q40Moq0eN_F+mjeCUbsbl_rAXR7F>` zFU@#Qo_#-Od73S)(PU@&DrR0H=9$cgw$_%2dEiR?L0BTBQIRXbC*pi8N@7udvvDU} zLR%I>Ht#&&^gbK8T~85aFTa^g&ONXi-PwumT*9zIEg{(XtX8y}^P+ME9Cnu*TRBn) z_F{B8pmbdF`aoL5pvywM6{wG(w2!6O_mix+7Qtr|s7O6sm5+hY#}Wwrj*ftgWnVz! zVHB8|{O~iG4-Pz&%N(&ScPF^$-;&%>{R%O8&t*_H%Mh+l$_Z(6y`D8#W6y5$!5XDG}*~;GSi`I%x_kv z31*!rbcMyqIw`2I`Bppz$^>`tmjh>FVZdBGmdX(QPL3QiOk6VMe^uEg#UD2)ilcA7 zz>zPOr0Bsm$rQ3gI=dy3JI|3+TF06+IBVLUqtwdmQ6Q8XfAMqAG2!AlrdQ)wZwSeA zOc++CD0aTlm1Kc38HSeI#lwPL-zwqV9<))otyW1dz(Oo+ncU&l$eCkQ(HfEhQYm~0 z0Z^~VYpt4}e<3&j$5iy>5N&ln9&NoE+G~9dPJ*|rNA>16s|f1&CDpN=?v&rG^sbH- zy29dA$14f<88WNJXpv72$136j@YXen&Sguaj*_`xDvN^3-U$`QjZEFJUi&)i7%KT;_ zj2YO@hpgx-y~=eeN)W8Y=asN1ot}L)19eA-36hYBZ4a+(4a3Z;Q|cG*&A@loD_uK? zs!Ffi3J5FsWtQFo*kC(;-x}QCKT7ElL;PyT(HL@dy+Ru))MF;af{l7=eY&ePkTX_? zf@ABI`aL`=m2XpC*biPUOT+9eH>}i#sycNytNSe?|7l#`HROLlWfF@3sQr(HXy@hWX$(^<+L!O-_-{x+YrWz&qJT=SHK+?$K_&rF7d}l1B;7VZwlULvg$&6q zv=wjeJzIx0j14SZ(7&S&b52MpzUiZJS0-<;yj}r+C8jcJzQdL8z4h{`c_vvWT`^YG zm@W}(^pbN`vo?4Z-*Qcbe?&z~h?3>I##tVsaK-%1u5)+R&gUFsJ`j@i=)QHqxAw42 zV7)jmnsbL|d-2BEfygUmyP8|ByeDtb(fN}aGAktsV0kA6UwL?YzfQ`R8pc684#!4z zl3#x*>*z}3KSRV&Uxz+|{?M&U@3*+0mEN~xR=vSMPBO3Uw=yfS@F?@{8QDp)bh6)C zk^L6QR%CBcFKEVtugPI3!8PYj3iY0apI1^+@gik4R8E2YU@7&T?WbrvT>tLMXF=5P zG&fK$$lRP+mPF>J8f0!-k-dpzE3!97$eaZP*qTB{6>@5^_f!B`1ydMex-nBu;`YrN+`hRY`_0bmjVrP@M!1c^s0~3KM!B&ojAF1~#i*2< za~>0p$^97E-;GDGMWDF&MMe-D#Uv%|?P zKIY$7!VyLBhvM8|JUilQ$HEunGFSAb1{8#Rtk;tJG85+y5VG%0femjcl97j;u);?W za+$;C^7_GTF;q9~kswl&c#Um+F*PhyeS4i6wN!srMPK$w(l-S18`Ye`^a3$>vG2n{ ziKyI32g1!XB;*<%j#YYLwX2Jc4TO+jDER3Lg>b<6I|vC*{gC;_7vmMS3lrr`=RJ7% zyrggZqaxfA2fuvF94zUD@l3ccp)@Bg;1Fo5c&bNRgn(0f)-N4R7|ih zXz9M`xkRu;b%Cvd2o`9+=aUi;OWaA~8a`hGREoX)JvDqzZn(4lsebs*4qyq5i!RJN%fW!C!gA%XQ4nh_{@DIr!9spXl_A%uHRt@J~ zNHshxo|PxA;63<0)e~HHJLpCCi{}Zaj5kw3oZA2z!ZFby`~9r`d|A$G;6xhaM#rTL zQL=V04f^MRJ*D}}%paBK4&JHy3NAMZiG15HDtBccqJrIR1yC%27V`{wxb{*zt2uVS zDTTJ;HuSeZwq-9WHunc8B%z5m?ab*jQZu={d`Sh|1i!Q!@~?higm z2hP-Oeq?9pXE#dhI3niCirITD*AB~dZ%)dIBaeV*tuvDy2)=;^G!x4#aSo1I!U{mo z5Yq%!z;7vl7g#XuiTO-gN``{>{Y;aVOi-7n-KW4mD{vNp201>&GV%wn7awSZjW-pe ziL&D24z}?vf=_*gPl;RnD-l*+*cnViAX!LFNPe@$WeQ)Qh?0E-d*WI!&IxmunZY#k zE@;G*U5$%T>GwSG^x`ne{J8aal+>;xdAO1^2jY&tE{cJzchUE8Dxt z7Hgjm1CSi|k)!f8rOIy>0aRkA1kNJ^`D6l+&vbcy zvjX{=L;36lR9x_rA80DbPYqduV4H$Uo6lAW+_mPe9&ZEXO*$wuxZ!clylV1DNNKuM z7F_t*$9w!`lhW`J{d$%$?62oT`2-VsByJ!bS=wM6@{vEVNaG07b~Z?EQXd>VB3etv7Q$N< zexSndBHW~x`^!MU&2S-jhcB;Z!JjD{qe+Zez)IgRAKLHD=qonIMk;hzvj`|I>8*16 zh|T8B>Xu#&9{au&*t6U>*${TVRr(Np9G3?I%p!7%#IXO1HZ0E_?zv*Y_$9%Qm`ST! zR?0q8|BCwc$1jz#&vIp|Ilhb!kpZ*)QsFF6x;qQgdU~*GshZrAXa`_!4~~LupV;V9OJp0{bV>*R!n#Ol%N5Q9Ewr?w&og`eI_*!Lq z>3vC&QnyQv&yoZClaGc<7k^B1k6h|cgl`ev1tOS!J^3GLEMfK-qm}fdX zKG6kHgR~qJxL6#DFD6VGDcr z=_Z^9or`e3&8VGt81KO&XV8wm_?=`6JCJbN%c-=8V1mmQe2{GB<>L+!-h=DN7I#;l zra*GMh8)PT;bV#`8>Fnb$U=(jIq4JGXB;;Mb*`3WX;^z&bDE)isbHV!Q2vr&x1?Y% zcd)-k;|trE_l6CE2*1my@B#1h2{33$Bb4v9lXxH z0I4*Cz?9a=9K-Ly4}hO_ukeQVUsNcY^Rbf zW@(Waa@%r$R`K@kpl0*D~12V>yr4dA{_iX zRS##lY;RV!Pq}RGQMM)g(#=wQoxDkjbi#;vAN<&uhW;{nyx74zUhr;l@V?A@FboTV@72-?*j4eD3`5K+5XvOJ5Sl}BwNg(5;5dBCV}Sd1Xb7YHMql~8oq^(xQ3U5K`f4U zwHtG;J{zdA+NsV8@4-nzcJ~yrj}s2)J7HVU;j*2rZ2#i2{fn~glR{SPAjfiYgghO) zI>Yg$#;<98gjqw!O6L=)rQI9~KRF8&o^~jlA{2`7G3J-A*6|4xHfkEhG|P6cS+Hyw z4i5!~de#)wm#ZtwkBs+~`lZ>%r;7w_hlBR-ya%rXTJZSI$x3~YaH#%*IQT)AZK|^U z-evoyvTXu)EVZ5!N#W_RDZNn0r&Q68=gWVDBSrfBG&X@;k~l-eo&b+0G+dTnS!x zJ`M>XwktzTZ;G94 ze_=oH%_R0eB^+Fqt9nj%*$!1Ue{=a7WqTZ|V(dQyJaWt>M_36p8beN=q`#W;gG_Uk z8sGlegtuXd_cj!}G%$=t?gbhu8 zZMH$BhE!b$$j)FQEbvF2Y`#<-Xr`csP_mC;#*AcVIx}ay-2V)iGQ;umcHV=3g;_zz zHka<^EtwHJ~yqca1PQ4zX<;zt_Y0-4@*;SIkJ;;@}eBJrid&@0r zB^^w1%?hl+4Q;eI&A z5>&$@{!`70$bPf=0lQ-qx%vyWVMofx-OqT2-s&$UWHslkBveFr#CVa7N`Cg5 zXD`z28-nLWOn_!r5kt#R4HV%2_BUasVdbO_sr?sp+WF*h(Qd3*D z+k%a97Pi9vx|6>hy>@wZcvZc`UcJsKLRZeo;KF+hUBJOY&Vlq?7NKucqMs{Kt4p-T zCz61=26W3mf|@?!2Bi1NMyl83Ybold@1iK(T^{^-oAGQ7f!h@Lv;v0+tXT5Ai80ev z@DK;4p;OF_Pm7L~UiGJsa#UXo&3*1}ZjQ*`-^7u+;px~G^2_HHvPQ`@r=?cZt&n9d zWW+8c>p03|Kuru#EQ@!-yFo_6dnAP0NN#@Xbkf9{z#74EzAR#ou-GX{a9p);MCCOK z@hYmaHy;(7(sDXuP)PaPyj}|?z8iMI=nvNwKmH}pe7n!ce7Xotn5fwjnRhB!Zz)|= zDL3B5FzjpyHg-A3Xq0jOoJr<72`*3Mp_8VcV^2+K?&=;1UGVxZ)7H-rlR_F!)`vsC z)6jRfZ(w{kxvGU*6my8W7xlT$L)crTNGU|6^kPh^XTa#wo}+%a`kOkxZu*w{`8~le z;P*TKegkQ5t&_f98UGhnpSSh+^5kE3?!27(I2=BQ@s}pv!?3^S`CZEWd-DBH<#|7J z#1?$yFQ@C#8Zia{POG`s=?Iq;AE9O~1Rwj8zB!4zIIGoZeK!H*9NzUtGk*NiV&%KV zGRZ7+T|)r089sr40?IOs2MD1 zf00~FY`mVQICq2`Bf`n<9K?cQ;e@iOAdky{Tvfq-nSyquIzz#2FCU--nHs9nyYZEWbNa zmY-0yi`om?NoPg5E8pJ5XYhmRHWqAaV=VZ7#g`}kBk#eC;|Mn@trr}gjoq=Og#MRCp|IoWT--*ErY=3$a}|ITK^XFCCod0BI*{Yh?V96mL_wZ$!838s9+I|U%Fp>m82wEu^_cLA@ns`CF+ zS}-6?;!mnoQOj*C6toCvu^>S?dO)J}5(gcXYQ1prQg!Oo(O_#5?BVo46{>YWjf&dQ zDp9EfBqhO00-{DmjWg9bAfx+e2czN;l#$=(yVic+^Ss{SZ8@&!aDM-2Wil_cF{l#^Pf8^_!Yt zoW`Hphtq8Q+K;Z*RDta+M(C1ogS}6r??2(a+`Fs1cEUEwoPCdq@8M1m0x$9w!_+g3 zH5WVw@?xibi07~h^1_ohE65UQF)mmSi^;HX6XoF7tuQfs(7_xbFjsi?3k2qIxmLy{ zxGSkqYo{5$+REU*TsX$HI?Pv`fJaAXd(9>(w}XJZ{QC zf>ti-yL~};zBiE+oMS0I6E<$08Tctr<=#Ev$7r@qV2>xk@JM;WD)2ZFa^GWZH8eaA zb_yYF2c+C~YNa!JSh!|8&>zHfvha9S`6|3prY`BMFGqxm3+9{Nw<*!1O!c!c?us}>Y zh`V?W*8-xhPj4lM8pl#2-ZWbKhzc7$#vU1r@Xse2Jr@bs-45(Z0ef8z*qa>KPwAor zn9L&2FwOT>)J{=tpUEDhN4a&1Ibkl!ClFKC9T;|Do`0>qAs-JoYil2S!+2z-M31Y)Gb7JkgAO zzyneU%ev)uA#ZpR;;6Ec>NUT%-bAN-Ah*z2F1i@+7pUz28Md{xj9@I-i~-#&(rK6hV-B7S{ll2eWO2OBF6m$eWAVM1IKzgdk_!N z7XbB$j>OPd8G~6N{EhN$4oBPCYtzmlO0ClkQyx>nL0XwDR&1|L)XQ~d%N29wI%|XV za*ML%%)TUOnLDnlm(x(0;$5DDx45>lUT#UY+_GG`B{lhLuu1K}A*#bucqDCZHbf_$ zvfaHC-iO*%Xiv`B)8?klw~(qi5)t2rhWLkBw13ioPX1y3n)OY-8aji-wdXfTMS1!E zdVbt5j6WLK-h~Wt@Qk#Q9dvd=UVZkj4XI=i3^38ky6Qgm>T@3M3-S%V)8RBJqm5Vi zFZIt|WH~dtXq)%vblH5M1wF6AHUd3~Mp)>_=#g#7l5<=_X&G4|LMXkw_MH!lnwIzf zM84d~91yt3rc}H?@H6#v@&1|~4^8H* zi!JZu$B$%9?%mHM!lz}1@Ut%_1ITRcAs~3Ria%b(zx$=6cseR4`+pL75LN2Fa3U8p zK;{(J@);u-8F#);KvrJDh;KvWfxPN^zllyAHs&`-eosX{cdWTgzkCKR({o9{h3o## zv)jVc@IJ%6eeS?^GZid^_?gVY?@<|^qO@1R8Aa>D2q6WeKT2gIq;ISzW0K)=92 z|L)s>zH@2TwOdaP&|U?db8L{zuaDBAk%$SpEDg{Nl4LZuAjD1uGr=A($V*887suo zP+OJwxR>x*g(g|VL{x((9vO=pKTw$yy^A%zJH58;V>WtwQhMDA?Ag#rZ)1tuy@b&_ zaGfx~UZVNm zdZ|yMHshotv2R4Y!wFvP?W*=+ul8|OyMb!;Sx=PllcgqywiPt5Iro+eg1Eu2w&st!} zhH|k;l^|t5PtjOatn}_;?7Dv$V;8Js|Lg56 zX4&-1bE;|1DayI03CeNxlm$(2uSskFiA^50PwuVkd(yJsRavR%tn|J(E&FMewOukF zJ<`S$G`9!r@0}_3{mXMU$`oYa4qk%v<{%rA>nCfB4! z9358=)IH5Hy-k>GZLG5J7M{cPM`0e`_1;soNpqKib=}p(fV_fy&>juiFnxp(x=huN zb3*%6eI3=C49M@HUQukw_T^U%Io-%C5|tMQnTc@E1-Pz92&g-_k996q5juQnNuddl zEztkT^Rx=6b-pQI&^IAcQLXa{t)4UEj!(^_JRd@1ONHxdoe3xj`OJGPv0S*02q6o& z#5dngewg88FZMSte=6;Mp0~Tqb65{M!|7D2+uL5!Vb_0%p<`Zco~qdtm(7%_b{5r| z*tLrqDZ5O-;|hRjoSUiSV@jPUYe5|L_k0tlypuV~3;0KP#s2+*U;Wd!7zf7ZC-D1| z_?(pc%Ws`$|C_wHgueM6eev~7AN^0@Q{OkjksLI|?_#{5zLusC9FlD+l3BhYSrZcf zq*X3wZhpa%gne9|oxemcC9aW4ThKb*h_m#c8{e29cJX>ve9fq2+%mv~0_{70-6?I! zmH|(BIVl2{p>SUdY@IFlD^~VD{#{vrxw3z6?!9kMSM;A_6U{Eqdy=XB*N;Vi<>h0S zuNz}dPi;+4%u8*ff5?QX|caA%Ay` zsLpB~yAnVkm)8$&*nF5V{On_3xRzRA_-lC%i|B~D!PJry48MY2sQuBH!uC4(G+~g1 zDt1@bgApXQ)po0ld*HU1cC2H$X9-x$E2u2|6VKr*Pt0Q3&%5<_VKE=u*ewP!ZtyJ+ zT{`a|llDo%R(#PmpYP*WPlua6wO`g3jVqy)L6TVnTuog*G{$jb&Ua68AoRSoCg_x! zV-N93ClLa=B^$KP%IBM49NH($I8K5z6G9*sJX z%nasK)j=X9eGo=&p?fL^`xEFGLI2))=+q}@ug}`-DN(x!j%W) ztqa-(2?3;=Q!(yp8Smb(XT69?wnxN>@pwV|21Vm^lxv#Oz`MAClML~0n0y|sxkK@U zkTfA?s@xFec%@vqdx$NI?S6)owgMKmCiUtC%4Z>@c&2v4>{foad3}KzBtj9lPi&5} zz<T%%@Ee|}T+zN=KOC*a=0qV_~|1E|`z0(lszqcs!8=An}jJ`u0iE+lxzWwn-A?sTZ*oX%f%K zTkM@}{7%-+6-t4St%wKv*erXpW?y|sKDASEn%xDprAc8ECC#g*AT`cYrhqqLpfdZ6 zA22>MQhbgs67mF?ro~evAWtF`ewwK9yRVM;tUx;EQ@s~+w!)5DHxu=GpU?wRQivqT z4-kpndPZ2=Yi@&49-l@{*3NQ>buw+|3tr768F8nmNtZxQ+MR&PgfH&6S*It(!7@p) z8GdKjR=A!*S`T{y_TYo~!aMnQ7u~LZyW>BO4|-^je>d~*yYb&w_)W_F<@f&$Ug)#_ z=l&P^<+t>``fz)u@B4Xfny+x42maoz7<|Ns;J_nfCVjWSKKAdOhnOL8(`Zx|(icn@ zw0>(AGCOlQ*-KKwwr2nENd%I%k``{?Lg0ke45CY;O8lr2caYe;{BmX*566FoR{P$l z|1%Cb2E#uR-{LH2WAf?*LZ}go888#T`++v#^rza10;k)@R0d}$t&>{!Z(eBDUF{}2 zmOxF@r??}=^5rH$20pbjwFUndo4?XL-+QN%ALo0oN#8WzTN&SCOV3DN)2>i=$aGZI zfb4jd>^-b9(`%=i_+Jf&b2W7%&-3eRtWVzDsp6HB7e0}$dK=H-S0A##SJlUoWL;8F zYrj=lx;7ke#eO_6Sd`)=F^79j6-eJY3`l>+dlwGHh!~TnL<6Vlq2?>u9?fB?> zYDA30gAiLI@3Qj)m)CSX^RsB7%R>BqZRAba`Lbl&53j(R$$DrW50_t*mdIw;zdv(% zqQB^s&@e&sft_AC2_a5B!OZ&RKH-DCMJ%59I}?zHCi?i|=KY)DlL@^RB>85ie^V}j zEu(MECGbg{*23yl+B^C+nX4xp*wMctmvE3zW786&e=y97qo--%5dTo3W`TjdhWI>^ z5&NU^#%zDs`E&QtBjKl*Qw0uoyhy(ak~e=*=-Z<(Xsdgs%bZYmJ_Lo6-e5D3kPgwl zbe8B>`n_mBlU!mMIuzjXs<-luggfb_`^vrd1+6jDVeuqW+i>LjoC(8Z)+^~AoB*A> zq^-Fbrrp;!`crkr`!!9AJfhGk9sL=mk??xoSY{=nRGT}PBv6~V#DnrLGUG!cvn*q& zK-ltz%olyykfyaMn6f8yoG-z{IwdpRm%mgqT?F;=qXZh+yax@jNJTn(6l20$C>RNc z_l>KM_3=US-#`ytr8)5j1m=&gpN+H|;dhR-ufHTAtr$r=DGNmP-G0bR$Hy+Ue>NRuhc=7(2V=@2D@j1z zzD4zV0_v7ah}v~quF&~8$pOp-9sLS)*0k+F-D~HKVj%q+r?_jF#V3+{xvIWIWv({K z|D`XJrqccRDCk3pt6g8QILqiM)G;Tnwyh%W^UIw&c;LwX6Yj8WE8bs{H7NgIi1!v8 zT^#?HrEePl;{SiFP2}p*R31Q8-*!X5o(q=p&-O z3l=o_U(r@Hx99$;Op9u$O2jYrNFVQZSyeT7g=bz$)r1a!mxi&`h4 zJkXQWYG|MLhwF~$3@>u{>cdv?*X;Nan+I?BI#OC+4QISE!BbbL#Ga@>>+NgcP57~P z1zNkZ<&ny@LHi%IJv9bFYKiYW5~1XcB0|V?X8t{94RSK_q$Zq6*V)-O#nP5_Qf!lq_~;o8G{ih> zU^@parnM4klFF8`cbXLbZ{6d5qHf9VvWYaEZ{&GKBTb%XG$8=>S}9Gjvi(TRV`R`> zq->b5$$?JSpU>6!H8*{HQVV_D*u;Nk+NDaDT6O}QVJX**b;1nw(}+Nd-NjF&2! ziUZevw3;vn+UFW9rD^!T4=B-y6MRQOT1M(l83J5MA!v9z!n_i> zNlQ(|QVcl})D)!_Q))@3l)M_jV(f^e_<8#>N-ejXJ{tijq4te-sjVVjBfy^8$#B-1 z*Z=W+D@Gk^y%nRe6{;(Pp84i(b-wCwB&gmvRM#8VqViwoD-XrW^)?SBZEl#K6K9=fe#AV@|Z_kF-m3cSm~B>OYD?$M>IiT-KX z?*B1*p77tKhx6=cUd|;xn&pu-`e_LiKr{p?)jYOE zC-;rHV;U{z7PeRbFx%aJ4u3o;KZ_&n^j0j0l>5N8#Ri%@RLd!kSk6A7c1C_+cMwXy z#<8@;{Fppc8%N4^xnGVSEooh3Pz~a8HM_KBS##?xr)(EMwuT6hYUJ>uyv%nkt|M6D z2o^g6WGWH+9hOrbv79U;QnAgl*GWz!%x)ru?9OJWi!8}*kj#^(ZcIQH?7E=+hEC(#7JYqTff|_W?VwVJcY6{S5Gf>MZk62DipmYI5 zm}V@_TZ07062~#+I3^uO#w_fxobrg}WO3}(I7G@P9O`H@RLd!kSk6A7CS4bqJnT@1 znxR@wdBk$|2{jS3C=lBm>R>Ze%PEgo&OV{KI;6t8)uC=~hH5$G5zE;p)FpK#+vpJ2 zH$$|X@`&ZMgcuc4c5+GHPIfJ;BUtAM);NM{6d^=nhvi_1m6Ju#((pLRDI?BzsH>Wx zS`ManPEZr}CZ^Y+u55;St|g6F&OT{PL?H@T(V=!VL$w@CuX6SYH4)pW49gwrvSz53 zgZZ5k)WqUM#a-f17dJz-9Bl4fpeEK}nOlQJ4z#lwsO6MLET<&{5En$oEY7n0NRi-J z?l{^VN1Nlwno7&T04pbpqor9-*byn8VLOTpuzng0uqBOH&OV_gT^E@g9BQ>0s^wsT zm9tN%iI_!!m~yC-%}^}|n>#0{iAqG_op7k5%}^}|n>#0{iTXxG8+NEe%}^}|n>#0{ zZe~)Wu+5Z0?+(F0UJ}tqyT>Gepb5-p&d!8ai3W<@vF)%MqkxZ*(N<9SN2( z@u7EE4kow}Nz1`9VMb)}I)}QZ8LH)Acjp8(>9{Bk=R4F@%}^}|yE`YSiI7FnJ=dYG zY=&w%xV&?MnkYn6v!X-oYKCe#*xflnO_Vp9gyjx(Su<42!S2opYGP=j`C8&o7dJz- z9PI9_P>~m8#!O^a!!VqX9+50^B%O`~yK3GXm3LSUcDNBq%b_@7b7V-nLv3q@YB^Zm zIYCWCB6i*kA1TT5>L)*6u^e1qilu)MQEjV464ri|oW~i2fA)XV|r1PRkY;~xco1t0`#&}Lp6G4mOyV0SpZ-#0)Sl>B8 zO_U<4+B%22rWvZ`V0~wW8r4#rx3Xd2NJx)J&UYlM90_`y4jh()F>XZCa^OhV92s)1 zLtWVn)p9V#bApSFV` z4Q4Yz5=md;NESO1bR#vJmV<3>MAFg}B@BsdUgS_ao1t0`#&}Lplg^7G(e6;&nxR?_ z#&}k!QGCRZRSiZXAw43Q;iFR7X8kmH#g;T;Ia#i^G#Uw;BSV5itu{lo9Bi|4T0)Io zBGS)qP?-ctBz?+}OgfUR%2*Djx)Dh#h8clbli}4m-L65XxFMb$??cIk<&)rU5=Lzi zTKr4=I5A;=i6197t!5>@rD17D8Z(h^ixQXq{~AAD6q(WPVS)dl7;w(9w(XhI7!w3T270Qa%uou1=Ty9^x#md%}_0;MNBz` z3h7W`)0f65V$zq9^eIO&=}5BUu;sJ}DyQlK63WLgQk_@J)0>g%+ri@g@C|zci`(h? zU$V`w(T2x`I;}M)o3nhY8QAENwKT1FA~$HU#0f3_Nq%se+8MKa7h$pvuKkWS7L2kU zHk_FNQDf~WFo$z6fk*$_#-?-`YM&)jjtG4dEFz>4{Ja=){`dLT(g#^8_E|nl#p1L-{jRgpmSS_e zY*n;8VmWi6U=HO|4bfs(RzsH53F;Chr7g>ypeZucGcBO`wM=WP9RP3{SmWpL{vA2=Fw8aPB90l$Jj9AWGD40X})YxeW zC~NGN*9kJOptNNo?;OzWJ1nO>VmVoYQiIoEn)X?~nI&n*jJk_5+)Rb#lt(OQE>!HZ ze3pttJfa>BIThQQsj!^#h~>_jvSk7Fi*k}1H6|Q`#=&y1r&TXc`a>^r?GZ!l6P(C&OTJgvl|AeTh z2`inbq7#KRNCyGS!Cg>JmZ)?PXfW6NET3gf(m_#7x}1vT%~V(pKEhn7*k}1H6^XFM zSm`pSVo5U9spa4*G!m1V>ueJfM#m<0 zI@I=NsFuT+KP%LRL13Tdvs5HP7rVR7shG(xh#`DCEC(N9wgoZD>2fq(NuZnLr&B-Cn~FMmV-yoNK~qB4I(**@~KFk-z1Wz`-4u*RwpJa zik5?8&`3;16w^*!6GeE2pub}93fCwGpMDQi{7djAHx>L#@TR5ub|Oc7J2>V6n9{4N%ocQRz;R$SvymegBrTp?Lf%gOLZnBcVg%O|J{AJ&I^CXv4#Gb zefAKq`82}6U*d>95DIP^U?+G4v>r!!gtvMe1|I+Py-v?4PHFh=?ed!nL++ps7gyg_ z9J_0Nao&Uqd*VbcaiXvHPCg-iH4V}^Li#uiBK1)a-*IDQO5MN~s%@ll&Y`~jEDXX3 z{^=W^TeudRQbhereA?YRm_2pyNGm*4`>5$g_mJ0UhgLmuPz?>7_dRbWhiT|Mm;CWq zYtrxeTK7k59$Skl&jwiN{N^DX*>KuZzrUhwrwL$X;mJIQt+yWH=kKx--e$KLbN=q5 zCk_#MQBixDR#UvM!neNJs-vE6C6ewDcdE`PF(!5o&E$Kh@>+6x2Gu>Iw^{eZp4gV_ ziEZ9JL%GDE*4?wM-aWuhE@rfpL7q8>Yj;w_o(o&b&u)938T`njfGEi z^y_>JhafSSK@5gC1dTHxt{f%*(!wXUan-ziRO#oZ?l#HUUAuv<&WZ1={n~iG#8SX z4O4S|tk-C2mf^S0#nhyi5%CbuyHNY5lWz)>8NkgeMNZ}9jo)3-cB2k%3O_s3&K%)% z939YMr+P2F#f1Fzl-YT-m0$Q4p2JtakrnbbKmPft(um~Xk#1x-y!RqbEV1)~rtnRR zupZ#+ia-}v!nel^`T>Hz)S-6>dQU6ple;LatHUcN|L{AIe4HS>ppZH1&pb|zu!S(8tSbM8~WwNWQny(2At2Er|VSot@m<#py>cfHV} zOrbL<1kUQt1w4e|uhahkNUnUx%U`$1vnoGPL2iZWT7qn|g9!HUO=#^=4qz&rqld^* za%X%nsjtu`=f_CC!*AZ4FdLmJE~ae5@h<6npwslhPVDh!^%z3na}M7W^cpUm$@8uH zOJ~?we_0g1Tz@HsdoE0m?m6Y#^vx^P@N1t--#8Ji&L`1$A20XxrY(m@e%p!~YB$(D zQ*b_avq?$y4y5FDBDAvb0iMItkRChe+zjnSx z=0BbO6N@j5#l3SkP^UHrRErGNZFkQRl^6fVSlm%PMyU9g`4jJK6@7FE+-~R&zWhc= zI3y=CUtO8AS1jnC!F&9Xe&>rWyUel(cv1yRv1z%sZd$rDDo&R7PG-+Tln zi32}t7RkniGhZ>!&u}%+I{V49lY_1$HI!ayrMbrDy72uAMg9zEtjb#f-Pe0v!mxJ% zpP2F^XZvGXDYzIRdk}qOcStQ-_3*$`T>f34dsUNvS$bZTy!t`2R5h*TR|hM={R2>Q zW2Nkk11Cc`5|m!cK!;Yo`WyB0 zt)@@7t@Ir;^EzV9+#Z>&o@poy!Okc%t*ehE8U0(W{P1B@k2M5 zEG!>K7Ak6aW#Q|24j=e>Ru*K4kcIsaki;SWv9qb_<~km|$Q>GDUt5j-fQg(7TV6XA zzWzWwdo4S!`G|_CY}CJ4BfxWNt!WQ$kjfgTv(;9qhKjhDd1slE2a{A&g29g&)v2)N zZuxz8*4$rgRn7%y<4>)eUF8sOQC((7be)+!f9${2KTY=08*WaO)69Ib#Qee9Y@PGE zVe6c$zDeg?tA|)d5PbtZmUPbXZafk$%{bGTjUOyY(u{S}&7Q`QsfKnG z5_C+uNEk*|C&(6~CyFZyqaA&x@x~dox^87D_I9jxx?cw{l+N9lbSU@8Lnk;#L*{OR z^GW6bZKAdVb77T7n=0GXgqg%|A1WR`!MXI~?sh zaEN$%3QP^#a_Mr;N9RIXH{oX;Av z{v_SOQH-bk)%CA@X-ln_=^y{7 z)9Dhpbi)qbu~~lESmm^NWQ2RJ^F-*KPD!ZiljG09`(tN>cR>TZyT}MvK5TgZoWOfr z1H3W8JM&?~yD@=xTdbP2_mhHm-&Y@Qd;c+k_wELG8wBr~hYjx^5_rcnz+RD%G`2#WUg77)MUs`5{*6sNXKEL?xxv1)k5%W7Rp<4M z?pIu`GeK9Wu%sn?_T*%qs!JsX%n^D2SIxeypwLb^blA7`=W_kjK|8YcElyMizJ?=m zze@RxYf^G$zF0CzoAe+EMyGr7*0$r74@KMgc>cJ4 z4BiCtm?KSYd{nvnp1!*}h}~RzFqzt1tI!LXJ(C;TVKXfA@sEfeX8~jQYupc*oU|NI zWvUf?hDmdhX1kea5uaS;{kI3W3OVQpJ3bkIN8>M!tw1ri{^94_+AbQM4{z}1KYD{& zc>e>0_3SM$J>zYR5Z}BB?6}>A6GW%N#x=2adV z@f3H$tkQxb$1e@nUp$Y7F^^RcPXfi5xSV;il~-qb(x}Goq1t*E8_J9_R9Jh7@~(}i zU?HhsJ?2)cQs%(ng+CryA^+}m&rtNMY9e1T$d>}yBjXk&wy?1VcdiU740rU~X}diuhkqrb7$K_8J3hE*m6CFEGZQm(GVe#~% zqdZaQ(!%wrObN7!9l~fTIZ@jVET4pmClPjs-B6YIiI0LnD$Fn3>62|vYqzOBa}*tV zugh1Vfzg}k!@yA@paVuDQPpP8{F@Z6T|gPDfj#vYX>}(!+QOT*MU64Xw)92Q@aKFT z4ga{RR2JU;5)A*NuFY!r0rTuG@=Zf^$99!#Mm7BS79r}bveYs5i~Yj6O0Vnu6L_Uv zrNXZ9!X3be>t+c1dUv&TT*jQfZCLDFQP}0D#o3z_=KxYQXJ)~qFjOksft*Z{WIa*t z-nF#*4lKH^3M&!+YoEYuv9c}BVJc6?0h0$1LsyJ3B>Cx_G_+0jQc@amK;%L_Q;r8S-NC z=(=e;J}_InbZc0Tn82xIkR!sB-gnUT-`B^J5JkALZ+$djkv>kkK8|->{&=I>^l?)9 z82+%Qu8QNA7RFnt;-snKWbMnQiW=)&6%B01W!}FgtCOaK%$e-|QH_WuzYo^do5Uym zWja{?tTCyD4!)GawL_iKXsWq z3|!No5nY-co|%mYFtaSJ4Qem#hROoB2x6YG^a@$%J+`@?x2$8JJLYxl?3&j%b8bh! z$B9%~3F|rrmO4-9!L>lRb-!>ys|d>LD3t_StZ4W?OJCNjLZ8_96)MI*(UVGk99<+M zZY%!E3n+nwSHwv5_2bq6MNF5d>hY@H>6_)xF}i+o2czph@El%vtT}xQZU~02M_u(f zv-Z7|+4&wTzp$U@aO6K_t$lR!KmK_NC+ktis&tt+tUPu-6#K>(2ZP}gVHi)S)jJ?- zG%^$D>|90{w)+uZ@-Yim)#G#(1>{Tyi)gleKVaMea8!+y4M1jakL7d^ogWt zmN&Xcb!#`9{yVJlMjeQ4WchvqFo^7#uR!)QMD{nAM6&(fF#P29+N%YjA;g-eKV_v> zMovP)qvG(UR>k=MSJ0fKRuoUFr7VW=BB#7&S-6l^)z#y@*O+>|2FiAhsJ)eiooC?; zE%EhNF8ceVO9GQ3AU*BopqIu5M0r~l$8TzDTAYl{0}rSQX?^PsrUCLJ^>$I$ z!Sly7bKY$iRu3;GT`&A#5_Vfx1>$03zuXV5e(K9`wL@IJ`Djyr%$C&u*^~}ff7;r2 zF=ckjve3ROcn(K>CfmNK{-2=HiRJ32wo@i=<|up9V1PbYP+rYoRy}t2e#s4>S3S7g zYIt8CEUFfYs-OI|`Z{%yG{px>sdzA#H#j`9*G`vT*k1Z>-}t=J#qFirN{4RDnZOqD zV5w8D+Gzv%`ysGF-=dJ@#o{4}h1tzSA74pLpNB)_%!)IXb@X{ZxWXVZOV{oRucuU5 zF$&$|vrIqn#_9xVl>$w@AN{99_fRuJgypl_wJ3Bp%`7k2IE#I=yE%}wu0^#Q*-);xJuvTPNk#8RaQ{pUMO92YWTF?kyMw(vm+RohDfx9{Xc19`O7aM zmOocsWno_dwX1w8E0$61+NGn(sC1%1VpMv`*Nn1IE*{!<*PkpR4d&u9Q+<8xmChX? zBicUQyxbzb>-*{CUmNvZi(Ees>lk=F)ZV<=^ycJeLF|nMN%Y?wVR|;18D>u!v<5v! z4YJkk%ED844mZ)z`f5Scvu8>vlLp~g(ObJ|mKZ$=u~q4~8{*w&h)?x4SHsWXvOM={ zyLGvnKekP1s0wc%PE^2sAKB$DI)UfLK3gSy#?q-%4&!^HQt>c9*oUw=MEbcp0(i zc=CEcCjLrv2l99FM86VNb}=7vnaa3k=A%V>Pk!`I<6+%ekH-a=3QMkQF%z4| zZ%1r?tR__!9?o+Z_(WE0-b4<=PaCq7m}i7voi?SRn-x^98R)Cc)6})^R93#-_76Jn zkuL!JE(gAg=ddIP{2~YbX#_X{{t5$bOE=hR|Eh$Q;>qwrGJIl!`kQ;;UX#oTt(y-2 z{wW?jHWSlA_z7udC7FAq*DvP$`3-w)Xll)}$uM)j90Qx1Ep$Ya;bpdCVW17^t|dMj z-zw;xYYFV9R2YP&$#6{E++Z(<`OA>Kbok3QfNx6%l8-Z-kh#sKJ+HZ1&8ZJEF)w_W z2L&j~g>9)%YkLc;<(@mj))!|dOWjt9&@SVpe_Bs;!(RRlV#@>iyTUR$E??u#8}cvh zwJ&vdo`N=j*&W<8V0m%1RVL2Cp3?EM!B}cZifyf)WN@CJ49*ArVR>7*vIbnzzKW1S z{SfNn6fCvczMU1=3doPvH>++|SyIbZF-lsxm35=|V7Uh0<*>X!QJ3|7c2+vu7G$e* z(dNJm4tFx`%hqDi;x;V-#3J;fO7gbOXzd;3@QUzl3}B{1emh^CrG34frGYn7u3XVy zlBP~H(>18r3oR)Zcxu-V!-bC(2uDLJx6<#!b=JQ&k81#2F<3}+Knt^#PN5$k=mI6J z6D6>MQO{2ru(vM8TR%U&?5QgX>*HmK<8~whbswtrVur2uio)g$tER=OIE(|i3-dOh zG90M9R5ML5f7rLVAd<_< z@#uf!NchP|jC1E2gf0G~(nyafR9tf3Ot^v0E}$#iT~J;touO1`s&!%I#{_6hT2RSB zbIu?0J<_f5O9w2wWIycSqM;1?yP}n-xC>+|hnnu<3JsS2^MsK~3{#OyHti9)+-bzO zperoBI@7vH7GgZVox#2sWy0>?(Fz*v<3N^Dk!w$4pxdO@8@{o24drNfAJjf?p8bRvwagDz- zAmktVs5y&#>2}{v&n>lgMjKW>bt1f?f@LD++daw{eM1)@OA|{A3cxYseN=(e!YB)e zu-cYxJjh0LIkXoa=>fK6$42y*%{<)MQ8@=tRA$ozdo#*r4{2*p&^S0&{K4JDN7}ax zo=J7dD_pq4UZ?ns1Z!!1f-fQqMmZ`Os zg@52V-1_0H`!dfrJD;(&?qPh<3?A;#Vbjt}c(j7}Sbv<)>#f=`;L1#)H__Sj;!t*b z;t;ilNJPabQScI@jO4?(Cgu^?qJYm1pXTUBku>5LS3+ogP=B=NalapO;9goa^n4+D zX@^@M+GiahyeMDuC*;+V0y_cI7LNZ&}uWe<1`gCR*k9B=ZzDMGaD*W9k2~&9F=VJrDZa@|4 zXvZD+K>F5+=k;z!7-ejjjxcV#&XcEI^gfv+zrd5DpkA6JpG0!pZ!CqU1yX&qN|wMr z%0c^}4Cf&9P*$u_?`8HVC)=4~so&6xDiv8KFaYkUgZVQ8O95EzikY7OwH~;QDwb@? zW#%_ZHqOL#`Vp7BfuoyZyQ9iYdGbHSWLLRweb7|yJ)cD7HZ7ofW#LD84lli;h01;B z%DT!OOk=E5-@PrOF%^D~!&@qNS31121aE#0-Wws58OX&McsHpqy!8HblH+`&U6$;G z@0%MUZXpKul*FlF-)K2}!+`x*8y1QQ%AErd8~05g;F zAP06BQ5vnC3YPFuE$8I7IaE}hrEmlUsqdK#`;SE)n;m#7*`|}@g&}VpaS_|?G0fG} ztY-H0-o!%AvHJ-M<9f%n{ITgvVUS&^w-@i{qooyvZ5{nmqQ2fC=qh-FX~WuW;cFj? zEQ~{{Qu$|AVlsrtV7G;Lfdx9K-d1~k7RX(%b0gG$CaH>X17tHm0K|TBP5++!TVLYn zKf>x2a0TS?;_~>HcN_WL?7Nh$-R}aGwHuKij13>8%rz ztoR%Gvr5Dv53_+1IBSdjak>w;UhIt;{_D%Lq{*h&;?SoNt1i^@QH8pU$l)=NiT$v> z7Xt@6=+W?pn@m9`!%a1fXtEw!TidW}JteY(n)yeZze`6H%lm)!rf2gbZO8NVyNybI z3sGsyq|Ht%6a1W08W^>o$}m6U1Kaou+_v$7D|rHxW{GQJA}9H&s@wK&UlLoPhLSUt z=6p5D@wIO|g39ZBH0Ja_%j;CB!}%bp%Jry5R@uoaJ6UBTD}0ifWNBaz#cGGN8#d7% zF8ov^;S9iqH%EAYi;YHrJDLcHpk)jL-Z@Y})#US$DR=XbeA+|2u z*C%A#LC`m%zgX5+Q-*9Ibz?p{=$QLuyq#;tD?jlwyq#?Oe3(jVqgVQtyfou*+5W~B zt#I7xhA{DO;)Gr36po|6neA;PJxO|;C#}yU9pFjRO6s$Vv67MC%LhPopB=r0(S5Wv zVL-hMQ1z&-C4@_Epp++MJj=DJ8}BG8?@+txAEWRWH)e&mn{p<+Oif*qgEBG`j92DUYic#6n&PutKzxRRjM3M6+cZBg@> z0UEqFlz}sNm`Uz}v$7P+6GfX4sm^Taf+j;c--|!UksYCwx$}jNfV)3Gwxxg}C zuS~VO?2{ z@C%Twt|+@$>i@POH7lxS6SK37@=f1VM%mt2;?ef|>nsTwadLA6{vG>_>gMhV5NHw; z>odtWK(#mG>bo6GP0#qiRuF+Y;VKJ@1J{r=J}?+Fkc|luqX?y18Q+WL_OiW;KEjC_ zYV_aw;*kr!XL8<;D78E4tqww{z%U=Ovwr^(*olF@n(H#1q%-BBq~%3&;ZNyHEL&8Kg3QYR_qOBF})ARJAPx{2)@F+ptM z&ippUexf@gyJMXZ-I-63-R#ah*e}2;>!vokGhastiWR#uFueOncArOg=HGXlSXdvv zm_B6e-fUgw-p;cqrHksjQepQXqcBb zFD9YyaYy+q!LRlHsfMQGttYcCPf~afjS&hjJd})MP+~;4bY{XoW_9bm)QQEz&;G%4 zjO8R&p*5WHVF}a_k79rA9LjI7PHS>j&Y?_nR@AA#p?J<&DJs7}s&{(cSvgag?yRVC zUz4+<0_6eyWd+Ed^|v%2tY!P_7QwZ@?yNYAv(8HNQi_$zO6rCsk%vB?e={R&xuSuA zn0D%{4D&uda1(#Ugt9%YFvm6TtQ`C^L}hhF1zS2RmXSIudTVr6L~a9tA2`B0*$Mns zGJH7|X5R%U>#SVOy9lk1SaE=mv!eM!eNq*>*=GYIh-_VAUz=c}%p{e{J5)6+x-1s* zu~@k3W3faAx%MBs*tVfDHy)mC%%7ps28eW8gO;?_d@L3=8;kW2$KpXAy=Ahtl%P8294Zci zN~rgXkHvyxX%Z!OsNtHA#VW6+Bn?oJj>?NjiM_K|j-J0b%hB!BYDq?REcWiPUh>xD z#^Qz^YtO+yM|2ujY%CW0G#2Z(E^R&lQ8La;63$!aYAmiB6k0e+-SCc|AUM%Pf9*;0 z;KdNh`QfyS6o$p~wznEiEpx*z4V?_9Yk#QW)YoS=>{&@775_R`wDFXMvJzX8OMJAz zH+DpmCph3?G>IaQ7q*IgB5j(B5YOrNS6e=}M@2q+W1!GCh`jGTHab47%;@-fbcfOL z$%ix9e?)I~bbKSVne4y+V#Sj06R6r(Iz(P!(w5W)d79#Bta?CWgm==l^v6jsY9W=A z2#t0YUq(g};SFB)*Nopug!jJMS%#>0BHZ^wIN8_BXC6sJc9f{hR*%R&f;9%cWd^Ss z|4I~cQ-ock(K8X=`Gu^dxQguP=kdvv&9@%|ZPci$M)=`?m)_(u4FNx&f`GUb-Dek` zL(1V+$FD!vc5%POej+?0I>~MTpK7$k#cXX=@2(DaQd6IT4=}F-ZTD0?SkroS=jo7zBM;S+1H%EN4tmfDj^^M6?;qc5F`h_xY1d z>qy*s4qfKI#g$?IE9GMp0-L7=(;xN3BmMN4_oe+-TV=3m0x=|S!l$hmO-NISuBzf> z_;*49r|I0dj)9bDl?n@*iGIY~h+Y|qZV&4RQ=$d4k?7Z6TqpVq1PHCaH}nqw69Z;0 zW}z(twex{MrVbLz`2a^L^K>#-#K91Ac3k!-qe8DGyQ4nt@1)=&Lv6(?dgdcSzMR$8ofN}{-u^b&(^0Wd@#^k=&KP@9 zvF|Q+n^f(f0rnCUHrAeQIQsd>$iFUr;1ae&evhsV#RncO_1l_y8F13-34*HfcZtU@UO;-2xCtH=yn_Ny$M4GH)qfNtqT}Kn@JnFfUrIOnn*ed13 zZ7vBD4NH-Xaoc+XZU*1;dDj!{W4^50cG>F=> zM@256oCiHrHby**z*75o;U+{3>^H5TGb_tdkm~!JY%hn$H>|vpY$FGef7Wtus_lXd zqg>6XJ&oF-^k%3k@j2{k7$-<7Zb-?!T_O_e$M1v#_)w52Flx)Vz@z~6y63LT7ZRz z%{MLXsPq{9PEK+!&K5`01o$N_0jt&FvA~7xG6#svCm{taSUq9kyv)0ESR(nRS>;A7 z>O6vf9LP~xa8!8TF51G!DY!rl?J=~2e6kwR4jc#4z7hSUS+B_<^!CiwtoN|~+X{X~ zu)=9VVZhDSDXq3ef5709rsdSyp-B=A?(C=#DoJ6c{WX^cU-pf?Hu&1#)@j{WcYXS+ z^|EzIb9P~p!)joO+oRTiGcyf zN>+K|Odl)rrgMHOU*reqO zbjkY7HU(VvK3X!^ieP8k^y9{aw|46vMlFdqW)6pLIn3|7cmEPy@Vk4Bb_bqB4`vK_MQ|`m0&r%z zV%4KcZ)f@;m9G6gC2QBy>zOWb$1WjMle}bv^#xDfBH0t37s=M#yH55LZ)FX(_gHcR z*(;oE2fjlyD@?6}s|XHc3jkzW^+@)~-;HFylqN;x2gCV#`w+JEgxkugtvyp4#p0m& z?^wZlyg&i`rgE}}ZstdGh0muj!y<#>znC_5<3Y16!~qv8ZvRU^3b)5FpnKv^Z-qh@ z&_{q*=TPiV;b^Hb1@i1F7v^xe(JcMASg}zjye5b1Ry3&IoO1U~*_Qua_9 zdp7n0i~dqiD0Sa+rarJ@`bzg}S=SEO7Ul_Bl8}9w)>DAudxr0epJzduog=Y(Md7}V zisnNqA_sqUH>bPU241FDIx+W9pzXGHa9q!we1}iP+AYX}p=HBK?mVy!do~N0AMpU0 z)l&Cv$edDGAR$v9n^YllluqT)@;%`eOoPw3n7ko45AwIIwn5_BJ2k)K@-JHIol3QR zr+Ydoh^GQXwvHPQVrCg#pE2Y48Y%rWSrwezGQ*V4=r z{)6`R)%Hu9%r?K>p7etm+hutjM&d|)|GK-}duKR9bg`Sh@2+{sfj0Hyn)Kf3VWgv) zGY6Fkdx&o}XKqy{=85zD==%n+o8zf72_MDkdZ2BRH&_fGuj{CML0L4CecTuIT-P@5 zd&yTVM{2)*_b3sf^4jahe$mFY1gpPaEFb(mj@%p65ha<-dD+aZ^~{UbUN=9Rwb_m~ zu`xLI)$t;pzOuB&?%D{4HrBiAEEtbPVsid)x@!g#;Re>ehMo3}{e0u6&uZc}ecxIo zna*ylO25Z1ZrHP){w|jHf8IwP&i<->t{1-VwQ(qDS}%M}vjLY)JP11qN`{DCRYzSaxJ-s9BHvR?QO zvYXcn?;uXqV!g24aa&;ewo&z~2dR%IUV!JgS#~`pJ>HY1m6Ts2`~u?!r7WlALfmSJzg}4Uz*A8UipCc9hUs#B%jYy4$OuhG*O6zYa zZZX^c?#+2mw?kxj=7wDwhwyf1ZjiT|ocDUh-<b`0o*AKoVYjcG7% z`0F>Go38r&vzO@f5_kC9B7c*cL;1zw(t7#Nds@}kg+9585_O%N^vq$;?9XQsoT6;+ zC?d=%jK~_5JLSu3+b$!8w+yg82Zl>yAJ!}jhcepNap~9umzciZC3ToffHLSXU*<3e zGccd#Fb9FT7{6p$7`;3TvonQhD_YCNNMG2(VeRA%7pk3~ZE<0X-{MN%htIJ^u+DRA z5sVI0A1*$}eg@Ae+r0tc>{@wF>C~gnDgE71?Zwioj_N#zKa0*Oz3iyP#nPEaEg3)a zsAXD;3+3`Wtxp1j^S0YNomo8U3BK{EON~jQ@Yb_=OtOc=?PSM|hkm#gZKVZ>5u(Of z?4x1kF2q+T>}xNY)&t4ikZk!&!W8*OYDRY*T?TuTdE#LBD{(b9cia~KSdn*n9edp+ z&wqQyYtA^YasHv8O7DZEwKL`32g_?`f@Y!$3e~@-tmmJ|nMtklsoZxzQ_TnQ(hnaG z|0e}fKXJq7lLXzt)BWIB?a9YXKZy&3Y`3WI!`I$8_Tk&l z7Q1h;RMCBl+J|pH72T7_nm&J_0w-iWPsk5CIj|}wV$4)3T=>o?WoM8d-uxQw}kt$ga~JRejC?HWxDq$o;GjeQUTVw_{(ykJ?k&Kh3#2?@vr&2 z!8)>uxO2#g#HmA?h$|}JU0dbni91u7PMk8EiBkdgnDLiAX7;SV>@l-v{l(4YFEhd^ zetf5c0K#-7Fq9AT6aMY>&hSmoB@g}N+pi>q?8Qu@ut1&R@n07qNw=@U769A?g!n74 z(oYKn-jhJ4oba@lI+k?1o)Ry`8FW>Zg4Q|=U@{3&HR8c8AKjhdiEFZg@$&gQx*=Qt)6_3lR6o0QZisjGOY>I*F{$8*?Z*7=sJ!2hpa^$L zgV=gbYJT6`b5w#&{>n)A&FKxRnA_y$CMI8KcV;)qmJsI*+RovRx{4 zBCNl$OUa16l6I-evO;V>b<*CJn=hXXX?yR|`ZzT{un|~@5~|UkK5b2(u8dFg(;6P> zr{(;Fi}A5hHa+{t3n`cHp-bvq{``Ci_I8RX>^`tf4|a_&;&Lu|eIx5hLdTa&n)!rD z067`Oezy2ey_p*?&cc2n^{ttGBi4qFfj>KtNotpO2v@iynw$Qgk;OiA(w3SLP30V< zUS6sbULMQmPVzp~>Y8e$+VM@a!~2Hs4yfsTbUn6Ks=2C?sI>}pY1Tp5 zvSAyQZ9A|YYF9mIoU9teM3n>>-@Y@Pv_9JuT)fPf=x$Z=Er+UvqZx?IliTwp$+Db8 zcMtiH!=6tv!2AE(hE|hb%iOR_PBxR@KYf0=cAolw@q3QV5YX!U0_L>JN~7PJ@VK}7 zdwgOuFy{Ab9(2YFJf;7!s=!2dyiL*vh#7&XP2$#hvR;7{kAJu!)*JA8$>|86O28fA zrKg!E2E4^8{PWM#Hwz$JWoz#;$Q%o@^9y1x4@Y0igC7Pl6&Cr+sO3D;Uxw}F&u~+7 zRD1cYzc9xIz&-vlWG_GV7j{GSZcQAa@5^uTL(2XN0>f&VVm^n@o>`JRW8jnK==2Ud z`|iU8)$OwmeFoD|cney>1Eg|r$>fWKf)UB3&t0!xroC&c;kta@nFgRRkxo20BR#vz zRRAZ#Z(iw0H!X3NDwTgdfaGwIw_lJY>34}k!p>rBo7h?nPmP`4UqF;B<-zAGdIA4C zE3pUr#mM{sFWuWzvd-Y}Hbk@W*-C-RDnG{(9Qe*Snrs!;z5^F{0eFK8)<2EqpJ| ziM6Os^Mq)={?&7!c__3s(2OwYUUg`GOpaz9jFm9X%5Yy|mW($kzlmna!Gvf&Fh}#V zGQj9tdi? zJMDt*a=Hdxxjuq&)J0;66SYmuFrwN^*>)W$qBdcv49{_fXHA0Vi4l(y_?$qfmU+>w zVpHhG*QsODf})_1wKcr|Z#=7#r|nNK%+}cCHR`mzImh$2h(kAe+mbR{Lorw8EC(?t zq}IIK`m)VCwocPvxcB9ero$6{p^)4ck)vrwdYlqX^|tW5T!9}`fM$vy{?W_V=X!Zq z^{EyA9LE!-MW0GfU~5Jh&8NcH_AH(6&(&g_V13tj8+mM!dUi<4s9=SETjdSue~Ll( zy%BB^hQh@Avw)8g;HP@04f=ZU{YmX3^R>gp4`w^(H&m+KZbfgA(v{tzHEO=9wpNoykm|cKlFm72m<%wBi@Jc~lnu9|@ zEy82MpY+iz{R*&VI)XaDi_mxYc1VoCKXT_qorFJ8$m-Y~azli>>9lSZ{=3n6KUI&& z_tHW?Th(i4;^J80KDKXnRE{zPel8{?4TVn(WI+!mprs<=NNl{&_P@hwu{YkvD{Z17 zUk0WcPA7z>GL^$Ubu+0$;Rd*vVHzw249!uhF~~1It*IkpCkkJW=3x| zt@mzZywy}A4(YLJQ3B>k#vnm zWYs_0alcBVYWt_-@cOpT@{k-!_Bww-?kUpaFQfKS^cOmYoE828!!$no3&Oz5;r=p6 zLk1Hc;-8UI-r=bo&>6m{M(Mj6MsWD9aH}?b*WH|dQU%Pj8`fu^o#kl7^M=Fqud+gr zx^_A|9y^}t9&Muoz$AGg{P}sgymKs%j!44g9DkSfS_E)1oDyB7O?X)PNLIEu?0SyC zV$l8lMvOT39pg)Yi)t2OuNEsitnf!xWy#j&H4}vK!X`jzK$!^rU0x(N`uxNZt`x$T zIznzY8qvEW+=(MVb$UVryM^>YYUgr>yFZr|evS^Jq)tG#O^ZBY-}JSB9cl-~Bj+0_ zZc%|%4KL2^E?aB>VyPWoxMw)*?#*J6_L|~Gh3y_iagm0KmFMfRrG-tU!lv4R;Ogt$ zRM%O`m~%ZGew{N1p9i4vidIgBxBaa%Dbd;CoX#4IP+sX}5}n-&wMeUW4NA2Ajj_R_Ws)jFo z(zJIoS}P^ZZ&-=?+qb8yaWcd#W>P5P>6~Di0{kjc6g>?+%>S)Fbqt>8olagjh&Z!i3g~IO)--O+< z)cG$Az_>`{kH=r>nk{Mez=}$ zEm$%^vPd4)?|9)FWR#yl|GC-|xBAbO`T=D%Jnpn8MIxINYhC!c^h-UzW%Q_d9bX$Q z6|RIH?&auI#WEj3aRA(R=39*ret2p#jB5DATwq-4Fs8x>t?A75W(J*^&@vT%?Jtw` z;v}O}^j=U@#-sD@i&*2ggHHKbG1X^jhXFqBWj%piVSM4!Gri*MgEtng;QU}~2}#|P zx~b{vQBp50T#;U8M6dydB)hXH$G$wff9k;E>Ykg5kJKqF(~`5%xT%lrvt1pP6RaA# zzPfOYZOFf-T)1X_VXI8JoF}f9P#u;iZ9+9%Q`F34tG*jpHZArA7Y}R=*D+_e;rVd} z-0b(HGOmgl-rA>1(4g49EmW(x>^2UsN|UWoY=a{H?dYa*VUrP|)lRlGUKf6S2HA!w zVYO0!n5ITnPbl@~B-N3#$v$NlYrZT-7W;lVkDj7m*ml=_UAPQGBSfL+6y^&$(i)LJ z%bvGmc~=y+cWinj^zp1u-VU(G?Y3)fBiA+djV@prJi9Y_TSw&&6ylIRj*J}~n|ZQA z{2FZjPw~k8ihWhEgZU-xeZQJF_Qxmd!!9=c9nRUZSF6I+OS=aTpD1@Zw+I}Cm0!k}?%5aJPswIJ)64)<{KOWjU>F7ntsMmQlZ7{>|s zLZpOdYw>U$@Tb~Pa9wyOpv4ZQg&+OSd)xW?3ZONJ$3wOaBvnW8RCG!p4r-wk)1f~H z@ex2AFYwK&;hYM8jk$D{&YsGqh?LozM*GY5UKg;c1gx^qTU$k_A>TFwPsEdg?L~>o zgj*sLMsUM*ANJTspo5JVJbhaEWqaPOXEvXrY!ilI1@EdTerEUj#@7>V>o1@^H@o}S z?q80~6FgIiii>t5yw(8Nt|#|$(r?P~{gy~@-*d&n%q>w}ayZ@J?Ax;{XPjxiT_Wg= zqVi+VgXBo%E6o1Es1;lp(*O6?Qe#sPn_l(oR%|-Yj9P|GcCB^NEJp4uoA%l)uJ354 zb;&kT)wIuw*rVN6-(?Qt&8BFzLKmR21ADULvNyWEbH%B)Ut=3FY83SMKD!4&p*Y)# z&4!BIwQo2py+HiXkb6R03=t8wZugyvzi;;=0SOxDGSYjdmM-|9AM~0M)pLhb_zv4R zey6s;YbSZnXgu8cS0bd`y?ZHppgGrG5`tK8qgxuXQqc(x#^N04v?z8UQ#y*xl&Skv z?G;du92lNDdrIBgbz|K2QqLVu&HpqJm!ay30E_Jd>}HZOWIL!w8@t6;I%)yt z=EuM(deyz<1slBsna9R1Q$`ONo9RPB3a$8PJw)|8^Zn@KtoC|OczcI@;PN4oi_@)N z?<7t%d#ApbPOW{)tSNf=C5%!|saMV7kFG41ri&GQ$$Q9t7b?VmAdWqgHSD+ST&ZU? zj#8Ms(Hk|6g-`K^ZzJufS-YK*rvo}JL%-X?yG}7*@!GTS6)#iwRu*2*bNKVKvTo^x z6vbD3_o+Gv!j!-Ec#?`0&980bm;2dH>g3kY9#4kZKZ`zFnLs9sc1% z%k`~EeSdhok4N|Wm3r<;Z}Ndb|NivohGdQQy&@uGAgXqU?k0Tzp=7s4)p#?C$zs2< zhWVra*2A(%8YBn3uXi_r(N#QUYs$79iM2Mjj@zI%;4MJxkd4l7 zaD#-tsUGPX3hb*zN>Mc_SighhTmaRc;H*%!a`%-{OTDi0Sz5OrpP<)C1=_Ho{THtf zkj#f@}f>zba-CJ{L-RbswLMl?_81Rh2x#U&~P2SmpzKWl4HP>Rt zH901`3*u)T@B)MfC*N*UxPy&JKrWW|?|wtx zAZU)jnOMr?L>yi)3#%_Pvyk3p*k~UxcX-An0tK8mUpErfFmbtXFtdEx6+Fl(tP9|w z1h(8*;ZUq;AN$3;@a~gyBKkX;0pB!Tad*RQ!c{TZdmCkEL?8Rrshn!jZujh@hQ?iy zu|O90506#%D;~%PIf)s{=I%%CyjgQCXYB6f&2@3;t03jpAG?Q>$)GM5Klr!Bu^L%- zf%Gnr;_Y@%YhcLdg7hvx&ys67W7TCXsXA$PykzYKuX1O{tK5ipNlU!TX2(m`Uhpb+ zcD%}sco(*xe@Q8mUx%Uj+d;x;8pJIc$FLRcDBTO)a-c4+6!Lg z&W=~P5pR1-yo+bYOV(cSDtC6g$~C;Ef7n9o;BJIJnp`}}oNAdqA2z!_leHIpRxYH> zqR+~Olv}VAE%bTO?CmFOFYQb+Y@M`Vr039(JO<{f8~u4hqb=g;KARu;aH=TJI6JL!sR0Slg{ zNtXwyJ`$1ADmJN1gb9NG_*Xuo*2IVy#EQa1$7NbP4ga{*(EMNpXnyW!e#vtqe7GQ38h^X}S-brA_d1rStIqzQM zXg(q|hdY|D^BjHwPwQwR?_LX>mT6Xgn#kV`N ze9Oc;bN(%hDpQb7JMPqv@vX{6EPHr9b42`H1ef&^kG5!W$~<_~VTwEm;T*r$9AQ-_ zO1BpHZvNhRd~Q_b3lNT1DUF4<-{Ny?2XJ{E0OGw?T_oUNH2>W+3i;qDO0IK8HmczV zto_%~vnyOQO7ZyDgBY=Zxst?sk*DU1)FG8}kX%RaM9jR=e_{^-JVQqbc&7I)jVilg zeI1sG3tEqASeLrak|lZ{V{eSHZ~a4kk)oVcvUs|lGIOi$#j)qU!^EUcZ z!S51FJCrD|y(ZkSBv<)!R#_bmM{LDs!pd_13JV<9#AE(+NZRV|q52$q$gI~;?MHMl z2Rwmh!ma3(aP;JHJlAp1XTq_W!kde}5}F2 zM;>iqeXE7u;`NeDuoZ~&)%Cc@t}#q!Q+O~zAtET?|06x&L|^_-f(%L9=mBEEY%i;z zlxqG~f*rY7f#MAM|!sa|EyN~@qw&!r#PkJPU zUj%tV5=Q}%?HF)G3OwNIMnvAXj>vMnEp$+nsN)+cjiP5&GH{V0NeRh>vn?#Pz4i*C z4s=pi$K_i37a#nVYEz*Rjb@(2UMfq{j;R>9*scq+D(9Q5Y-g>nOl-HHRX%;migY6e z!~Bl&i>~nOs|PZcN+Mb5!;Y^WI#bQZ)4ny7MpV9_`6ceD;dJbx^ zMGHkO_hLa(>6Tq>w4n747ApuM0&2LZu`Nlko84WiQY^~RD0s|KJVd#L9w-T>Bw&>Q zQKD4cV#V1SAYzrMK!2a_nt3lf*&C{lfBc@O&3@l`*Q{ByX3bh_*4*Y#RPJdzIKrA2 zN@IN(YgMe-5>g%grm?Y6pT(E785YoOSQVKX+`;ty;BBLg zu|FuYI)I}!kl8^|lE*O`c?a`I=#=B*(tT?FsI~47uMbvG-bUn>NcjZ04aXmqegIp` z<^mdHd*}VBGXDU7bR;r($z7f!?vBrfCYcSJ;mr_U6zdp#ZwXc!@s1t65%=j3&hsEC zD?NrG2Q=J`_}iUnd+!@{Td>mHulPB!Zdnil8>7EwReJ+jQ>5dytZmrrI zvWMKc(h%{d1O2C{O;NU-l#K`E`T@g7HtFm^UMdim_V<^??VGy4J)y7YK1_?L*!F1Y zhhGr)T4Y@dQ%*M36zz?8mOns6?C&I%59aoIG|huMd?7`50TON@%zj-2tf|vMbD`H=>>+v}ga78l4Y_arA&n$} z6mgT?2tr`wA6A}E-1R#zF8X~sF9BjN%t4|DO_>jtXi4=`)xO6~ePso$5DCzbn?d`h zhZM{crQ4_J`P*m2ed?vqJaIgB|LgF)H{wsYjh&OnV;8={#uVQHXv>%7bQEU(if8w? zSEil)FsAs_LCKin%bqPL5I-JU@H>;WD&w&i`C?8|G1vNHE>f^Du zKN|_P#$$haEw%fmYWIAFokD7qvcs@BtSz${MVPSG^-{=BG{drbkB4KORrpgG*TFU~NB?8c#lS z7~J`(xO2_dCXXju4z#xaUx2ol!VwmJ2mse=}OK7P`aZemi9{*dbM3wR6i+wRC ztC;P+?ei+;>at=&+wVs)mB*9EnlfX#fsH5sHjkP;s+yhu^=jkE3nuoLz^`bCq>0D{ zn1y(S$j{4s?UXy`){R^4|%YTP|>B7u(MP}w_s;QqbLS?Ys z<=wwbtBc#hXV;*1lTMAP__$GFgTK-S1JkktymJHVPt;Mby9tGylEM!GjlPyaGBv`i zpkM%B=XsBGBS`0%Rv4FRw@~R^tv}a zlE&~LpMyHwX0o}h^kLLtsm^B`ac$~Seo5MhyU4$E8cWadFL=JmGVHbp9piX_x_xJ3 zI6tyDcee)f*Z&~h=icc{0W54d`e_+)NBhq`?m09)=(+^w&R`uwilYqxB^*_+&F}5U zC|7Q&#KBW{l-1uGHfm%mnv2H4*O!6Z=s`9C0@(6i6=Ak})^F07)_Smr(VN`Qf1dt) zj{mGG2uruyT=w}be4fw_ucIAs;)BMZ_U`lh%d=&8i2KYs&9GWx=!mivnwQZD#Vhw- zpiLf+g$-`rEYl<(o=X=$N*$*#^LC!yO)pDpk_!Q4DaGsllP-Q6&qh+a<*bVLx|y@nG=2G{M$^!1py`dCrh`S(E6Zs5l&9${{{c;8S6SXv zzXw~I5(Mw-MG+bHKd=ic9mTpJ?Zbz7Rt5ikJ4L7r=LYK`)-RV>**X%%{~&hrX%Op5 zn@nFvo~vr1Rg&%K%&ebCqF<79Bna6bvmMe#qXSqi-z1=Pa2)e-k4bP!8aY;rdQ z{#aEu5`v~@di-A#{ttWnFBbmC;bek8DC)C?f5K>DNYd**_jfCVTCz{z=w)Er{83fu zo@=D2xBEbI*m;}Ue;d~C%=if2)KsTvKAFUy|)cap($sPd9yqn_tvW?v-mZ>v_H?Gv^V+Ep5@uy2t$&J z2NoZy(ps%Fzes@K(8}gsTe!WQ#_k4ztxM{jvNrSG`VPOkjJ3-vIe?Rk5a>B9=IN>b zBCE&0dqw8E@o;`C;xLf8LD@A|5{%|dQhA-tSU_@fwEsFU({FLc$!ISVH_5;pK;Pe{ z*zxXRT{P#g-oQEAnH%Oc4`N5x|EB>GsUT{FSd!_6P^fQ%{SL4;_~mT4awgwtgWvP) zu7O(#SAsaqpkYcM5v|R{Y_{vL`OsJ2?&(>W>921;DS95PZ?|^--u_m`r7A-@mNME@ z#?h6^=%zVJQz;`d2;8l5!&)uYQ19)|=6;fGyN9LnE!}Hp)IkKN0@$K9Xi@ML(eooQ$eolXlS^VK=nO3HM();@pBfa zSm)KpY$L*&7i%%!KCE2kSNRO|N!7S+GE9oiOsYS%NYk2p_wgf(-{h8$QhSLKuXX4? zJy|eZKhyOVw!G+(Q+C_#-GhU6sl~Wkjh{@jC@vI7Sc1JR=ZAJy>~LRb5ICLQPoZ5_ zZ}RiDM&#!%Rk<+pY@XeVkgG%>gOch%dZQuFalVnDc>%_hC6DFIyz1-)bXv7SyjJ~T zB8wB*6|A1oo1A~GC7-f+%yuF8#J`3qjJ6>f_tZJ&Zx!8p&ofVX&{CKBmtLIXc%||E zSP?z~&@$$9)0fp+vHY-;C`|WR#8?AnfO}OH_wg41ZVABd%(`HJqU|U?{PP5|Lm;ly z94K)69_-;dUg4|J>;5q(q#~Hd-t)1dEI!?XZ-U+=n-Y5)44X`CWbjiGFBf5|l>UZ}!R-YDc%x zy3^LGlHT@4tLOds678?{SbGzp^;^CzM69J{=OZWfr#7#(4mTYKG0;G?C8 zEW&pRF3Y(Q8x-RXCBU$IjFW&2ig6GBFv(JZajPgK#W=-pv{wh6hZm2WF^oSUK$rn$=M2BXUMu>8OyXb0|gGvG`C={uP z;EY78qNBanky9=G;?K6^ih^A8SX=8eEbu;*qIr5{{dzCN&&XS5>rt-uokwNRUe81x zXzlQ2i-DvchCJhOo^hXNJXbr%@{GrMuD3i~a1iqBjPvaDd3NS%cOI#7cE))=WqHQp zJY#X5F`s8FSKDuS#^OAS$&=Ro(SCExZ?dI3U%Q5Eib>0HBAux+QzNzKg>-onr0)@> zzc-|-T+*jT>6wroSjJbetegP9|EN$qlZEKnIA%0YR1y~rL@8~LHfmlaJLLhNbu4=%*=GZ=rtF-3d(rd;3Z!`pXq)8D2G?y^;$)G~>tRA3G|w ze>6Xa3xFeLGY|4>c$vW(N>d#BAw6{JG53BRB%PTk;YDa$14;XCuQ6d8wJS!U!w-}+ z0LmXf=yZmgqIpgj5sxSmBpSe0nWoh17Y$(4zZRjNLP4 zXLcH~?LgK<`xA{`gMla+5vRR*R^B1J8Rhu}_OtSW>Dj)=rsAIdZ05q6+kY(Jv%Y#j zO=%fV{vMg?S*}x-`<3OU99dL_2zTM=%lWwZ0ew7%3Yc5rYmvCq(fDE#f8S!5B987E zi1%)k#u(#nf6@XAB9|+~wZ~!Ji&VBm&u#vE#JosDxw(mpsq;-w^ z4*ACh*c#J!msPEB^bcl$_i5pM)8!VJASR-wK2b?mPW3}ZV782_0)?3${~wM7cxi0~ zm;Z}<0vw$_aDbrcb^}c_BprIhT%&XOZw)_TyF)P6fb6yv;&VCrlH6J<@f zo$O!5D720d|DyY#b;dL}T(1r(m7&XT&eSverodjLc7{EoH6EX&f2 zR)IP{-eR1hfmXUk8dIhFS40mCDN;1|laB7%wTh6J@%7j}jIYNW0AFnew=nZ9JiEK# zcQTav1o;Sby#Z#&eASUWs*~@ScQFHIeZa8(W{P1g?hn=j1Xq~3lV^8M8P;<=)*aJQ zSbt8MVYQxhPK5PUN?zGIN`#f}boA#zwpo{Oxs$(SqEhscfCS=9LA*>5e`)g&f!{{o zB2QnF=+ov-=zFK=yBBUGwGIQw#cBGY7BYnvow?@QBtPF;V#0X4>3udpFQ#OU7K-~z zWN-ZOdu77VR>q3c{}C8056CT(Flh7L-g^51Y%-Cu=!k*=t!|=dDOv_&u|SM07wN@1 zR~Q63_Y?5PZ7b$e8OF15N0C^?L-k4WWrJU^`=h0PKY*E(Jy z7CUS_TbOa7Cj?n84!Hr-1#=T98n-})XOD#>RXRH)7< z5NYX6+`P?b`;BNE+sAGNGU}=@Ar-HX%}5#GD3KF0d%mH2@TI6iTk*wv_xap2cM+D(divOY%_i)dtoLzyG-LBH=Rz0PO#pE@Ed z5f4_!OM>>6H5E%V0Ebw%c`cz)oOl;N93?9(&?&a72a?x?Ll<1Jbo-w|X=w_X@^UQLdd zMtNiU56<*CPDt?~a=miTtM#Z>77=ZC2S~kIa|UhM>pK5RQe?HiB{Vw60flA_7T>86 zmTzl{v9GOfSFU+jXxdkj0ciGGuo+Sz)ZBepEn&?qr^b8R&1jiH#c6z|5i9!;%cS@O ze6$T=hH*O=$Z0uhD2nK#2Dv4+gZRjUCs|SRSe4s?q;Nh|@Xr}rz&P>0e*FhLb*5`H zPSK6)y0w~KWZ!+L%lM9dk@)IaeYaL6t0!68B<;};G3D`L)7j>7l6yj!*wn@Ze@gv} z__$rvSO}fUda?Xcbt-l97MEYX!zm>_mckiI^;hn1to*Fxz{(eLz;$2m$TPvzlw1wguxU}+jXR9=>~Gk zl5s7p?E3@zd9`%6xr^jp!XZ7$*t?r@l{{o&SP2uiWzNoYugzTPDPZ+W%@xg80*1eF zHyr^Bx!kSI?kW*`FaM%0;?~vyI+UHK{^L%}PUTsPLq($31idA#|Mgr*AIekNe`!E` z)C&927`A4};zA6}5|YceP5 z1(lylODVtaTist+`8^JEcSHHTgf+Djl;3rTbFBRSTWJ0n<@aGS&{$I2Mmf*1BK&u0 zKQh+s<5Cb`)$(4d>SF02wrlSUq0&IrK(s^$l!zG5(DYWbSpP+Q60+3>jbZ? ztoLt>*lZr-AQ_x@9_hK37p)NGTX%*B9<)B5pC)BL0+{df{#_kxgxUI``u0W-4FsL~ zxIyDd4`lADKeT{s#Odf2y(S*dYEaT+~n>&F$dqHB3ObhtFwP{;D$Jjz0@hhKw<@ zzA#T?rEBa(lAcM@m%vP4P+k3c-vSJ5o+))r{#@{%u_n)ya>?g(Q=A);)mX``!{WZR zUy`II9il;)R8JLpq|fd@w55ux&?tGU#xvwV5lo1Nm&>#KOEdnF?Ny%AJ(h7a-q4Y8 zn0&iY*+zB9r^a>BB1M89jx`BxD_cG%JI9{}SKy@|8frLUr&LEX>tmiH#bjo^Xf9i^ z^b_jg!G)pBXON)pE@xSv43m&pET@D z|5xYFl@s|x(A~=if}%MTf@2)An5IF#rw?8zbdb!&mn7G`Y8i=dWBLQLECafjdY29& zE92viGCm%_9@dF`O#DmyHPhEV9_zyh#6aIz@-d7KmL7;La#Br6s85A=o=`@*Y;K}H zi+okP`65zG5BZ#9sz=EV)=E^Zo0zB`znl723+P~Io8thSqWM&jLT9;%+}l{8P-9ev2p%*JC^e8?)KV?sGu8lB_tc`6GAs&tpqNk&)*qOPBS)pkIG6;5xTS^=xI%3 z#o0qjSlxpEXorbez(drU(IQNQ#DUq4@LA5$bDZ`%v0ec(-cT4yC{LDus$uzX>5DXY zTKk0l>$~n6X1R~AVFKE#k}+M@QqrJLA6UK;f9O@4pA|j;9Di7?583d65n%k`0)5b& zyHHI_eb5w+-BuX&Zi6Jzi>e7{kkFm+Fp@bpHdp~eurOZCZ{zM|^<}1Yw!w_*T+4Od zh?CWY1q1l@PU_Dl45fQi)!=_h9?M76Nzg-UuzXA|iQh)@OCF1nMQb#{g6P&D%wt-- z`J}(Cgkhf?wY8Ziq8T{LR#UG*$`e;)o&fTS%#*edrM$Hgf5P;wJYqks!M+S;K*NId zr{fzKp$1RQHZfJua@(bK@ZstD^+~|e7>2Dh?}m-43E}a20@)h1PpDnQs2G1XT_1D`L+YYTA|Z(Ejh82zs`K;53IG|;3P*oXB-zfX`g0*E8qBBU2YxAb&w@?( zOV%Vr!^mi-*{Axj*1#b5j02c0a$$#hEVeP$7Qz z|J(hycK+q~;eKRK(2jr&?9m)T5MbsQ5Z)2D{^a0ad7W*e5L1mXGz`GP7qix{6}t+x zJuk=GE9|@9tN3B7N&eJ^w!hb8>oZJ3*ce@%q_}ISy1h=F&l!=n)S^dzh_CGK9TZ|A z*EDIVK!6INLd`>NZ)uun-G+RF)C`%I&o!eq94**E221m`^)ugC)10rNOyuIu739z6 zZh4RW*j)>3f6wYI?|)VVVu zyHj8d^_O2P{^jj0%%NWN7y1TPv&Nltmb$A)-*%@;A<(!;UtYGudhJ^Q-J-*5=(VTv z?7s243cdC~x_GMm^C{m9V00R#g@}DPI-Dq>QXTG9Sn}s7@JVFS7XZff!!5Ru<)h32 zg(YC2avi$ZeF6%9*SmcIz^+mq=x7S8;U?t;$>aRwu`zng8*Fx=F}c3&{fM9707g!Mi+MnjIa!CrzsLgfgr}PEix+^S;8ne!x z?({#mcxpScme>IK5@+@Z_CEF;oTS%#D(#dKBRkc~6B_Xn>j4`Ls+}h|pQ%M40)mRyy>FleW@T+7OeH989SQR||?9;F#P;)HJ_fPp{GjhxDvn@HE z9`ubx%)Q-fAM2YefB3&Y(REK(2VL;t145sZmdso4&vk4!rq*89Q0b&n`?#iGYKfCd zZ$FNSn|%`h!RyDwW=-@zv^aLQg+Ifdmc5Ow44A)%B4VjAMixbw@(<=m_M`)M zSKnU4G~^5E+fES_g%xA#!&rJH@lwAP3I(3&L3h5PNCQvO^skWOl*1wA!op*Xn@o2p zAZTxkWKHjyZwX(%gN-+ASEV~Fav%=6(lIU z*Hhp2d%j99+1VBh?j~uZ<_(ys)c_#i%+Ji`J=feR(E@OjHO@xPnWVF?IKon$(pWK(pMM0iVdi7mi~TI&w{`t3=gG*Jgc|NZJ|KI80` zed^^?Z)qP`q-x5G;EWy<|vOr^f%^$g#nFf*O0oE~SF)hyJq)Dq~mL#ey{N??ww3R7zT|I$n)dZbe) z#88zGR8lI6wx+)m9;aQNFrP7ha_39=R`15zOzLsTQVd1sUuJC=yK^J%hX+`%54$!} z_ePX?Tv0r-$;Mcz^OfK`G5Er^*A1WbQ}+Mt_+j%e(a!;f$B>uyZVkf zJ_{0L&g+P~<|-miG4Q+j99{hs!8nPjJA;Tp0{42s@n6N`$+rL-c1hp+yeHB8=vZmg z=p>q`e$U6>5%=_$Ldj|0^+3vIkflpg#weTr!3p2{_!rWr75wGkYCHFz>nfBr!A~w4 zKYnAUFNXEaW*(yPRkZ#s8Y+Z|e0NvA0`6lx522qMjP49)7_6HhFGcrf&H%?sOqLfd zTZujNh@UGWdDZ^Aa6BfR)vMk>4ove7|12spNqny{vWRHfRlL-6naMD9u`EHe31HZPAkENKsPJ-F72-v2zA=sDsW>Xzp@qWwsmh z&V8rD5}p3oR<4NlKc?C<)HfFQ_PL&NvDdj*i26xYU5wXYqHKR`(sBJEq*;akZ%BL} z;(5&7sAm?o4{7_W-?UcH2*Ta-unj539Ycykm9sE&Mu{QC+kT!NQhXdx7M$Mu3x*Wo z=+Jvf3h~DEd)hNh3ftk1=3T`~!1K$8-J(j8xmKB)hheU0+7WJ^^qJh-a~0(6UA~w$ zo5KwFN8I9Yw86T0sZu2&?$ao$Ni5TRzGvBwam!K~)Zc;-?e>Z93sV0s^S`9OC|sI@ z3NDw1@k40sT80Js=3dVPCEW4eSK0iw^dZvK;?n+CboU!0@qE)Tp%&Rj4gQz3^)6e? zLJ_xwHN0Y&?d2A{UyNAf3Mt;0%4^Val8FW>@UZkK)EH+ir_F{Jxy6AjoTaO6-Dw?o zizj`^ojD)6b;9npBg^`yMeJ7_6m&1l6l48As15<=huqKC2PrY&cc}c(X(AY^N?hRk zSPl~egOi*DI!)SuMOYNkNMQEjjYffcHAdY1hnIKYrg*);1!e6i=C<`Vq7UG%8ncca z-fgYd*VKnQ$Ys0hz^Z;E?4?VHJaMU-olVe5S&q|2-29(bYRqOp4XZVW3m1D?L)K6t z^-v4zu{SgU&f-AkS{0YiTq{qhAf2t-gRKj3|rx8!ql`33_X$8moAVqLjRirsTLGzhvfC3;IS@Se`9lx zJMMlB8%@!6vv8=3#)1HVrZPhjrAKKCr#(ObIvN)5W6mQvlsn`S#MLpx>nNzV^fq(*wZ8d!chf_am_H;Y+G(ccQ`+K5*%IclR1@fNC7I$idqaU0{OYo_ z>)quKhmkYXT1#|I;NL06Kl!ex@~Cn0K-<_@HE*H8!l>Amh+G@S0v)dQ8vZc=GxsxAOzX+qu#F$SQZ4*@s!@FS`3*Z=Ii^ ziPTTf6VuH_m^+PnyT6FJ6N*mSBdizA*S>4l2@oq?hj8hFn-)}-?yBlB+U0cZ zLy0C%-tKJIhtd%iO<-gAFfK=o+>9-$LB8Bf_tQgElp&1w>=VEBBT8! z6lf#)L0dYi!944E{60psDyHmjHMX3Lh`!_ROS zmTz!-=O{a2>$hp&$nbW<%kIra)9lOAmiID%gvc!&2&5hqQ2PnWTfUZtey31MAz9f2 zu!5bCPjR+KQtIJRsSLU9@gy$q#_fT`<_+#@)J6hZYlZ8^@H&<;9AJ25U_dWXTU*+P zBsiu=o=9$9Yl=CSU1q;=mokB=b5C>N7-dQfXb!GkoUeO=4*x~E&<%#uhJ(P}0~`S) zubBAllZ)2towYm;Dzyg1-60=gXS@ z)#M_8IX-8B1u*0Ju*TRwipTL`2xaQ6r2a~2W1d4ec5uMWmx{9L8f-N8$S@*;ZA5+q z+vuiMhFy`sE(ov-+=%+yWV~7i1}B_N&yK0%$dR%pg-H9=`+G>&d-z53XeuyRjA;II zeq7%;*vY|Ut3EZudzWSPku@=#CSBMxAb$!ZL(QRNs5ykVjhF5K)}8J5eIOQg^llll zulfpurKN}n5l;!*zB>F24KDU^vTzYI&-L)m&5me`;r2_zofHviLDw+4A99b26!F8; zZastUK=I-cETk@bt1d{GD!{LJMYJJ(UW-4!mkcx}{K_?NU+jlh;3bK`3~Pqm89y;U zamZhP9mL18jc{Fgb4pDp=mrnf&lPG$Q-)|q1c2g#_LfQLRf2@x~YyM^id<(L{OU~1SsObT+O zXqr_4)2!XY#CbAm)@Y;yr)Y9N>KQBD$*8(C9V-i46#np{e4JOTw5VsQF1oDBRM2~- z;@lZiuQaCq#TN^Xz|b-zlNeeB%Z&*Z&&+Zx6PZ~B%Q*=a&&YBt6B$_riwsv_lSI|C zkou+Ac?aw?0bMU;K@7=G7JS%06Wdhmq?g5O_3f`A&5RP}g0+YB?Qbeem|EX1t6}S~ zD1lP6NJ4#;O@)%+a%LMW@M>tmHU!v)3b2Pq1qIky0d`geSZm1`Z>1XRqpxvaIo?2S zT?MRP1TqxP1c@HR>zOZrZUiwIqp)rf z9avn9E+jUVEK3`q-cz+lcbh$6kOv9))zx=sIh?J#>}a$n?j4O(K3dlYsoekG``oV5 zCkWJ$r=h+Ol)rsvm)2AZfV;&MxR?{?+-d;n;5^D$78Zcl_BM?JK%@dP_{0)LZC;u( zfTuXMd3$b*@#{)k_Xl<^p{_}EF;bkZ5 zQNExeS58~Q_NiS(%0_r$1Lb>y@dB4)AGT55ZHwoz_~k;gWq`#Xip?YT%ONewbvIp{ z93$iybSIL-j%J56*?`hQEBysa+N(-QaVeq=Go_LSjkceTYq)NasM60UDJt+jp5v-% z5+Ozbp{kk)-R7<)yMe`@U#MyyP8E1&s=)W|UV#T!DKIX7QVsvimL@vjJPWlgRKTkp% zZW}Z4mXKtaEH-I*a9<%u>3?Z>sHY$PTd3djo~qQZrcM#{9WR?e{ZF?3v(#Tpj?y26 z69vR_cU^dvc9y#QId~@kk+ChEX;xNXyv+w^x-xX++_X9F<*Z659Zcp)%`ovGfZJy+ z2qnboY67kYwf5tF zA7{L&CT~HgEL)$l^%3uvH6AW$d>{H;BznfLn0j>qvD}T{{oJmpy0*(^4U#UbJ}TN$ z3M<8ZEA!4ct3Sx>YAclZO7qB6wuzLrr18K!uWlZ@QMbc>XK4=}JO9NY+07pNqD`f8 z`XkHLm4rb6Orh};>}5D?S8O{Y_q6eA>nFsx;S%`&GyXry|C14p=>I!-?%{tw|C10` zY#*B<+o(0P#3!(g*hQ9Nv+Gxuk7qN9*uzmfpWTlIdu|iHyEl*&+x!Otkkq;T`DUw~WYp`7O$?CDgED*R-Bq1FWkPF1 z{}h63oonhzVUYhdDfc#OPUvYHK*ObTH@H2@a^sOr%FVn;RQ9a$+_PN&ZRxV{(I(|q zBrs6kSf0DlU0#-(&+x!|aYM#m{|v{H;X&!w_^=H9vra#TL(7lQp!H@y{Dsw2i7Df{O0sDusAYsZteY zrV6RxLL^y|LLPncpRGwZIlMD0$02Y5S9GG25S8Y>z9pDTIfj}_SRW;;$y>0hzW?ee2@NAV$s=^+Xm+%Im z@fH{)vcik!X|-6e#Ct$T%rXF}I|o|CqY1*AmNscPv7rIB?X`#eE$-M{fBCiD;ov>nA!dQnu((u^{n!m4h6 zte^P1K~t?`-rCk}TVwm8}n7Lf+iAv^Q6lG42V$n;UY6 zl5wgouf@zvbXG-M&>IGy2#b~ZBqrTw^>;lb-rSC<#2#P3o7+~^o7-kbg#7!xIrjV2 zGn73q{C|+&^#5a#68*1W@0+Bf%EKK?3G0`3cPupdu$bysBA7D9o*ti^GCM!yDra)^ifxgLfP6 zKHv?f5Cr62Wu}OBU-o@fl&7ea8A?%!ULSVnCA~TYDKSeyT7ABBYp`|kr%E+XG9r+} z?sR1`pRH^^xFP7esTq{rki_0S^dj{X#!Xsu8()Fq zmtY;_QH;1(yci%2vTQbucw0^BMl5r*B9gFjrWdrt%9x;RYrTW`&AW_{ZA3~=_E>ti zH1Oa~>J}Ff6Tjy7Y|v0V=f2nJvmPg{UUR>`nZEP{rq^r$6>X?rcMY#pl&350>5g6X z>sI@xDfL%gGu=7#z!g^dWFp4VS$wP@|;zN)^*_HggKv8=k6k_(ia z)NfypDgUaiP8B%-dAOenU-C=1a9;Bbz;)a3oaoEfIn~3=G^l;SQ`{r}TUM~POvVLI zad(z~eY6_uU!dSumo%@8AZ2=)Sg`Z%A~Q`Dhupi$i?Op3V({{s5+)|0h(@8NgKpGD z1sPYiCXqr=42W8^98FT&Ti+h7szC$vx<_v)t2iS>qNvHOQ-9uDeK5H@eTAQ*wDm59 z+V8z6b^ds^PK`s*}xEhK&YTdg=Wg-*J$!#J#q`1^cIItUQ7R;D}m zyMgV|t)zCpufOG2G<*Z3K{f)u_BV(8TTn_h?$Eg1)Sbe*v68O6f-#gKZgf%{|64X~ zwk)3)PMe(7-3InqcO3LGN$2-+#TzpH=B#}4&26QrM7#<|SkVTQU0L{;S@r3I*_DfY0pzw z-K5M`Shadp0e`{zYCf}Sg{N1hp(-P)!M`9Qrauo6lUvMl{a>yzy02=DCsXPR`To1}}9=g5Tkt%_+Aav+TonGh?}&BYfp*Dy9Ag2{L2ucYa3n6b!&gsqQZIcle0CHeaZ zLD=te1EkcH?l$X}p$zF-6R!N7{^ypnLA@C(QsWkCC5tV(jQ4|j7|%^_RJ4D2pyM$9 z3Ul6`^3Cn#Mnymv6+yA_Q%1!eF)BkohnWYZrHzW-r^QCaa$r=3l5&zgBc(482C zle$-Dr~Ng9)R^7Jzot_SXqg8p1|WM4c1fO>$0SV;CKrJ0H8Mp?HB2iE$n)}co{b&Z z*;x!P|D&z4J;@h*Rju%k7wmcpjacTPY-4ap5`K*VyuI`gy=6%TK^KbJP|b9^wc(e) zjXHrbxsK10wp(;q{mSX^NiiK(*EAjR_O!_ayd)4X)d&b=q}UJ|22N-pWR3Wfo$V9% z2`oxO`xb&hX=qE_CvYtdZFGxwX=qE_heZ3J0#z`DTD7!LtpXo^{ojF)eR-=0p)t?V z3dNOIB^2jdI}II*qbdmvp$=iaN7)xo@AGi_c#)_npV}jM%H5YQsL2m`AZNcEBOs~B z=9kRUO+g{ipL)=CrywzA?-3))YVT|7ty*8P7E^Wb8Q!XycnyAwk~|~wL609eNZ&XNO4KG@BotBk(2A3{o%ZgMn4_qIN;=TiVD%38c+`}Kt-C{z$(*KyD zT%bD64o5!tBQJCk-$4&#%>vHnv&B>gtUy!DkRww(LoVeW|S=ax$HmW^r4dzWdqr zu}Q(*$k}Nb*?jHE_g6B_vxIm}zf2}elTRC$X~vkgtIE-NFhw3guxCKv?J2^>PR<+( zHP_q)2|Z>{JHyr-CHT?D2HN6|XDHe>E4B8xZ{JdGQ+u$f2RzG0ke~cdxlKg?>;mv^ zY-*QV)+2kit&}5JLp4ck>2Y5rOT2q5*wkM4t((MvZPs+}1Kc*3MK-mUVOdYvuxt)2 zh-|8r>4yIcrfBFG+f>2iJM>pH)Pgj!sUBZ6EbH|)^-Et12!c)BCT^B~vbRW=o)$N7 zLR$IXvcb3H*k7R{49hn7&m0qAVKft!fsUn=E!dGb(tM1;FTgZ;9IjnscO zy;{|(rO&FuiYhho)vepD>NY%2b*qu{&!$%+zgqf%RjOO1M!vdLblim2C9qJnb*qu{ z&!$%+zgl`V{8iZeZ;&%=dkRQ{XNtC_BUrEPt~|0~LWf>a!s;zy26>3&?=)_QFc zb&`j%R=dg4_N+IOWK=eb`|)alyNT8zErEPR3|dEe%ptesb$_ul2HydStGa=K5| zQ=#?|esH?kZmliX=5D_SlZ3l%KlzRJlXkb4@i|1iuAS&>>zl}DNO3B~R&}%u>B{94 zsL+?a<-(62vH3&FV3sdF3Vp4Opv}d$!Io9}7Cm~e?0t`m1e<9K{&lar=$hEQWO^wV zPMxd${SPbo*Nv*fn*Jg@#lL=bw32`ArHGXvqYfd@V$u4Q(@Dxp0vITY> zsN_a=`OwTIDxgq%;h)UK?xfke+~V()yVza0*nVtCFx)w|i5UcyNcc*doB~bL3)o<6?J}x!BVnGIFu4 zOm`v2BbU3_g2{L2uV@(ECvmYozV;-9As2f! zwcx)GWm>K){sxdgs%F)L@gNRU6t$d!~GCYt;(Ts&!klR*S>8T;CLldr8zB7b6}Yn#3oYCEnrUwbufXoIErlQwhV)IUo!Uwf9m`ojRt*S7cg z^u{{A=9kRDNL5O2tdf41nPbagK6ofYKlViwnX_ykye}DG^vOHRmN0=3Im?yO=T=ES zta7?HD~2ddpRa7=?htRDupy{Gy*%DZR8~u`LgfC&n&Tf$@XSW)ea%wA)StVW8 ztP*%NA*d!a-uhLk)!fRp@-4GlVr5QkwJOVbtyG6*S$TVqG;_tEE@NQ>}AUVQE#JRIM|4*J%>(l#uA8Q{*#O>Gzn{;rJ;722=b&RCe`H|EDD0-oZ3%_>=3Fo=zYya!kN+YQnRew#t21|^jZu+&2q~gs|>G^-n|7JP= zD4^NR`Tq-qzfjw>!v<0tAdvb0Ys&{xn*aYY0Pa;^C?805A{?pt|F5G$n0tT7)@erb z{~MIJdgA>5SHuE8|9?H;FEIaqJVZtVDJ#>>?SSmExeCGLJM>pHyd9*`T*busf94}< z-0vdU$pCLfD*^56n~g{2pd&F;Cx7bY1)Q$+c1! zcV`QkZhEg-uVpGYT5}M>E&e3?cvjI0pY0Q^qrOLZ;-dBDoAtxnm2R_&Do(Kgw|Z?X zs5Yy(!1C7q=?9his(oD3uZ~Dx-D|sF@DrW?(_rhhwcfjM!i7b8({Lelvj&w`sNJcv z9qG2E8?1B#Tp_^kP5|6TgbJ`N0ergvFPi{(gpT+U;QJE5Hwy5*69CV7A^_^d4m!1H ze60ZIPXOG&ZYaZOb9UjxAehE7cwMh%C-{W*v909SiFr}|8&!Yqz{{~6%x;kkJ`@Uw=Y)0`}sq8V_7@Iw+zM7=u^I_A>TS`=QK2r zW%H-h?c%%$U(DPJFw4j6A`-hK$_fM+Fv@+#ui;NGzlVr$-rWkwur>{KVhi$8_Ny$- zH7BQ2*z$^KaS1fJ`79+vKXFIn9)6>jJAJhs5Lo;I2Lygz)D>oycy^DiNgoh+5nniG z_l&mWoZVsRDt{=#2l(37>R8jSjaDEh*pl^6obF=B`98hMin&z97_SR6FHkndDj)6=j?FhVsjMazj$AnI3m28;TRa*QhXY zzvFnyKrKV`B>|qTE3OC}N(1X~u&~d7?F9=n{q+THfl)3yXQ5DgdsCq39(Vc@zGxK*%k0B$ zl&H|P;6Zr1&%!2ZRUW4|oRwqzA792t5L-*z20=ct!0ATt=qu~5v~`hdS_gq$RsZ=# zB1HSa3i}@AiCDz?+Tr@!rk}#myd0`y`&`D{$)A%U&^cyZ*{Ph_g;R663D`{_@Ve+o zp$c?~y&UAr3P-LPEbRO96IH+IryTxZ_US)m+x|YK{&GQ=R#wmQ-xIPR&{_hL&o~;x zCP{iEle%JRla*u()+kX6Up#4tA;P7d`U4<2qdN=j0wXbBr+998ONHir1@LMfxB8R2 zc4?VzyVdm(^gysI-dL=tbbb@}mgSa@F`?nG57>xiZaI*TP?K-n={|^H(C-)s#Nv3z z8!L(@In=>)jwzWG@-l7yo(oDU#d`v#>@#?ip&R5b9rA9*gNB3r$3 z=QF35aFml9za{2$B8J0!&)Ovch2UzZ5^ zh+FvmH1a8e0Yvp3cXwT=2HaV{?lnt`4^G>>tj>1H*m6Hd62eIYD1X4fSrsuXHV$H)D7eFjR@i`rVdB2|03@5o)gBePq6Vn=4N zvO01v^p$mFO47)XD{+&KEDcuPkj3J-Y;=W= z+#5P_gQ1?>k#*$;Vpl24FBg{geWdpggGONgbScD44NFk9W^7@mJ9OUj=xe1K>SpXt zI}%#vzZ`n574l{Cn!%JUzZ!I0Y~eh*v^ zFuvl{`m6j|?|g-x9`}FXp5R*~tskE^vuv`zAYb0S+*200p=m=d1Ej`?y-(@B5!B@n zvd_j6e9HSd(!$d*=#HE~$Fj2X)f=<9K?SAkqDzF39Ut1`h$?K^NyYtDqBc})(^2F} z4TAj6Pi1BMwZz7X~`KLTxh#6GhAO#G>T4?%YZvBf@48c0rv;|I(o_c zGWx3E57b3j&zBHb*7EhVwm*CfSK2ndFn&`7t=ldiqfFs(gp29O-Jhsw*Zg7XlonT z8>S8OPjTX}@hvcDwbz>eXiC$#-pb)zn0Ae5$WKEP6Asrax%ID26Lki_0&!1Y9+JI6 z<_aJgS{P{FNa;A>O#J~&yBj`)p;@ww5-40E?RUVAw5zbEN4?fvTaMcDce$%^#1h6{ zO<~x36^R*Kn8DDudFqkBmbGp!aYrvnuky(vf=|o&?}>05uSz5IV}(%Gp=D*+?LJh) zO$~&3dC7q|X!vM2hwmg|@FaYTuKoff>|aJgEwvH5+*gUcTC7)}7-YR=XAcq3GWIBWW+|U+yzs!-Lgv?9XTvvZh~}(l!US^WfuEVf;*0 z{SgE>DouPUoxz{z#`MU8S*;J*@B#NC&aoQSlwKb`V2R=nx^Ue*7pr~pNA3^^Y-C>X z{v^x*S6Kb=Bq`tlchil}@{7^4elXF{GR$Bkqn)A6V_PH%?tmWxZz&*oH7Wk^jH3Gr zh_pYm;*G!Fo}}*29LN;OOXF`_m7qV zZ>;C6AkwpaiZZ?F(?mHe(_6|i-5N?^X&Ylc6rE|ob(=`$iUoN*Hhx~G!<0mgCL?q@ zVSd_Ro;{%t5k4)}D@tnKlLVI&&QNbYb{ozYDjeOy@I5=_9#6sGZE3QPvZ9KjEy$~D zbJKEMT#qvwIoP9iOv`BLbdr)iufevbW}qw{+IGUXHZDdYI*tHmzV;ek)B|ca@IWkC z?{=mK;lP7h-%zutrwO>Fxjtf=KmHS~Sg5@Skkt7K);|7zYF+%z06Nz^ioItHt((?c z#`DX$4Sb9PAVxXn!oeq8NBk}8))oDa6~Hu@_t7%Owp)hdpyNbkyV+s{a^U`ueh?|f zuiMNi=V3P!3t2*!cT&HSaRH|to4LU$+x>YO&ZsLb z5=%Ib@t$dQH6_^y|Mi{q1*w)OD__0DCu$37O?}^7S{!u;-y_c^pFP=J zgq@<(;T@gK$UQYvgtGqD?36Y4t_E;zc1md$ziP?S6x&n&(4!utZtn-y)|H4O>Z38C z{0kpyurXROY$)pv0^WCW-xT7)pyxvUtuyM{?wbM!XuT01h8c5pID=k|nz)sZgkc%c zn!?QME`3AI?Wa+e`y0Z<$XG+o--7D5^UyJHk-FxmhcMeR?C`-5<`h=DqG>ns=Qt6lUJf zv-|5x7s-pZ3Fg%KXY?O@ovK~O zy09CHwZNo!NwxBP#xMJfn$u4DYnke@sEO~Y?qzZ3PUgECBKl}WD#C#N02tz{kq{HX zuNhrovRHfd7yZ%#TfcLs*1l$QwKnI~?<4)e57FzA=+up-B zVs?d=?m)oiCe`Y`)oG7rlYl&pzI|>HLGD{`*w+Uyt|JTC?OWj%736o}^hW@f2_R;k z;5_rLivZ3@VaVSy20%8yQR3lNMTgs1xYR`770;XhKiY36uogOh4UXJ;g(@3Q0X+X}-e*c^ecYLpD#Q zP%p14g5gC>oK8$xgtZDCRrvFIkir9#|dI<)DMwt-phSiSf) zH$gu&+|{HCaUZ29o+SdmS+p?%i)F;I6P5JjX(s=VpO5^%%;0DKg=cp$6OobtZ~DU! z;VE^N=vuHt1T8Cn$9s(qutLX;_M*!v7kGXuw99g!cu7#~zj=L_x*yU+QWg6LYp~*q zJz+1p4st<->mZMY*3B9dxW`mCV?atjQ+5k+^W{Ymiq3Uz*9XKWRX^=BgrTyp!p9V6 zl~Z%wa#~VT+Fay1Uq1s)8Y#=xscznM$t8`Q+hqNvzpu>fk&oT`)j-jioH`ovs&IU) z`^RP*TQZ{%3-ZB)?)UaQtY(`hx4^kN_#N};U7&avNP6s%BwXt9r40E;p z<*dm|;EoX-|Am=}2`;wPsMCt!#djeyx4mSxSq!J)2`(O-8F8f^&7kPkYAm<$JKVSV zd{w*19e>Xyu zN7c6<cko!A`O%O+N*`tK7?UJLSxnd0$A&mOA6s@Rb^WCQz?j~(5 zdjmu_5I`*l``us%?I*)gBVKo2=)t-G>-HyVj?4qs>&kE~HK0t_K$Auy5!w;Zk`I)P zWhl*{23`Wv?GC>x9RZgCg=CIxF=Sz3N?`to>;JHq*mZf}U|g<`2ne$~ZR2~?uQ%g; z#CuJ7%|93AwNc0lGqXIq&F@PquQU0Ae{l2%Fy8B|NNe3r@xp!mOKFPE^Pj^s%n#?L z*?0=yN*_eoi$M4Ash&7HHJARvig#HOs>7MO+_kwb&-!`l=8qjM`m;z!{Qc-%Bqj@> zhTKSz>9ef(xo8*Xxz)e8N;+setzr`B`%-s+_5!H31<{ztmYUx;&%uP4gN*1MA0#bc;_XXNIbPA|;2 z&T@D2%dU0Xu(`8&&dllE;OkGBOzc`9S)#EgAq z86T#EU_@G_HhK^un!b6y%Yjk_w7mo0!3@rTNnums;7G`Ac&L z&RLp!=bXB1Zt3c`CjlYYY<|C^it=sMJX-Gy#Nb7P#J`Dkg z(mLH8O3TyoH+{dnpG)Awc#@&3rd<#cet|M{R*Sa^yw#)x}S(JY|_NPWC}K1JDU!J1D&MwRU6Yv0PGNzy7W=UeG& zujz!|!`#M1bh5@Op4q`2F@02lpHIM& zHeopM7k8;|94=`I$}G2uW9;o=S9heBNY#1x(nR*cPW&hW_ z#rk4qH66~k*ewD#U1};!;MOC_af5PvgdF*e>Z1&!H2ZxB`!tUJf&{61qb>1G<(< zg&h`Wepm7tdTeffmV5l`A@hQA)IILE>wFy}ElPu@>TpZQ=e4L-K2nix_qM1auPjH` z<&IjLX4y`Z@VS}(8Gb>%n!Sk(wxB}t0hg)RH%0?(f&co#fB64<_T?mfbVF=H%#~31 zV>ximUFhIh?zVYcmNdDMT z{Kn1Hy~cg($C4g1HREp9+oJ|M+Owf^3*a@bvoVN8FibRq){bzsi>mv@eSCF2OSRa* zWaA&f5p9>#Ns8#7MW#k~_#;wm?QN~?(L~ z_xjBhc(1BD-s?>~yJy~>_FgXq1K#V!r{KLd@f^w*|GL~6m#16dAQi@Kf4fSD^5^ge z(LAa&IU4;+q06>;7P&)~*~2W?_+6Q#Ar=XA0$DcSn%IkI@Y(JMNttl6KBHpTrg1eX z7u2=gGsS%an?2cRI3q&Y>VPF%T}jT#guG`~%zFcXp=ayPkQ&ruQAqsb2=3w_5QvR= zlc*sY(k)z6S6_IW6`^V1zHD0`24Ax&%0C1Mhu?CG-NL zB9MdN3kx?`s)Te!@Bl4WR@UcJrzsCmrLv#^W+({?gm^@XpTriv{N~WJOtuw9`O6u} zjPV?agV?ImZm3ea>W)CbSbe)Js5qE!>34@VS7Q6GJp;;GD`s52S!mT3{1ka>>)Vwh zjSGbG(*`}4bT!oIz;|<1QXi8XG2}{|km966t)oh)uz+As5u>W~c z?_*rll?sxHC;{*{=R{%3CWnth6nhVNMUuw9n*?nX={`ZNE8@@zw1@ zH;-$Qn}@lc$I|rRx3F}Ptqb9<%kIOk?cIn(t5>}COG~!XIk>J_QlJ*+OS8)_sq^#8 zK|D~L%X_q7v@iS6AF{JG{1-4QFIFz0Cz+^7d~HQb(Y)#Pr$QNEJ%l^54;8`QE$qaX zCSleGz=pNBWj2)Vtvw5ahzYr748m!fuPTq>qJVN#)iX{ILZ8c$n` zD9fSG3s~DgeUq!G-}z02S2N|khPOIyt|tDVT)xvF?=y1Q8D;%`Math!%U@VhloG>> zvnGbWdmm!>Rq>@TbDU?lYe@w${PbI^i=hlzB!-Wo2PTMNG@lgqKgs{6Ka|NGS89!@ z<)k&&#p>v+(-L*`_A(J03L-YN`yz%Q%+r;D{>oJaGTWo>lyBMYJ}Sr0ya~oRafkc4 z7Z)0-CPJU3uoWu^ z8wGSzJirJY{(G_XRTH|h?6GK;OOC%)`1$1}#828rB`?VU!h0FiovG^ov?ktxdKh=R z&cnh%_ZeF4)He7p)G%4M9OV`khaNn43gG% zr~a~vZ=V0Cyqr@IK>Zs7R2ryblur~_Q|dLh)24h}f2YPYe$H{BO|{gw`+jIIc=-UZ z9)Ns|2}FyV!c0g=C#OF1#ux@X9-w%g0T6CRK*GeGziF!NP9;WzoJQ!#TP+l4_4As3 z`X+DlMQ$(bZ7L`>2KBza)9O3CFBr;Q5LF>R-+ky3E{}R&3|jX*pckJ7s8-H;tX$h@ zTrAk+EGT`YQpocg#ciiWDy7H8l9k4O_r`^|lpQzlEnm=I1i1$ot@`q*_IIlN^|P_Q z-U}_IK3uJ6%*o%<1%kfErntQ`Wwn3GnxGm@P;30=g0?lVwdB3NfN`6M-po3v6f>{e zU3BuO&6!L71l9zzo-YW0NHaBSL`Ii3c{y5WX^{r8$!X^M#9(*ONo9m7BJ1T{9E@b@ zFyt(6y&z|ToVUNZj%%&x+Jiq?Y0Az%uIX1NW6EyfwSF)EYS2deznh}|8{)I9-m{oL zGbR`sZ%XOkQdcs1!@=kU%cR8YfY3oFk4(=C79_0cQ^a43Nk*h2*PrNNm@YCHtZpkf zTLx`3DkGd7cbgWe-^gmRGYfO;4YJTS1hj0SM<1I(TrWQ;E`vPJi~4&fya4KOO>~Jt zF->WsrE&DwICXaO-%Msd`NFE6QMYWdz4P5hghjzj7mQyMlIXX#(PfkQo7`tgMMmk# z`x|Sl$T4^Qr|6R3MS}T8*Dd=t_#wVsDd{GM0O+tb{TcKwv|$p9t`V6ieFQj&Mj12s zU5OF1Ykvt)YJDiY;B-#Q5#E<>KGqu65QKzP*D*8E8h*f8o|P0Rb~#4-|m$S{>; zz&QbP)9SEpTGbS!$`9=j-BB4e3!IyneKQNnr)qQ4u-`Y}qnOMoH*cTHLhAITsXd54 z|K)MesjT-5$F8sq|9bE*t&eCcr?!Nilxh~{6|7TELWA!BN;+qP!%r#<&`VP4u&tk6 zV98p5)ci^(#Y960o6^SFhYqP0HYRS9a13PD@>jB2bbB&+Z2_>Ch7=zFxr?x_B|j7; zBiuEvD@txvG9x?WXm5R}e*>+kF|$vz@XHnGRr8;R__CVPoSUl=sJ7y)9COz;`67ZK zlGg^TLI=o@JMcJQqg4c#fs0xQ(|DlniYHE%dJP!RgOa|@#St(j22*Nd15_4^K_dYZy44Je;xzAr>FRmYwapTCX^ z7NqL0@9I<7@{pBmttCBiioPR-#czMLX;Is1b6aUg>FMa-{ z(_U`&FJ-~sU*o=|o3lxDO{nhw3C7zHXPrmO1%4mI$A`i;0Wy%$E>=Mn^DS4oV{k+z zNEP;qU1g5)Rkl}*BXL;~`e~n$8nhIBwC>@j0s~E=78nUS7Rww=%INmu+QhhDrFb&- z^OO#O1~%z!4A9%eL|%4DbK-HUU5?(hfG7y?mZc+p*sk1E>NogkEj+N)dWUWI*Mf1w$ z4N8y>X28}SB0pgemA@-Ypkx3x3*grweq@1Zz31M7*87o)D9qgRt!TX`kE@{dKDv-# z@U*D3!+XIqWo-vhb{2(b0MERPb-@j7My@Xqf1DLxO z+hMG=sQBrgn!hZ8n#Vjf&+_aZgF(rHw4naa5H~nGJlDpjmm6@@B-TdO3;QXeEI$9@}2is1;YR3lpIRk zz=Ecv)IJXe7Q>W)ol^#;%}J3+_qfM{;*X9n@VesLN0;dexy%vK_n>%D0x}*5=EBTX z^@X)OqY#kAxk-D7(xSD;ePzY}r;0x;fs>|8__*c0=^8yrDG{k%?oAP?bd?$lJlMCm zdz3y#mkBiaIho>7))y{58R>hI3`Sw*DxTfh$E2n2e9+Msev7D!qC+SJHzU8xsRDQ6RHRnCArSsLw&!z9>?d3I0J5J`6r4F3eJ5ODk61qNSA zyPxfxu$Yv#w!b_guuM`@aLUm?Kd zq&;?(w9dj`nx_h9k0Y{q`BGoPn0pANlXAAoGXBs5sq;8@pI&?rcgQ^}l8H8wFkZUW zz=+Z36sKp7B}CNyzV?-?k2Qs`(e(uXK#JWato><_|DClE7|F3B2mM@5lth2l7o3{G6DYhA-e4C`0qleh)}6! zrC*b^0vAsU$v(Oa_ofX(CrxA5&Pv9eJNany&Iid(0)x2v8=31kM1VyAln(c62)1nZ zQxp-muJPRRHCyl1m|UshOEYV?Hih=j&Kh9mP9}ig<(*XmyEQW-l=S zjK{%~c3|T8R3gvi?JymXFo{vR*qVXK$Z`A?DV6qUKEUMkZk!LBJOs_pLubE@QyCA@oSqpAGN_qSh9r!X}f_z6f&=`{uz+H;BpG?!CunW&UaAaTTs zUr*`h1IBE@aYreUxH4hIY zPi)Ow*>eT1(9mRoBRiCRuQ+=h_WY!fU44Onn(AqLy`|ZvZ0jTQ>LM0cBt?QFe31~| zYR^0P3yO$U6ilxay34$(r&-e0ei=xxT}9&>iL???9D1m0sEq zI;!u*%&=IGd=;NG-x7CLESEO{lpc4}vNkN6{7vTH8e@ABwI>+-6z*44Rj(DJR&tLm zLScP2=D`AA+xhy*FN1;2&fPT6bW)M5MH=`m25eKvkyP#{TQW&1k1#+P?x2VW@4c-q zcYoW!l-%d)6b>U?oEX@Nl`D@HUk2e)8V>_AiKNvXI)} z_qp?lJFVGKgAvwCbEp0;@73Saiu!w|0iD;V=awe@ZC%m7=yT_HtOm`}!VPnJDVpR} znbrDh2v!+_Rfb@dAy{PyRvCg-hG3N;0Mn{MrxCQHhK+$+pF96;o&0%MFMm!i^5@n3 z|9B&RE^6Y>=T>a}-1(QQ=xpKIIlcVye!}(4>-}+$voYRT%YzZ-r;Pp5Ql{pIiuJ-xSg>raOt*V7rrtv??AtDX+o zx^)Q9q7_@exAV=bh5Pi*t)E-<))oDIEj#b)r#4IH zz=!j8KIor2`}@w^`3wIHlGAoR>Yt1Keam7^FXZve;a}wiGiKZg{(3Y+%-0k)-mn z!d}<6D37#yWn$^Zq6Umk{5((mp!ysx6G7`PbC?5r2#;~Z0Ra~p(2zmi$^dUQWRMdw zzzGc*=)sJ~?M|Zr8?;`I@pDPhqmwY5Smw073vq{Gu-h4dom)%zJjYp3+1VMf%zDgs zN33#2EXSKc^PCabOs&KZBV{RPPF3eN9lwC?Bh-C`DV=Ku%@0%rMggp4Ooi{ms*b(? z1(SwXj6+4^{Pj8uz6GuBhm<1_%^6YXj@ZZ!hUh_gyUQp8ChWuSq;#@0j2(GUN}x~E zN+E+f*DNH-*kTg)vqCnvFr{P7@OgzP&;?iuwder!R`bQ6#e6Zm9@vB;xxp1t;Vh^^ zSGKD;#2ka-ToGjf$*@hJC5>|$g@V`c(p}`vO-z1yC@`?_8&nE;>4z{qAULGBXC5&< zJjts%1`Rk8fRUMBxHIb>uVRjr>uWINfaC(ug*OxD5Gckv&?*tGDe73`89t0pvitp|5b=H}32HF;A!H69sjGrTClhtZd*pW( z>;+Y3WX#P6`k+!k)@)TQN1T^S$pG_7?Zx9T0!mj|J(5+E`6iQLnOQv|EKZC+$9OH{ zyUgeiMjb~^l@UPHH$p0u2-x@#?qwsk6t%0V7Rb8A#>?;UM8&c_Uk3n>cN)vkZvq4j zLqpMR^h#OXmR9;b!RV0#9dU&Px0E)hlGn3ghbOIZ8l@r>A|Mp}YP+zYV`+hmagqD% z6{S@vSBbL7Bul<2IVDoaFLyw-RL7_y55-48R;c(WdU?u*&Xx=*m{`8KXzrAa@(e*z zaDVxBzSeG4L$gzNjH1MNE6R8*%TPkDoie__?P7KV9(mfE_;%CFAE&5F%q{4hz$S#ud~_ z$tgOv--{a*J+yx%Zcu#R{tdVRh&}tuanq$}+y33S0@SAc`)~trYxmdU1|W;}L(gXm z*rKcq8Z*XxR*}2g>okXJ6kmf_QIx}-xN@93af3Ut+?}|a7X1dyT$G+fso$^^?fasI z7_Pce2A5Iq99KlK)7av&y*qf03&JHDA~VJIu2;m4(9a^?30{4v>^4MU&|fg}n@DrsOEO%iB3hyz(}mmH~t??(d{^09yfK@qzhND$v!i z3yWT_NddJ>OOQ^38R7+ZFls4c@DB7Y_3@qHQ^V50=lT|3LlnV|Mi!yFDu@Y;pK8DX z^c@QijZhIdEyweu#jsCU{PUxvA#2$ogam>kfGl)j=bD{DwuX$}(A}A(YpC(R72*+K zJt?>e(xZm(C&d-*DTU%;Arwd=K(QUZW!|AACMR4f@ARUzrBE}>J0s&+YH~IKqJ!`$ zKcEUQw<5R11gW|VfK$+n5{tBK#^}W~en?c{45EURSvAXrsCfH;^f@cq#j=7iw0Xyx zDi)0+skTW0=1pSH2l5KWn6X%Srwb4G^ZreY4{(8Gm(G`*)X{6%{Cq$0VfFy_*ac2w zd4N?(Ve|r&2gyOk1o=wHodmbDklaZi)xx4e6vBuJpeyuF@S`jA7L!BJ6?%)saY$7# zBjX(!8)RAqpS&tiS<|36Khh~c+Rwm3+65#l5G@r`E{v`LY=y2tM1`(FL<#1B0HTsN zh^XWZBFemf3q_RKd(R0Hmo$LY0}8t%wvvVzXj@%IMS!kh^ek>lPhU7aqr>SLA4X4I zMt^|z;{)AK+P_0%=S1|h3yRL%B0E`b4iKe8D5T+sqNCpw9ttoh(S)HY3<{}84A-!n zPxy%i1Wg%cLQSG6!%V0tXv#1XY6_Y%%!Ham({1bkrZU)exgzO$xJ3;#m~DqAq3HFc zMPiOU_XCv1%cW5c*b9CuYOa40R`j-IMZr`OE9!O2ih`Y>tf=tp zr-_vXyRO&OVjNI{z_!{TR@5fi7o4@xk}kju;Kx;~D)d**$)PgSPQO|jSkOrQ=i>)1 z4zZ$M4p>oh16I`AmK8+`(29E9vZ6?VFe?fa@LN&DM{u*OD1{p&t)C=xVpt@BiYbH@ zMUu#54D$ex#Ba_0XYqi61;S*2qhU(nCul{9NAgElPJaKD*f$JIfp$0h&2gE7^PL41 z@Llfc>^3$!3wHhz!l#uh!VBH+iYRgBZq#(6H72wuF%Ko?Blr1kV-*VYfF@|GayoN2 zAX}eks5qB7;!WgT;4Ih`>oy9I{Tis@b0L?J)tS4V`C?o~F=}3nyk1m!w%aH}_IPK3 z57X8XWOe42FkhU@0H*zzmvE73M@!_tROP?Tx!$L+43@yunZn?D9a?lwSc`_LJ{pQ9jY5-bs!3O&NgcwPG)gsTJkXpB6x%2iuK&&t<+sDF{p>QOd4L-GWk)jT<&u3O+0Ia`Qzhcoe!&HSb0=uT5C?`@ ziNw{a%4i^=Dxc5svV%JjZ!IS&T5dYi^>~MByLqzCIE?{3WWx$> zcq&16*(I;cAc@E=Qtj_V(=d(S&U2bQ%uNL zm;+aD!V*Wp&M4h;^ZAR#mDt*LNe&8Wc-cz#OtTm69CU-X=!fjqy601F!hXCsb2rL1 z4>UM$%|{-mu}jD5i3S$NJgvfo?P&o(_oO;<;9uJb6`s+8KYi`|{dF>YYeRPz9c$QB zbZlB-(V>QIMTe%XDLR&&LxhUO{*ztIqfK$@K}ZJS(JmyKO!lMj%D=5w3mxe$G8Y}jEhjm%2jI) zm8(|lD_7Vbs=_q5Tw#7JqZNzUi}qA~%c99FI*LW5At)*hKv6+_n<^?uFDZYL^%rfb zsw`Sq{_K3-Z>!o_^mh4+UX@-|^m_R#6)L@==;iV!1t#;)Eq_+vGQX$%MS;Dks;Vfj z{1w7R)7bw2S0Uh;jjy*=?J3-q)pJio(fX>rg*(%3;MDzE-IHxUzRH$YM~{J;`nM)a zcrH7L(?bDQ51_ zw99hPcKq5>3rL+D6x9yeF8(37KAV0ZD}KK>{lKyKjNdE{)2PUcjC8qgk1Wykjvmmxr~TP|9)Hi2W`@K;x`33 zaB(6BE_WgaF84&GA3SD{Tp5x6+97+S7ngnNX^%Z}1D=k>N0vtv795^|saYkfTPW2n zRMjn1)h$%jEmYMllK3Z%7OLtN-V^0EAB_HA+U}VDrR|RUU)gTYz4qg)5qOS3 z2oW2XcbnBq6H0tpxGS^8>d5p1OYBqD_elTeLi>~wT;5hsuiK|=z|+h2DI0sFN4{*2 z+!dJ~`MN!F3odWlBiG}y&>mSFnSS3A3|K%p6komu0?1xon7-qXo%j3f<)!I6_Snm} zrvLU(d}(p|%wzV_g7le(?4_&HXYR9?ZcLxK$6mTM{ouCvi!t=y$E8GFzEqc;>QWU^ z^yu>k@b@kLcHwU;{x+#%nkuF)U#iPab*aKaF@FVf!!R{XWMLw*T@YTTelq0}b)nw)7qN?GquF{w?G( zBvLLTqo6Te=FM1Up2}tB3Dz>Rjyt=KRp)pe3*iaPE6Ow1AHpU|msE&G@yTzs{MJLe zq$M5?S1>#{BdAt_cijK`WctN~A^!iZe);=+P{l8DUgU$NJoo$6t2sUz?cX1wUw<2x zjXHL}rDHdXjvd@m^y%1Ea+%axF4LmrGNX+s**lR13UxHH;PL>n;PMc%;PPl2j2Wd+ zH`yb1L$9v2NAAO=$R1g%wCr)wvYXry`$fyD3Kyyh7pe*ustOmX3Kyyh7pe*ustOmX z3Ku@w#*G*g%AZ46i&gUH?^*wqKmV7>AKHK03wKRyu~BIQ3VvvVQl$+x;R0>&h0+F_ zPfr`{i>K`0W-s5JzGIWUd~f=Wwf6Fw^c_X^@}ud$-4|b4l0I{ry>v(V%uV*vZ_{V4 zwU-`DpIKxtJt|^-l@k1=>atB;zE+q0C)Nh5l;AH_mu>3uwYu#8AJqo?x>ELUyYvX# zf7ubX-*JTPzx>G2^aCfQ&MCD)I&%zZDY{`?E4gH}mdhj2a>;IUnhFE)uhb7%LpJcW zK}#G!B|`p|D<8uc-3hMvUiUny#bdVj<^J6=e4)xP>nN4qHS!B}hm^fRsUN(f{7-*> zt^JaHp}Y4J$&B8$a_Ltmm%;UN8F5%HV}D40?^xF{-t_klbse)Z{k?r% z$81P{Z%@}T<>~Kj>pEt)-m^OM4Ix8o`RyN}XwpJ1Bf-U>(733BjlR`xE*dsCx564X zT_|I9+oV;P4C!!z>c%sU9Hgau%qeN=Wt|(krfMlOkH`ddb_(WoRhI;t+uU7#sxjL^ z=Z%gjnNg(I?R4VM46`>@kk{*VySS2T_KtHJ8^oi`1Z)e@8{uIa#S_hh8NAbWta+bi)a4Y}V*;(#|f6i#;${s(mbF|G%WPihNcq@ z3%$=n)3H5)AH8*<>D~Z(#R@&pu^e6Ijz#FXkWz<#-y9rgQOX&M?bg@B{Wi>DcNt?G z=&$8Y^mPO)j<*_)Xf#PPT{uiKIb_Q1VQ+vnoPBxe(B4d?v5pN*3mEMyv|7od%yf z)*EcQGlD(nj0IL~Hi9u-*t1u6)**Tk0ICDX;~Adn3Wa=m0D1IvX;@#QpHa*i>}L4) z2RepY-K>~J*csihDXbf$0+bB&z$o^>cwwo1LF%|7e0uB_mqcs2XhsjD89mGaXYm+x z8f@u!+Sl+0KjBD%5SRf5N_9-;IGOId0kI>l$W*klz00Ay+7EOLaJ3)i80u<2#xcs( zeu87XtNm2RWLNtq9Mkm+R{Fk3oI`9QI=qA>mA z+G5>UUYLHcc5sZIxUVq%NbQKYu`XLuEuzj3*1lnfD3Qk!zIq3uSv`Kqx6=~jRfYUk zGQ*4{xv!SrV}(19)c&9wTR_KyZh-Vk@`{5x?$-hV{PN@`_GC2kzJgY02U&TE12_ zg%D=2qTg{rXqn_mkh)cuttK{u6*lXnj!i*qHUS&EpKSX=$W|*keIaD4^OMalD+qUl zs(Xdhy_#_Qsk)1${Cdfw>fS6V+oW#PstRuNQ{s3CB^2KEA(U9*r-Wa25Xvh7vWIZo z8v!oaF7@pRwsj9`P4Kt185WWJo2?d;!G%SXXpsRF09_&E-KUy@Q-Vy8mkfTI-T9JZ z6u8J`{KYYztcRv-@T2AL0;zti6EKUU>09tSgH(W|F<)@xu>9#sCrdC5gJ60YUmBi? zU~=OFxaI}Z6bL5WGuu%tc$`+CBJI0o?I*Ts(n=RhAGRuBJ$dZ`>uG8q-MmmYHu;_a zLP0{DCINhJU}2@o&H4dDH_!ELY8MLT4C(0`g1u?Zgo>>}_0ywOepC9S*(Mc?wPmz> z4&n{hmXGn8W}EEg(_#FrA8TtU9-CsD=EcKyJgnzKF&@6b!xlc2;9)-=cJZMM4|RCh z%ZCcw9O8`+Hx0b0=1=|DR9i+1{`8IE?_GBO{we{#q7d{nHPt#qt_!v?07(y_P=qevMy%Al5L3nu(bMzz@r zrnED6Gy47sNA!nWCOW145AtNBk!BfgA^ada?}rBoe}6J5D1@IFBz)#5rV8P+K=`+R z8o~>C10;)f8LdG=i9PXCEru4Fn_;l)1JvYD0Nt~rkFT`lVJ9CPriUn<{%FGxObA9Ia%P;} zWn{#=j7MPhX5))Yi+Rj{2=kn-WN~4&ta30|(X!7-GT3p=b7W!quG&_*(aDi`oZ6&c zG!q8LpbU&FrdYNc^!2XVv35xp!);Q$+{2*S6|mYu?6oR+TRqNYESEd%l2C9Mi+NSC z!8xWMztsQB_zRyG9;xLn6cp=8wPm73VLp*O(ipF#tYV5qs$xmm$dp%Txkl5dEBn zeF~I|qrWGrm>OEt^eUJnlS=%a4&68wkj}9e1f=uSp}KjAuLKC4xvu85f=#fOEQJWi4NDf|kaMO^&nf6Ch{cpDX@O&Jz4ztB_E+M*WtZl!S!CmkuU`{#$Q_``Rkxs&d zbQv`Av}DWceK+zoRavXX+OIOufQ46D_N{DoF0;?(+TA_T4Ql zKeTZXBfV11(WS{Hlp+ z3A;lb4_$>Lf1|<@J+W3byP5AZK_3b#mQE#iAb)_zI zBEk&UIO{gK%*+I5m$lBiFI;98qVYa=)@^onS?7vu?P?FL-yT}OJ+yv%X#Muk`t70h z+h-@80-Ny8$pNX9DMv$tR%L5gI??|@t8!vA;-xIZ5<-FTQ98bA`oG;`(>)WT1HR`I zTW#3ya>iO#mNOO(Fq&A-SYhu;@y=MwxN^o8 zT9$x0DB2mj%^CZdnDB|mt0J-fVU535GW^caSh1`-%Tl?O)dU@MC$&~APn|C~(qO5W z1J@=uF;`^39oK2A+$r=EanS_bXQRQ(k~hS>5(k?s%RDfn?|RE-k9ER8DIQ&Sz&U6|kH077V|=OY4jbBdCdQOZ7G_$gLm z7D^$N-i-)O z@5TnFcawtCyJ^Ac-3(0cBv_OazJG6C4G3R=Oxf5I0RlQ*1axysKO~LwYWWAMNn9f= zp0IdE*)MG7-k9?#D)XuafW#-MuLSTY`oIL2Ujyi)R3H8hN^0 zJjs%X#iyOOeVB|I^seh=-{!m|zA)9LrI!Ylkr$`ZRy_u^n9zw$z*d&xMz7Wtn9sg8xBO12Eg3wGpP38OWGs&k= zUD!;%vgM)JB?v~%)w=-s5;veq)dLF&(O14+3R_7m%tLK8-*T01)oKA%G?DI3k%JL@ zFa0aDICHBlhG&NrS5W3QEk3+y@hH}wc6!AxZd#mz(%0(rif>=k1o;>iU!gkEYP*HJ zB0*S3j$GEHd@Rd96;__4RYX}AmVRQmt((Hd(9wL?HdnqWQKOqSi=olJ>UDx{c(a-o zU%9YJtKh`deE&SX;!ig%&Pl)T;pU1rL)5bhnpA%Q%U>5(UWh8J@>p2v`O`yS-w?Rd7+BP zg??e_C#K4iP2uuW58pd-hToD?ji9IAYl7CfES}L^@n)LUx@q<8S^nCv^3p8f!AHW< zPu#3`mo&kPJ6ZZRua@*vHEY2?n-o8f#pg9wyqRVtG_4+Hhvpj^R$iJV0%v|$`iYxW z_DK`Guw111wC2h;m3Ln*Xj1$_7B5)U3{{$G);&$Dzlh~$hLx9Q$=FyKmVV-9MKpyA z^GNe`ZLWONX0>SAES|OG`*!8&HEY(#O~}G8aeQw{`MjafYOu4Ccv04wZBcS|L4Bl= z7cFW2QNo6sbD8E_w~|L-wZ&~M^jYo_-W|6+8%ul7^yjw-64oFQ)QRr~szSxpK7bWi zznAF*4)Mc6h9u`M!(n3^Y>T2|3M!(FJPoz@?LH$9r+E3x)g9K&xqQZXw<_0twYEha zu4_}G+F(jcjJzlSu&Sy%Y|5jteq()Z#U=iHY)G!Jr6KqP4aJbAmlhL=Mr~|{nc8C4 z;L4p1&14QEh-g0hJAsDT7HPQ^wgBlB;DsUe4?NBKpTRc7uuaoG3AH&@mxP%+ReDcuH9;mX#YEqm4rv(4`MA%)~$J0h#*rV9mL%5!M2*aaSW)%3A zY&!<7#rh#O-<17>u|bbIu?U%v(b|an4bWHeG}>KRoo{(J{Or@glDgrU1HXlC%+1He zX?%~9u$bU9j({{wOWXj06kuYNz}0uNbMI)j>LT43UhOho_92JMm|KAhrdefjSy&>8 zdBt+^cqMU#p8L&hOOr{0t_^wwqObB6^99ZdOhQ5gp zzJb3s^i4wW4Lr7?Z<0W0MT&*Q*7x#$l4Xga#6qF0Iai2ide{a`!AM!(<=Z8nRg~G) ztY^3?uPC-qftkyKy6Is-Yu59|rqJTdtqlB&QG7+-OL(Tep1Xv1INYiid(K>PLa4xs zn53E>7VyP?O?kuHTpW5RH=Je!SIb;XAY^Ap5FSn^j)P zl(JZi&pRaoX9-2YQZG8dSDh!aj|F6K`?fQ|Y-x}3%f4!!ag|3K53-LU=U$$FcXiYA z@0yo?*53P&WIP6{%$A!X{Uo~-Ln7iJX0t~z-d3pl4#mE!nSqKF8=3Px_9B+jU_@-t zT~Y}P5FdFLVyA3tecIY@-X11@AyR#^7xrZkvubPodOf%9xK9py6!DAGKHWaO4Z?5b zEX}|Qr@-S`oW#IDaY*XWGr25(RR!=g(~|KP5&+9PT>de!M1&L1@fQOkmbXwu#76$W z4N;ewUg(C!&3V%l^Vy?u9BLSW1Wb@r1MlpBBoN~nX0K&BBWB^WGWA|0#Kr&QWKb3ic}uM z#sff(l1ui6`%L4)68B~D*g<&Jd zA7Gf{2nk??EAYbL6EjP=G|-Ana1gPQ^V?WoRYPbiQ#x3 zMs$I%mBE3HAuGohdC0Rayz%`L6q9Ub76$mBcxb7>ySaFW;Y`nEU;xbS#wSyT18AGf zsEqZnk{6;b!E+e|NozU{1VD^>Sum1s))W z-@lS_IOuGb^*qWaBkQPic`JbRnac!+Ah7o=V6?e_Y~^j_1U4Ad)KSZL-Awq1 z^!3$W0WyMA8pz0hfm}0J%;BTTJULqBUWMFX+f+vfl0L`E&(0={ITj3%Os7$%<0hH& zY+P?X3Xukah^uBSW%& znLmTS$(xJOWIr*3qzlE&pBlhSQBNp$CYae3t^IiU@$n~rqQ+)3Q8oGfXjCuC2G^`7eV5&WjKx&(WCT3@GlyNLPZ6)ZPB~X3xTYdZu5Pvw>9&cX*F^HwM|h&oyrS^SR;p6)l{OmvU+o~ zY5?SNJW7Qt_yT&^$|q@7VL8uK%{)RiuJZq2zJR_$xqzU=IW2gCm>jg%OxtS|$n0L< zxKlvhhtr78#>57bo8ck*G6(cGHdmJUl-2)&&usO`*U}QjwkKDjcmm_#W`2=sk57J#Urnpz&XOZIoDMs-|PniM;iwQfjJwC7ifUx6g6bq;#INXNYgh_F(!6)c# zmig*2v?`$m(dX!{*<6ilrf7_>g!%9iCYYKbHX2WugJC)dU)+iPbDdY6mVb`R4nVTH zF+(W-oWK8?)c60*d^k7+{PSh<>WVZUsjmi=%)i->@PR`zfE{?`c8xmtp57Tf5{Y;r z?2Xf9}@etqZk{{val7E6@sN|nYTm3V>9}nzUezIP$FNy#V9<@S{+!uAwHY2JA`Pcxw z#Q}mx`O;V|f}qQOyl-0rCxjGh3()>zJ*;9aPF<`+ zNU^J|Vv(mV)+wZz!zzYGo(f4vNU=^9x3NlvW5Ae#7dlBL0k5|);3ItHSQ`rlV!5{7HGG!!kPx_2M z{CsiJ21euagD!l>l~Fm?_RG`)M78bTiN7j7ZN$?rQ}<}LAr-bENX^)bT8~EKXB&R@ zm*TJJpe_4+{Pl@JwTP$ti-YrOM%)b`UtwN|PaAaHjb|j~WF4P2z`C4Dn;7iN`C}62 zkIBvzUe0PU1J#YSzNy$iil%7{bBQ6H!2O4kefP=>evgF>^Tl9hdJ?Vd1id?R^kfdR zlY^EYay$VT=2XJq_C<+^j$WlFLe&k&x4!r~ITK&ff^^^Wjltd7(-0O<+>w1KzttYa zg5$aG5hCaQB04uRv^tj62 z>#lnS4D8=0#eKIu{ZaePqbE;(I3qb@^8J&hOqp;^#>3-o#V0?>TH`$;_|=3_ky2Lx zvqj5HOvybQ{cyKbvvbWiy>O!F_qM#5(4KfrE6X-}Jua0QND1_J@cTb!-Iv%2v!7?+ znrhz8+{weq++8<1XYSIfj~~Co7QK_tH?jn*sl)PD@qP45@W0nn_*Pz<_H`Xaz$vsti_+;A$;@^*qX!%K5UNjDo(|D zEvjN=uhu3U*VlMr4K^(~bGD=RhM!>IYrzzY56MFC=pfi0>xCOMSHyPoPZV!;<7Njs zJN)|)>?i^19)>YzebB*;K9JIYnFl{s^!L+Im@8IY%r9>hzoIfflcO@0LUV!~4)BV@ z{bNR;3$h{5F%=7euHFLekQ!1O1jmpnD#*D#*V$%WPfj2ieuAc0pGAgLBV#r3xFEY( zMlXik%}2>t{_%#vW=RNo$WA=o0*&-{7tcF6?S6~MZ`8hzAO<6+*520~SR3E> zq6r7$`WnOPV)_~r>f-udlzIR!hSetYH7C?2^}T4|fp}mWMS1s$z>tyxLqYQwr!W){ zFiyNQa$ws`+c(xWc{jG0U5CWIL@v=Q-($d}X$yllqeJVlw(>Rj+k}*1QT*;LDr&5) zY8BoMY#jsprY&=9RXMU#nWJh8l83d9(LKp_qV@idkf%ZAXnlWUR0IWSnz1THZS>v} zg0!D!n9B=yJ~eUIgHYp)PIvd*^6=TNuG{*0Cb+#-m*n^Jba2y-l4olB70V#pv2XY7 zTaZi7-Gl9!b~(FNSyq74^}`%US8XiFqw_dt9yg{cQTt+dDDNl@$< zpeVbJ=HnK#<>2kTw9BaxuhmYArb>nFj!&Wf zSUV}k9b3cwz%Vbw!BhmMHV>K>hc5xSf4h8|U&>nZgZ zj)5?QfPJr<=Yv_J^{$x3-z2@Hcg6RcAJ<--hz+{1S&msdHd?9yGqVj}6{hE+za$C7 zW70SBaG%=$XP-Rmldg69do!dnrBw>?2i4w0he#tSW%Vq#A2?~xjwXFh+@tJ8MLdCe z%;EubYt#J)RL`=;W5P?J{o7uOms!2cJoiRRCabgkU45UThU$|C)s{`tD0aLca!88( znC_Q?p6YG>VcaWDB=vV^_L z7UU7}7rU@hYu*R>`5@%y6ia?y;JRou#ODJLpAR94W9AZUU;*)&fu4E95}(DH%bdB} zv0foHZKi0aw)BRGPkeuNTJrOBWu~6{tv&M}y3zi0#HKrA($sMo6Yqcc(SL8+9ZIn# z^Y6y<@y5@A`8g-xnX#Ce|EjE)R_Vk?4nqI2wn-Bl(Loi?2@q%DFRbyQ7k|uj2nW|dAQ5-=N#0F9d@v}4u1N^aDM-$Gj}Hx)#QB|dS?gz)QX+`7k0Fwnf`q-we zMS<+wCnKd0DO-@Ti78JDKwAcEp9Z*%rfp;5bNQ^rmI40`wgv(qCjMc*N(=)yYk^7( zhv`*`;V?^7VmQnSl^71QS|x_V)G$j0O5rfM%GLx=yGjg)nIMS`TR;-4;arakG;g_GE8r3YoFb|PP7%`rr-*2w$NiLKJ0;w>=^-LLVAL&#U4rT18G3}`gCj89 zzjDU@AeoN`{63tPp2Qg>_Dx@m#Cf0;J`Kf?*}ofq`$(Wv)s?Q$u9Qx+mEWENqpxp1 zI=uoncg@EQJf-EoT7Vm|0abbFJy&S&p*-p+zun97CI0dNqRQi4usrtL02bJ7l$U`H z_7;jKpkxb{j`5ea`%B|hu(aY@6d$09k5a`av-V_`AK))P%3mJutn#+1J?PxRen=?v zcP=_r^{+VkeuV4naw{J5r}3XDzYDx?n13oCnQ}q+y?#NrNh9Z3I|yCNc_y<_V_j9d zAosx^8RAc?Ju`n=kDtV!7DPtP|Hje#J9AgG@~-h>n{DD_tDr_1$5{bZo}4lze97gd zbztmqc0Cd@C5)3P;XmAb8M-Hnnjhk`pS~XT^30})VeUF>f&nySV(3fZu;MK1bd-5W zy8}k9>|cT-=%7Q#V`qw%`H0Hs=lRE3IRMP*3k1D}Kb=aiteBW}MYZqHD+ z?m0m>^`n@KI`PE{J<+$)Q+=xazm-1}&eUo+%dCQ`ayprB4Rv9=jY&ZdHcB*cf8NS^ zEpMRHm?0upe9C@@uGK7oth|}ZIS$A{@3r5t8`{EK{Vfb{oilfZ-Imug;OK0&8F1sD zQ7g`A+KRrOwr%u)|C-oVwf5^P&x`pGH~%#aU=3gexEa$x?1KJghjUKg-v^`i$5=QO z!@DC#guD4UHvDV>S8@pBH(j40W3XG@kvMhoRD2HBtq2`&ihCllv?asJS{=fgOenu| zaA3Uohm$N|xFgR~MM4HtDBE+4gjS^9HPg-}>`xX%ZHoUd2;=_~HnY(<2yZ1eFgG7K zVM9ZQgw;^u-e_1vUPEU;QFGli#t~#F~7<@D&`|B7Lm@{9ovKJN)!>yeA!>k+{IenCo z1Nqv|a{@ajCe+Sxz@8KT_fKlyH0J@29-9U^govYa7p z;3NUbx=HuAHOXle<)IPo2%O%>0{{lv>Z@P?c7huGhKt?=E~iKYVVlFw!IFR+KH-k2 z;u#c@m(X2CCz}j`O~D#a|2Z+hFr=CQY}N-@O)H2yVFkl%0H%(yfKokKJM`Sc_!uey z1JSC_Gf_m76=dKtu0_qdF(kSf|JzB4j_?A|8cU*nLh}&~45NOeqCUwZJ>gE=9q0*c zEoc>u9CNLb8KDG25%z~789TO~T^72&-Aw?P?~A)_mDj17jm z6Ke`5L&63@bXd!r4fw(sf~3sagM`#`i{R;8is=f15d2)*+t0Kk{5&g^vziyc7JKr7 zh<>hO&_W~58j0e9@Co~Th_Jbw=b;pfiY5uc5Bv22Ma(5#UDq<8B%*>Ng@S*h34(>#>M%h`L5MM#eaCECv`9$1umCAeIM`tKv>H zziJ+*>QK=2L7c`_1d;MJhZK$~4>l$`h*LFiVpYJYK2YwIRDeVJ$50{l8iZ{L8A3>a z-hwUJ4nvrDjBDBt&9u2Uy5ST}Ry~J?lIX_BYBrE!d=nI-)6=$VU(Z0uTdb!=L-Mx8 z9ar4yz6{uxYGKm6#ARYvNiYL>z-3}rNfWzDn%Gs+#9q<{md>-2$2l?5ZSV5Dy}(AM z+?x?kC)>Z2Tlyt5+D|*MiK(a-YpjTE113^CnW~*i8*i+g7BBWklZ~~1q8&`Hp{e7U zm<-}EY9L0x3C?p{ZVugxr`UQ^zW^ao@W;w#8zhjme#r?6fFX*n$!_EL4p&4^F;~z| zM4@Jh({#u2pMo&vur=}A+*OcjU>mG`$GM$ecRy(YbeYmi8m!lS#jLLOC*7G80oNT=VsfiIvA3nL1iKMVQ*IWrX)OoaM$T|WxRe)+p?)yS%vX~;D8WAlfePl z*cCgvVk=kK!?h3x9y+^x=IjEaXN#--Wv=!JFKCbOg7%MNarR1yFc6Wup>Z_9Ys&Ns z#WWx8xu7d9#1nTiBeh+qk=o^_w@`z@8NOR!U;Y^LG2nw^C;(#58S~+UD-I+J@xYxW zo;d~(z&rOn_WKei2#X*#1a^O@gRTQ~w|sCISeO$39Db}7C0n?g>VMVB6sZtclbhvV znmWnKl&!oEs9WA2e*E$w^zLW>VHAa=t$ZXM`D)R}mN6~|U67HFpCR*+iEB}|jFAg? zd%7!80OBQ(5(24UNwo$AIMo8j3l`&20Uw?_@d^||YX~NWVC(`$Ja7P$AYfz($q(iv zD^L4_D^J*w)xYqB7?WX+@u2}KV;P{rkPDpQ7F$Sx#)oNf{+Nb%M5r(}1$>HdpXLHo zP9uy#*4$4T%McdFAS>+%V>l});N<=Pd+{l$5}Sf0lvapOAr)fuSdbGzD(3{-#`(R= z^Lz|67yV~+$YXKMmeGe?*+0mYvsB+(jQOT#X4I?Yk~4V|-kO72c)dd#vHp?IsyI{Kg;-Q9c|_)-ZC>Eb_uEa+!Bx zR_}9}4)oYn_?>@kt8wXJuJd@7viK83N_rs6#z*+n&^Z&k{tKfixA;r(0Vye0Y36(!~Z1CY$ zgqT7WW%q$B%I;(5PXd1+SF-y+u4MNa#h=O6PUNt=k~3H1s91)C;sDdc-R{JFD)d5X z#qh1dQE(sE_Kub?zXBO{C51cR_Xj<$k`x5U{k`@{?tv@WHcBE6R(!4YNxMIBt0ej) zlrCPf?U59mt@wOx?*vKt?jR4B!y%F;&%H4RtFTD5HTyA~j*yJGF=k=?V{iZpa3f|T zVg#EwDZfl0;>5qd<3vJ9SuH8R7^v|3UP&yK#B!n{$Ms3#wqRV}q9o)*_3E?=6&PA2 znf6P`Ln5W{QDh&O`~B^LMx3CbDh)+LH8m8CgdiFWo!rLg*LPUst*BBRhfyxoR7jQh zRkTw5)#RpjI${idl1Pn_L`-*Y1f zU`0VaG{4i>?=r!{w5Iy&av3r}E+cV#={THTnt{VhAHmtB+0%8;H5PB{7eJg1_A-zl zjwYHN;rShcBPDnjetwD4JRdrNyu3Q*7+qNF~_gl*}ud!M2$^Uln*(qBr`!b zI<5N{c~$0+gA|r1_8a(lw183Ue?;z&jFWQ|oc@`-A`pEXF;j==-EbD{ST@%17D127yDsxnMof4H!fB|p< z3`N0FC^Q}gAjsex)wy&C@2EIQAtPlZm%|5!`Z6#ukJN6Fq}}i(B-P^Mp%>1H2Hjoe z@9en9t9|kcWk$yHpax^493QKS@r%}^S~yh)o&$j65)^nz+=dE(XdikDo2zKxIVw2T z9Fp9q8XcuD#T^+RM9->c*EK{Ch$+m<{S}QHfXarV7&vES5_>Pd(oVye*x|_PU^=O_ ziT*Ef^bK?*_4T;gVI+w9kjV;&7VsZ7_8ao_7~8uz(k9e>$Zs|1Yr(fSisypy@!{hq zaQ@G(TI>8Dm4egK{_XRB2J#DE%(qh4OsA>T+@KQ93>ix&IR0ncI5m*CV-`OTR!+if zSkZJECc#lCK19`2YaGc1EZoeYJwh7D8&HQssj6*o^o-39r_cYKd})Rh<_l|bz*q7{ ziIoOQAz&y;4I*4zqzMT!B~9-pUpa#!B*&@zcjONcA-58rkSjt|YJ^4qAo%B$9zs@z zI@DOl5lOn4nIx=yqO+28@fa#5x4|}O?eg@&1>)v}?!qUK?8F0|nnj zwiuIFXw(2 z!GmT(n6Vif9`zyYZsy)-GQX$gB&y!r-PQ2RAtcp`j&phbK)%sEvmLw!{BOt*2#>>k zFi6anot%S&V7Rp{ThB*AFx1+XJzzc(f}z{C?4b)9!|*nSQPLPjMPnF1JPZ%5F^HJP zAnc7nBs2n%oZJ}3fW|OJDHz#9Cs)OUklTvi55@%d%E3fF+ck zl1Nu2ksK`9D_M#TkfNhlt0deznPms~%i@J9i)6oZrD~7c^GC8_AQX74b+`}s(w4Ue z=7!UA>A~e-DEWt+%pG=i513Iq@kbhuJTP^8n0o)i*Nz)Kb^QGgpW%K9{1!v@ ze=%>#9DSqaoBzPs;Qo57)N^}&-E+%Grf&Jw*_xaMBU`&j{@lG#`Pc*YT4v)WuDMy& zh^v)ST*KhbJ%%19*WALGCi~5x{HJ!Q;`%@T23s^9Wh^xO)BD?&d1M%;}KN1UwnO&yHU`+f)0HJ7xJ^ zIrm(xvP<*17Bd%j?eW!X$b}og!bZ5B>tDf}kFMvN8Ki+=>W@FM=nbm}yZRcL2txvG zO%2=q`fRh}1P1om6@n8bAG)Ky@&j;^%9xBLK<4Z(IoVUvym&l9O9?D#O0^!DWNo8f zt#^xonFHN*-1nE#8vv+j1w3q0pPA)@gJq=cN$IM{$EB+_c+ge9Vr`y|mALnr=)xvl z)e8L==&Duvts?YaKJXTUPI z0t??wEx9$Y+W*PwUD+ipH_Hc(C8FRmatOJVEP`vGe;02c9!&BxbOMNQ4uF4nJAr?0 z18}}yk<0<*=UUX3%Wa)uKb(|5T~d31>o|f#xGqxA0;OW~ZrC);V!1>?sVU37(}bs! z!@-g0kx9)k@%Hu261#F(QzpK3x^P506C9BP@E}Ga?tPy<+6+gekmLRG#`f1lsY63-D4st&C}nWU5T~&gXR8-{gVPkRF2?-W?Ya5ZRI^p8*)J*;uEG>s zajH3@ZHjGWifvVjZM6?u^Jz#_328oz{JD+x!&lJdtAd?vR@3O-)>FTU29Pbi{n& zP!z<2={ly_7F8GcVr+|!cOQ5ts-P;SyX#n#%7g^1`!mOw5t*3dg+tts8)>`%ZXDot zN?c#CDmo=`RZ8OOl*Emxi6yCtXKzaaYU%N_ zw`rncF#-kXxRAtkXOwafa{Hmlbc zq$HMsTPo8rr5&5EI3^Wu!9#{O#rQG>n|>G@g{3hl&S<=CR^x3b7J%HI9=H96##=oo zbM$B6(Q3f0`Puu`hg$ZA_v_ElmI~Ce`)6-U8EV=3v$v%LwUqwsZ7D`AYr@-t@#dBB zb{>XX)KtewhueJ^Zm|C_WK$Ejs2)u*ic^gBDaNuCquf8<{Q4`!z)HrZkP)QRm8GDR za?+ruprD3BK@Do_oOwJ4I&A9Qsn})=YOVtkyi7O?`YsNoJ5{w!GnSIljYvrznp=>_LcmV4GtV9@heo zYZV@`3J>^vha+V7qk~G>Sy5Wc#PWri0uZx z#h#$(7t?Kb;s6x4nVH}=vyz%+@*s0_8(}bafN@=I@a5P}FgJqF-C*uPVD5v?g0I2c zhl9-hxwGIKF!y%1kqPF`TI`hVh))Q|3pmB96E9YsD9o)o5j?>`Qi4t_Q_OI+V!ZZX znD&bCu2zf(<|YFZAHX3#798ROIK&4GoMkaE@M(U~S`5s#W3aL9)?j1XG1%C4Fz_IY zflr9@889$$Mt0&1VN+#yw;|5B5N9xOmab@cslrDFi|Px=0OB(M_zYET$3P$)YakE~ z1_I%X0-W)RhJeGiTW~0_0EYr=GH5tm^+k8p7wv#gJJlE6r7!X*72U?%Ik+s2!q2JZ zdx05xaOj=<&Wg`5^Vi&zJ@%FP?@f8jHPrXmqNTI?S6+ML{?9sPY&`J#-Ny%ZzIyyu zKU}#d=2*ek?=PD(cmYre|2G-`H2j}6Yt~iTRs4U|``Y{OYkT+Z^=e)(Zr|Un?cS|j zdF7Quv>`)~Y0o`}qL)3XJ^7@zfB*h>wRhhIhzFn0 zo_Iog{`u!G(Jr|Jpwe#DZoO5z;DQUbYFoDgo;5*J{(nb{!;t$OYQ#q@Bfwdt6!nY=kC<*yi;4UWXS|= z!UR(D{lv17+CwO{@cP3ZZR_SIL~s#U9Ewb)oR zWz%)qb=PTq`t*58d+8-KY53jR-FIuZ+;YqJ+V|h1XQ+wFcpd*A^y-F!=X>n*KayLR)n z`SU@7Km1Ai)1Nd1cBO0S=^(|Cf!e@<+L|?MF4iu-7$jLxp;c69S6_Yg7;VfLkY;L( z789eL3)egUb?escHSM+6G`roNsbyw@RMk&wPd}~w^Pm6xTKoEIkZg7vtxX&4_rL%B zHf`HBkZ$`^+EY(yE|)7;%gqG|SFhF9uGN+;Tb7UAtU$^hQ?w~lv>7vI)M~Z0AnCN1 zwU=MkTDENYsrKooAnnAvw7c%o{`Ieam1$*VAo1Udwc=teF){Ho?X%B7>h&|VnKQNX z&p$sy%g6x9quOij+iROQZ@y2v?>>;eL#0+(sSO=E^sm}q|B5d7<*VAOuWF-5kN!ma z6*=EYo)bng)VyO z8||BKwDZn8?;-7>htO4bmujV@T3lS*-?hL09bNYQ9Bs}V?b1sx^=KXsx~}12?cs;D z)YQ}uwGTf;7p|+<>g%=l-h1yK+CTn*u3UbDcEb(Y!i5Weq5a|)=+eh-)^5I8`|WRk zdq6vI0A1@y){>L8=;-K;+QyCOV&BKw#~*8NzWHV^tyeE}^{9?o$Bx?3qetJ?-hLZh z{=g&JBadhU1`Np2a&pl1Z_UEs*GfuC_F~Y31?FFg!LDUxW$nQr2P^z34})7X4C8tX zYOq9lTMTCHcfb2x3I;J)W8i)aUhUp{?|mMF7A$h{1sJT_+_`hRV32}UD$c>+%=U^;L{2V3x9(_M;5BWVAFJ6{~Uu1tn^v}2A5V>S2q%a z3M`dbgu$ehmzQ6NK?K%%dItuN78x123WEkL_H`c&7H!LxEw^BhfYsVWU~p)+-FDj- z7!+W+ZG$lwv=?4@!Hq!x)_bZQm|q(wm!GkTqq+r#T{{`mMva_=j z!IWUxPtON4YCCuC+zciJ>)tgK%%}bFkAEBurUMI?T?A&+uDIfgPGB;yaz|x<^ftj?MZo27GFcDaLW-6FRd-25=-viTt#WNOyS+qOuxZ}5A60myvXfTJi zbm`JJ!4zQm`;LMcv}>-pW&oG~tY2Az&etA&^wBJII)=bs4Rp5l%rnpY4xNml@anzj zTy4^%NpsPu7!scxM`vo!KKtwjbRvdE*FtojcIeO{9i4_Da<~qir7c>ts2rVyp>k~` zI!8Np?AR7`3Wm%Fx1lq%d+xdC1#|+2&h%j*zBX^(ycQrjhES`%Ah!1FU;ny0h>W51 z%{UNO>)pHeK@b%~>Y;29Q~T(nk9LBH7+R%&1o5=XFTeZ>5Di1@?>B;2+U>XBeiMj< zp*H755J&s-pZ|OZh=L*KSqfrkKm72+H6Q|p-ouZg@mlNFt)D@oF$6!HgvM%v1`T=^ zjl@u_KZM3<-+lMpA~Xs^@*l_0811aH&bkMUz|g#59+20ZPUo+IG=}IedIMQ){P^)7 z0Z9zin=c1)T2fNd?LZ1c_Q0QkjP{qm{N)EAfuWn+8kKAD@$rLDDTeUI?@*cc_~VbC zg-S4#KXwARwsPgl@c@b;-75*ew1R?yzW@k^cE@-W)^_dM^*9P)h`+rOnYEglngV3P zP=90>UTP~=tf)aEhJ4NnJZP`rAAT@A2`vfYl%qKXVvt;R9@Gl8*EFy-wda>mrySkS zgWVufv{4Y#)IQ$>ElRJ4q1MR#%b?yV<^GQDqc;5m)EBitCd415V=JgHS`kBFZfMXp z^U1xDtv^G|vUi>VTa)WHpnItu@*xJO6>1@lNyXM| z6{PrIA%-c%u7o&eFFp%(%F*#2*o4${g1pqSUqS6rO7;R$m(N}YC4!_?+?L(J2vs0KSy%fAHiNhx_h*qPSWw-|2Js;`0VX?48=HGtmJUV(W= zsl6BCiqbp>!;4buYOn#Vu?NBS9QAL4ZE3x9gLt7fxdCdPR?{0$i04C{5VIOZt09paNxb`8WKwa0!8e~#WOpjN1L_Q0H^G#rg#L@9qE)EA}3Z7@qY zs&B&Zqt==QG0#!C2x5=YrX1>)+O`yGilcHK)Ca8|AH*H4JQHe?Ql|* z4`wv2)3agT(dzpf%tLC;wlJG1Z61ZXr*#(#u}Eo_4KYP&eksH)t%q-5u2Q<(1NB7h zwgYA{rRNq5YihMyU^dgrDTbP)b~+bol-6Vv%pF>*Q(^YeY8wc1o!T=2VwqZL2GlOC zmJjA*@S*AP5Ob6|gP`UqUB<&Kr&bsM@klAT6yk>3p#*A#QXX2mkXkGeVx89RYM2?c zN`3)xPwV1sh&yU48_Ymz<5dt-oLx+Y`lr@74s}Lr_BxpHv_2nznMmyv4fBH5W;*ph z|3S^tYIVTurM0{s(*s)NM=+hBRQ(9%9%mK%ApSVpNQ2s-l{XXWn%3eJm`k*}C(zk}MMmgx(#jn?vVnE%uU*FX(WY8Jpuq}31swM?t^YnTg^;+JFE zK`p1lJf`;lJC+`vGPTt&5{D%V{;-i|G%o zh~Hrv!C6WJ%umk3eg*TE*6lwqJ)kvvGt6~bQ7%jqX)Q!Tt<&1P9_BE${y~@{oMm1H zvx(N?Vwi!P-3^DiPp$iFm}i_#K8NWiXMdY8&7k$!1?D=fqf|^IIqSOxgDN$YqC)Hi2I+b|vGEPOYntDK$v31+GW)m;H|gR`rrq24(gH~=%8R_+%t>p1&+ z3}y>w10Q2LODkX(rimIvb26rnoQ?NCXuJ3aJ@*HMsw`^}x+^1gV8k(R$q2^ux;%Hz zbavf|Pp5I{ju+lRSJzUfanxzx8~2y_a8t0p&jEG z3;6iUv?B;6*<}tNr7MT=&TsUY`?MH(j)(kHZ#?8;Z*Z<=-@JX zSZ5<4f;`66b7!g* z;VhwLHnyHrVCzW*bvhI&pqr7pd2e);b-qBFiT0uaQE93*#c7BlV0#4%w2FsR*%^^= z=`PiBX|~noVke3tvlE3tidCsNbt(>-Q$fK_si2@;sE`U8IzWc0T^hHWgsJ5DSpIkg zLXQ_hUEVk^LxYW9MOWP%Y%bP|L87=+G^|r9widCc0$ayRM|JEnXm@(DG$EP4U?kSN zhom;z1)PNGv9b zAgt(kbB3g7tM$B!d|24OYE9F831Lk^tFiL;m())h*hCh=!DBoHNi z=3Ya~ooq8UgUfTe5w@n4jj$&&1GBqq`ir2F|PA-vtmG(=OASyFbBzR>JmqU za3J@aD!`LRf8}N^K!BhPce;lmhH3LvHijF`w=Kd!g%xo|+9yq409e6}7!$AB6rVUl z^hq-WUgCy-k$hX&3~$Df9r7t$N3}Ad}IaFJzu|X&;r|{wy}xD zbJAXY+WjhWfhYY0sX(mQAf_Rod%>Iz(Pr8Lgr?lvV^4C?=KWC%wxV(}F}uRR?VO@k312=B~4%W#bAku!4qYOHgS|T`Ks9r zftR>ZLij&ddrfXuDbyC%Hk3L-#Jdj7TiGr&WpFIjH-vKuP!1E$;j&2Hh6v|o-i8S0 zCU1knx$!Fq=l@LAjTy28WPx;O`3Y7j_?-klM+sp-gx34YUkhPC;lG)CD_9CA3wv5V z{>vM2m$!fc*`AIQZ{XA167@9lI(b?wPuJgh4WAaO{o-le;Mj54LAaK&TC1qR<)wZdO^A!C0$Ot2S1DEw;497Bo^` zHkc(rQ3ImJf;B42U5O^XRDweC|9;QCvoo{13G`|I|NrlKo*y4FJ9F>3=bm%!dAoP+ z%#`3G?&DD}6PU2I1>F^o7>CE3JYPi9dGi+VK2WsmRzc<9CC0Lha57Czer}WDh-QE(y+KFQu>P#rB!KIT$0MqqSS%)jN-5n-cda5 z;4GeY$ShVSv$!CYMe8mYd@7d~r|yx`%ATbQQW=#tDU3;z)Is))XkL<=J>%f)o^hz` zuDhKidmZdLE-$BHdPaJtr?J=~o{<(?reU2eQ<${aFm>=fBRwj~>z;FP*3UU))^9-n z$*fP(WwouI@M2xf;*~2&7>>z+#JddRlCmhIM)QKyt{j*f2#GkXpE6Z6L`@k3Tr;;}4nj z5)z)odXX+mX8jx%r;hq47F)zK(qhXrtg~eblNKAM=z@3DCnS0AOApTarH9P=8R$Qm z^*mjc%=&38PGx-#15T9oB!eR!Pj|m%W-QO0Jr+BbRH-Jk4R%SgjajReSR3_xs za-FRI<=ZSQ_`^x~kz{*PQdGF%P?GPbbn<;eLT<#~P4d02KZs9OnQUE_tTKIB?3Ej` za4U<&7V(U<*fNdEuw|;XuwjZKc^$>Hr0_6E=;Fk zy`9At@r{ucMFx&h7y5A%ity||d;y<>5jrOcgMOy4!x39aO4TL zbHWgLRt7LchrBZ2jMe`hD+91Z&&q&UB3C)Oc0!IN9*o6*Yh|Ek7b^qFIaz5OMn z4g9QUIK|I)&!XdJ560rZwK6cGiD|5Ew5B+YTrG_n8<+F0G zp}|@OmmO!@Epjl=KqCh`xZSRWu4B2&Nydo1o1~)r-&#fJ*~KbCic&91RccSZiB#J& z;*x5Um#*#BNwp8g;(uTjVMN!f2+7*5R}oSq;IUy$syst0ldA67btY8@VfVlJDgvg` zo{^TRboZ<~Q|W`TenXlxaZ>s;@oE-(69#6;KW4G4BJ}Kb6(MgUfx@Y~IM6Pr&)-O%N`h@hXk5A8fKv*Z95#6pLq$oTa9>k+#*~~NQXB?dMGY*;c z5)%I3b`=2&q@Gbf?cl7RcF3%sk%o1y1wb6hlLM{=q*3@`ES6P-p53k@q$oTa9>l9- z`P(zH#a<^KJehI4?JYnIe|}B`2Ri&0l0PL8TI}LXTAR+v)(HW>zvM~8TI{0AJQni zvk=g;+l7GS@zo0f-FtZ4nDmT#--EN>_mEltPc8(E=yo9>Md4*3AXy-uoE^8HJ%irs z;GFk5B+ma&TL<8DpRczovfpnv3tI|qzOviRhb7@syd_)q9Ad9w9X4&;pV&HQZyIYz z>>uO?y#{CR4lA%gA^QiN4SMMSvJ#v0(qZVPQtw+_m9CZUca`jj=?Vb-b_3w83`VgV z0_<_yTTo@;9KYq&8NMYaIom3g!@caKlN~)#v`MP4#S#_rx&i=s-2ik`>1^lhqF-k_ zXF34%+YLaX65}!wTcfZw)xT;aw|1`OPAPwzZ1emA+h`lrY;2#EJv`X!ruRD5bi0!W zwcYIGL2WlXd1|`e$>ZJI*_^aR%)7TUO>H-wuIj2&x1Pjb!_G4*OFLe|N@bxAMG&^F zlB_H!lB)O1X0v*K6gH}>gHgP*-oFg0*4uY)U)h$7E302y9{^10wJ^}5p|cr?%=mG? zFEp;GQ*Y8uDWw^v8&;=X%0}O`I0hs}KW*R9bfu>66je^?`ydeL+lIg<=0niFFaG|2 ztM)-S9y@DrRK9`RnZ0(Frq-qMDYcHuCs%pxEKRM;xYN{j)2YkOyba@%y9r1up^gA| zM=IO%t`yJP6#zuk4L~=Q+VigHy5AMjZ&v{5w;KR&<^KdEdOTzp373=-e!jU|9KcBb zO4)7w#Yq1O*>LYQj%1JTHI6j3EA*%ir(z+J}b@DD^8u%nyz+?kL>N>}id*DGX4fnL}u46~1 z;0U`7GpKbj2v2N3LLxy3wJzzT)H-rau3FJ;r>O0wQ`C0T>58s8t@p2BYF6);mpvsO z9B@A>V6r#w=IuZv^YGHNySDk*z|cEn*Y;AZ7nI>|0{+gxA77mPB~r#W@%K0Uwc=}Y zFXQhI_yYj>VtZ@4bMzqvdZKAIbUo_;WH!BS(+NOY?At7pj9d$A>32 z!nzyqOj&e%7&rSOr8V5ny&Na3sIK=fA&a<-;<5_ARe|t}cyN;Mg0AvC+XpG+fN&|S zCAk7nweMwPhi;(H)~*4vx&`Q_Qum8c-BrH`)#$e?0QB1pK%x=^Ace*yH+#!HH?PB9 z=4kJ-)F;By)VkCxrPfii=O)i`3+(4BoGfXEW`meole`2> zF(ZZj`Ku&)xZE&|(e|EIsrr|u)+N`JT1ORMxdIvnvxObveOL)ZQ-+06ss?U2m%X+RLb!a$#fZ(#i<>fJ#k+m@h= z0$pdI8w~W86zE-oyHTLG8|Wqjy)y+`33RhS?=sNJK)0ko%O){PR*p*|hOS-Mar9&# z?qhgx0g#o9>~%MHM_GkS`>}A{B3*bdt<)-*cN7a(SLwogU~t7ST`TkY9F~Wcp?vJf zUW-Z)3-P z#<~`z*t=FHZ5Ot^`?omVxkzhpN?oMYIi)VrqA1m-S-QoL)?i4hGo(cgX~xK#Yl=lG~<_6w9BX`XmgoR0B_g#uQE-b1kyyACM~83o4RbM zKbmYYO)x0Zgjm@NBq2rsy>VO5094hPCKxwq0)H$`AT()$adz9yKyaw_z7+k7a)KVQ z8?Yo|2A$%mDDG6F`JYI{*!w?`2r^jiSc}Vsx{O3RB1kZ@BLd@5wNcoojKVTPIKe28 zi%!HB>4qjEu;FskaD{0|L@s+80+1!fI2N%A*Hxwo`#?~!$#4avVSuVMtrnP82NUIS46N*g2?*Gq(qDG^h3<^|gdUys21`Q}RLY2pW@=(-d znlLD^Nu6mDHBE@ZWjbd7q}eo)C}ps+7Y0D~BB9AKf>9_^=SKQ7(`-3+WdD03<*P>a zUmuyXa%BIN*m#a3CWgzAafK(GW6t;ziONjOW#Y$hny9O>?pXZ)DYW5(Y+DS5^Z@;v_lm-3HgSjf-7^DG&7;Lh`hOQ~ZyU-Cj&!ckPc@t1Xw zzr%WF^f)|B|oWbv#d|KN+61x&M)F_rHJj znr)NiL*6M1oBuvI=Q;=9=++m1e02*yaqq)l_P_aeFQNZc&&`_B5^ja3jUmePOqo%1q^ z_im&@_(FH13}1h`RDZt^FLV6y=f1K&_`4|kb9{e!06rQ$bSYNsr}`@JT0tD~`aK-4 z#`_z?uP5H8SVIQ?Mh>4Ri)+YZNd&JoEWwNTkcM80xA)=Yfdlb{=J`nMXAFTqxP1sL z{H`JA@MVxi>nQm^`1T%=0|%@I4rc}q_zfJ+@X^A0jpeoC z{GFQej^g}JHI=)I^S{!V4IHo-IGhr{cNpkB4fN)M-XSGD-YU+2SxaGKasC^c z@=uEMKi5?5EzWP(k}+_=YT$5Y;DF!2_3nJxCo4vj31!1CO%`G3Uksqfz*Jwy&H%cd zkjY_Q_yWgyVJ!!G;YJzho*e0(9O<4M>7E$rlAbpV$t&r}k?zTn?un5Gp7FpPJW%Aj zdojj)>N&=R*s_y~Ee_3SXENzPxWq`26gW@P++L!k6P+k=Fr7#rb$u_HAHCj*z36ZD2;5-B`zmozmF452QA+x zDA=@2OubA@y#qovO|{+cIod(swC}*Ev^Gukjmr23hWRyIya+t+PW8>++8>86`r@PO zTTqh#dnXy}Sc3J|V6(PefG@Id9*x6}2ddo7{)5;bAokJYIvaeUa}bu%3wei%LTnug z-r+inX5$68W#7i%t*C0P!^u=Q!Pb{qg7?^pR&GbZ+fcdQ_`5J0hs$$uxDM4+xR0Q4 z4+>4aQ#|;)KgJr|FbX8 z-tG!B)Mr%2tKDHfmYoRZ-t6hMV-uKrYs@}snLnXs(1xg7@1WXkexR$Kp@IJ!@T8U7 z;fdFqwX$CbJ%j|P?Kmc>J0#lg@qcQ7{sM5d*aO~Ej4HfU*Rcc)q%j4YXQGbkQW9N!ct^*5U7EXerDE2e-ZO`tl+kubTh^I)4)FX;zoYul+alzcl>X zxZ00$$L-yiOV1e^hdW1bqfuPkiLX+=pOI12YurM-H@XOJ_0MpVfrTx6MIXp28+0}H z9H7gx(V%&rPJ9B^k|E3)$6GlaU*Mg{)}Y=L3-slM3?5&ah?W&42$Q&Y?f1MGKV$+g zc2K&o9&(ICX%@?NOPf|{bNvFA?3E@r({!)`LD1W(d7QTrBL#5ZEI|7zu8-mju)d0$ z8*v6m05;<=uML+VMJVxgWbXT%b)>{sF)kZtAj4O2Q7#Tw;%Qmys3x zkO}-~^25w3ge=^_534wC428C9)O9yZg=>TN3r`i?kyZ{5Yi$3*Z24iZ;pztNx9 z2Y9W$#)t49Z%W}vfbVG~=5**c*`}NZ{eD4@cr^P>@g)Bg^x`^pqwozWJe%l00TV+Q zaA(j`%5ET+Wq83kdwqk4chIzT8xK3!;hQ|be|5ZvzdhvV3m!;+*_Z6)O9V^9R41?Z ziYxrm%M?{HE&4Zzo?$W#`VK+wFtu0E3sZZ&Omz@_jE7eMBOaTHmk=)F((yjJP$ayC z2a2am%gCW#cPG?CNbVuo+ZB58t{9he==BIY)N5f0^{rm&A*%`*2aE|cu#CflA<1U1 zZ}PB{OufhhB9jCX8J7+uEFB+_pZz?1K&G^e9Hz8l2vZ$irgnFQ9uaU<2F4{FdOgAp zQ(CQsDHyO@&pu?PvTeUOiw`l^(7F^Ew5C_mw;+sL?&-?^uGr?R3{YMA<2Rbfp=5bsb299n*JZBz$VCDvU zJDP&465n*H+4OxF(H5M{XeRPkP!3*-eKV<&Gnp8`5p~cJbOg))J}nuw@=DrEwZAb>Ci`0mcd5wYP+28nBt-IZO2?5=D+bgT7@At0c2C(f7x zwj*4fg{nJr2+NiR3}j3P%PwOyt6&VBKPzB8yFff(>+PbLt#70G>-gITm^+IA!`>JL zO`jE)qqTHgQGwPQ*qWF~1Z4&){tgye-{9eYjSdcItGKJJK>D>NL=yoHgm}B>z`~D2 zG@&T+&G=%>Q%tn=1#gA0>={h(2~f!#`X|Si=5K>=VV4*bW1S^K^5O+(YM4C~(UKYr zfKIO~@_dzi2Rud)LS!b+PJ9&@6TrdXnSJAW2B)1L@eE2Ee*yG4!I007{R{mc%FxPy z(Agx9X_6>?l^2r~5}#|-!A<|Aq+f=a+z@8rM;vrsQF8nUhR%Qf!}R}up_&whYaDO? zk%%ELc?|C|V+e4r9W4APDok?$ic_U;ajMk6)Vf$tm5xb2RjT6rNT++T_B&(q$_Cxi z(%BjNs_fXl%4O@70*Lj#p6p8WAm8c@%**l;~dVG=Q}!a4v&i?9BynM zz;OWdzKY@nI0Njyig8sq1LVGni>h(BVkKMd7QC&*dwrAzdx`euMxKJ6dC2T=nAe7; zyEAYAPy7gV`v|+Q;^u6e@v`E!TpZ@*?YWNn3zk4Ajvx_7A&$9QY+o5kDkC*z zB&6($m8icyio?x~IIu(HZKxQGKVmN<;<9;p?0I#(vs2PEbTxR-agNQn&SX9t8{H9& z<#%k34e!_%8{DxY_I&HE*fXsk$DVHeGWJAk=Y4AK#$DMwek{i?<=B}WJGNt2?5K{9 zV|_ZljP>Z~jQz4T8oR%Bb6xGtt#8!TUf=o-+eG{FxLJ zFhvBn)Tw;t7~q&XHJBL&G!(7~MEouhkXznei$PGxwrw z#@}(6xiPk{1A6#r2lO!B0X=-TgL+uecZeX%h7Q8GalCy1}OwwZ~3=y{cO$C9Z>Ym9Z>Yz4k-E+lV6UFo7@?DYx)PV&C~bR)#jsF zasJF#V{gsqh`lxQL)gO^ptOv>$W91egd2)&Zap*hY3l{qv7=gV&5dnsy)`e^qji2! zYj|-UTd&QI^=Z8WUANB9i;Zp_TNK;ZI(9*=DvEHpd;%^npM1waV`%&qdUf;I3wX)lDwHa?rQ&{88O|RF zFn z%DK&Ginw}!kZ*Sk-TfZw4lu4BsF;?EGhSBAD#Bszq&<^eV_g+1XB;gr8&{13=_@0B zWuU5z1eKANvMVN`d=kN?5sZD7u}_%qfiiYbM%-m{C$aOz?7SSFv%yRC2R!0g8U zF>6nh*ha>35Lh2Xs0q#fv~TR6Scs2>_H2&1P<`k|^+^I%Xm(p~qB<7vg6ix9Dr@$q zy@~2r^s*V04;g|3ok2O)J-`Yk*^^?YBMJCp>z8#KOEdPyh9Volci!qY`ZGGw!-pVt z8;Jd^Z|vjQ+eqv-o7h$my9302-Z%CE7J||F4mYYV-KaVes6w+p>rGT7R#1^xjmnz+ zd2ga3u{*$bEktMtDL@ooZOd~|$8J!y8C2PF0&_N1Eud-}sIm!0FK$#F5Mct?a^L3Sw!u7H`#H*oj@^Ot!m&*_FB}`qhjh=Of{qsjy-O5yJOn+c17@1j0W;0)m>UHLf#$l} zK};YrCxhfcOdv9+@2e}GIYZUe&YXz^eGo|*G;=p>H#hcr2h9294w!SS1Ll0q!#$4je(||u^)r(nPXc)_sp@K`Q+qH;Roka z294c<^Fd>G<-@F=F!(YOj>6Wlxv_t?UQiT!z4g{fc5=~y$TuJN zJ7XOc7Z%}Ah8i8p2DN@Wmc#ty^w!IYVwtV;6K&>KoPsuRPxG+$iO*ww)`1jJ@v@I~xP;2MHlyv@L~@T(%Z$krFK_z;}JK(1H$eZe;%BDTTL zPi9Kuatd>d158}XF_X)UUxzLn&+42xg0nD)*5qz3xNG=s(Rc*|~;z)A)0MbEunIl@9-)*58s-jP0MQ`J37wg#J4L znP2f|g7_-u>Hed*(Eayk|Gcy_1O}tr_*wr8{h!|Y5D`Jc);II_;PimLho#B3^F34_Y6W9%8NQC$Xo0pC6$3wV>>%*g%xN z%F#GdfAOQoNBH9<^%pe`Z)oe|(qlpE(rWhnpXV3j`)lc9e#L$4;`T!D z9>s|s+g@TjxTNinf&)yoyUDKi>+IV3o@n-lDhLV>bA>(|m9b_N&eiPekHS7EJdVm| zRzp8v(S`3E0hq$;0keLzz~^M%GbTg5*?dGsel)ys19zyc&*;%NV`YZA_&osE``b~J z5ub>Ins9wTVB~AH+X8&tkhn(y_erS4_jcRR{o(BX`viV+GP<{$>nHO3ZS@Pdi3M9E zuys)$lx@dvJ3bVbjkj>i`j0%17;MRwmv6H!GD_84i+&^c;#ROeus)Z_@2NW4F3Hj* zw>u@nbjf6=WSTCSASM2G7Ztka#0+ez{(dRHT`GNhUJjm0U$C5_<@Ue$sW^~EHAXWh zg#TcYA>1nXxDA52lC&@8xJbXu#|^)^;1@!jgAF}?6|4~{`9j=0Xg<~&-z^>BWe^a^ zG0pul!v0+xSj!Fbf`-A4pi#sVh~%mLkM+wC1#rXtO5o68upYyRPJ^59aOK2Zf%;mG zjk+HnpO*m*)(57K@R{^oT#-xD(@oZ zbePnipg7texYgkj1FzMlIlM`o8Pa^;=LS0sVDu6RvhbF!@EZ`-sCOW$zs^r1s(mDi zqJnrPzfGmxlA^S)J22oBI=KmNGuVPBSl|5z(9S?BHt|sM8)=fzU)^Tn7WHeVoO;Xh ztO&~Qb;_ZqbGE3lOO8%E=(n=VczGI5z6%r>Sb8~lAt>_}dxU3=>|%tq8W*MczJU2Q za(H43g~QKy?#8D&ch|P}UgZC<-mlOXpL>s#wglrnuo2xl4+R3z+ylaCi%e8}^~98I zi~An6sPqHhvzu%8_3qQKh(ptkC+(Gdcvi`?_-e8L1K^LZfI{VOHb{KWPW*8A*2u(` z;8)q}DV;UPvxky525-gl`EE3B>RtZIYmf9b`U45+ZHzGux=C9!3Wb7<_|uNwsgfPk zj_oPh5i&5^b~AiSnVRFFGm2rvLUA9<(02nkZw`#{H~4~C0FWywmGOcTf(}lR;1lRk zZw#uz9>L$_a|H2$L*f{YH>%(#GLe^Pq+L{xt=dDS;o^PWUqhg$ybBVhD*A5gGB819 zHcrDMgX-6RPovCFQWW@0e5Se?Bec@mEt zspS57utSN$=Vxi}=Fy-cgD@gP3;ls+jPW=5LKmWGy?-Z;P?nu6vd$tl8Pd|7zGq9a zpcMFc=ah-K7=KijQG12{c8c}v6zka;=bHuM%bd2`H=*eQh;#(CwTEx%>8MM128222 zCR8j~-^0Kt7-}LMocG-`|0TMHbx#+%b}5L0t|>hAuFh&QdUmYT8mWg@-IhZ)L>kZdzt*!TqWp3*PAx*p$c_t@MuqpX7aaS%Ph$s z!w3QVeto#K8TkVBs2wKI2t{J2RImIf3YNv?bGyji)}KwRf5ITK81S}lVY{elUqiXn z+gYp%)T50I1I)-iZ8B%U@&-(Ht`s#bZ=hCyum;`D`MR5xk~WqINNHQRhgihPyp%7~ zR}PRGdGX0|fUY!1RtBs&%hzz{n>t$~ss>%l4V_W=!j-;z-qeJFN&8(aQQvyR)3bdc zzEu1H(5V9?$-GRL1i+u)|~S-+E6V`o1|q_%VNxTAaYn7$ftN~gvwl_7`V3U97pM#5grLO zUK*90FCtoN^gB09c?Hl5h4@_*3#;{j}PG^J6!NqMoX&-}waf#>sZZEn7pJ>5boq#Dwg-yOM!|gICp%CV6W4eR^?YxX*Kja= zCAEN)H`LYPK|u76CkK%;;yFV7y=m>?AussWgp2XSBr{*|*gw8XT!NU6H+wbdB!mxP z;RPqpeKd-8-VkTPg_<6|kg0i6*F@u+bj@Ljn)`H3P5dcc(=$=CZ0i_eTN%Gw*Yrx% z_%4*13)d8 zjTDU=00;JefW{FKO|bbe5eSnGqHCojEcSuNT?xIOPZ$F0_b)n|SYN(me`kDf3a||o z_`X2>4p8V#NpGPW0M3LabJhWlF4kY3M0Ge+jcP#ghYNUs8gE&e0x1kcR%^LG*aVP> z#qllXN6|9WRO~f{c-T~3=>tjUNb8Vp9b(6*)~#1d>j&BTc{c8BB**v3DhvIkcKoY( z_b8GX+piVS{_J}n0N{mJR8Ktq`tDFZ{_3c&6Cd&t`Kpcxd2AOfZ$nyOT)_C<;vAae zWyMG5%I;XFl%kdOtzn4F6NB?~yz)KgsE7k~(v@b@mPO(<+4R{U}; z45^qyve+BfhFsdpa3oe?dJYVQ@2r47jMKrB7M4`N=Q0U%V@u>m3I4-a_0fFGs@>@? zL3gdfdq2PmVIz@QIh%2=R&OyYgiMgu--H8{EAN#f5((w=1olK%Xm>{ZH#pS$n{lKQ zgZqZtQR-n_2Ez5~!oJ66@Ex_=ImeyFLe|dHwUIf^>RJF$TnMy~Y=2Zprro4subu!~ zgu^~Xw?be>hWp(hOEHG-Ws4I5p>+l);!637y5{%{2rW4U_OAaya(X>5*iytq5u<<= zI$L6k{BQd76h+v6Fp7f3{x`*MrVtTE*Q)V?uVF_R>y+y0s0Q!QggFWyK2sl_`jxn0 zy|zeWL2a9oFe^U1yh&ZGOX18nsSmS`*NlsmxaZiS&A_atpmVT`Mvwv5*AO;sdob&r z34W8WgDtr>_ikm$*euF&<@->Uc2Z;I{0--7(Ti!6r6)AV^dG-NNM|;cfjm_u#!FP@ z3Ra3pD~AajRATHe_EB=psgfH35N%9G%|!j-v_}3A!sd%>X%68m&q(Kz^-8qNu-6wo z_E7I{VwIcKoCaaF>^-oWt^IZz&edZO0oTMfxb0#9jL2rSOe4ZNW#w3$swLxGI$-;X z#JKt$t=MUpS*>JPP3RuX{Ld`? z=&9uS79IdB@{YGl&#^KH((Hx(>-B|}m-cPQDCnT(W`kvkdc2Ix%~r*PWhP>kH>wg| zVERGr9oCS|iiUV%M%G}n$yCMmi_G&p>+@Y+yY-c+J*-Nd40G2iB5~?u*k%wQN64AMaEU$tafRB#ac&Y8f$gCssGY6 zXiA++r=glg6I46>bzTakLLd(1wd4z6AgL_=$AQ78sF9UB>no%47$^?S%6tyr1 zepa#x%&j4@M`9ikBa<+4(z+3US_-hHVim0U5H8@J6HRq-mrGmF&MbD-jCOFhk~k2?#iD`HHbD2FOg=EU|e6Xy(6g zW4vGL+@Gx0lu%Z=(A+rU^co9g>gy8m0|2JS)(OW?9N=uVm`}Kd>$&KrmeMw~#5u^o zHi6FLULw-@h>S+InkbDRMyv2eR<0I|OrSQYr#CuC)M*;Kx|AA}bT`(uzD#{>NA?8- zSkIHGE6%apsebf=G=vZm>w}124!q>lG8iWr8dMFQGZIba{o23r!l?0gH`urm`*BSE z4Nm>-iFjk;$5=3O2FuSr#_2Fjz-Dv*Te=!hhRoSG~Uxuo-H{ zKY=-ss)<~fbZ!`c1F+5_)>;B?D*{$ojb+9zfU_yoR?VP!GQG z8RQcz$1Ung5s9H0-xzKNhm?StRxE?i2)2t^xSfTUu+XGkqGXc6C;3a0?^&4zXP%qk z_&+Oij_2C=(+%S6tb*R`gf_3f{{tBlq;H%G%N$?&Vl+V_rKjQ{?bSr#w!DL;Oy|{K zIV|=5Hk`YX)Fg{e=nwsq>BSQwn40LDDQko{vmv4Hw=jfOzt*UXBs4we(t>j_ET9TL zCLGA}L=<>_ul;I%F=m)Uu?LP-KK(>SGAN;EHou66ZLY858i@`rj4( z*#MSqZik^I6P5613tJ{g29tSs%NT%Dzu?@;p)pu<4^NDmZ(c#1%h`Lqe-Xeb-37eF z8rEFcvpJpSoKCV&MW^V4LZfK-^`Shwrar_kgqo(g=2Tt&eNq19+MdorwHop_neeo{ zjS0_gc53D9#kpFs)=YS~2)4dAUNnP+fK%2VkrBTLyu;m}_8Try7W@^!YxWS+^lPb8 zArgnxBcah3l0KqbD6%T!b@ejZdRDU_rye!ZrQ zWt$eTl0+_3Tl+KDslglfgXN20Buo*eMl$bMe`dziaA*+3vpDk>Tr3Kmh;!t(J$*|i zv$3_BmBg_|R{S3Srpb!UL=UvhS%y1AJ#n)psCovRTcW2PEk?ZzZz2xHQL%YbuPhiG zq2yCEtK?)Ai~#*$k-P?@9+fkEA|S*7g%J}~_Ep})u{m|7{Cy{ zChS9)SPQubr6@ydeg;CcwFXPbwqLY0KOFio1rCP*JLajH${M96q zNr2jpK7~j@ewD0Gvl@k0`9kHO06bM2$(ZJIs?|Cf@6ZJ4R{w-U84eLVRReUVRl3tT zRSGxWNrl*_ba9QZavG@6VsnQhjcW{~S*b$_Z|+E;?AuV*YH<}4o8T(s;dm=&63$i5 zb8b&}18~C|RpAMsINTR~AU0L`tLPgXEC#%hpw#a97!tNU zBR%dhLb!-r06xOYY!Uz-*V(*Eh+Y0Bh`o~%wQ~N7b2aT*H?hWbz7G!K{m^;*73QcE zemGQ=kSt_hE0*ksSp8KZMcl={L`xCZMYwT}f^$uQunO2hjLYY<2_6EE}Z?sU4`D}+rC(oO55leuAwY|BSN0gl9 zLVBSuG|<4=*JiE=Cn>kV(O!C8rp6_DH3id-V-Mxa^u6s2bPPh<>AiyM_ydy}s+o{N z(I&2)gDVzjS=q633>O8h!k%Dc{eyatj>Nfo0fXnn&Yz+=H0t{px%e~~kU^E$S0LYE zPN>(MWvUKt)~FHtRFw?4hDwl*3}M~t=w;lIMrx-BeL_A&-H1prKurLjj$(caF~{E% zFlm1e+xO|Z{XmuNY5xq{KjyT*fbBQ;GyPXc1?LYkKmKAn#`O;nhuTp9?;p{GSp_>; zzJlcsOk_Df4^^D&isdcOh&WdPZv7v%I5*&2-3~E3;xws9D`Xr$mUN+a_u(Z@EF!j& z{h6JL*BWJ$`%eT}uaae@RkD`}S1<3OWfvIeTS(2O9LdS}vUSupQD;~iT*ne<1_q1h zA&sJ3jGDl?RJTi2eH?Qi?dXiEu7kHQYM?Et6hr@D8#Q7Z49ywcZyxUIzml)h0{;Sc zHZ)1#Blfi2liuM`gqd;Zjj4 zeMDAkF+NC2RGp}g)Tp@#%EBS^)d3ecpd3eQoOqdNp+Q8s1R@&I7+oVpR>3*!{|)wk zGW$2aOe(`N&K%X?+<|Zr3=)Pm^#+DXD7X-XYS^DO|69So>{7OJzQ(y)3As4@mje_o zVFb2o*(`#8z^(a*@DK6E3wtH{F!>lpe;9+#b}B|V#1A%L#DuRgl49A@Vl6bQU^+4G zCdP|6V7N<-CLsS4k{^^T3<`TK>7Mj~BwH8mll)iu4 zh`!r(-_PJ&O-VcLDqEln9|^#H?{OUVi3^AeG-Idq2}%oX0MDuz{6x0lVnQ zLBuCtHc$uF--rWhzW!A98r+GV;!gnB@jJk)(*p#qqquM*ySx`a5D)oT0kh;_E9!5RU8-wqDH9s$OId-{^TW$^?VrTX;?j_ytTIuEtPi*Q6e|it6%PdXu|US7%d@JMkN5t z@Jg8kz`9vzV+ZS{e-JTV_6iu0tu9v1^*C4G@-T7}I)r83581~5hI88uOyiiCjx}$@ z4M#%W)X{hbUl=+IP1F$GQ_IWfiLZ`@^6bUAS^-g}i0l;hbP?HfmL}r8KPB$+x}x0sXq7kfa=pyLteh`^ z4FfeSk6V8xHg5o4U@3T47k~OITCiTiVWJTkmo0Cl*ArMtRkGE7EJ)I)V{ub!e{dZ~ z6MavRzO^mrCF2uGJU`K@4kz)(PV_o+Pu5+?x{pqiVG(_|3iiB&@(C>8hH__1wf?+K zAd-3BTY3r0-hso^L4Pz0`*66-g?%_z9L9Y(?)7=BO_}w4xr>0MZf=ve3JP=3Qx*<# zmm~FtfPMceyJ%4xQ7rQB#YndM*3a3yhDxLMgH+Qj(VqkBTkqc+RC%fEgL$$Z$>*>1 z{oO|3f`sHQ-{aK#{^i^Q1v$&oZHVh4YSw)iAgEP4bgys$O3adx`kh$m$`@ffe=cn>~hfTeR7x!M!|8sD|snb<8!=98ay3${#1@Xs~UmoQ#nwn+qlovi9i-V?SL z^((K}hS{v1)Nmq{Oy50&Ni^2F13lsFg7sfxJO_dq)o{7lI45_dNggxb$@DVxUp!_ryS8mrL9xL`0}6JQ^ryuhH$aJb&>xaJO}hnu)QL&d70Sb zC*gp7PPjdS=Y!tyJ=gal-*XdN25$}S%Xpr~2!{x1k zre>&H;Efnow2K5Gm?g%i>d`0F0!i1UiVdV*JHvDwGRNw^&PLkezd^Oh#DraGxPT3_ z(sj`@sSAF^Lj41R6=J?6*og<)U4s+}qS0MoxDsR)5&Q4cwz*X1vuJZGI(N6pWt%(f zHsf&R)XwUmr*W6t)k#dMxWp07HP4*XBnt=!^WVzDn}ra9~!?9s&^M_+a#mPC!AYmSZnodMX|f$~lm{ zgV`IL>s4LTpZlGPA#BDdC`(={odeaEEW5rLhoil|$e|r$KFkhv~!KWfJi3{u#ntXyBC3fP|g z22M7(4Q%v*0{9GWT&zPfBC&bOoI3Ri_Ic_YQe=M;z-<$O=fYD@u)-qt@&WE|h~oDV zvtSL@`Sqh=+Q6F7Poj-z*E48iYeJ}u{DqM5Qvhr|#=jlIzep+;%Q2w>l>+5p%OwR< zYzlN@#$AxI&XwBlXd6;^Vm4}cLK|%G;1_Wq&BfV?1g0np5ATIv32y4a`)5-&MzxukBvrRa|gzu`K>!J(eCtOs@(Hha@KMkFaeaA%a_-_7qe|BA<{`)I$o4 z`a1OdJIqRA-yO4$1G}5qT#%=>;x4x^`;sBnmW{~CC22TgeewHro-+D8RMhBnwf#1|T?uiLZ(U<}lH!v*D^`6}&!(yOM!e4%d< zzTUqKfC6cxR)bbGvX=WZ+lIGui6lNu!|6J-*Y>@AIP0+V2V38cqt@|Y`F1B#*0?Y; z2rOa`_^ra4HsV-mXj>Woi8eGK!*m!6@J;9zgyPz)$TM|80jVYjEAhKb z1Hc1q!I|8$WQET1z?uM6rLdT*$s~*1yq(G-bB!)o+=ch@Yb#w8BG_U%YD9|#UH2@C z9wx|cIZFWl$4NF7ag4B5u1|#?PKN%IWe&SpcZE zCnHyB8crq+t(t~voU8XAb<;3S({L?m;OrZ+uU2(mBIxMPEC+h_Kwb!PCN>3zZ23t_xA||5uYLb>7W)_%_Rx-&|o{R z3C@Q#&g+P?UE|z|b9JHzr&+>#gg809u!pRA!6-3~kAwr>nCQ<0rhY}dE%fI0!ZG*W<+sutkR>9S4F^ljq zfjMsw=Oo4zauJN%NAaWOXcc^qkVg^nSU{SsDE4zoOd!;|17(W}>EIIq3+t+J=AIoU z@)>)-8~5KaIhDjzk|aeRB2G4l#mST~XuO3o-a^G=B2(nFxYtWG;-Ikev9yivK)BnL zehFsDNQWmd17@**ce0@-kj4MxV5jvc5UXgVl6iXGFT?y7d|HY=xT92HO21Fv-4<%@z^#QT*x4Z?iRg_PUHx1KGE--Q@7W(FF8aH^U+8E1 zxIHZK{+VoD6d|3EH5zJwyrf7!eQ|;A>|5;YG~L-BajxFr5U>|n zEH5MRR?djt@^IV_-CbS9D#;r0NI~=y`eS{ISccs!_t8kSG3q+*13bxYXcf%F4k=YP zU7o26h{h(sC|np~6u|ENtV#2Gd#o_f_I@<#GloaoC&tj8^qa{uM-sT(64v@U9vn=u z)>5HSo@5*2Z%HJrXvL%z1;(76Ik_ZMOx{Ed*@Ln4HnZi_K}KbD1L$+vRGOHa+WWP= z`?KK*z|Sr;Nca&w1bA}D_CA^5$DXVB-%s3ZXVWqMU7V=+-(T#1KjAuV5o%^;kg^-k=6*7mIRq1|jo|BlcqJVP0>(Jy`^a-i~;n2k(7Mxw{cbY$qPek3eRCv2> z6?n_lyuFTdH5WtRh}!V>IhE64McRZNr#37}p-I#QU z63tbrwO$5{p^pj#;n?Hj$io>Q?!Ew-d_9zCs46nto8WDf_$w?=*&w3C;wc?dfRK{& zuV71FLjHC#WOuTsL1=`^mNz*@Ahs31j|8{`e4ix(&i*UJGD?f(9-OOVpj3{4r=u0b z@^dP_Enq*&)CAppEACFLAETR}&*n{(HXcC2dwiO81~h{mTRCT=7MKDqOh%OH>|N&{ zj8EqINY#2b5bKAKxMj!)7b*-G3-2kq4uyO?MZ8O74xT!}?czsd`yVqILX|HU$N~+i z1_h76rcgYH<-EP8+J2UvGOGrC)y7x2W?W}lOu}XXs1azzS$kmP9v<0aOL@w zIWs62cyR70=z`Bx5-A!bv?c(GQUHnoP^0q?v&IZ`QB6r{qi=n_ete_yw;FAYrv^K| z0o?!;%Q5R*6{vx)L70KKG}Ey2<&HEDndGd?V@mJ^H)Mha#P33`4$AG zLJ*!Kq*^HtO_^AW$&bZDH{eh%QMA6BuKjd z1m2n9iV8KT%Q=mu z25sr)Zm!GUYk5fiCo+ku^JGh*_^_xtocKj9UHEe$KUb6g#GgR^QtdCUB>BrR=+598 ze}1xy`~gC~R^>=hp5a6##VNOa<|h23jsksvLFK(9b^~Y3sXT69Ld-~`N)MI1hxSQX1kreOa2GZuL0fbmznP|&Ub-d%gZX{3bW$k9rq#RZQ%A6&XSn@ zctU)>u*wmUtrkohf5WCTr5xJ3%i!3uncH2MQhDT%n4*ckB+o~a=Nt0uEc(h*H^0Z# z1N|)S0(4>T-yr=?ypY+c_W0^&;dJvE2VO!spXao1)3>Q%LOXSYG>=k?dU0I!lgV3R z;3s+gCzXEUZ%dc24ZKIR>#;vTyAH4)E9WhotEcWwV*@9`U~Cii=4%1l1{e^M>>wdq zm;U5={fnL7e&=d;ek(@$vyc$T$H>>qv+q{Uc_gr>hd|?F=EGKO0#7D4+Q&3Wm@39b ze*K1)Cbhbrer9_juS|~juKhQ@_2qlj(0UoQBy%wHfkWJXU79sRSERG`tF3N%6;5Kg?W)3NP2Nxt;o+pbLU-zQdzY^$G!Z12_%@JEod`Wm|eQ)!@B~m@DP~v^r(kITVJxpUm5>$oE9;B z4RH073oMlO;z?3OF!3YdZ}juI>bcXu>Qoo!<50e%Plg)R*%!|fVEUmRj~#_)8vc}% zftiZ_XX5h&kAJe$JFOLFETEqm@wcd@Flx06C$b2`S_}jRu9;4~SzUQ2lvyS9}2~Bl+=%pjrd2D{wT&x2>v_K58{kJg0WrVYGda}P0IKe=Y zsAnyA>6)(r#rY4W3h_*$P2B5823z4)@3DGDJ(&XkZ0dNQ5ytiC=|8!-!9>?@w^21PT3=kq|vYT(xpWLk6mv zGbt*;gNe8KC7FL>{SLb9dA~uCN8e<=RJgFc7=kbOArcEU^wguZdU1^}SXlV9EP>^c z2hLjZqg-j_@C!?zpL2=$U_JaweH%C^K`0kjtBiCo2X4;NLvLkcR6!fGQJF{}m{Vz!3%L>sGrS;@CHnws`q6T_0eW7TF5V%0l z%CjrTCV1PTv`q~MM|^R4`4$Z1j|IZraWP8NKg*@#%h~afy5r3_SLLQ-POVGuT60Z+ zWL;LyT0nq+IFwt&B(J$NFZC#Lum9`!F*)%uT-t2UvGLmo0$^cV^iKnSAXhxUFE1-l zr;;4U%xDquCwRyrAR`4TRmo2zq|p_$tDEqddY7=J$*q89%mV;)94}kjXzr-rXEyXS zV=S_@YoOmy7vBJpz?^=M{$*zf=GY_?ml^R~91JEAwCayl71<7eEvv&YU)D~DOc+(b zjJ=>8cTU#4j;6|=Av-b~)e@4b-P>Whb84OTS*{Lc@G$*E)4$KQ{X)j=G_);n+9K@* zsI}u^9u@_PXX!TpLZNDS%jW)Oc@u;%%ra;S#u8q?)fKzECk#5Zd5O^NCdBi;*fom}u9ej^{K4Mx9Vroc$bz+SxS}M0O zFg4}2Z!A5j{#+x`d3w5hI6GXvU*XoCIGvCv@nA~}OF z@jn|%c+}_Oe}9j0SN~-gmU}G0!dhbTg>r$c3;)Z0^hW1kVTC}OTfBv{+4X}b8v(i# zyUA?BhG6CfLUp2RGPCpqU3ei2kIgro&i#Bl`11 zH3TMizGw0+_@WVOWCEA2K0N0OblM)7^Mxu%Ksjr#DfnFQp;b24Zs4I5P|#6oT0;+r zfamh&o!O7WAmx1u8@`4?a(-eJT*E@X-$DJJg=WfY;;TJBrf>bm3cKe7ed-w87xD7% zvKQD2VxY_b^%PmM3vs#}3)xp~=U3X}$*r<9n*qG@OV@mt@!h_sWEDQ$CVF=6H^5Bc zNuD@=#S@}ugE5pYJ!1}_^~7Fo4pG4)g~tF~ojus7md9Vo=hlLS`>O>ZwN5>OV<4RQ z5sCuA!uNEIm>rSZFRS_DQ3(1%;8%n9i919RLHm-8Lboy@L;MHKdU?f)m9z6P#((5l z3|>0?nzf+Y<{=O)1!_iljBlgtpOIT?_py_S>}18U^yu0>%d=((y#gA@Ml<+mHVX`p zU;V_HP)uqdfD_0I?xCsIAxt4tYUPeWq_F+h5YJV)FnYlP&rzzIy~B!gSt0pR<#(hQ zJ!u8}^jDzn22%HZihuzbPbRVOMivfdp&1EaZih0$%e(exYycGA--hf^aZKD1KCI2MFxzFltaT=Cuo5m|Ux5UE53gzJiv}Dbe!`_|pMJfL{d?&noYUUC4>3Hag<%od z-FTg^G5wK6o`;Z~L9g3?3BBeQ>k!$`e*}7c!W_3={{(}CDE~{D-G~#2YeSSAuR+i0 zCIU!|RkmI=_}2H4o&L|+TYm5fm1jq(+L!en9d4X>Zn6Kl#Ks9`S5PV@D%@g)hf%vhtE$2=f1H2I@s=d&%E9eX!#G=cZ;4*4X7Uot3- zf+T#!U@Nzp(HL_xTB?T#mT)yu4pspsGo z!kPPi#dmhO)!)=(KSv&PSR(9t`T}((h6n6o`Xe_D?QQwu$oOS~X7eBkB625KXX0rU zZv9C7`gC-rZXD?G>kH8}bZs!@=FHzx{rd9&fE)M$z|~2|r}OI%1ESu)3r9$4mn

eyL^S;5*cj7(VtC!+H;4>NeJZIhr5|02syLVPAYo{rHCPK@63 z3$%HZZL*HGV>GI{p{X2WRPYk(A7i~b%3YrgJ;0}*igM94bpl<<>mjN4<}%wB+jD4+ zGE4^Kb;k57a>?yd;w$E8*9Eo!iJ1bn@9Q_!UxaJzf~>+H?-s-R6h*3KfXDE%mWkm} zy?{mrw(0C*w-xQcmH_=TU^3XLJo0(O|Mm zh@ll2)DLIMc&~T>>xfvI`|PgSf@Mq5j(goT?Z}DzW5NK(ccycaY^Y-JktAltSLm(UXeC(bvyEKgNnzIYJ+`N>0@P z6_iS}u4m?#j zbJv41csucfVU^(j%UeXAU*8XT-b7}toF_q;8jOKVNopU3kU=QG?59g4C~2aRU2#6C z&ic)9pv0YjWW!!fj)Gr46#2mK?RkphE$#II_k1RjI-g1GKjeJp_&?ZqQu}k=fBz{N zlQ|Z2cP>ZRgi%m~3K?42L&s@YhA2v>C`w{lwxbGzH3BA}hJ7MK3qW~=>PA+a#tNTQ z$b9XOEIgfsUwsVduIFo4J)T0p+FN~a`Cam~-7c}$FtOhd`&(u68YYhA&1Zf(Q zdr-~^o%Yob-KdyEdG4oa`yPNc6j4aloM!dmR-rjJu^&s~SG~Ul09cM){{XeeGc)`v zo9c}w**v9FgJ7A#F{42;$WxqYqhQ9Mq0KM=8aLp%Ae{h@+Td)uKB6MK9=t)GP~?HXB;(iTrTD+v3GYNUlv7 zh&eid*yE2O%Q1$ojXRG-d+(>2*#z3b7BDxeeYaOaCYtl4io|my#I*o4Xna=T6HDc- zp5kk*9DY<>U5qW)M*a(12y43#^FSMhw_OeTOmZZQgXB&PYVDgQX~N_5>d(E{s$QMH zT)(vAzDtRQo0c$Fets@4YVO2AUUt1!-9J_Q;E5n*{dfXmqX*8_vD55CMc)TP`Hi2* zdv5N#8NsC)Mvm^Is@U}Q*6(1M%k&U|#E)2iOL@}(IQ$nZc!i6ATh%F8SU9u13WFIe zoP!@bC#Vv97>RJ^O{_KF>jc?&jwSO_6#0TT3QXn?Sbs~Y5>3=kb43;3j|rv;kM{-L zMPlT$O%xF3GLc!?>S6mqFFu8}Si`H60LdkU`zDe1h`(BdbO$bKm_>?^9#u1L6d`@J z1VR!(D<>07sV^YB$ec%Y7c$Jtx#`=^>VEbo5!kg5W&F>K*+Pnh%s&Iwnj6rAs?M_W zsFh+iex#VAY_ZIfR-pIq*7VgE_iXZkb0MsJp0(u@* zw?RB?6|B0-abCC-gR8P1$43isepTqN3S2xI0TRQ^Ol{ESdr<8Qz6vCPNak(0fHt=oZEmK(^;2m}7K7P* zK&d}|h*5Q01f@TwINKMTBuLmo#zfg;B9FEGhzQ8Lnn47DI0;O2@nphr=~Iw zW!6Xh0=X{?NIu)Ij?<8BMs96!*~T3y{LK=uV-++Ka1;SQ{eZM*-h*=f!)eey4RY_W zlfRhtB;KT#_4!C)=Bs#8V8R8kJz3>rc)*;h^%ayZ{z01O2PPFQl6Ti2qVRh{m>^-v z2VZ!`^lkcg(H4OgVyw}0_*crWo@V|4=jxv8#mbu?j`cDxv~u3TxjJ%+NeLNn?GL$! zc_YqVnLUBV0&nPhcFtb)YfNZ_-m{1_Un30?=_M$DA6-nO&rfzE{RwI~{{zxEUyul7 zxCb_;Ms34|y_a7;wyK&Z36JH zp*RJZp4wuOWl!|WHr{@x>3-K>WY#UbQ550e2!-gQG^K7HmJv zd>G(()W_F|pDJw>L4~vQtC`G~K4c-kCy3FX=$Z6x(xek9UfTUY#(iKo8qft5ccuL5 zTvaBKmtG^n{Ovv9`hLP#Ikh-fJ0T5+>%)7<``j;wgzeEA;@EhD`UD}z-qT_U-u+h# z-V2ELVU71@;;r=HH|k6m;fx#AtDSsKdOeAihH`8u%F!gXmJ>pXeQY*QPC4^ zbgagQYt_k#m-VF17bAr^FCvn(oex=yeVh2wxf!LWj!qL_a&3E+eS{F-Wf+t-H-k>~ z(c2K8p5HZtFNr5-UL~WL&rzi2Lpw%s6xTzvj&>MR8%+bUt=Hz7DX$>6CRE-c zrE)9nZI0V)c6@yYJ7&fQNHf#WsgKy@U#=7y{>WjxUDL3N!+3T&8dgJ{Us7-u zR9;1QCg>lfzFBpo%}f@cK7`S%8BM511WJhC%0lh|R3R275%1(z_WF`l7()v+U>$&+ zU9en$z?PcTsFG3&hAUPwOi4I3fA;+oWLxImgn9~8ptT)vXi&Cix&u|(GhxascV@HH zKVRjvl?v8qbQdk1wEYy_1e>F{tbt+1wl(#{R{fCheWHV}T`ubV%H7bxR^cFLAep=B z3bzig-#p;#V<8C;bJDN)$kLtlWM^MXqnwM_Syj5uzQNA4 zpWOBTu=g$SaaGmc=_8O*$^;}5-T?{}DA-ym zVt<{JbI#g(?X}lld#$zCejF*m*2cW}AE*XTD0~aAWv<9BeS?(?x|Fy6#nWTAFM@35(8#ACo5KI z&65Q2wK$Xtee-8-W2D_>6YPKuLAZfeitpduWlt~`Ds9JL%jJZlO#XA^HKQAZ*Kgkp zUjK>(r>pJ)p=L4Kpn%uq5DicQ-^b2`!cZ3WcU5uU0mjv|&F16%zLqE%kK@7^_&-nA z3JKFc&CFbZX-5BCc<%LZk(o2k6`D^Y&ATEIXkLwb^E1??fabF)=AND7IxaL%R{Db2 zIrKfx&hm__Z!qIL-tMZ0G^s(R2L*POb`w14su{9+^6ly&l_>tXK zkp!KB^;BYPhH@e>k9{V?&t?rX*_t<=7~+};8?#2XEJ|b9uz-kgw_dqF{dTX%rNTh)d z(*h>4fD5&NEx0$2f|~)?cF=QJC$oTqk%|r;+Ppc7&X1E<8=zL!RjV_LovuGUZak`k zgE-N9p4cB{>KtX}Mzka?zq$6OmFUj{&_yBj=h?4H6x{8*kJjR05Ml<r3j`jfTi zjKRCQ)aQT54Xp#E-PK?WTn+lW9KO|nBxn2=;G0ntpZmR7^hf8EU^(CmRul^77T{!D z@PaSu^7@TjUVi~!%9si%=4p!5!p-I~B$9TaEXI34o?Qq2;qTbMx%JRsjv<0FvO;dK z5W_Ewx;E!-;y5cTjJ4kW??Qj4*7KJ|;X|KD195T!hV*@y>_2*)s7p^!WZ+R&FOvB8 z>mexjk@j@e!#6-s+RkDC1+O>cWvw%ZG1vF{_Ux(Ow1stRW7!=T}>jKcaIu(MbZ-rTftr!063fPioZ+-sQ z_*P!~qQSD-I9N1`v5_7`{|2L9>6tH)SaFooRaxAd>%pa<+gzc<{slF#_8|9NDnUdL z#ztU;Fcs~m* zGHA9T91*8KA*Af5q?D5sh9}X&JCl@$&@e%rEGY*#r2K-3QGR4qS$7r%*WvE8QR8|! z2BfWLJ9}pu!{)Qsf#}23Xkf>+OphVq@zK7>twPF|>V&=5Uk6f-Q&JY;-t1kBlrMu- z9(&IcQaHOHve0ktJ$zH)qrp7ShfnAp335X3?3I0e>#ho zgQO|;adQMH$f5wK0tv*!RyOyotx+_;`~qA)ncsNd>z)^YnW7l=E6C==wt9bKm2Nnd zwKbAg5!Tq2hg$Ol7xlq*B!tUn2oBw+Tns)%;NxSHP~IdVun-5|_s51$Q}Zs;Xnlsq zQ~56NNJ|Y%PaeH~hXPyt4waGGYKKB|pm~nRx<75}3r`nOJNffyYlb1vg)hXt`Ry4+ z+WKM$K<-M_M;Qp~OlDAbD1(e|FGTAyZfvG=kqFpJ>XI?#e7tFj*Sh>bwe{HQNE{Qf z`7&~vxyY%!&&o-P6eq6Xf+tJoKZ%98{(d8o*LzNrI^2Zf*S2UK?!mp;zgQjagK+1* z$yD>}c)Vs%27-=b>QEMxO|l{aPX2=sKfvpT)g-9b620w^iC#gN3=<)o`dW6C4LCj-82Px#BpII35Y%u*Pf> zahz^(!0D=oW*944LZe{^DF|~_G?x1jomKc^3v82&sbH(fEP^_RcU%MKa3xZkho5DO zP>RG;?T45Nl{YgWn4Wn#60TjPRNjVroLA`9)Q0VDK}X0*U9>5zP9Izxs|7j0y$&8L z7OXb(x3SIf9u~34d#PZzsfZm6eO@LN}b+ZU0DPer9}=OW?S-)Y@$!@cKxR~N<<@sJa@8?;#zsF z=4d5xFlC!KPd@yntX^Hia_sK&^B$0PgsIEa2z}DtIIgPO%y0!J4;zI-5>0tGi6*_9 zL^bawQT4k?RQYZag}OuW+BrR=Sb`bgQ3#86Log=9xwiaH1>VVVLAOp}I|O}fitS@F zytaArerX%BdIszewF&zq$J_npE*Kql5na7{Bv5(%(Cf2M3NTQ%oj;?v^84%NPeVZ8 zMrN~o!?67oJ%yod4C)xa@pL*|w9%1U!v5k(#P;QrMXZ~Fer*M{X}YQl_h!G@u2^4* zr0BBuvJY5ml6%POX{j>bbuh8iILCYF1EcT?a~IwC<^rk-C7Y^)tCt%s-`f!ic2^4i z{wYwv@DeEa5GlC-lp+-D;ZiV>6zJkOsTq5Oc%_`vG%K29po z5Oxsl@MvJ&KZv39(~Bf?M*Ly*vpJjFi=b`pC-mx3g7rgWUiH?Qq#U=St#fqZEaB_H ztd&?Pd`=YiW&>&)s0+*2SzvZf<6tseDaFs;BK(YF>Q{{y2Dg?{jDci$BT9K?tx)on zt3ipZ{Yh8-4EN@QVwC&IsXFv?d+vdhvEf81;}IlVd#3iLzu?}S87jk?sb?XiUKzhbVpI`Vx(n#F5NA7% zhC>Jf0Nso$13`MO!=QPV1)#V525rk7C~~gDOT?hext_NYE8uBq?#LXj~+3CQnN)8j`jRAXsJvFjPshea7=C?f?DP}WUK2l++MfP_4@021;!RNGuH5`wnu zVLq>=i%zG{w(C&~<-fM5J@Ll~Dk)N74zl39un`-d`kS7Q5mvi(N+|4}EcyeJ7(9Wk zoR8^GWIL8&Zc%2imsXe6Ws$2iZKM+jxmZ)t>)N23HiF@e($pSS}2IR^#!@+g2NA{{4a9 zJg2j*SxAh(KH&YwOMkr>iPj!SBGOe0aBm(s!PN=2zwXJ-?b)zrgk+gD$YQiuW96_- zUdwF8IF>w#CD;Di8+bD5B(M!cG);n8e;Th7F~+@_IBCE z9cXW7d{PO1Lk47~Qu^entbj~L%rL!N=_2Pk>)j$eo`=YE^^6sUmYVj#hw;8NyRLv*ZEhC(0h#grRjHQuRrPxH&HSZd$rW(H2v2#eacHOgFw5VL~8!$#{}UgkwCV|N;|l;O|i_I;nVhyYw~FO zjF$BwEo*-%%PzP1gypeM*SVT@Cr$h3uUS-Xi7{JZyJ@Qkt)w!s$UkR z@=d~IClMR{6u!{Kc0*J83n}Q#iwfpKLD*@W)A`&JWfvV%9((h3@d5GbMcl`deF75g z{^skchBb(CnkRoagtKB{X}IJX7|gftdy7Jlu_4f@FRs-Lf1Q==Te~|OBVBdM7R?7Qa>JCIGUcZ@^o{q1iy5_^vXR3d# z&cynDEKJ~Ra=du}w((FaA7pK0Rei1gMer^?{pEQ==7M%ez`>GCq&}N!9x&5h+KpWV z^*yxyal!H7SCG=;c`{i-lkq5w z#YiblD9yD{)CMAw=5tt7B2FWgfg*>5r-AqgB8Jz#KAs!J8RPf+)uksl{nl>?;fV)P zML^*B^vMKpU#Oab6`1khVDy9Iz402>LQWifBDqMD-ufbSD9 znSiVS(B0G1AK*(yh0ODOX+4fWKGnZryNR*Vb&Nd1S)ZwjF`oJHXVLUp$B=yG`}6tF z*8jkIED?E~Z@y)Uw8dCZwsr<6L$`b%?#)hUBdCLQPk#_EWy37ge*z7JF(lrU$zp+2 zoqQBkqCIGnc?19sl?DmoLSE?tLH%mzFLON@+f9?p21OWsd~uB2veJhaqawG}_%CcZ zvAGtzeDX)qn(hxs1y1=GDli8bP=Qb2-kdhot-$4gpaSbrD_a4Fz+inb>GR`hATkb% znmCPEVZm$c6#ZFR;tLm{MCo7YsvTM4&%w%oWtVD+=L99@=xeg-FiMoRr9iOyJiIec zJx1B_oJe}hby-QMdviTr<+C>O9<=J&Mu)MX=Fw zEcdf8{e2gL{>w=J+mDLu^R!fUdaWd;WW9Ua)?lK6ha#gE@rZ71mc$sq=z$P70pk-_ z;how0C%`DPXJ`)@K0t%Wystz)HXbQeI1}mDeu_A-Y7Y12Tr^G41a>6#W7Ny5f_1Nb z?&h=9_16piYq%28AzK;OB@X$skZ%?0BkxBfMfccyVtwRZWB5uW{YT zp>`H0dh!}OH?J_+m?FvOj+w_N3tNu40Bl*zeCet*?#)cJc)%7m8TvvOcxBn*^o3Rc zZG6DBm$KB}SBF14A1!|;(wQ-xBDoN00A&hSq?q?J_|9+n@DlG*@`|28b^CeZznA#G z@jYL%7?}4Yi<(OAef;krSrdWri3gF%boaTEMdyu@#W`n@tj`@GEZjO5Ec_Y^K`a+} z&ELS#WCfiyut(H~>W>8crB(SnN?-jQQu~eXhWHE5&*v|kyZ;J* ziU0k?|9#>=Meu_KJ+(1Bd;G2U?%yqc*PjReK0%C^{Mh9$2p0avJpS%>xbXKbq+k0a z3rtt-4r895HQp3?G@L z{oUdNu+(`~>=tT6Xbt!fSyfvb9~v7;c)cGlX3+_Sy=!Gm$Z86_7!yg*-H{ilEH#H5 z@qv3PmK-&$$DEy=gt(>kb?X?=EAaxUpGv-8ztEDzV(GOd{q&&#dr1GWnkjLtY1Fyl z$E#B!qbD245@?U~(~&?wuo{bBhcB!~U-LeBg|Glz2MM|G0Ik;+M_-#bDzYlWfT)Zh zRJ1DmlX?BMcyK%1?&jO~z`wc>K_>r8XKzMY5Avvh_jp|lRNx)vf7oVt(^Ov;xd$Y? zxj6c!kdW_UhUM#`aPg>wtM6zZJb&gQGRyWcu3P1rD7O4>QRQX@ zPK_lSC^7K!2iMZ&GGDfDU1=b|SMN)4!pe4jkQ3k6lE20L$5idSQuNn*{t@~1)@1LdN&30A&tR*f z1A0?Rha_T*ig789W2So|1?plRMoTPtV_6)vs?vif!rf;=Md0=ST1P(E zSZD`q?r7apDH$}6^9G~QuU^Js?#3L5VtsIj8(`fC`448Ej*n&|X|fwqCej8$H?sIl z=Xh=d7H}8Ae%b9Rt$h@dlW?%qm=DW7%YG3CyVawgy@qNP5srg+vf7ql&L@dN+?v(q zjo+=l_xGzi@!Y59v0Qvu_G}ndR@XfDO`1V=XD9xDkh*6`w00lKP<1ly%>xsQ*uFgv zL1J&*`!G}c`vYV3!0LO_2u-8pSL#tR)q$zSngMm4v+%;^qLo2J(_9!}jsG7gL_CJ{ zYehuTRZrpG>{*P6yADQTjsGuV0SB{y$U`W=ql{DSo&=#hniguzu)F8Uhw5Kv{QZE` zihnWe-*#nr9DJGw$x1QGGHe<;3xH_^+!_ETfdwxUa5Mp*3IHXuUnTT^Cp{^cf1~&Ll>yRPC4D&Su z^noOrfeaaYUkg(L63cSO;eu-RBjf$dxPciDmyEJ}?l!*Uw5qAnm%Zj95NIut8rP6J z9(8ktKBOKo3u3PBm;X+3tOX zk6(oY!mqE=0io_T-1ZI>>}mz_Df%I_tM1dND;sm|1w@~2*lf-NC93BKy_fywWOD{y>WZV97|lHa2Q&tMy|G=n5yJRI4`b^h$=hsrj>9ovoY)804GQF;`b;VA1Igo= zR0H5{=^s`MeWvO>!~VFior%av%`3DvS|>O4D6!{F%y%s;^|+w+h>^{LLd9%;P&V!hZe22Ie= zhrME5_`p%dd~57@NB!907W4qd&&R{@Q%8X-O1%K z2|R;{NQ=Y%uSm!d`efje zV0dT)`h0?KZP$z-Wm7fe>qI0qzu8m#m4hLFYZowYx@t0I@yfkjr|FY`Af~ltpCDlH z53~|nQA!n5UshDVI2EX_R#d;iz1c5>>Ka9LuY>CQ78TO0(q}dsecPypNVVk0ojA_N{>&@Gvc7Zw6 z<7IRU`fGbgu;z{ z`Aes|^PySvzJ8eJKG4!9B54ha0qU~ccj-?l1mY=kRb0ZP;;9`}6DGv*!pugJ+ry%L zcD;9RutZr`gW-j@BdHgD29q*=l((?EAe)!SUD#bRk-M>15fTT4{xO@!z;jmgu# z>~ujGLOhjagnS!fqSm%6ys~gKih_TW8H1uAhd34$a#?2fEk@;wfY{Co3Nb2q^N&U9 zvVy4s;wXsuOYFUMj^QQt`Rg2o8ipUt9mUF-E!1!@-!ua@!;a(0a1_}%MgP{%Fy|D@ zydyH>xIFL?J>SSjc*|cuMfOv6F$XN0{)_;0(-{w^zhBBz0I0m>RFO# z(&qlPQj7CZn#5fW5X!L}`j}UAM%pgHgiRa*$p1nV)C|2T{PK3E2mW16!TCnXI>upy z4vYm54ZQcQW3YefWh_BrZPokt#~YQtf0v&5{LnFIxapBu@IZD$QZs24+!CEO_Vi(m zpB@7gbI*fZ$jRY^2M_FfK0luSDe9^#mipIZxxV2HzNB;g357BobRH5QA-}G0H3Fd+`e2j;S5Wo%HY6+y zz8^=&fm`5B?oNz|#JZGrmy}N<7n!bbp&H?M#)`!j?C0Y}J9 zv^}sm?c4*)&-CTL#OCVp(KRJNm8C(|r9cw%ELuue2@pyt1wttVrAXl*-1}q{A1qqf z2b~2K2T%Wd7qZ(Ag8Wo;tD;9oh_)j`U>(2)Z)aXR7nHAoIvo~TIV`lgG_-3N(6EJe zLGKTnw`8H7kl-(*%5yLbni~vi=Mj*RRXguGwYM$$;NrRmkqUC>aU_)nhLTFaJb>`i z;|~G?=r2=yfi6|IH5KjPZHHyLdZD!{{rzP1=9$N+ZCR57q)SPQ{{g)4xq7`|YDhbtK1;R;?+vS4A*7%+;Pg_@Vt z=qGnYN|%GZkn!9@aB-zC%h!12B|s30_S~%iAtI5un#{$ADB!ZTK+c2G(A_*++d|J{ zd5F#;P^Xebpia}|L)%Li+CFTdfDThApu-gE@HL;FaElay4pV4Y7V`6Ul&&en(-DJ$ zjKkJ6Ecy9)m)!eA1=P)(Z}GDS|A>v+kcuw3_szFb()97al|8``StQyW&s4vdF60<=JFn0n#cN$-dOxd^)WACx6qNbIP;hUTDKr^WZf9+!7>EHLYv) z|5sTesaWm?>?_PIDKtmd{*&hD{IjScL+ZAaIpSJ$)vMMV$&2)a(-D{O^=eUD@IT%h z!6Mr;5dQ0$^IWp;-PKKC0xR5hK;b*`w_Om|F3afjkrQ~+k;?* z#*i^`&wnXl1jcELfiSu*1@fc2NFZ@tIYHeVuHh2lkr!tBmxOZ>QAS+(Ur;poD7D95 z6Y&54MNs!1^oHCG!;0M8_n^rA024tT)Bi1Uj>!E#jOgA$(Sut5CnCBTiRd19NZ3SR zH0MQhXPp(A%cY){`P@YVok&C#ErVT+cBRVu4|cURVsH!lN{4j4A%8M@mj-w-;7>*w z-NlWKpd}mHY)mrVys<2D`%WkocV6K4+puO3t4`W~{6$p3o1poh9{8o@`Z>a1(x9l? zGRz)t^KLX<{$186IgPfVsUFTuY`I;E({O9cc3zlj4se zF5~;0D6=rI`agZ39cE7nS6vf%ao>Pz^E|HEurHs%HTg!97cGD9dFmS5>5I*OR%aU! z``uV9_DfNd?pzrAeO~kn<}?su!<+{8k|0`aBruFU_HAX6#1TjlOFh*@j;9`%Kl7t^ zA$GW$p+xT-$WNUB z6I-fb$(V+_c;f8*7bB~7-&G=%M!7rALTHY@j1(QeI^9=4~xbGKfAHHGi8Th9eGZnx$$1oXbK#NZwM^S`iL zd*MY-1hG}=UnPRCo;q?w@Sjv~jNQ1iT6~7|+z1!em!5yCx4zs|c5JE_SV-|k{vC}V zHwvN=KiE6$YK|kz7Okf2C4TGh`xbs_{634{T>NGuzHu;qJK*;RqesKy^ zYa51u+*F0b_^0vvH{SiMv0~%1-MzTMN;JeOR;HpW<>h8nKb}2_C!I}L{wJJ&m`w8s z!_?SCsfNwnukI9o<)q|`(^~H=gFccsyZLWm-{j3+{u>Nya6WYRtE2rli1^5x01u3? zyb18Y(#o3v4`!Y`9-)d2ebY{^km}fnot^4*%9g(s;=90)@vAceDxlJU=3oUXz4qY4 z?oI_d#NmPuvpn1$BcK9CyPQ@4V-N_GZGnB93bd!_J>H*+-aq0h5Nd%Mw*@9T6~Mxt zWimp(Ys6I`)B=;-7MSc*00a7^$>B6==g8e=^#dinflp3WQo< zhT8%sI2C9?WF(om5!yQ?*AZ8ZP&?GR?Jzs2h7Q)`noL|PmEm>7RVLIXF}F?TIF)IX z3h=7Sn{=hih^tJfW$N9QIoGL-tdx=UGRXv2*ren-;wlqrnYnJuT;x=S5u8+l*JR=% zx#xAnRVLIj^W2uX)Tzu|sQ|CZ1Q!IPyPX>wcUMyE2hQUP9*i4)|W*AZ74woL9<&NyV2 z)<_2>v)mfZkXrDXOdKuuyoPIpK}qDdGALO#0tY23dDbO%C2xvUhu36cvfT3;uG$Fj z??c^4b%GtOxH@5yRDjoHVxrvhI^rr5>PD)qZOgdYx<)F%YcjEq-19o(DidlMwWGFW zTsvAV72q|Q*j?^<9dVTjwTyZ=wq;xor&21wYcjF3-19o(Didm%m}`1m-?Kt0z-uxw zR_=Knag_yPsc~Co zqEnfyRDjoHVzb=yI^rr5YME-cW%h9@(=Qd^HJR8X_q>j{%7j{`(ruaDoyzn{1$a#+ zHp)G(Bd#)`mZ@-CW@o1|y;1>QlZo|m&+CY*jN3A!-G&+K)FmVI^O{Vok$YZ8TwSzb zFflVGndlNSc}*r($~~|7lQfuyk<^`%g4bkXh1~O+ml~5kn7WcFB1~P${86Gq67yZBhs=6~a!7O895Od%%aA!UZ$d4U z!!1Lm-E0{$9fuq;R~O3RmLW5GC_@hi$H9PgaCW0Z$=FzXBA0(Y*A`BW*+VoismU2b z@4Syi16e%1)BGV?0uySSG}MW=LhkF7+j>mL>BL)J3iwCvl-n)NP`Bii8&}|Z6L0Pu z6-KvHH_7N$TKIp;l$*{S>cpE{osl-8RTE&xO^yk`c4Mw|>X3=I5mo_LQ=Y5_*?Q!T zLFS65<;iHfOuUV-3Wz4)95m-S)jhHg69ZjuXA5=WZG=@I)B=-SW92xjTu*zKtfXB! zLJgE$ukJ6qVoi8n4_9I+GsI;^%WFgxf2?rfnu z@ix*b6Y38!w?E8rDs!#G2zX7(N_9P*VPv;Vz3Ww<>s01ysSK}ni@Hv{jp&w{>$c2A zPGv5Y%J7<$DK|UuHqt5+vK#ZU$J)lOy3l?w2h zlqokm@iwAcrqOMgYn{r>k;?FzOvL1#*OA>aO>WEF=u~F5RDjoHqE_yC9dVUmpLv&) zZ6`=Acugi|$UU#&8eur{^_~&C0#GH-Is&fb9WB-2HJNZG-bQpcQk`I(0#_$Ymdfy& zOiYq{Uc>D)0>)V(1*h8Dwv4N-CrSl)O(tsOp4SmqnULvGJ8E0TwWIq;1$a#+s^y;7 z5m%W|%czHATgLTpc9#n9noKwoZzHN6E?%k1n_W}{Sq*JPqs?s*+?m2vw_$;mcn zvM}LHyp7B*qmymUoS-xD7M`BriM&JdWht3)TPdx?YckO(_q-O%@{UtYoLs`U0)y|Z z#s{W&lTGr0EPRiMg>%Q+X1U>xwSH{-l^tuFgB@#|QqfJ*_=OK_r`aSs*7_wOBAA#u z>koFUX+i}eA%L0*7%?j+759!3CtjF|9KjIv`b4)*SSK~( z1YN%{IyM%k)DPh-TzeM6HCwiCpZcPGXUwH|v=3Q5Ea4n^Q=Cg-3i|Nr1dqHvnd&T2 zCrzk8By{T(=29L;mrG&3=V5gDj+siQCG#)>Sc*&f&4keRN=1J9z%BoyRy-)@y(~mo zGflohArfU&U=F|=U!n%hZu*gmqP^@rCO?Y?S~%aGD&O$(arlFoZ+x30$?vd*zsoQ? zDIXccp(4?CblP70T^4U%kL{vI$eE%z;>17F1?RFteen#eyqE6rSOuU;|9GqdP<1Jg zeC4EQDJx5WP)aEfO0l4Joat8~HH|m7W!?3Y|Dy1nL}fTmG0tK$nS z?L(2)Qz#9DaivLmb_FHH;1j3lM_5#n;UCSK*%6SXdOoD=O6MWu=?Qm@LjvbS58JLh zpdBJ*4`}BHN(uo5&FW;T$Zv8VRuUiwv}a0{6qZFFTM_B@VOD_ARo<<5otk+Mi&rnT zXsBC3^?B!{FDvX;MWBvs7lAsmoey0Zbf^MQs6!Qj4pV5jLxuC^_9|g2@co0LO1x7) z0t76c&ZTLA4?CV8=q;KH+O0T9zcx^S3cY4U2@pyt1wttn5p9EMJfAG{Oe0*9V%8bPrXedI;Q-jtM7HTeVCN$U zh2TH|7Qi5@j_NE19c?;PHWpv@Hw+~9W@emo!fkLa#H#;+5=`J5fkfrKuAu8_|?!Qc@CK1dO7#&>>Ok5Sv$7TCHr zQ5Wn%c`wBSvqO~v5Uf@y5Uf^lklNA$R4^9SmKJ~l3tRvSEHGW)3e*sPo0q~i?!exy zma#pk=Ku5$^7-SY&S`SKvna@!W!0I3>7kF=K<^L!cJmPgMRK9u5ecn)#oU$ zBG6$vSy*l6=lvI`6Ns=c3%Nh3gt=o$DxpEVHeJyEyEYgU>IJ;TvGA+ZV5 zn=l&vdE+T7TO5=?w(NL{(TG9-#2C#~90utx0V@fR@f59U(UPopRR{~5vV7Qh9mUId z>Rrp(^4xn^&P1bzdKMIvH>7IgkSgpF7J)iFs|eJwnfXwsXBB`#HnRwHm_lL3OBR~D zsD#;|SBhf1aT9Hcm<>B@DFC4-lmZ2VoxEK7skpqCQc6b&5K1WpLMayHs|ss2_WNIH zHlPh~QWZ1|)}G_On8DcFUi`ATn z5|trMo@?Q~%NqiP(gRkB2JwbR`7nP7~>1feZZ_2V5}L31CItnh@Agq6Kt?)qWv(n1WmRX-RGnq2yTu z07C{Q{N1V|P>0MS(2}|yy*?l^KV$fde?_3f6dL~GUpR005c=WAW_g3MYo94PDC77E zgR-T6z4B1t6F=4B#2yDFDH|6$fb;rXYRb z6Bd9_ighImKq!SEjRuM8*s7Csdx7aX^jg@@O?A)#z2=6OaTan_G04~O)q0uq$;eQJ z2m{gU2;{wk4pk=P+Z2I1qE`g!$a_B2`QS_eXxKv6gn|%7@|G+V!n0;wSZ?8AmEpU| z^B}apd`%(=Ds_wp#Ap6={49L%vh_e=KKGt;U|-GIQvR%CesFN0>-b zl;4UJANyfs|JpK%C&UM8W62>l&74&E$tbxlRW?WFU>PjXIoM>~CWsUsG3~0c1BzI0 zAg#S3t!UKzmm;lw`u*Fy^b+tb1%ezAgvAr^ObXGKKnR&Fg%C1Z3gni>m|}mbVUwBi zkQG4E5QttT5WNgVuP-D8MWBx86@fZZkPpQG{a;gb{x`$=L~c^$hh&OMWi6yKniHuM zdGhA-ZGb8rgim%Alt8P1P%>Etf=4MLLCt+lGhQjd}wDN*9D-ETo-{3Q)p5D z%o2>Q+^%W^eiLFY@gbK8?j6sfExq4bU=mU8dnBMp+o#H)z*X z-2nOip5hu#MAk2cfPLsZ-k3TIt&4Aatca|dGhuLQZyQ$)_6G{8pVG4e8ROX<;XvkE z;M(AuCSdp*v;^u&E)B^ZdYI=)E-jS3B2Y&Ria;IN%ZEC$R{#phUJ>Xpg@$D>oVO=B zK!swD-3WVws+c zh4mavz`yleS((UjzRH0Xbeg>g)RDD(s3U6yppdK;feuq>Sk}UMAxwpO?o!cn9nf=o zI(kkQ2xh*jN=_A+qCZM=tIwxqqO) z!fBON0jN|bngkt;UyXBSJ;E9y-`Ey`I`U8i>Ih*z)Dgl0P^dABK!+(bEQH~_!znyF z*NMms_|heMFS=?ty?4pWzTWf3yrTcG?ALmX7^%UYS483;0Ox^qC{?$WU&?~LN|#sO zHN9-{?iKd6ddtCF;} zAhAzhvUyu_;ZUl1TWaBu*#o1q$f}Gcy!zJzVdqk7=|49S2i@q6@bb9aH_D-7U*OsF$#`<0@TH6=(VL5c zFvcqd!WgeO2rDN`lmg9B6ogVrflvxT&^oeNVj$Qou?0t!O%oD$W?ArgpMmb|ZhW7K zJyBM+aUFqV%@pjruI?>fRt(ZDWHP1CX`kQz&dgvKzBmq5dff4Iso0H zNHG}T*MKyk0zoN&WSms#-C;B_8CF1~E4e;((QkmZEHKP#g{5P} z4tN2t$KtgxZ~#cq2~l!SbUnF(C{kr4Jys&YSO}gjKk3ftW$_d6b-&g_0fvxaHwnfD z-M`t3D3oBlF!qJXF+d{8MoF^0gJgJtWby*63yMaiJu>*-`@B#&N`|M_A^X<{x?kNP z{>qrt!h!BT?im053FF>KzBnGA8G?#QH2^pv{z^oEyTpG##RH-i0^B|R$|wO=#ecuU zxHshX{qf(=@Y3NML$WQ)NYSa*MP*}|({#VOqm*g7|5)LaDIXvLFe0BVA{Ee0lDtZ& zKyqOBsX&L-=0-~;Gh8CI2vIj_tMJw$?(o^%-Mb$~>Jr#ngTP)m1xFqT?{Mre7UR}l zZe7a4VJPSGrskro!84k=urHs2Kp7cWFdMhrXhZS z4|R#6V)Uygx(#BqJ@-M}3-rprS#4#Z)K%OMsyDN`avDii32iQC`tfN_z&s!sQpsMG!UtWz-%N-G6IX~jW^I}}5O$m6mSAe2%Hgi#$DK3H6qs z#ag7rxDG4trSQ_Os44)V+)^NvTO6crasevTuCoLPrIZ4p6bs@y%L>#GfB8MuB@wD| zU590YY8t7gza})^jhK-vS(R#XS^*r$OaE?G4HxFp>CggHs3x=#B9TQ)DFs3`34#ur z7G3UaVS%591zGLhnk=MYaJf&1doSD}p4&7^*-B&$B5~Ou1d}Zc!4!cygM%VaXGD?@ z#hU45XjPC|x^xULDu#s)Q+jx45-uG)_Jtz%d(5*@GO!@4fs#QOy@gR2`CAKSvS4bzmqdEbl(d0=xxT z?^@vIrQh=c*GnB6>T4}QUu!AsYek@rv=@OoeJvmAbg=?ZsEZYW4pV5ji-q&%YD*Xr zMmmwyiz3syh=yH($WJj4x1u!Rz$SB ztcA*RExdQSKFVKf6-p0SCCcI`(U&79AJ#|tTTxPV_j8Eu3x$`g%#jK2ofhdYyDCy- zNf?UsmSlBd1r>`F!JsFFEigCTCgLIcUQ%_-38si3!Z#IT?{+?S3d8a?!+6HD)at9x zlbOMmn6S#Rtq${Kx5NPK=&NGjLVv=^UEpg3u<+`u0?gqFf@0v|3NGwDLBSz;vqr=T z&9?-CFGd8xcc-KxP=`N7pu-rEj(|J)8N;iuia>`cG`#vMocEtueYK2Z=AP*N`lnt0 zEZ0AIE3tkXX&m1&=Is;PcmlCFj;dZN8HNm=A}C&>aN$#_XJOd@&XO%({|9gasuI-Y=db1z&q{U(%d+ASPFq zdl?r5db$z&jc3Ms4UcU(v+)L*Zb2sV=`Xycfh)!Ac05@-n8J9ZGqN&;~)W zLX>LQVh;S8l_SA5Pf|opylEa-`C*&huVn(^D~aGA=wphSRQ)^~Y{(pb zjIL44a>w9ep1x`v*go?w_Z?HVb`oC4(pCS!y*c$$<5>4~sfC-LCN*Hr`cIEzUOZS4 ztq;ZX=3zbB)Mt}F29pORtY?)FB(9x#=1|VkSece?*c40Gb(*`rv|nMb;W!)RVloA* zMbZm5B6Y?*Hx3nP-dKs&c3>iC8aGtZ8C>4izNxwIUX4lvpV> zfNTK09p;C-3}Ma&%W;yk7C2Z3t`u4iB-Tq5>oLT7Z3ye900FIkLIrY@nTi_62MzgFZop_G5*nNqdWB$jXAG z___*nDU1g?J7eKc-O)^ZMp@(zDPZ*i;n?6kC}5Em@IDs6_9-afDX=m3B2uv(pjAaZ zae+^&X@RL9FXVTD{4S6${rDkbOf`2w3i`~0ufByd+cxsq{1*2RYmbVfm5NW2iaV5w zH15qBRKI|VV@Smu!R+fda=8WYgHwz zih!zCGy^iB2TV6##wt|01?H01BE*z2lb#<6hu5X=w<3){Uy1e$;`!8SWBoqsE~pfZ7C?p_Li)<@dp#o5$x<~ zFrVPce-=4uim4=glWe~KtO$=SMP+~g%SALB?uJl2$;9cZTXAn5zM_aw90*CtE%jxe zOl|~Y8-S7Wk7-?z|E$P=){+0qRQ~TmA>CTY0W9R?Vud^fG0h!;LMZ=WaJHv*tnC97 zK$O?iXkryom3}a+-|NQbYAK6Z%5z%ElejmVQN=*MKM4rB@p&xe8Kz1#_e;;Y>p73^C_N{Go-_4DbeilO ztoFj!nx0?4zx8F8n`|8Xkik~Y`&|j2pl8RZ=x%GBcmSh6uK9)ef^^J z`}23KrwI3;Ns$1%;=@Z%UW$j`R8!VDsxA5^4jfZz@E$@+r`5iHU-*4>S>&z^GAxe1 zDGtAD%v^fdUV}P+iF(9QP9!mfZFIs(oa@%e3 z_t;nkh#?t$rs2;#?Q@$yI>2F&A^ls4EzRSI$e-p^QP7bJk%L_rt)PG*L97FsK6Ans zcd_gXoiB;{^#(%@5lR}lkWw{ELDajF$9raZZRE*gE%}#R2we^Rl&tHA%7kHzn{km= zj^2bf=z4LpQ>3+pFP_3>Y6j+PFn(-VTlD!zYXomBd*LFp)t+A*eO_9vKo)P6w3umb zesThM1eY(~+?OY>pU^aY5N*h8L)PpH2?oz|@NiHNGG|I>J{W1lgitF0ff}6c7K1fn z7!Gqe4_H>4zdi~4_8l+WQws2lH!T2>TyJD{pEnNbf9C1%S=K&EC7-TZjC*tcC9eK# zMpEd{J?8t)x;Ig-2x(?d-$$wyh?27a$=65P-$b8?Zw3JZ15QHQXkQD#Pfw9#?efs1kY)04 zhCVEXfo%gJFxApgdZI0SQrE0?yxw-^iNLL3thxU1N>Y$PQaYh-x4oQw9e#6bR6uC}huDPLHCwsZ@4Z>D3z*I~Z4z{UHCJ%n=o0QVWr+p>2B~ zrgo6N%`CV9>6!74!zw{|i&b=s*0&&QSOfd(`2s~porFVRA=PE(*TP|4{uk1ZQ>1^% zdK3075xA`HgQ;V86fl5{?AqIiY7814V&FM3t{Bj=Nz))Tq&I40q||R(9+?1sZ;Cf> zg4~Q#Z2jiG6WAJ?eC-X(7MO3ac2Q3tk!x?XKl=6$^<9RAM&^$! z#2UZ6`lctm^&`g~5V!r5rEde&xMXk|aJ+dl+IlZwgA(IfMpUc8m_Nbo01vXV-!BCD zCK*kim}4I~VK%(prUv%tIxQb|5WWKYJdGTUT0*uDYV0m+P9Ljk*1Ae)9gLUn27aGo zblCIkU9H!i;*X$7Wjx>9Zw5|>JyXR3E#6dNUPBxRFM1)*2ui6k?YTgd>Dx&t({k1^ zUG>Su5bU!qa+RqaQ$F{xK$)hsQG3^N0i3Csr8cR#7b~XXZ|$?T40VXi9yF%{0NH>> zTR3RGjSfJA)T$1VzSR{4-`l~0?6|rQ@f|R}*L>(Z6Lj!oIn`^rH!JPO`Z2Yda6@~`WkC(yQ z-CK;lT2H=2aBbKW9Y|uM<~)RV9hpLCf#bL#{3*+E!+`B7U^Lu_omgPta@gQ>ueoK0 zlj|ttf`kr2OfcGn@X%$OVJ>DG?7Ed_8Mr}?GZjFG_Ms#(cr``;)K}==Sf$wmDhF_+ zA-u8L><~w<;DdOotyFLdgCb-n`RE1PH1OhQA^>R`EmD1)Ux{3ZiJHH*T6|*hXP8yL zWax;6S%l>u0YZ5Jr#3zPsM`=!pmSn&{w0G7NZC_cgJ;}J)L{Y>EMkJ!ej!l@+r^%m zDM|2zu4VotPh7P~?-oDtqylZ~$@`*#r9_<^ocdR7$EfLvZjs{B%^j~!GJsSOf zVHX-s`~={GBQLyd0Z}cnKlS$GGmx@!JZooNo=^N3| z<^<(T8VCk=8~M6K|#wz6`fwSZ|k*Ur)5Xg1|Hv`$apY?~n!EFwJ-qR#j>gyVG28_BJ@8TYNi9Zsqk) zS6#p+#hanQ5)k_`a{(4+`Xd~Q2iP_PRkIcn>a;9(4=$dzO5q;aG2w6!?j$`VyOmvt zd3*3u5=+L5agW61kpvt(o0wgV;@+=X_uI##gZ-7y=4IT<&F5kLfeoqh$C_fN zsxfJV1AUY(fBRYLODIu0o~C{p)bSlnJmOh#Qbs1Yo&d=O0pRfTJrJHYyBs5)4@{zj ziqLxr&O%W7&5I{nN6~5kqU|@6k1c|>K*7ssxCPi;eXjJ0(g+b%r=<>>GO~xf(>RPv z_+gp`3`5o08h3%Q<-8Y~(fTce=D@vaUOXYO7QidN*5eQDuT_iqn*my@$3i5n)8fdd zZMT3=zgG{Dt;%;>`0ho0*QaD0qKNuI5$KRs1{ZtH#&cYc^=wVm7oKA{a_Jzbg?%?aNDw&w3PIhXwQ=P zmO`FML%Fa$p*H)XvVD+j$3#q@>Hd(=M`ojL=%(};?P$cK6zs3siO>g`h?`j8esLO%4q6G&{5;USEjOoNH)m#X!^!geL zrnk)VshHIt8RzW>l6ZyhLj!ROw7YnAAqT)tH$mFEI)Kf5a*7lWoj~moN?Jp!PZD>4 zHnh>%*gV;`Fjf$&#)JaV31?_pOgNu*lRHuPJj$RVO~sniw_dy=Jf+E=4TFtJkho>`FKfo>P4*M?(*^{D>pINu8f>UI)ZQ8>;GOuDPO?Jw(N&{TtrI}Auun>Fo!MEZ%^`Mbvirio(Q_L9D)k1{U#{otIEQMUl^EdHqjyqj^n0BGpdb7>TAQJ5+^2VDOOR!aH znXyR#5--0~Oo)GI#h`hS!)?jwqR zR4=H;6^h~`KoM^qU}V=Wy>X)7e#p}G*D$6H_CI=h+M8xW2kil3@Z#|0f2VMJUXcjy zDWDS#+HZdJO#pdw^tU7xR3$w*74Ll|6vckj2IMJQ}U zuQcjmv)4xz_mTqKwkFAww{4%vBj_XPT{JW5vgp|s-22t3F!PzJ@=&C@-A%<7PF4i- zp@?@qWLbE?H~x-M2B$*BeQgCk-+wLIA6h^I>lboEF2c)vao+JX5$D)-5Tq{vDP-|d z+?zX2cLm9c^G=X1K~Nb;;)a+Y*pUdXQv?SQ!I>chM2!yhEW}n2)C33;ieN(%5Zs^$ zUctSY5JGURB53mv)CLGLE}wE?s(zBA87CH!Fg9 zM34$0VC7JS9Xte%QdxJZ@L&uPEK&sf6T#^r1Xig$gL(-M0>8p6QUvS100ePG@N3+g zaUlesR|;Ac!NDzf47hNjqPUqT5{lw0M8Wn6xL}paEQ=znRQ~>9sm2LJahsx;OBC@C z3aeE90n$n;m0&y=AE@{I3omZq>5+WDncmwFIz%$M9=*<}j?v@OtX5|q&25Afqcabp zM;a5uc17|aB2@HkiL77C>U|s3h}H1?n-Vo*bhhnyaZ=|3U}-$fjPBpSnR( zGjzyu8f}jHN_~!1z(eXck;ne-XsUK0tGUlCxX|iEtD$@nfKwe7%7Uc@7~vEpUf9O3 zABu8LOP$XFHr3TGmP*l~po(V`kur&r;cu)`C`vxZx0oRomoM)x;w5n590Y>YP5Hnn(w7^rL0`_Y^mNrS+?yZFcGUrg zD9~viM8_8dj!OFD$%5bmMDU6tIFATEA3{Kd4Fs=8EdocYKB5Tz_&Fe8zz`I?p9rRh z5L~YaI)Ol<6-8W>y!i^+JMm9sl85u?-iVI#EI+ss!9^M4c>c`r>5o~EpWfG39N%MI z8VIDP+9!W8zEZtpb~#ae^FDYr7{-V6&s>pxUuWo8Oms#iyrtgU?Zn6~q$_^O0zRf{ z=Rx&}!gE4)@QP|?mpJ%@L z7q`pQDK@AHR=Ba!{2tLCie*}&vkX_01xUq0p-B)^WoZ8cXg3jT>3B{(kgCs&f|kW5 ze7Cpw>mjGmzIfw-BEG8S@{zVuc&tXPlsnP}jd*lcKrF~>P2~@3qd|!BWnx%D?(D~b z+-y5uBqHPue^~38MLmIlNa`CIg)%QgDuViQaEOZbTdplIoo6W5{O*7gKcGI|LPO&w zYbx&*htOvT+(MQ2)Xeh7k1I1vk3jDg{4||d?eM3Sc>CNw@>d!A+$>{YROH=f z{1TS^do!oE2hMz3h7<(L`XKjXveehUW5z0KC%pTkF=g1 zdIf`kFUW;nRrA#ep;tA0HJz{c9;en^J~p_&g7;JO{Q}-k)cY%W4`fXLN#0wp1#il7 zJK%!tNZMcwz|?y2U-93ue#cH(s|d7oB0WU47IYlSTag`oo2spa3}Bi502CgCDa+~q zZ8>F}``+w@oW6+U1!(;8YuSH-@)3dNR0}j-2D!@?H4o@Wu{rhN{2>*>UKr-=BI(GLs9($_vZZ}R5vNAI~`OH z0hQ^zTRLF|+Bbv#DoW#n;;JFe{E>Ua$Y#vy`y>^*72ZCg51zu7EZYN3T>&)vpfodm z2KyMpUb8B+3rW&VK~m@sO}bN%wAxAfEhI%OZIoRVz5IA#+62~gjn;H`)^zermuZ)2 zO&><}a|;v!=6Pl_J$n9H%9XhQHYZRTCksW*eQP;}H7AB(hXB?SrK?<)Q*X#%BFM)^ zsWv-@a%{ybl+?HOc)|u}x+V4F6|e~(*myz_rQ7s|(uvR#2Yo%WA_Th&uToKirD<0A zQyDf@K#Hjk;X(Fcji~*;@E4zPOTPd)<>Rs0wPT2PQ6RkU}&x5gq;Gd)!7zCJi# zoj}mRBs5enwkT2AnZF+^4Rz_&XsB11FI{yN?oAvG7!0AtK+{0F{{i{+W@{*3fBdo) zx`kh&YVP&>U9A_wa{W8>H=b&B?}hL_xb}msD$Di2TJQz2hBHY3L%GM1w0TO}>sNs^ zM082oD3WH5b4jy7w)yN@1uIDg5)RgPvLB#ybUIop?z%qD|LGd`Ll4F`2$wyK&w}J_A5S6DgK?# zl8VGF7c!zlJ+*9WHZ}~A?3J=sn~&_1lA42LNdn>0zm1jpx4znZ>jL37JTLP53@@n; z26mT6@Z`7BDy$y-%ouXx-N*4xYCNPhhIPvqD6K{i1o!GI^?{#i_C^8Nv1r3uh4VnEug!72+35dC3@uwtnB*8Z8NlZpz#Gm`SC@}$=8y=SQED-6XT-&Hz zrimViCeebEi6LxSN1C|XImTPR3B)xq59>7SSZf9C?s6US0dN!s+|gsh%~Ld}ay zv0%YRRVL-RsDv>oVN5LjREuI<{vxW>q!=Yj`f)-OV+%3HpCa=hSZAS-06+I_hDl{I zXgxI3Q*#yh=?j2-Z$&QY(~lFP$PWVYaP6}NDA{^IH$~CS>;$@tW=ZWOZTfLS6y2sf z+}azWNB1@^eDNE+F-`QEbSu52^ksq7X zY(p@I%>MrD}JmH%9|rmW$ysH8UrTrLD625oKWJ1Y|FR5o?>1`WQkY z4d{vT&8#`eeJ0LHo;wlqO0y?c#(HK?q%p_(c3DQkLlu&VYlXGt-SdmpUx16&v!bm3 z5_=M*)h~_o-$bA5tQw7VFkrPN3ZF+t31Bf*HHMVgBm5BbF{GtznwY+x%V1xoFn_x0 zKX7l_j&|*fb?nA`2tLXRRXd9APNH+1yGK7L=$eR*ZZy!{OmxSF&{^kh<@CT${DO~F z2V2V)TMtgxU5JLaeqO)1DlH}#>p_-EDmF&Hc}5>XQ9SGC!ICv$w3m=7Pf!{+T?!gG zAOMZO#J#y2tO%_ArGUWNSAxbISE7@HsoEwl)^ZLr(nK!mX^~s@w3*Qk=46KWcmNi5;B=&WpTKai?9I2Z zYBKR5h6izo1(w90_CZP2Z)!c!=}FRC!x;y5O01D%vsUEw=T~ao{*@mOvQDIu;We0e z3?RfXvcbWbE(*SbUa>|oa`b6z930WyvPEef1=`-Yb}upTId4EjMG?0Fv8QX z%XUO-D0TgMCM*aI$j{sskl)bn(cOu+pnFWT-)~O@MndhGE`R*tTBuR4KB@ArhMpN) z6u+-LA@2is&hwuu)t_U0!>e}%_&Bs3BTM?R`Rj%1UHRb#ou23>Fah&Z6j?TCu-K~? z%E^ryJgeL?j>b9FzKWH%@J{!4bb)3_o2PhiD~e~(bbLa}$hhO=%aG5i8R?l>J^mn# z=~PAIRf~!TsJMU`$C0JZ#xp)xfs(A^8HD1=IEts7hniE^H+O`VhB*{X zX`&Lz8x_$tC${xi{ah_B<{?Jn(lbAGG4$LLyoR1@!@W7`NL9qn!2sVm3P~C6+ztIA zbV2|+pdat7x7*2}|Da)D^V!jZktkUJFXlP3FFb8(dLficQRXO55HD$^{{r?PaNRnS zw;aI!=%5gLpfW}GTlV#tN5XJn%t@@_`opD$sgI$C4`>Zn;oi)d?3x-f51PCO)%FLN z$1}CAI^vlLvJB2YmS^ z1gYaKhe+ym;9S5V>ke)O{oV@Y|3rkw$9e;?I$q&d6zeC5mF)_?e-HQOpb%E;6+Yl# zy~oF@Ug0e*gN#TcEH2)`tj6EaqMJS=72IbOQkuMS#WMj2J(KpkUw6_fJ%m0*IlTCIIJX9w;qbQ*Yuy^PNV!9 zwUnb_1ffPb{?nGElRJmG<-$j@^3c7%mb(V!E|GG-#P$MMvvCm5Cn2{hXLtUpEG3Xv zW~;hzC`c62A_x8SVm}Uj)!E5)v$5-8>C@VARD*xWB8MziuSEqBf3&`0D+6;LSql2; zbeok;BrZ&^Ily}-wEh7AF>tvXm_*_Rte7{CA&k>)Lkn(m`So2b4AU9nSt4Dg0{5Mk zfJ*bN{b(bbJHY+UBt5Zw_Q)((aevIm z2Z3lo`e;@M_2=mf(?4_B=p{0fJPouwUbC3TtP|O)lU5D zzk}nV_}tUNXZ{o3@>Q~}QyxX{)C8yovB0E8QF)}*gcsP_`5Vt)RbSLiBJ@M}H^h=} z8kl}Ky@4~EKmSBu;^|(JlAb>4qcB@@aBmiWQ;cU8`j5e3F`hp=P{eEu60MbSVY+H3 z+?$Ihx?*OH=S!4HFPz*gstcPkA)IBmEox&4)f*9U(nvCR;g6f+UA#q+=Q7cJEpllC ziu@>EK(g<_y?O1RB1K-#A~|4APyaX)tv-(!e#44*bo@oM4Lw>o6Unv?CK!}ux)RY2 z+9Yc|{8WrG&Gq15#2^~!VWczORvK&v20SA7Hb=1tTgptW4jD*7B4oRg^wY0}X8cNSGJ7ZSwVG2ftl zgyTNM=>LGAoazm)|3hDRi`S6^pFCObCn?&WRKGa$7g?z-@Gt72%!?{WEfrZ$FWhQ= zig%b2K(s`R$75a+ukD=kHas3u=cu3QjzWv5p3@$t>cPZ)3SS;{TWPSFTLYO}dYZ{T z%gC=)tMQnpR+|=>L-rJNfRs3nW>0xQGMtTe4m#HZAl9^g9k_Jp>n|qu^-E~2P944j zBWt0s*yzpv!ALjOv}7^s7tf6XF@w4&j62{G!0WA4$hQYIGEk%)@%agD>G5;G(3Vn; zY`}IKQAwwoimx#Y#NQglFkV^YtZqL>0L}W&^g7hyWOkue6j@$;!K*Lrsw#NummuC? zzc1tMQ76k6^(;k_6n3q10nIEtv||HcpdU+r z7RxAPeB?kH0pU>ArOC=4PCI zse7J6x_tVb?z26w_UXCo2}bo*q^GvH7iE4 zKNZ_q9^?<6#_ALQ;7Jq8A3RkmjDLVOR?SC{&cA@xD3pKt7sn>^sZIVMZPOI<@TOhC zc4`LZnIeDVO;cc^ZKM+wFUzHcGlG7GP0GLhFhR9Y`RDoIrdoNOYK)<=vZvv&H+r(> z(I?rsUMWli-<4TIr5x&`iN$Ow{0l;3_4c_w)Cf~t5q11I=ojgu9=D-x#jihJ3m8Pr zYax8Kpl>zDIOc2jf<9>xuw*&L?xLe{Y!Op1ZftI5ilXuVTHii+i&H~Qi^&Tw$c?#= zrW&y8B3n!0*bjmPmrd{rz z2$$POMUD1z9*R1Ww2wIw3RPn266SIn_CJLb33v{g@vCs+7fOd;F)Fg;BmalJcLA@n zsMg2ROC$wK0yI(;C8b4L3epONa8I!tw%A}rqLs@rS}sLUgNJAl3W+-#v-|afiVaq% zhoD7@B1CL4)TZ67p$S+ag$j}D1`EuVYQwduT>5+8wPwD{&Mu(moacZ3&m#}b{^qu3 z&6+i9)~s1GgCwZVyy6BufJ4p4qo5!}6ZYYRsmsPFyq_pMg95oVa_`O!=ZDB$O>7b` zyLQdbfdN!q0K}&b4UFP>Sp~|jC}=^Z?DuAY_iOviZIAM9hK=Z-KJ!bIkb6N}WVV&f z3{*=}ngdX6ew1R9Gt+Sv6L+Kq8et6>$MH*K{Kki*Gpe#XQ=L@pf$mHJ2_IVaq+XG; zY+n&mubcugbrs3)SC*X$F?DEVR7_org0TDE_Q6n0-5!PI^rjs9{@0HSjryepW?z^a zL3oTdxg;`5Z{2R=E)H?8nMY#PVLuvoxJs16yG0c+m$8GbF~2;{UY!$#XuYJ2dHd_U z|E74=2{GQ!#&Ot3+e>OvBX;yVZy%xG-3icdiPG;ee4DMH zYq%7=1O-693qe$8j1Ek~p7f6Sj9^To7l|Qtn4>kW7qshj6~4N+R5+a#+6|2hSm71L zDtu#1SYfkRI58M> zA)HO`VT64c8oyk)kV~?V6|*2Ktop`aq5N-UNp0IlT%kZH2Nix*D+Ch&Y;6{H$63M6 z0jw)O9U0sXI|uOBXq8z4N-mdK|NBustQ24{#ro5hdjvW#E(V|<%C(a9nASS4W+df0K#3TX)MHn-$`E2kz~z0~}CP3Fi#gE*{^6KByu zubEyA!u(Cv=;7oRH;OLHyZT;i8?r1<8BglK{TpNqArd`jgqMUj7IG) zQP)PJ_K>I_MWgnVsHdV)qa`XIjoM41-i$_-OBA;#0!ma!)EpB2C1h>Jphj}JZ}}7c zaXa&WMuMu2{o%;&MkG3bGbqGBG&|2My6nk4og`QsjjeF8S4E+?%YvlR^P>4jy8Ndj zRtD$7-GMT`hL>L(t@{(vQo(2)tEDj0kJVBm%CEDAZmXw6VNk{d_*c1_=>{M*yMxX} zN_G@2c_U&Slxr2rJN5|!(2qiu>-)qY9U%F1qjHgpVpa*fNEx`UK=vOT9#pc)iNJH z5z^~E#F^u+qm~(9RRf8d!&riUL9~vf+kJ%QSd&CrKqu>41HdA8h`rWR0}=XG{#3%z zdZ(CYHdBcW>YCyxaA1(hD*GYcyJ=NycX;ztumTSBrTX}MkBQ5lc3&D2cj5&{scAMhhbHs}IsKXZ|sVa5jpr zXL)?%h&YdP{}LCsqjX;;8Sv-)u%;7PQ`*&Z`H-5jQq$ZOe35!}YW`}cENmDh^UIhM zFu!bPDZes_Z*%${(fQ>YNP%{8|DH0x2NG#^RidfgSc%4htA-TZ{8dtEg%(_4&b8Fmrb@xlEZ97x;7w8xlMrj{ zFq`kw8f!vS|APgSLkfOX3f`dw?=Zi-UkeUlB$%e0{UvfN3bcj6#%&;ooiUOaWER@aJO+aV$eQGC0v9D1+!;sIsh=a@^V*d)tvN zBA=B)=^2Z$I7!-!v8y}7U<$6SUNe=e|Q763bXA z;t*XgiU)`2`s5JZi|6w!+~$0ZR;1+@9`?S=pK8ma0Gf&0Q?FCa0-Ltyya=i|I-$|P zh(e3DKKx5{&nmFkSp5Ox+3kM}h|7`F40{so0KyADf;-yhTCN# zXvcB4`UpL@jg-b-OQ90!X0eD`-Vtn&qKWJl)6DgPWbi2p$vWL}D&O zpssz*Wr#IP>%x`4UF0k``)RgzbK)T~u^}U7aNf*X+F%fn%in-sqfgB)flnatSJ5{^fPaI) z#{xK(4Ny;=6oZjy=T7Zxu2bgKo7ZnehjWOf*DS1^|0ub6gEN_3hp;9DkQT&WJC-8NhZbP6HUyaNK&6Y}B3ApZhX%b$r{YlT5B zzLmB|xZkAY3eQp`tiI~4wCD!2Nz3aXNzM5n<+Ed=$>uqY@yqAn+>@5_jidAJIrDkr1rAx!#C@dn0`M_MYi zf)z)g0+CLB)eV?VH6r&iM=;8;7oH$e<@3UNmTJP;ct>*8kUA@mTOwe4<@}}5f%4`*YWW?yytaU76*Fpe7;e2-ED zZF2G?DvqM^46Fo-C~U|DeXr#btQ~a|2gykcMX8#}Q9{ioweXMBLKAVPwQO~B`0BeV zX2l`anKD{zTu_1nxRAzn^{Nzw5DoV;-Ff0DJ+(qqt`({$=v9Zx20s`nMqlCA_kO>n z=>yU|#pHK=AYbXLU;89nA^XrxInZUQGzy~JpLWV~NAbQ#`_N#t<-97-tXXSfN1;j?y+z$m1Y|sn%y%5*G0DPSM!(UJvXFdEz=-ze9&4HnYh9*`rF7 z0DnA%mAi8cXQK?H3AW_8YN_kM1B_21`yPiw()`{D2bq!Ch)B-mHs_0a_YKo zHQFHPm_JOXZpX7%`D%?LM#lpqGv(7oD50~DtfF$5`_0+k{xH@`_TW~5dg%7EUH?0I z@FHyQI*yc|_3jHUHR-y+d)ds0@-&Uuj!FA_O4=clTo=R_uh9V#+FN7mrKtQkhHMhZ z581@NW`|4^2OS1+{xy&WQ|I0IHhaBU77^#WtJ7fStui74?B2h`nRZ$+iBm|Q==h+# z*@nJ-FL~oNasK3hX(C3_es|w1^%IB)OIP7}8Sf&du6VzRAQTF7cybBF5OXSxmgbCaRM=HD=rv zD-X~tMBVK`b8=X!9izAsytQ-VnFMHgWW>nY}P&~ zjb5ZnJQ=u(G6l(e<252%-69@VY(;pHIiOM;0<-26Pz&#j+i}+1-2~9=@?bun6390y zhEzsrlDq2#c^wM#p)5Pf%*U|pid2feK2TkFf598V`;!g<@4rCO`;`yi+w3zK<$bH` z`4}jU_hqR?t%R(48F+%aN{d|^NUX}V%h6Ct;(!KTK&P%xC*qHt8h;n0&ul~{SAiYn zzzL1#>T^nbKgG^}n6!kUbFi!QBQJRlg1zMvTAh9WCKZhOA^Wp5RaikIa@J}I&8HN5 z{$?@|j2@)}PT^`Hu)o&0wF303Os#RZ$XNt?65WEQPR?BUa(sX^17;&cqg+6S{Q>u) zF=W4NW%jw35UBgn&<=N1tXol#lXy)%dbaS*qb$A87nA;RsP z3-eI+B(GP;e0!oYXy0RE`M$?|_~+)dL9z_yw5=%cGRNnA??4@=`X^vNAJ54rjhXY0 z%z0BR=OpA*JfYfQ;g7d8&E*rL=SGz2oP#Wwt|n%Y3+I=Je;nsEjw<$p+R9`M8uTS= z<5(cm=b)IG&y0Wx#$F-o_d4FoSdW zv;0bV1m0{k`o4vVNq1h=nd-#8K zPhfosERKr~rk&aCO5R6wh9>AcOM#J|OR&OPD z)MBjsx87S2CNJ2sp&H(kXeSo zzkwvc+7Ii|$SVxzc{^xv?t#TbpI!LbHz0>IiS~%@X)k1HZ=N@DI5@{`zjWhidYM+A zL8JnPp?a53Gq|S|zPE$IGEL+ob=(9PX1kH2!c7w2B60yQA7IcnnT?AmR>{d?v3vU^ zQAV$ah*`4~B!Dt{GsR8%Z&78`+SN*MJ}Z9-EBJs`&>DgC8-moJGSRJuTTsW!W zMG!|#dI`;j5%i{?-wKi-wyp_XiA#(G3-gOF+AE!fKu`Wv2y`hi`ITaF6=m;vF-$Ch zoWWEgy@@FH#EL3>o2ydmr`vl>QiNTwT6ewxe0UnVyZ#*wDwAK7g zKD3#8L(#-lWsZB%+IejKUq2;z+s)@b%f}^@LEMICb2mpyI95n5H zFCfH_P(g^shzdss3Ud&ST+@Ux?p8ZJFP$E+8+in`Y^5%*z#G6X1{dN&-JMqI0xp>CwBL
7s2@!GFXoRX=hJjY40ZvXm8Rr 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%0DbZ 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 n}EWP8fH`r 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

B5#(`6pCcc~Ng0H`zX;g<&? z*Qu-*YXAJ8g<6{Ke99j4qi~tyOHj#c4WGN>PSUNu1jXR=!u)qu*$IBcU%O=|QX227 zhLVf1PhAv?0!e0F4E<&tSo9m~e1({1v8Swt;Wg&0B9~<%-Hj&)fVLe>JdmIQ6!J)k zMQ%2ty=u7>oU}2JF+ku6OPn(PL!Z*4d>NP6gGnbI-E)ACd~sFYI~v;2`C$X1O+Ee2 z;eAYj&@vMc4sEKV_kNp798dLgF54GpRntta|2?m9PH*J~^rEWAKhAodb!Lgi*r-L% z>XelZPJ@w)z2l7`1dLQu%H*%cf$rv3=-2%^8i{M`8)uIxIOh5*kEQpYtP!01hOwG< zzO@i(vu=&e3k3T)cWVTQ-gC>JQnbtiz9!H7{_q_q(EPlnS9h(-Wih*TY17>55$$8C}C>vxo4-o<3IK3%18H;2>Z^C)>WRaa2<=SL( z!es&wBU;$8;s;Az-E(mvqMnV*#6-~)s|69HPO#|l*ns{*rQMR|+yl?3FPQ24&mtOS zsa}i3h^;?=>h$+qsatA3ciUoTMe>vT0uR#4S5h&W#zy^zxyp;jOveiKqU>A&9P>t= zA&ZDv+pa(Y&HUjv%ns#jfgh2roy{8zu(^%w!8}+Izk{S^F3t04!LqUSrU?2d`sqtW z;&t;M0c~6C|EHPSVy?v7y*_GP?@BkW0P1YK1x=lexnHYN@?g~?6uNxgkc1#1%(6*& zDEqv_Zl)Y>v2PoEHh?J~EtG8`dL?IaF;@{fdR ziVe|7;!W+CLkGbpiAWI6+RoP#K4*paYpSHLFt2Tqu4}Z|dhh&lga`+hUbEB)78PNJ znd03hkN&)QOrzDu#Dwb<5>6Ie#qPlayGNmI=o^VOXsHVjO{<@uuEC|a=>fmM>xQv8 z;Z1AG8@YuhOvlw!IN8FSsfJLz->Ij2D%S3bVYhZ~?RbY`V73FLQ1`#vhEcX6zPC&h zZ92^G`<*r+qmglJvf9UvaqU3)!`hyM(a+E}D-^tw7MXnZg0ILb3(l9=k+hf3z=u~vKBC#8I%n|>X%J46so#hQ5&0`N8|@rPhV(kh&XbYF zk8>@3GBo>a?q8QTu$N|~c|gFRT}Usiq3SO+SKln2WmUZ(M3i<633fv(<8yf$SvwZt zPrHW7@Rq^t8blBk*;)ijA45B_tgoauv=MCByZv$7$FMNXTBhwElR~yNvXY$W=Bi7f zlR0Y+y*sBd&^>AFU~SMGh*ohMxyl1eSF;^2h85Nt2D@a10b5809vGmANkb=B$H2kV z8rCcW^!YDZ?f*V0kRxJ?jmeD-w-+BC0tO-#08zinz`n2g4HJN5aqXY=+yaWV!fi0X z53&9rX7ET+&sSR2;n8>y_bwS)jPI@aF?2giy|0L#3?*a-bRT{P?2EOHF)?mVoA@NS z#83SyYQso~-KAxxx+L)b%pOlrMybp49HJukRHZ`hozj)M#4Z4(gNcGYx2=o!p%Q^P z7<{6ai0XNR{bkUnrD=)0pklI-_nP!4Q7f;usNVd%ElgJ76X_69?;*Stog-0_a^+0x zJRIda%)3Wu@Lzf65q`ZMZnTE<9t40Rx~2{;G-6@}8z%swK7x>M8Ja|C?MDIvv9^y;5E?>kp&{>D+SvQOVQpr z>S)C$J$q^G`9J%bn^`VgQT7+B;KC?Lq)kWtr-{!LJMG~fgjY{h z*a+tZMBz@*!|?-hu4;wV?$^CfLgmPCLaTG{Rb@_}6cP0noll&@d9yR43GvLASn{EWdS2() z)U}}>md1Kq?ehq82jS!UEr|;3REi)F2WEH~Zi2qZ@_i$h3ik}9O>pf%bBaOzGs+05 zx$dKu%9|E5V%bUis-`W}hSCI-`of^>2A06H5C0?8&}oQe4HeMkH<_u)6bvK-B`&E+ zEshXH`Dp7o+Sb1D@esWgOGJulqvhqE8bN4(P`Y%*a8FsmA6O8nB0> zkYl`6s0|BnOflZu1WhYO=rU})AHU6>{9>`IK7%v2I^D2~v^klKoD9pSn5tS_H^hN3 zUl4T<$?;xSQ0~sZ7dpaU1|G9o)V9=h(qvPXiR@yn^JCLn#*srg64JFt8?@_XM^=P* zd=NLxj?o}yDhyX^JO8Xj*wCBVb@?Koj~BW|3<~d#0=9NhmO&cS5{4vn#-7AguQ+q^ z#A;hMTJC#dUK9qkMpx$tUFkEvcnrjCA08ay_%9;wGkBJ*fRVIn&+SW!OnN=R={IX& z=ihC7h)5^ATRN&EQ3dyOj=Os$@=uky-@})&iYvraffmoONu^bi2DQQGNN26f%f)XG zcy%Yp*U90yfU8bc&D%fW+G&i=>S>w#wB|=z%LS)}5HA2#>OXBn$|Fu_1%dR2oUXKe z@?t6*xxYt@!n)bXwBBG$!{&XI*pjGySd>Irg62+Jia#1o;ZBi-18^v+J`uagv=t$_ z1ImHX$_R-#Jr;bL7Z|D-p%Te~Fm8xY*Ph_Y7WF3j<94QzFLRFftUPtJs6B(~Dp^sg zsJ=`u^d`oyZndYG$er&NbMG`P<-h=jih=$lP99rFzBt7V;xV0ciPkxe9p5@&&ouk_Vy*W8$nP;e-aW$%^bp zBnq^)*lI{5`{SR%9}-|cJB}L9{3ceE^U-P|hE`6YrD_=su6o-0wLuVfjNjn57_%nX zWfVo}HnDnDZkxhmgcNa$v??riN=0PjjdQi+s{>k~`OH*~)h7g&0(>_goU<#r@bz=W z*a+qTm`xxIpQnNxrf2D!@Q1*u{Q&{PIeF}@V$c?JLW&stq z-*p=k6n!np_vDb5^)#5Z*5YUA!w9JP^wdwm9w^n|H-fM3d}xH+U#levY_g@X*51WX zcIwFNT1t+8LCh3fKDQ%Mzc(-#L;EY&CC7NRZ63DQ<+HnBK>d!6NUYldM*%KLqzX2g z&vmQ_O=Ecl{S3G775o2fQ<0@?5PZ;rb;GjxB?9%_KPj{WE8(zQ7cRwQzo^iQQ_O~fFxY9? z#}#Qr!WCErEvlyFEV4lY$P-Xi+}UUEi?I!R>k$C3EH3#=C2#s$F1) z)W64`Y?`~ba{We$`y`>Ue}v?`|Jb6voRxL%h^5G7pI1ViNej5q z=5LdKyK}0D(N|;*r$_UPIC_g~sO^RmV9g8$|IN3uKLyaowz0mS3M83_BLWMuiD7q7 zIJ+A<8D@|k=aq(jtp5g=0JScvEPYDAsZ<7#qN=6Qvp;W-Zb$z?uw8@Xl_JCoiwjis z6ygQRI>)6rwxCv82XvYXXr9iH5KAulnvH9Dw53;E=D#NANXiWd!;o?uIerN)=V@jx zMm%V&StSM@z6JGK1Eb@iKE7Y54b`0X>oH{V2V@^yofiGL=KNrlii3^t1^{J$`YS53 z`@m4s+SlKft@+HABt??>HCEY_^g9@d*?USu-_-(@5JRQRg;P*I^+WxA=9t~7Gz?H| z8XneSJ&H=kMoU`KLw6+5#A$>xAhRhnK%r4Su3NV6+laL`RksZE$N*#dfF?)TwFDUliXo zoJTFUb*ti+|05c9n%@!-oi$yOi4(>mUxWIt$5C$C#QeaqoTq8w$4prbHGlPat57pz z%6TwKS^t_8wr?UUrde$Q?5{O$EbRvLM(&$env;Ds7ur~UdC`vo1jR(krp{b^K84s{ z&0nL9P-Q^t%3Mi|-(`tnso@e(s4Wk~9M8d&8%OSS`v?lioAJ((HQs^sSV?e*PwzUi z_-80znxE=~lXQ*rNsx>;RX7{A*phqmNaD}9YB^@3d6#9 z7?SN!h9;4ZRgAY2`3pFy+ONp#y1+xzY4KFmVShIZ@?Wmw2io|k4ymY}#CEnJo1%j& z|G|NF(%34jmohkl`H8wO5&XWQf1kazDwY=Ha{Q0NBbBUH8=&@vP^c zpg{Unqk(nR&B!vD#3OK$86tE6IqW#s<*%slgAS?7uaQ=)j*klis=PtfXeN#MUyI{q z8Q6LnC=~}0&c*|L{Ky+N1Z9ij=Dy1anA;5K53mLm(?0%Y;MNxyPzz1QIGrx<%1wk; z{fn!M?K)9eN{K>x&`U9GJAe0rwL*@M%ig=@4>{7PFAnhm@}goQP`U50GVV}N>RC;w ziKlHScYoN#l9cz)qL|OZLkV&@a##7#xsW;aOa!`0i1L*q=%`w+pm+l9=1qeVy(M3o z?%~LBvU+c-&RLRn3($9>mu-G3gEyq=ZVX%%XoceE(PqvwVZdmvqMRD_RhWL;D6Gjtx-6el;)< z+i(V53E3L`d^^Vlnpl4*Z4HQhU_|u;@eZP~le!msSEg$)k%g_G6rykT9LZ&+4Vfow zoYdEyR=XgL?Ah!yy#MY3B}=_$1np~D%2ptZa${Tfp%!^&^`ujMN%_bJBbWi=Hgfncs-trl8@(XLN_ zxV*4m^eIpsYa?I$vBnDrb}ZE6{H|zDGDOBkgk4-&9T|>!8Lks|fFQufoTWQe?#ivY zfy<(6ZS5fZ&+oPwx>5;zxWJcaE%9KyFshuy$Kp;-|NED>IC6H9T^mp#Imhcacca4J z<9RYebs25QE5V;m+dv9$+?4vg%M4Q*w32frHG=9!A;^aejoAfEm@lPFm-b$BedQ|M zra~~k_ji+IdSn^E2cWTMm&y#92dVnia*y^~qJce*SAqZdXCQTbL`9HLA!2xMss#nl zFT%ig9PMkS@GuZL*9#vNpYkze1oPB7CuRV5bO`5@n2x*s<;E1-9l9-Se)Um?c%$3T@^V_H;I3LiR_c4dzX%dH zEQe=1s>bysGWkP;;3n5t79R$s+Ef^`(hT46Z2`dEP(6b_@}t5RFul9dfwptNL&G}6 zZ3HhNWO0RkeuSLV?iUG>JmKNSxuIjd?#VxyBH({=YJm?KGfyeP%r#@a#YIP-7a%xp z1}~C=w@2oR`^o~|NiM?7?85y2!ka0Af(~w??vI)UGKv0+Cnu(R+kxzzDZBimgKfE)Rq+$|)JTjk}Y6L&7rp;x{*UFJ&*0Jgl2!QVvgg1JU#H$qST(`V6+*x&30E&C$4?jP3zO@2cqivtDzIM5 ztV~dw8zlAj2>$t0sa%cpV*BR{62vK;G`RZ}+0eirIh3DKx)4;SPY1*iSqc^Q+iIpb z%D*%`RAj;Y%;C9Ub@JexAt2~e589b}nY6~3L?h@UR7{sFqj0EfO_ z3ywjGwLJOOs>=XpUMkt%`y=TQe>5Mgc}dD!SiozAEf$I6a6GK9RASxa8E#P%#Up!@ z)x^a|=;BuP9_L(heR7}0M4I=e1Y=t>&_erS^o+Fl81(0xSOee~)$smx!LQ#W%fas!nW(B04)1w-N!15{e za{NMMT~*9H%j)~*;8y51Nsf`7Pf)djIZ?9qUIS&hoK0`Spi>12Rj9sJ4Y6zy+CrkY zSJ_Btaw})u)1($_sRD(3V}3n5Mh$Z-1IH&6Y7^ubE5N(1wFBLe}C+Sr7fu*UX%!LLPl79Yc^FKM13TQ zp3vt=zi)F*KnqcQy@cn`1E7DFmHih_VfQ85n9DVx;NVGWr-Lqgm1QjW;M>iO+CW_- ztqTPO#JKV!NUFkZLKumsWrL&Lv+634wvl`n7Xxx2L8)Mw)&Ps_uAb>#C5lJ=s$g$l zYGuE(ckW$v%h%tXla-~ki}p7c0(2;OWK{zacCCbb4s?!RX+)4i$eY+r7^#I_+Vl5x zu)v?YVG~C=F$dyz8@AthAm;|g+TVF+g?Tyg{mn8^DwfA(W1>Jgg8@4W@bw@ zSBQ}IR4-+k{{nCDE3RLZBFJUq?)75etrmE2ZN>aU-`m`>3sY31yR)C_X$Z@A@8i8= z5km_`ki3aCnt|lf*8@$0r?x|$Pp&hDrih#evuz>S?f(Gah~1GuNWBuD+JLe_=QS3J z%cnA@0={^P02KZ(;CdT0v#&qt4BcAi2-Sa4tq0Z_GRSgDmOzaPoFWgRjfWgI!{Qr; ztFr1sXUX8#j8i_5hL1&4tq6{69{{KS6+y>fW4C>CAPC11gldnRh(=S1%?}DPEyq@Kuzd3S%33$HGiX}{N&MnY!B=Fu!^iy zrDZ9sc19;`_4^kf*Y~X1YcDQlMM`axWIA?L}{B%4xW40 zmlUYnf?pqrTwPI~2VrB^XMdV7Q=<{%f!e4Wz8FiykV)iOJ`k^!?bXL&lB|uVtLW_0 zxRjHbu!6pW{;d|8@GxirEfHO18Fd#+m_eU!q z+C{EF#s6D~Qh(rd_+&H*aGCcwANr=v!bBpm+1Hf88pJ~ve=f*^-LG59587YB6b9d| zH?F9sL$GvAb8()buckXL4@I1QL)8_rLgHusgIG$!QyDD6y+ctTiC+9uiz`$J?wp#a z`8zfUZb-urUpE5Ma9)f%R5u{BKvrVRya{nTEXIo-1;NYeCO?4fUq$#NBsc4;&aG?t z^;2tn&Z(lAZ5JDrWh7)92wb@~jVZC_o|+xFTToN5aJuqgo^L->)cT6a7JkrbO6%vl zlop?kys$jk&gKcUV zL(U8x)I?zec$zAKMNCF8i4{H{H$Bh`IrFjd*LKEo61Js`8+xCqC*i`$zrIetm)Ttm zPy$8|BN0a&cL{&N2@e8%vyKIexq)}oEz1vM$f*lApxHPoT}1v z!VT%t_o_BLTDeG|PM(n4+cIyK1h?is3j>Rwh#_a<7q-u{<^S%UaDsf^N9l*B^>7zC zD@~+=>qHKb*VN=HacMsuo#sLgf@-YR#1X$tBE&-F^XIi3l$}Hz=(N^&=ulJ^y>eYt ztR?P>;$do)&GF`xASW|FXBZ6)^AdGr6#QDsr1vs=m%D3LRtYZvVj`%@M{ihZbHEy{ zXvhM-tP{pXxbjX+1%?AYR@Xy#C6%kko!V3jP3R`_JwmlYAcvdlPPVAu_K;bES0Jo< z$MhlVmiAAtbF!-B!+9Fa2okbY5HNvJm@y?ieV5 zX|cdB8XU>={~7@pL=vqg(WaGODK6)wfxt0!+w}4}D7!Xd^v-$@R29)|boMj&sPo6l zkg5JttqnYSd z=~m$31;kNYoRh(rUV3p8asta0#I*MG8>1&u(kWW$)Gj>qS>=J_ll&QV47Y84c*g59ap81JBC z$^(hLqij7j?zf)7X>^K9G6_Ru}R-pMYox8am zCh@dcRGdz?DHK&xAE$0_E*QRZ1;yWdu%pvNjlN>quc4dMWvf!l($AX$7+0xB)e+xH zK%xTf1C$AIiU=X}26Rbrt^`mClt-Cj!xE@?Ahf+ggo4-)qjD=8?X~&}*uymW{2ejHFrnOwg zK(lrgHoeU(IVgQvL4=_&cyH<0!GysNsMCQNPawlGB;d$F$l(3K;7Nf#J0N&-It2*3 zy#!eWXd4jG9sDp!ZK_GUBf>+6Ko@#Jan_y)aGBMhX%sPG{6k)Zwu!M4^OQTP?Qtp|u&>muT2AQqljTf6`K-E@z<{i}m!Z>xrCoC#l52QHAZiO@6+-$xT z{30cZZw#L^KVTlFFg_5&?UZ>wg$yFw06GKLf4lbyq|ej#7%fH~c=&LY;(us>DcHO7 zX;xV>Oz&>Pg?=wPFsX){kC<^GM$TWgtT@5;Ta#N75@sc5ed;ixxfJ;Jyj~go}x`Qf{Di#bH%w6UESM94cIJeZhgg(bDsXsV6=c9 z!(;iYjAWSoGEK}g_W5Ur#`pc5D)b7cUI7cElJZqOt0B#@Xyl2K)04v@@C4=gIsv8B z;UTNbio(KpKPcm$`D-HfHH-6U9w`oVLN(|u77Vf#I%i?Ny-%=p+yTKC)>|dQv?GI5 zkt%GHmX>UXlV@UJSmwqfj>xzS+X0SQRXT}tD8w^K;iE@O@Gy4xHP77z2-vkU=ihgL zpe$IRlo$))R&gxAXdKu9Km(Gs6|u+wT_WxB2f2eHoPQ(0;&4PS^P&!wPQF;d_a(Pu zRIai5${h~`{GuC&QSDhxT@lb0^WgTG6=~Biv4BxQ3V%|`GJX}n?BJ*!2n&1A4Nt#{ zs=95KCM8YBiL#mgWcb@&b+>t|)5>SnQspYUt$W zt*Vid6t$%n<{E2sS;V^`Atz%gQ7ne=C=Pz0q#-k@d5;Q@$U#tK7H#4>J|j~FxN!v$ z2U5x2%&^hFgo`}wV_#1jH2Evj9xA%2)j~}n6Fk<%$89l* zN|w@57*WawmUYoJ?dJI(AgS0|k~U{W?zOk~8d#aU`-2Kmu zi7w+QRT|Mml)8Ev`X?j;?PTc+ccCOLIVcs)FUJxr&QhUCcEFCLQ$=x8)SX3;!n7C= zv1EG`w=(LY2X8K=zj3&mJT9K)5^=Wnkg7!GQ1bf*kW;<5?RxibrgG7m-wZp45yklG zpZ4viO&)aYXS)SOLlFov58p?zl9#&&%lcO2DPoW52jKG$x^GhS1JPo6oiniazB5n3 z{+qRXH9?pKXHLUeyN&uxsM>!E7{|jmg%G6ta#;CVJ}Q$t%ut7YT_?Al#vHckvRN*R z7NGx=w99V1Dg(;cf{-lJ+lC#w^^W3a3m&d%;TX%AMw%=jy=xvb4$ThIfnKi;HXBz( z9UKr?>YvS01c(@pcu{6X)QulCCYPzufpX&_(7r@nQra^uD@zI3PZSf5XOrdfDqlHjUi0cOkL*`EC%LT}@MD^qcn!HmjydqcRlUW{i7#x>lj`-Y!Sl#9R*ANPqYz(C%>qdosIK98;KT@pfT38g-R zkvFHmoQD$&YA|c16i07fY-DGqE}S)JV{!*WiO>2TL;qzpiKPdyN_A+_Vb¥nG_K z&L4nj=ZvLasA#||%3fVmT*K|rVD_VLCo$@0as0TxP8guBu#FuW@*ocqUc**j32oV1 zqQdyK0`%>+1d;{0a<>~ydR1CgrGlwoe-0?pY@LS%=c7d2?vPck3&0~y7Mtv z#webW+S%$x8^fGmsx!B#3okr1@>=lAN6y}*f~=wy_v84A@dF}3rhCa?5WxuqRj

zQLjb?Eb3N9f%5aOjl%kr^q!SEwEBl%5XIC%7KsUEy?FE*~%?=Nt}u~Gt&np3F5y*!l+_r=-iLPn!%A{a5&x7rIuRuB-0_(ht*-~b8(}hb9U%ui+589 zfP^DHw7LZzMEDTC?;%DK{t^0nU1)(WcY6eOsWiWVeexskNMDiS2zJ85)gh(&Lkl~E za>`>S`xACIxJ@0jDOZ1MQaf0fNU?{})2+LvGPeMh<47PT^a76Lojo|VP-{c2g&s$N zG>!Mx$OX`9>H&)fTmhHvugBA_qB~Bh@y$lkq0@r_L$DQrE3xNxr; zeVyr9WN0nfy2Gzqy2uPhzj&OZT9p_Xl|xz-)$8wT>MLgoLQ zwM=Ut8Gb0(ci0KseT5-GiDwjyMB`X~b5_jRdcGdhe8gqj_eL@6|ZiDTP0=X-E z$`ZEt&j2?-$iHf{I>*`5@8yrUvrg*m#%n6RckGTxGcmbC;RbQBX7wNRGWt$sa*>`! zqd&qy1P@5GE}EFZur6`5r<|gb54y`dj6xaK6kH%~h8ASAS9#lzPK&HX9ceNIPyT{0N3;jP0m!Bl|rHMI_UJ*`P7B7T$OK;y4wGl;IMn;Qqi#L zG%%zn_|B=gqW?Au8U^gRen1yha^`62mSB0D`*%G1`?WoV8l`0DsY^#8iyMk=nRX^@ zC<+pkCN_e6+ogkpNSYqzZ6So815np}h0Q~)2Mq$NS;i9DNUk@Otx{Cx>%vK7!PogL z987%7tL2sMYKR~c3>U7xR*-wUV%EUhP_m`S10x;5G8EWOpLPQu5^1J=D40`({iVk` z0^Q6zl-k-9(XjS@A;W}=B0rOSdPk{Jf(u0bigNZ|UcKaOS=c*VJ}oTr^?-|!#caE` zKv0b~9HEsap+aG{aOxTBI#{e=HzcbLn7e#2$W$g?RgA!le=ykQAZ0E7lZirC^GEUN z@ofFl6n&guu***^WYFxR_d#=x@cx6XToGeBpd&wIL$_Myt9XjjoXG7pv2}dEX!Q+K zE_K*Fg2o8rc1m3MH_wXZvQ?Q(g|9NJJ>Nv7lk{Ao^}~)!>n~y&WG9bJNxae zTeQ1y`BCM4<)SQ~Ps573Ji zFfmims&`LSX=iCXmgtrSzq?)JF5a4)XQQ3knD>!_-e z1-!)Xne-jqiH6ONrDyXZsG05>#dLzMxrNk~oU<@}Mbs2*f$zb*3#tCP?V?$vdNE&o zCqnd2br2x|mh>RpZtZ)a%~P0xB;?-==PVxgm@;`2doaG+crYJ4Hks~r4#LrGAgVk< zS4-|A4ut!TJ9)!Opo|~w>o`P{q9wadSY}i{Z;5HZ4zCr&J)~Niu-!hv_PCzZPap(( za28M3{JquCSOxr6hT@kt-nz~KadRLLE2u{XkmiS9PX$1a)DDi212~0w)HC*}QnDyY znmo~tWDiCkcJ?klHe=8>n+uauo0r6otaETQmsQPP4h}ekIXwQvYb>(k-|Ks9Q-Mml zSu|-Sx3)U+5i61ua5ubD+hF`!tH?!0qw={RRU-nb2gMK0OqHTi=fdH9yD=w>oim^q zs|c3!Y(q6Sjb(bQPb-bUb6)S!HGRNy(eM63law-w3ZO9Mu)kjM{Lu^_&)7dZp( zNI5vMU2~EQeSO`)qAC2rXwW`Dm$rpu+&jstv#P%nQm^g}sm2XK6&z$t0{a87#014# zjF*HHcWO$8hXiCd+IK1<#v7Rh5$i`@R|+O#EJGXe6K1c+=~GFo$*l7tRnb9?B1w}{ z?^(b)Xhi}|5k!bhRTm(zj~AMy&sBiVNkt&`uhDnSS!V{vJ_?|qDZ+9B?{N@Eu(rh0 zYtNeicTq4Rs5mAnzguKM-&q~iz@w+Y{X!9_?qhIFZOVS3?A+O4?T5GvRV1w-QI68q zx&m>g2xIN*2&Dgu6frCWFpj2*#hMBIK2d`dd_8J<4390kb!*K3RJnK_me1N$iLa@o zZ)rvL?3kNrv?U-8`9#h>Oz~n2Y3!=&5rpHEjs6OXjS1f!gnnVgeq-NzpJ^YZZJ4{DKSI}XLJ-$bDlE6+n@f@8#=B9x2 zQ{)2{!Z#F~G315|3SlYl@^e9Y_g6jerzxk8ej%J}Zf_VqB$bhoc`zNmu}?h}a4M#f zaW9P4G(PPzx2Un6e*%Tq=r6Lxck4I2k)hVP@HA^i7Wf64uZfBP3c*5s`zWv(xc0M2 zFUjbCWlqQBM`K)(&~uw(n+8J9(<6ybOA$E(AUzJYSI-ONYg21n*rO z+QGJScmRVAdR5r`(uL1evGZUAc6@vfV}RvG%PIwjX0CpafGZ&hi5zlG;ApTs9IQp% zu0eUIyA7%h4P1@hZZ1&c+#f>PgrJE{0Ya3>`%A*`Ub+W!@8G>4>nkDJg61svOQJ36 z{Oo}?f62}%C*z77}n#9;w)?6&<-Nvz@!Zu zUz%xxr^CQ;^#<`j3>Y*GS`S!{b<@`(4idXgbv9Ay%z{^5a4N`|3|Ms{OpNLkzn?Ye za9%-sxQ(<^6krSxKqAko9WQ0%^~|cDvR7f%D&23rQ0!r1AN%yAQq5~etyNAW3o?BK z1(O_zKPG`;)q|-V?zoR9M4C=DWJzv054s%A)e z?T4=c1g|> z!ql!kHn~}PiT4I3K&q*L3fZRir5+5lg;-5d(`18`f>D@oV7x8{l?X924qMx%^};FR zbs?c-ek1CT(p&PyBTNb{B*hhZQp~e!O!f3^Ngx?S9$yY-XlfD=k`2|c_SOq5{-M%USYjmBLX)i|%*r=W&Z^$JGh*(0kv# z%7EuIEW!a|^j;}U*!Kjh&ZrYZlya0D{!Ge}tmHD~da0+-fRA&DTm68gh>QsAQJ&61 z%pNOYD&1eQ{Xm$HIr!%RzgX7PM2KG)`(1&o`>R(K%aDG}-|WAyRc6s6N~~N6A1CvG zM=$2kr<%imDhsK1A@bvEM+)c<$q;YfB5Q#7E~YN za>S2TwU_1Rob&%Gt4?ht2fN!kiK~Tzl7?9#{;nJZDiQcKi%bTk;{xB6^Gg87ZZ%^~ z-p7O6^au(gx2Fk*aIz=LExnq{#7rCw=>AZ3ZpI6WekAvt$JCrQ=eMXV}?nhEfp9wHrGys$0u&sZ$~dE-0!ah%Gyq# zP2(A1yly3ni`Rz-=@X<@P`-3p9R}`#^>3lx#DN#&qR79Q9>}oZEq+uBX-!XJEoPl@(@GQ_+ezEO@|CFO}fNI>n@$sNW$QDtP86!rRhLJ&-SGgDpFJ z$XU7$HIsgvO~{>&*Cw(KupygYu6ri0l+!!ot`#o6CCrAZ0L6}KefA4aSO#PHM5;zu z6~DsbK$o!o1efWl1tNN4WySl#&~uIK=#31*kL^ApNjo;EgC*l0rm(`vxois>T*%vy z(!=*jtikjim%HDntHQ@+Oii<|gzClO=MY96wMsmf8*M*{#HCx5>DSGp?iWM`gGo_f zE8lCaJhE97!zTA!LBp~mN;TFpHI{-p7%Um9ACONePZlt6{>xwNrfVePxBTMb3>q3D zvxs~i#fUA*likO1S^EYNjugT{6c6^G_0)Y-F%OnwvQnGvShJq&!b)-HaY!o^gv z+hU~c&+OI8X=~;!UxN+5~w-9QlkCCaF;mUl>4hMym;Q`v8wGvWen==6HSu(dCG!ECS^N;^gg}8WD#) z3q}ce91fdX$E(S4Qpi!~$sNqcC{C1%2>Lu7`X3-q&LL+$T#)<%OlPyu+Hft^qz!=> z%H_gcncZnzbFze~q+H&FCndRK#NJZKa+n-13EtzvlQpmyFWeKD0Sng|DIMIVEo*>6 zMB#Dx2>=7rc9Qg}Gqe7oOTY`qo;z5zAYW;fc)qY5wGz;Y5g3I0Ll*W0a`FjeC^3lD zbV1WVGnheV^_G#>2zxt*QsP-)3~*K)7Z}=v#6FF(R_<6=rVcv+9e1LAx#`7JOH$wc zfL$;o`1D?6%1xz6Yf-7GQ zsCIg!Vk_ukFij=9?p4V?;9sB-Hk(qNZuGBy_C21D0TZiLn07IlapPmetw-9-I20xQ z>Xp_bM>U+vwTa~xZeq?zhR}zx$7EY;NO>T#lou}09TAvukLg&8%)|NI1!KyPu!%tP za{iH4|A2h_@fwt1sxe+Q^G4p!XVo|s&VLmw_t7W2{> zV*d!ORK@B7P7BfpOt>lm;pEiT72(l0s2O{!8a_m}Ma}r$eg=*3+5=u_>GQ2)7P*o~ z4xts#C8RjF<;+X;{jxTe)iL4g1=dh_L5K#FopcSfs!nJLTL-#woMt?X6_7@{Rg3qD zsEeOI-l_&y*M2RtWz~yq)(BsKJLdEywZXi@4IoH=N7yB>Xc>S`sNl>Ax48SxENcucy_TY@*wR1~qkfcfutX0X9v zk*T3T$DxV%fQbR<;7h`G=_pa&b$DC0x51;{DWo zX$XYqDzbNEh6cS~S%`+Hy5ANNF2FqUc6WW)KUU3lzbe?Nn02G#^>D%F%ZwObhp=W) z03v9C+FBLI62ca8I$a(WnOkvfglk|+F3XqsOSN-KW{b@}L;f3@iqvN+2`Dif z;;A149%pLJN~1##Dlx;p(?{=BIaZS$>T~Lki6o$2vadCuWV1(tOtocFrT~MrNO3H3 zFJ^`^AWZDEYuA6b{o_9mr!S%K=*QSW^}9v*s0zVe%4yl;qcY+{w^IO2TBP_ltUr3( zj~v(_#bH7`0ILqLQ#4EcVlZyghL6;C0{=sycT#L(F7$S<-gJRetj-5yhN@>G)pF%> zQDfKo>o9Y=_Zo()SB8y2$H<|eQkp0r%OQxEtr*PAA|-QqC*Y>>jX&S2O*O(7lPoy* ziMANn3~1q8>AvjQ{JWkttYWSloMfa%Gr5qh6_`Y&E7`>|K z$2&qkxbwie^G-e=Z|InOiqc3VT=@q5hB&rXun%5z-Tpw;z z>f{7mI+3~46BY5+{@h8`lpXzf^?M@jXDmOo?yohUQ%^DRB#mRzBG|mjNcp;Au#NOi zDc(X=vTI-b1ZwNEYT*bHt`NZ^BtACywG~Yo3*bu@L}+m^4QcfDBuL_@&v3DjqH~8- z^pWvGG4sBmm#RmS&=~Y^N0GirjsgbiPKo>5^CB_f7)vM4_IaDW->O*3<(;I3QFBNU zSa+2qnUIsaVecIgls3^ON|$OKJ0<+n&a`wyUa?(F=7khGv=w|5v}cy*0Taf1J5^8P zfkO!w_<$<|A*w!d{kqsyPUpb!m3f$2oG7~ME-9N@QG!hCveZ053fp4QL(;XFASES#2u62EiOJs~7q zhj>_V>o^r5E$SU}FG`LXDtqm8@@$3G{$!>T>oTT>krJf63E3=@z}>{a)Rhi}$-;j$ z_#*Vc%WDUQ#J-H?hSF@!z`*DE$|qkB+fA8e|5**F`(ae*BM@L_8b}5I`@5d}dO~H! zQvHW@X&P6s&hJT$_=!@Jhz3IHV9dT@uZE`+**PY%kk1}AAYzUhV`NYz;3FRZc`IBB zU7N1twVf2$t&J7uePOQX zN~Z^VMjIbM!9Pv_tI04Fw%Yw#m+3en(?Q(}u0nu8Fm#mg%f#Ky+O7F<2iYyf z7Qm2je+1$wP4vClrV$Vufd293c-*Ynyv#bbTd8sqHR8w5$Z9917k6e1_wLu?2{#Qq zK3iy-1}oiKWnJnNEz>$S2GxCy1|Q(~#;UY+6C&!#W;8Vo`70{z!>7~fwRxRGOY^sZ zrsWQfb-KhI^{hS5#}G5?a~C}wgRVz+5^?6JKx=&&U@`PD02G$Z?#v+tXjfDA5pN`C zGcgSBTFftSJ82evUBrAONw+D-Nlr-p4>B0CeeWz%vy-b?1@vy^aS#}v5xQR@&<-;d zm1Vs%_cGfZ)oH%OdYn;N|*ipI%ggXLH5Z-Xi+R%Gw1SlQx{+=wd>j%NiBTEOi_liB>f8>aF%x1B8f)? zepC#V{wvevX&KbfK5PwjaumEUI)CEe{&_Z!4DP0++^1xZANxIHH<{%xMs=&jyCj7F7~cVtE?Az=#g8f0wP+U5O(Ek=Idsb1O7Yr^D(V5*7Uq3q%ebG=2lQq zlLeLPRv|Oti5!7h*Rm0e{_&j1zzpUD6FIhZb<-tAjUIu{V&x_+{6h`{pf-(QOAE96 z7=cnqEcj1j5m_kBh2U>|D33Lnz%VF(32a_wUa4R%zg>8nJ$*n3=e${`tBD9xITH3# z=HMvuJid8oVH9mE_q(T21T2u|WJ>aO@R_YJpl!UEdNJ8%z-n2`^LP048Sz9+E%slq z7Ie4iHuY6SJJzm@S#%Gp&cYmqdE9!BRVglS zc4GlEQPjj?kdW0{fGqvlp*Fa(I5()}B4!PIpg~)O@tVPW7vpaj%bMB!|G{Nsp1E{s zKf>ikzI<__i_fQZSmrARKfEqYn4BPAM?^~rTFXGW?S=A65HHAllGg@j`X&VfYq)is2Y#1i)ifCDpm@$ei6N(I`eBrQzGTx-Nb0dfw@ z^Y6F7dNbDwJd5PTULsP3Upnz~42$>XzMM3IE(UO3X*mbyNKlPy(z86nDJm^F52DIW zd~#3j2j|T!p2=vS6DfMQA7$12@KVA&6+AxbAD?&`0T}SAXp~8uoYiTIkP+^3dBF6nm6g+rNYD(9&K}`D7;n}d?1tX! zL(U)8Ymi+cP1nBY)(5Lxw_1fKe_`Yn-NXB`-KuD1Ti@-9Pe`@xtuN1Q=pc`WnO0w6 zd`T8HX&xB*>^}njgZVMF*G3RE0oU2XbtA$J23 z|Mv9{QF}aY^S-jHn+AG;rp=VHwl7zMG@k>xb-(FsA-h}&@Dku4+VEr08_cetux&z{xC_%`E;M7T01^o379BR6gZ$^htzF|`ni{RmPN7YzPTH@XzJ)4)TX z%$gW94j_F(z~UC>PvYJM!BiOT$n+(gb1F2Cr6Mv-QpqQvPk;vq^HvQ{I%Oil1-K~6 zM?fByOG9%?u=oQk87gtBhi8^dLhet7LTnk#T+R+#+LOM)S-~;EBA z&bJA;$)3a_EG)<3Ye+$gHou_$Ae1|SX{>Fg>2A}rhslgGioo4(VPrBoEX_L#y4w)g zox}ri#H4sjC>q%LL0Q%0t!3yvhd?+mUi#YJn~U*IyGlWCXj1O_Lh9+BN?N5i7OD>> zxszW36r~yKm^GZ9((Bhzju$c+ZN)!QgyxUA3pk}o@W-Ohda;x*u2DEPHAek6LxK`Q`RIkm_ud45N)EDjR5Jhl*+w)I^^T+<{)LT3ALbU}>80vC&7w zWRYaivB;f=$TmwmOe1SMdl%Fo(Ah8-1tn?;9aDhsxVaGqT}iuSJ4=wddK9CR)Y*~| zMO9Xs+@&y|5_0fv%lWa86a0q_Mun9ry19M9|2{I)s6-aaj8quQy#Gm0)CQv%goZ9m z@mSUKQh z8_frgs)oV?!Lo&^jPtlmHvc<}fWFLwb>(AH(hFJu(cGIQ+IJHVo5y4;U80gCEFjEi5^r?Yb#9sp^*~Y z%1_^>7dmOc1M(LEPGH2c(72fjV;Ns0L@Xi3svz91s8SD7R!;4)<9k&2b@fR8m|x_n z%`vYWh&ai*~PlE*r6{J)-T8C#j7QsFrgj%E?(^xwFmW0Jj6Jao}c%6Oy@#z);gFklQh-gpX( z5>q~paNmU<+AGk^f@K?~16;?}(d!QU9Fk%Ozz|T_BM42?AJ0Sp%c?rpis!YXyIDc| zKW~EN_s54K0U8TfLig%Qc{@U2T|t2GM4{fN%_1h@awOJSmPzVK6FDDO?~y6AidwSu z6!H)TkDj+Mg~hE$qGg~5_B{^yG~nVx>s<<6sw6-}G+O&pf1eC%XpCa0RyJ0woWg0G zwnxso>mMUp?4qTfi2}~OK80hHtRLD1s(7AIQY?X%k`@(Laaa4(L>!LU_#r3j;hQ-! zhhR{^xY&8w5mj2+fM@l_UDbYb^ry!S1TYQa0~(a|0dvj*I`}Z{6;kh!U)YjB!GCfn z8ste_#v{^lflX?|)a?tv1_kCid( zy0vKsaU`7iiy~ZR5V0N^8==_pByerhl=PHEp(V@Bi|s8)g-G4n*r`~_N43)Nen$jw zQ1uEb@AgFsQDcoS);Y&dsR(a)C$G(Qe{;e@Cc6NKa3)S1L2+7z?{5bc!H5BYmom+( z$j;7LXNgR%FzwD5=WP_d?YxG`dhpcw2p;-_)sER(`_ZeuKGT4AmJvIUJW(*? z#K?Q3p576Ii!#Bvv5V~%Yvlx>CWq= zi`HfC)l6x*HUN#7GF^x_>Co*{ZM?a@2Qz--XlGoX2f3^14;J!K)y$SdrfoAvjEDdw zL(XrK*`7Z*Fe%yu$I+dDC$db6mi6{9IBTVIe++O9WuRoMGwLN6fZsS1HMhB{fAwRV z4Gr0Gc`+ui+e zjy7O;7(T7}94tNAc}|~b7hh~`w((E0kxf*3jLjDQ>!lJtFNbTT>2x(zqK@|b3{|b6 z_YPJ+(l?%Hi+a?_%DGgGLc@v(N($6Q(8hKZd<;eG>4}yf9OH?#7#DcB0w&MeLTk&& z#y66vf%9&;ll&$VC3x_)ZEV$5E#gUZ>Mpvh05CjbdWhh3anH-wa?xzdzVU3s-hrMl zn>nsvZHl1>e&yVrc_wVLK^*|!^pdzz#`2*SU9N=K3OCH}B$P6n-ytr&^4cIVnF>b& zEsZHvF0);rY_E6=HdY^CF{5@|obsgj|6%B=NsW)zK$6^W95S(ipJWb}&g7DZ8-Of5 zb{JAZa`$=kv3YDkyp!z<$y+`q1-yTzNw6JKFy`n19z*lSIA`*9L3JkM0?P^Je20vI zE&mL$%M)sN&UFqSO;lJBWXk>Y&>pvJiGFuoRY$6+H#Z|ZK&vO^k}*Yl{$KDpi1u0A zPFI3$;7d=B8!ajB3`OJ2hS1Dm5{g8sXGxLwvyslL?WG7AoA5V9=Ry$m9zqhRG&&3H zyw3IdnzN=%hy4$8LeuX8?Q;8Y+m2k<`87xDQL1>tS0Nw4zy3SFHTGG=A7I&QwD2D~ zbITyaBPh|yqZKJU;`5q5Kr|e*axBQ;Uz!8s}Y=KgmAukX;cP_R$eo+W$*qRn;Aynd$ScPD_ao8c(oB!1I zuIuDrK6dg!83>^ZM>6hFzC|v|UwZv3>~hg&EwRvaFOP~++;G0yI39oDJeZT87IR%4 zF+M`yN*J-?X;!ITY1Knt>Y2{JL?)fcW94Gm+kEgvaRQ!XFuYsE2K~ejPW;n41U54XB4@mYn*+<_UsCV6R z_g^4Pap|b?*op|9*h$nzZ*W~0>KSH|Vt?Jo>jHk{F(AB*ry%j?$x4lx0Pl;z+9Ka; zoO<&Z--6tbFGIZVQ8sX0j_)kRrGc2)pnHgd9qb^v+MVotJB>c?r79 zjhm)kFmMP|g^34j{vk-L1go566yn^A&+Y6bVRNsBaxY@F;<-3*swWZ-clsc#bF%Ny zTbJK?i}-(mK2Vt%hVpBLM(j9HA2rpqZm&Z8#Zn4%KN`C%6}vbtDKw}T{+a8;bh~EV z@yk!j{OIM))`SO$zM$u{98AdFFQ*l~4N-uH;V|rhukpM@J_lh6s8Ajhu7|!y7*~}I zazkqO7Zj#w)58bGhkkzbGV@YW`1(2o(xg%qA>kCvv`S68lIGsFq!u`!$aJf=DM~qS zHrB$D|eQq*W{NKz<;5<{w1p1RXuRKRn$n-s-lj{a~Z{*9D_EA2k z_{`)A;X13)yggfr2t{EfCmW{`V)^f3Ir_J2D?xGJ@AKCyxTYJkDGeBD6~wu)<=spH zQbob;yGwf_OJXc=^N8uw!srz%1pW70-sDuMu=xAOTNrp~Y}SRUR&tJ2EX zVY_cFCe>~<39m02l_{39E@35nfTgG}kYx3I+61mJVL9p!2q|WDM+gW##q|j`_S8XA zIUNYgV;Yus5IFm^{ARlU zeT)dl3gZ@e^dz@t8Uy+*ZCqNP2MncE%Nffsi}fGnRi9pr*^PINV&!X&cu?8BOxu2B4u{-$A( zeEJi{YsSopTJbW+6pJQ_1MO$D;`G*h4zyOzX_)u>nBFbGObI^u*DUVssKemzLj7p6 z!2k1*?HVKqR{f`e=&!K=*m|p#QVlUaR&WwPL;TqZvEKjFl!Y46kzDx5xNXldSkiPZ z(BHKJqkNo#hCCE$zR!u{*k~7&1!No0U4p*@l{pYa;up6oa>=dwOYh=a77TXmr*P zwGeWX1OESd?kvJ6OFr*fu2uaB*zBnVH+oW05fjo|FzyYy*N~i$A{*3h)0T#OShx1YfI8?rsOq>4 zZ%a$EH~yE>4IeF1=&xA*+1r?mHitErC#6)B$|k~V(85#BPB<%}+6G2meTkiSuoCQZ zutz?nt?^b@y1Ok#wm1ID@(KQF7cS21zaBj&{Rj3uIMu<5B@E#b|MxY3AXRLB$23ia zSn9dl@A-YgZDxknX(L}ig{l_>zy8rF{t8Evo`FV~o`0g^X_jg}1Z5uMq6p9=3TU^S z&(5dYLvD>TLG`cf%+*0fbKUn=%80y{-X_$w!=lrkYfsrooG17$yQ5TN@@E(eTSj%& zQBfk5|FD_w*Z@WOh@Ii{Al5D8XfmjhqDgpSpUFOvf`~UP`u*7L{)}(#KJ%8ZrKmsL z{y@n2 zwt>nR=A-zqn$T~AyghU0-6|HbwmNPjAgyq4CS#?t_1cX1dc1s@8HfA@a#ChXQq(L& z^_Uj7Wb+4jUSNBl(io&`yDU4P53nHpZ#Y!iH_ASUB!5HmKjaJlJhO|WGPDrsW%r#j zD4}CX_vSCYR@EJ>{G*^G`4Dzh`NM(e^n2krnXC=%uTQ9J7`g6Q!y=;8wnFt2z8##$ zSJWls4PM3{dAI8wPj&n6V6OCGl;``qF#hOu+&}vitwSr z;Xa+y4QprT)BRy(7hrJv|1}O`sQF~_PeRT%_kkwbpFzXK=(fITFa2u!0}XI(lethj zPoaYht+GJK?^_5|z6UZ_TYmlt0 z9ELC)i-K-Qy@sso{4;4|ajB8#N9pc*zQX5FXV;MWm7vtad#iBfd+T7XZ3TNdWIAIP zsuEBTGasUpLx#Ak3pYGwnHAz9*EZjgaTa!qHK;on@jH)l9qJx9Y;Kl0y798Pl2j?@ zC`v|re`~S{3is6y-wELR`Jt<+t%sX7A|HH(R;Bzh+2sH{W@NCCt4!A#@~RJ2h9eQD z_0^kgnBg^aKSsk@IDX76vebLZNcVl*F)!?$2u#fr5O*Wv_+2{R8-K*&#D;8M6dY%Hgf%9r9}XRWJAE(*|0tB`~}2r zKppRYFr^gS{FVqPMwrpeNEW!8b}{$>&>%5og|wd5V!X;s^mTpFvHVH5f`6biR8{-C zhxa-x_=DnN(9~|Qpc9gzpNJw?w8!(@UI;4|%0AuTG0U#Jr4ujZyniFcm%_Ry18XbH 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

ZBB$?zB?$Ic)anE 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

)kPu+?qJvRt$Gu+FHaMNGGiuhKWkN-ibT1Xy)B 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 }E<)qwqb-ydnQ|145}IH5j&hpa6uHDi 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

>C#2BU)rXLrK+ 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

  • 54TimH^M9GW)~ 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

    C~YVip=%=XuPJB>~8tOytfgK(5Xl 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
    5$n7`Vso}g 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 z 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

    vkN-@~?GT(lwFDG&nfbo+wjtgw>w{Mz{fm-6 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

    q6Cl+2(61qFL37)1dp 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ⅈ@;iKcty2ty3uoh1? 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

    pOd)wz7 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%0DgEt&=i>WTz%L)h;MdpSj~UWG-SR}xee#9=~> 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 z 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%0D>Ako5?g6WD1)C-2&%L^JeuHl*> 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

    *JCU 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

    2S{1n=Lm7flZua@8-ABl3-TM-Y=`u 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

  • J6;6Ayx@?vq17TAaD2fByYIC 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 >Ev@HB8&w1nDI354yL-;=;Gn09n5H=ex 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