From a683fcffeade4866a2cb6050748bf6f4c3bc7916 Mon Sep 17 00:00:00 2001 From: ComputerTech312 Date: Mon, 19 Feb 2024 15:34:25 +0100 Subject: [PATCH] Cleaned up the directories --- config.yaml | 6 +- data/channels.json | 1 - elitebot/bin/Activate.ps1 | 247 + elitebot/bin/activate | 69 + elitebot/bin/activate.csh | 26 + elitebot/bin/activate.fish | 69 + elitebot/bin/pip | 8 + elitebot/bin/pip3 | 8 + elitebot/bin/pip3.11 | 8 + elitebot/bin/python | 1 + elitebot/bin/python3 | 1 + elitebot/bin/python3.11 | 1 + .../site/python3.11/greenlet/greenlet.h | 164 + .../PyYAML-6.0.1.dist-info/INSTALLER | 1 + .../PyYAML-6.0.1.dist-info/LICENSE | 20 + .../PyYAML-6.0.1.dist-info/METADATA | 46 + .../PyYAML-6.0.1.dist-info/RECORD | 44 + .../PyYAML-6.0.1.dist-info/REQUESTED | 0 .../PyYAML-6.0.1.dist-info/WHEEL | 6 + .../PyYAML-6.0.1.dist-info/top_level.txt | 2 + .../SQLAlchemy-2.0.27.dist-info/INSTALLER | 1 + .../SQLAlchemy-2.0.27.dist-info/LICENSE | 19 + .../SQLAlchemy-2.0.27.dist-info/METADATA | 242 + .../SQLAlchemy-2.0.27.dist-info/RECORD | 530 + .../SQLAlchemy-2.0.27.dist-info/REQUESTED | 0 .../SQLAlchemy-2.0.27.dist-info/WHEEL | 6 + .../SQLAlchemy-2.0.27.dist-info/top_level.txt | 1 + .../INSTALLER | 1 + .../SQLAlchemy_Utils-0.41.1.dist-info/LICENSE | 27 + .../METADATA | 97 + .../SQLAlchemy_Utils-0.41.1.dist-info/RECORD | 135 + .../REQUESTED | 0 .../SQLAlchemy_Utils-0.41.1.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../site-packages/_distutils_hack/__init__.py | 227 + .../site-packages/_distutils_hack/override.py | 1 + .../site-packages/_yaml/__init__.py | 33 + .../colorama-0.4.6.dist-info/INSTALLER | 1 + .../colorama-0.4.6.dist-info/METADATA | 441 + .../colorama-0.4.6.dist-info/RECORD | 32 + .../colorama-0.4.6.dist-info/REQUESTED | 0 .../colorama-0.4.6.dist-info/WHEEL | 5 + .../licenses/LICENSE.txt | 27 + .../site-packages/colorama/__init__.py | 7 + .../python3.11/site-packages/colorama/ansi.py | 102 + .../site-packages/colorama/ansitowin32.py | 277 + .../site-packages/colorama/initialise.py | 121 + .../site-packages/colorama/tests/__init__.py | 1 + .../site-packages/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../colorama/tests/initialise_test.py | 189 + .../colorama/tests/isatty_test.py | 57 + .../site-packages/colorama/tests/utils.py | 49 + .../colorama/tests/winterm_test.py | 131 + .../site-packages/colorama/win32.py | 180 + .../site-packages/colorama/winterm.py | 195 + .../site-packages/distutils-precedence.pth | 1 + .../greenlet-3.0.3.dist-info/AUTHORS | 51 + .../greenlet-3.0.3.dist-info/INSTALLER | 1 + .../greenlet-3.0.3.dist-info/LICENSE | 30 + .../greenlet-3.0.3.dist-info/LICENSE.PSF | 47 + .../greenlet-3.0.3.dist-info/METADATA | 102 + .../greenlet-3.0.3.dist-info/RECORD | 117 + .../greenlet-3.0.3.dist-info/REQUESTED | 0 .../greenlet-3.0.3.dist-info/WHEEL | 6 + .../greenlet-3.0.3.dist-info/top_level.txt | 1 + .../greenlet/TBrokenGreenlet.cpp | 45 + .../greenlet/TExceptionState.cpp | 62 + .../site-packages/greenlet/TGreenlet.cpp | 714 ++ .../greenlet/TGreenletGlobals.cpp | 94 + .../site-packages/greenlet/TMainGreenlet.cpp | 155 + .../site-packages/greenlet/TPythonState.cpp | 375 + .../site-packages/greenlet/TStackState.cpp | 265 + .../greenlet/TThreadStateDestroy.cpp | 195 + .../site-packages/greenlet/TUserGreenlet.cpp | 667 ++ .../site-packages/greenlet/__init__.py | 71 + .../_greenlet.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 1506232 bytes .../site-packages/greenlet/greenlet.cpp | 1494 +++ .../site-packages/greenlet/greenlet.h | 164 + .../greenlet/greenlet_allocator.hpp | 63 + .../greenlet/greenlet_compiler_compat.hpp | 95 + .../greenlet/greenlet_cpython_add_pending.hpp | 172 + .../greenlet/greenlet_cpython_compat.hpp | 127 + .../greenlet/greenlet_exceptions.hpp | 150 + .../greenlet/greenlet_greenlet.hpp | 805 ++ .../greenlet/greenlet_internal.hpp | 106 + .../site-packages/greenlet/greenlet_refs.hpp | 1100 +++ .../greenlet/greenlet_slp_switch.hpp | 99 + .../greenlet/greenlet_thread_state.hpp | 543 ++ .../greenlet_thread_state_dict_cleanup.hpp | 118 + .../greenlet/greenlet_thread_support.hpp | 31 + .../greenlet/platform/__init__.py | 0 .../platform/setup_switch_x64_masm.cmd | 2 + .../greenlet/platform/switch_aarch64_gcc.h | 124 + .../greenlet/platform/switch_alpha_unix.h | 30 + .../greenlet/platform/switch_amd64_unix.h | 87 + .../greenlet/platform/switch_arm32_gcc.h | 79 + .../greenlet/platform/switch_arm32_ios.h | 67 + .../greenlet/platform/switch_arm64_masm.asm | 53 + .../greenlet/platform/switch_arm64_masm.obj | Bin 0 -> 746 bytes .../greenlet/platform/switch_arm64_msvc.h | 17 + .../greenlet/platform/switch_csky_gcc.h | 48 + .../platform/switch_loongarch64_linux.h | 31 + .../greenlet/platform/switch_m68k_gcc.h | 38 + .../greenlet/platform/switch_mips_unix.h | 64 + .../greenlet/platform/switch_ppc64_aix.h | 103 + .../greenlet/platform/switch_ppc64_linux.h | 105 + .../greenlet/platform/switch_ppc_aix.h | 87 + .../greenlet/platform/switch_ppc_linux.h | 84 + .../greenlet/platform/switch_ppc_macosx.h | 82 + .../greenlet/platform/switch_ppc_unix.h | 82 + .../greenlet/platform/switch_riscv_unix.h | 32 + .../greenlet/platform/switch_s390_unix.h | 87 + .../greenlet/platform/switch_sparc_sun_gcc.h | 92 + .../greenlet/platform/switch_x32_unix.h | 63 + .../greenlet/platform/switch_x64_masm.asm | 111 + .../greenlet/platform/switch_x64_masm.obj | Bin 0 -> 1078 bytes .../greenlet/platform/switch_x64_msvc.h | 60 + .../greenlet/platform/switch_x86_msvc.h | 326 + .../greenlet/platform/switch_x86_unix.h | 105 + .../greenlet/slp_platformselect.h | 71 + .../site-packages/greenlet/tests/__init__.py | 237 + .../greenlet/tests/_test_extension.c | 231 + ..._extension.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 36624 bytes .../greenlet/tests/_test_extension_cpp.cpp | 226 + ...ension_cpp.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 57288 bytes .../tests/fail_clearing_run_switches.py | 47 + .../greenlet/tests/fail_cpp_exception.py | 33 + .../tests/fail_initialstub_already_started.py | 78 + .../greenlet/tests/fail_slp_switch.py | 29 + .../tests/fail_switch_three_greenlets.py | 44 + .../tests/fail_switch_three_greenlets2.py | 55 + .../tests/fail_switch_two_greenlets.py | 41 + .../site-packages/greenlet/tests/leakcheck.py | 319 + .../greenlet/tests/test_contextvars.py | 310 + .../site-packages/greenlet/tests/test_cpp.py | 73 + .../tests/test_extension_interface.py | 115 + .../site-packages/greenlet/tests/test_gc.py | 86 + .../greenlet/tests/test_generator.py | 59 + .../greenlet/tests/test_generator_nested.py | 168 + .../greenlet/tests/test_greenlet.py | 1311 +++ .../greenlet/tests/test_greenlet_trash.py | 178 + .../greenlet/tests/test_leaks.py | 443 + .../greenlet/tests/test_stack_saved.py | 19 + .../greenlet/tests/test_throw.py | 128 + .../greenlet/tests/test_tracing.py | 291 + .../greenlet/tests/test_version.py | 41 + .../greenlet/tests/test_weakref.py | 35 + .../site-packages/mysql/__init__.py | 0 .../site-packages/mysql/connector/__init__.py | 207 + .../mysql/connector/abstracts.py | 1158 +++ .../mysql/connector/authentication.py | 191 + .../site-packages/mysql/connector/catch23.py | 114 + .../site-packages/mysql/connector/charsets.py | 286 + .../mysql/connector/connection.py | 1059 ++ .../mysql/connector/connection_cext.py | 594 ++ .../mysql/connector/constants.py | 754 ++ .../mysql/connector/conversion.py | 586 ++ .../site-packages/mysql/connector/cursor.py | 1368 +++ .../mysql/connector/cursor_cext.py | 810 ++ .../mysql/connector/custom_types.py | 45 + .../site-packages/mysql/connector/dbapi.py | 75 + .../mysql/connector/django/__init__.py | 0 .../mysql/connector/django/base.py | 567 ++ .../mysql/connector/django/client.py | 57 + .../mysql/connector/django/compiler.py | 59 + .../mysql/connector/django/creation.py | 141 + .../mysql/connector/django/features.py | 127 + .../mysql/connector/django/introspection.py | 322 + .../mysql/connector/django/operations.py | 308 + .../mysql/connector/django/schema.py | 86 + .../mysql/connector/django/validation.py | 65 + .../mysql/connector/errorcode.py | 1159 +++ .../site-packages/mysql/connector/errors.py | 304 + .../mysql/connector/fabric/__init__.py | 70 + .../mysql/connector/fabric/balancing.py | 159 + .../mysql/connector/fabric/caching.py | 281 + .../mysql/connector/fabric/connection.py | 1623 ++++ .../mysql/connector/locales/__init__.py | 71 + .../mysql/connector/locales/eng/__init__.py | 25 + .../connector/locales/eng/client_error.py | 95 + .../site-packages/mysql/connector/network.py | 514 + .../mysql/connector/optionfiles.py | 360 + .../site-packages/mysql/connector/pooling.py | 353 + .../site-packages/mysql/connector/protocol.py | 732 ++ .../site-packages/mysql/connector/utils.py | 338 + .../site-packages/mysql/connector/version.py | 37 + .../mysql_connector-2.2.9.dist-info/INSTALLER | 1 + .../LICENSE.txt | 347 + .../mysql_connector-2.2.9.dist-info/METADATA | 32 + .../mysql_connector-2.2.9.dist-info/RECORD | 145 + .../mysql_connector-2.2.9.dist-info/REQUESTED | 0 .../mysql_connector-2.2.9.dist-info/WHEEL | 5 + .../top_level.txt | 2 + .../site-packages/mysqlx/__init__.py | 250 + .../site-packages/mysqlx/authentication.py | 65 + .../site-packages/mysqlx/charsets.py | 286 + .../python3.11/site-packages/mysqlx/compat.py | 57 + .../site-packages/mysqlx/connection.py | 495 + .../site-packages/mysqlx/constants.py | 51 + .../python3.11/site-packages/mysqlx/crud.py | 538 ++ .../python3.11/site-packages/mysqlx/dbdoc.py | 62 + .../site-packages/mysqlx/errorcode.py | 1170 +++ .../python3.11/site-packages/mysqlx/errors.py | 278 + .../python3.11/site-packages/mysqlx/expr.py | 848 ++ .../site-packages/mysqlx/expr_unparser.py | 125 + .../site-packages/mysqlx/locales/__init__.py | 68 + .../mysqlx/locales/eng/__init__.py | 0 .../mysqlx/locales/eng/client_error.py | 95 + .../site-packages/mysqlx/protobuf/__init__.py | 0 .../mysqlx/protobuf/mysqlx_connection_pb2.py | 225 + .../mysqlx/protobuf/mysqlx_crud_pb2.py | 824 ++ .../mysqlx/protobuf/mysqlx_datatypes_pb2.py | 490 + .../mysqlx/protobuf/mysqlx_expect_pb2.py | 214 + .../mysqlx/protobuf/mysqlx_expr_pb2.py | 612 ++ .../mysqlx/protobuf/mysqlx_notice_pb2.py | 357 + .../mysqlx/protobuf/mysqlx_pb2.py | 372 + .../mysqlx/protobuf/mysqlx_resultset_pb2.py | 348 + .../mysqlx/protobuf/mysqlx_session_pb2.py | 227 + .../mysqlx/protobuf/mysqlx_sql_pb2.py | 127 + .../site-packages/mysqlx/protobuf/t.py | 30 + .../site-packages/mysqlx/protocol.py | 375 + .../python3.11/site-packages/mysqlx/result.py | 840 ++ .../site-packages/mysqlx/statement.py | 1528 +++ .../pip-23.2.dist-info/AUTHORS.txt | 737 ++ .../pip-23.2.dist-info/INSTALLER | 1 + .../pip-23.2.dist-info/LICENSE.txt | 20 + .../site-packages/pip-23.2.dist-info/METADATA | 90 + .../site-packages/pip-23.2.dist-info/RECORD | 997 ++ .../pip-23.2.dist-info/REQUESTED | 0 .../site-packages/pip-23.2.dist-info/WHEEL | 5 + .../pip-23.2.dist-info/entry_points.txt | 4 + .../pip-23.2.dist-info/top_level.txt | 1 + .../python3.11/site-packages/pip/__init__.py | 13 + .../python3.11/site-packages/pip/__main__.py | 24 + .../site-packages/pip/__pip-runner__.py | 50 + .../site-packages/pip/_internal/__init__.py | 19 + .../site-packages/pip/_internal/build_env.py | 311 + .../site-packages/pip/_internal/cache.py | 292 + .../pip/_internal/cli/__init__.py | 4 + .../pip/_internal/cli/autocompletion.py | 171 + .../pip/_internal/cli/base_command.py | 236 + .../pip/_internal/cli/cmdoptions.py | 1074 ++ .../pip/_internal/cli/command_context.py | 27 + .../site-packages/pip/_internal/cli/main.py | 79 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 68 + .../pip/_internal/cli/req_command.py | 505 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../pip/_internal/commands/cache.py | 222 + .../pip/_internal/commands/check.py | 54 + .../pip/_internal/commands/completion.py | 121 + .../pip/_internal/commands/configuration.py | 282 + .../pip/_internal/commands/debug.py | 199 + .../pip/_internal/commands/download.py | 147 + .../pip/_internal/commands/freeze.py | 109 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 139 + .../pip/_internal/commands/inspect.py | 92 + .../pip/_internal/commands/install.py | 778 ++ .../pip/_internal/commands/list.py | 370 + .../pip/_internal/commands/search.py | 174 + .../pip/_internal/commands/show.py | 189 + .../pip/_internal/commands/uninstall.py | 113 + .../pip/_internal/commands/wheel.py | 183 + .../pip/_internal/configuration.py | 381 + .../pip/_internal/distributions/__init__.py | 21 + .../pip/_internal/distributions/base.py | 39 + .../pip/_internal/distributions/installed.py | 23 + .../pip/_internal/distributions/sdist.py | 150 + .../pip/_internal/distributions/wheel.py | 34 + .../site-packages/pip/_internal/exceptions.py | 733 ++ .../pip/_internal/index/__init__.py | 2 + .../pip/_internal/index/collector.py | 505 + .../pip/_internal/index/package_finder.py | 1029 ++ .../pip/_internal/index/sources.py | 223 + .../pip/_internal/locations/__init__.py | 467 + .../pip/_internal/locations/_distutils.py | 173 + .../pip/_internal/locations/_sysconfig.py | 213 + .../pip/_internal/locations/base.py | 81 + .../site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 127 + .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 688 ++ .../_internal/metadata/importlib/__init__.py | 4 + .../_internal/metadata/importlib/_compat.py | 55 + .../_internal/metadata/importlib/_dists.py | 224 + .../pip/_internal/metadata/importlib/_envs.py | 188 + .../pip/_internal/metadata/pkg_resources.py | 270 + .../pip/_internal/models/__init__.py | 2 + .../pip/_internal/models/candidate.py | 34 + .../pip/_internal/models/direct_url.py | 237 + .../pip/_internal/models/format_control.py | 80 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 53 + .../pip/_internal/models/link.py | 581 ++ .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 132 + .../pip/_internal/models/selection_prefs.py | 51 + .../pip/_internal/models/target_python.py | 110 + .../pip/_internal/models/wheel.py | 92 + .../pip/_internal/network/__init__.py | 2 + .../pip/_internal/network/auth.py | 561 ++ .../pip/_internal/network/cache.py | 69 + .../pip/_internal/network/download.py | 186 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 517 + .../pip/_internal/network/utils.py | 96 + .../pip/_internal/network/xmlrpc.py | 60 + .../pip/_internal/operations/__init__.py | 0 .../_internal/operations/build/__init__.py | 0 .../operations/build/build_tracker.py | 124 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 187 + .../pip/_internal/operations/freeze.py | 255 + .../_internal/operations/install/__init__.py | 2 + .../operations/install/editable_legacy.py | 46 + .../pip/_internal/operations/install/wheel.py | 740 ++ .../pip/_internal/operations/prepare.py | 734 ++ .../site-packages/pip/_internal/pyproject.py | 179 + .../pip/_internal/req/__init__.py | 92 + .../pip/_internal/req/constructors.py | 506 + .../pip/_internal/req/req_file.py | 552 ++ .../pip/_internal/req/req_install.py | 874 ++ .../pip/_internal/req/req_set.py | 119 + .../pip/_internal/req/req_uninstall.py | 650 ++ .../pip/_internal/resolution/__init__.py | 0 .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../_internal/resolution/legacy/resolver.py | 600 ++ .../resolution/resolvelib/__init__.py | 0 .../_internal/resolution/resolvelib/base.py | 141 + .../resolution/resolvelib/candidates.py | 555 ++ .../resolution/resolvelib/factory.py | 730 ++ .../resolution/resolvelib/found_candidates.py | 155 + .../resolution/resolvelib/provider.py | 255 + .../resolution/resolvelib/reporter.py | 80 + .../resolution/resolvelib/requirements.py | 165 + .../resolution/resolvelib/resolver.py | 299 + .../pip/_internal/self_outdated_check.py | 242 + .../pip/_internal/utils/__init__.py | 0 .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 63 + .../pip/_internal/utils/compatibility_tags.py | 165 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 120 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 72 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 153 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 88 + .../pip/_internal/utils/hashes.py | 151 + .../_internal/utils/inject_securetransport.py | 35 + .../pip/_internal/utils/logging.py | 348 + .../site-packages/pip/_internal/utils/misc.py | 759 ++ .../pip/_internal/utils/models.py | 39 + .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 260 + .../pip/_internal/utils/temp_dir.py | 246 + .../pip/_internal/utils/unpacking.py | 257 + .../site-packages/pip/_internal/utils/urls.py | 62 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 136 + .../pip/_internal/vcs/__init__.py | 15 + .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 526 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 705 ++ .../pip/_internal/wheel_builder.py | 355 + .../site-packages/pip/_vendor/__init__.py | 120 + .../pip/_vendor/cachecontrol/__init__.py | 18 + .../pip/_vendor/cachecontrol/_cmd.py | 61 + .../pip/_vendor/cachecontrol/adapter.py | 137 + .../pip/_vendor/cachecontrol/cache.py | 65 + .../_vendor/cachecontrol/caches/__init__.py | 9 + .../_vendor/cachecontrol/caches/file_cache.py | 188 + .../cachecontrol/caches/redis_cache.py | 39 + .../pip/_vendor/cachecontrol/compat.py | 32 + .../pip/_vendor/cachecontrol/controller.py | 439 + .../pip/_vendor/cachecontrol/filewrapper.py | 111 + .../pip/_vendor/cachecontrol/heuristics.py | 139 + .../pip/_vendor/cachecontrol/serialize.py | 190 + .../pip/_vendor/cachecontrol/wrapper.py | 33 + .../pip/_vendor/certifi/__init__.py | 4 + .../pip/_vendor/certifi/__main__.py | 12 + .../pip/_vendor/certifi/cacert.pem | 4589 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 119 + .../pip/_vendor/chardet/__init__.py | 115 + .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 261 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 147 + .../pip/_vendor/chardet/cli/__init__.py | 0 .../pip/_vendor/chardet/cli/chardetect.py | 112 + .../pip/_vendor/chardet/codingstatemachine.py | 90 + .../_vendor/chardet/codingstatemachinedict.py | 19 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 85 + .../pip/_vendor/chardet/escprober.py | 102 + .../pip/_vendor/chardet/escsm.py | 261 + .../pip/_vendor/chardet/eucjpprober.py | 102 + .../pip/_vendor/chardet/euckrfreq.py | 196 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 388 + .../pip/_vendor/chardet/euctwprober.py | 47 + .../pip/_vendor/chardet/gb2312freq.py | 284 + .../pip/_vendor/chardet/gb2312prober.py | 47 + .../pip/_vendor/chardet/hebrewprober.py | 316 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/johabfreq.py | 2382 +++++ .../pip/_vendor/chardet/johabprober.py | 47 + .../pip/_vendor/chardet/jpcntx.py | 238 + .../pip/_vendor/chardet/langbulgarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langgreekmodel.py | 4397 +++++++++ .../pip/_vendor/chardet/langhebrewmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langhungarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langrussianmodel.py | 5725 +++++++++++ .../pip/_vendor/chardet/langthaimodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langturkishmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/latin1prober.py | 147 + .../pip/_vendor/chardet/macromanprober.py | 162 + .../pip/_vendor/chardet/mbcharsetprober.py | 95 + .../pip/_vendor/chardet/mbcsgroupprober.py | 57 + .../pip/_vendor/chardet/mbcssm.py | 661 ++ .../pip/_vendor/chardet/metadata/__init__.py | 0 .../pip/_vendor/chardet/metadata/languages.py | 352 + .../pip/_vendor/chardet/resultdict.py | 16 + .../pip/_vendor/chardet/sbcharsetprober.py | 162 + .../pip/_vendor/chardet/sbcsgroupprober.py | 88 + .../pip/_vendor/chardet/sjisprober.py | 105 + .../pip/_vendor/chardet/universaldetector.py | 362 + .../pip/_vendor/chardet/utf1632prober.py | 225 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 7 + .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 277 + .../pip/_vendor/colorama/initialise.py | 121 + .../pip/_vendor/colorama/tests/__init__.py | 1 + .../pip/_vendor/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../_vendor/colorama/tests/initialise_test.py | 189 + .../pip/_vendor/colorama/tests/isatty_test.py | 57 + .../pip/_vendor/colorama/tests/utils.py | 49 + .../_vendor/colorama/tests/winterm_test.py | 131 + .../pip/_vendor/colorama/win32.py | 180 + .../pip/_vendor/colorama/winterm.py | 195 + .../pip/_vendor/distlib/__init__.py | 23 + .../pip/_vendor/distlib/compat.py | 1116 +++ .../pip/_vendor/distlib/database.py | 1350 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1300 +++ .../pip/_vendor/distlib/manifest.py | 393 + .../pip/_vendor/distlib/markers.py | 152 + .../pip/_vendor/distlib/metadata.py | 1076 +++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 437 + .../site-packages/pip/_vendor/distlib/util.py | 1932 ++++ .../pip/_vendor/distlib/version.py | 739 ++ .../pip/_vendor/distlib/wheel.py | 1082 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../pip/_vendor/distro/distro.py | 1399 +++ .../pip/_vendor/idna/__init__.py | 44 + .../site-packages/pip/_vendor/idna/codec.py | 112 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 2151 +++++ .../pip/_vendor/idna/intranges.py | 54 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8600 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 57 + .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 193 + .../pip/_vendor/msgpack/fallback.py | 1010 ++ .../pip/_vendor/packaging/__about__.py | 26 + .../pip/_vendor/packaging/__init__.py | 25 + .../pip/_vendor/packaging/_manylinux.py | 301 + .../pip/_vendor/packaging/_musllinux.py | 136 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/markers.py | 304 + .../pip/_vendor/packaging/requirements.py | 146 + .../pip/_vendor/packaging/specifiers.py | 802 ++ .../pip/_vendor/packaging/tags.py | 487 + .../pip/_vendor/packaging/utils.py | 136 + .../pip/_vendor/packaging/version.py | 504 + .../pip/_vendor/pkg_resources/__init__.py | 3361 +++++++ .../pip/_vendor/platformdirs/__init__.py | 566 ++ .../pip/_vendor/platformdirs/__main__.py | 53 + .../pip/_vendor/platformdirs/android.py | 210 + .../pip/_vendor/platformdirs/api.py | 223 + .../pip/_vendor/platformdirs/macos.py | 91 + .../pip/_vendor/platformdirs/unix.py | 223 + .../pip/_vendor/platformdirs/version.py | 4 + .../pip/_vendor/platformdirs/windows.py | 255 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../pip/_vendor/pygments/cmdline.py | 668 ++ .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 71 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../pip/_vendor/pygments/formatter.py | 124 + .../_vendor/pygments/formatters/__init__.py | 158 + .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 989 ++ .../pip/_vendor/pygments/formatters/img.py | 645 ++ .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 521 + .../pip/_vendor/pygments/formatters/other.py | 161 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 146 + .../pip/_vendor/pygments/formatters/svg.py | 188 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 943 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../pip/_vendor/pygments/lexers/_mapping.py | 559 ++ .../pip/_vendor/pygments/lexers/python.py | 1198 +++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 88 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 217 + .../pip/_vendor/pygments/style.py | 197 + .../pip/_vendor/pygments/styles/__init__.py | 103 + .../pip/_vendor/pygments/token.py | 213 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 330 + .../pip/_vendor/pyparsing/__init__.py | 322 + .../pip/_vendor/pyparsing/actions.py | 217 + .../pip/_vendor/pyparsing/common.py | 432 + .../pip/_vendor/pyparsing/core.py | 6115 ++++++++++++ .../pip/_vendor/pyparsing/diagram/__init__.py | 656 ++ .../pip/_vendor/pyparsing/exceptions.py | 299 + .../pip/_vendor/pyparsing/helpers.py | 1100 +++ .../pip/_vendor/pyparsing/results.py | 796 ++ .../pip/_vendor/pyparsing/testing.py | 331 + .../pip/_vendor/pyparsing/unicode.py | 361 + .../pip/_vendor/pyparsing/util.py | 284 + .../pip/_vendor/pyproject_hooks/__init__.py | 23 + .../pip/_vendor/pyproject_hooks/_compat.py | 8 + .../pip/_vendor/pyproject_hooks/_impl.py | 330 + .../pyproject_hooks/_in_process/__init__.py | 18 + .../_in_process/_in_process.py | 353 + .../pip/_vendor/requests/__init__.py | 182 + .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 50 + .../pip/_vendor/requests/adapters.py | 538 ++ .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 315 + .../pip/_vendor/requests/certs.py | 24 + .../pip/_vendor/requests/compat.py | 67 + .../pip/_vendor/requests/cookies.py | 561 ++ .../pip/_vendor/requests/exceptions.py | 141 + .../pip/_vendor/requests/help.py | 131 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1034 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 833 ++ .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1094 +++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 547 ++ .../pip/_vendor/resolvelib/structs.py | 170 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 274 + .../pip/_vendor/rich/_cell_widths.py | 451 + .../pip/_vendor/rich/_emoji_codes.py | 3610 +++++++ .../pip/_vendor/rich/_emoji_replace.py | 32 + .../pip/_vendor/rich/_export_format.py | 76 + .../pip/_vendor/rich/_extension.py | 10 + .../site-packages/pip/_vendor/rich/_fileno.py | 24 + .../pip/_vendor/rich/_inspect.py | 270 + .../pip/_vendor/rich/_log_render.py | 94 + .../site-packages/pip/_vendor/rich/_loop.py | 43 + .../pip/_vendor/rich/_null_file.py | 69 + .../pip/_vendor/rich/_palettes.py | 309 + .../site-packages/pip/_vendor/rich/_pick.py | 17 + .../site-packages/pip/_vendor/rich/_ratio.py | 160 + .../pip/_vendor/rich/_spinners.py | 482 + .../site-packages/pip/_vendor/rich/_stack.py | 16 + .../site-packages/pip/_vendor/rich/_timer.py | 19 + .../pip/_vendor/rich/_win32_console.py | 662 ++ .../pip/_vendor/rich/_windows.py | 72 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 56 + .../site-packages/pip/_vendor/rich/abc.py | 33 + .../site-packages/pip/_vendor/rich/align.py | 311 + .../site-packages/pip/_vendor/rich/ansi.py | 240 + .../site-packages/pip/_vendor/rich/bar.py | 94 + .../site-packages/pip/_vendor/rich/box.py | 517 + .../site-packages/pip/_vendor/rich/cells.py | 154 + .../site-packages/pip/_vendor/rich/color.py | 622 ++ .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 2633 +++++ .../pip/_vendor/rich/constrain.py | 37 + .../pip/_vendor/rich/containers.py | 167 + .../site-packages/pip/_vendor/rich/control.py | 225 + .../pip/_vendor/rich/default_styles.py | 190 + .../pip/_vendor/rich/diagnose.py | 37 + .../site-packages/pip/_vendor/rich/emoji.py | 96 + .../site-packages/pip/_vendor/rich/errors.py | 34 + .../pip/_vendor/rich/file_proxy.py | 57 + .../pip/_vendor/rich/filesize.py | 89 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 140 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 443 + .../site-packages/pip/_vendor/rich/live.py | 375 + .../pip/_vendor/rich/live_render.py | 113 + .../site-packages/pip/_vendor/rich/logging.py | 289 + .../site-packages/pip/_vendor/rich/markup.py | 246 + .../site-packages/pip/_vendor/rich/measure.py | 151 + .../site-packages/pip/_vendor/rich/padding.py | 141 + .../site-packages/pip/_vendor/rich/pager.py | 34 + .../site-packages/pip/_vendor/rich/palette.py | 100 + .../site-packages/pip/_vendor/rich/panel.py | 308 + .../site-packages/pip/_vendor/rich/pretty.py | 994 ++ .../pip/_vendor/rich/progress.py | 1702 ++++ .../pip/_vendor/rich/progress_bar.py | 224 + .../site-packages/pip/_vendor/rich/prompt.py | 376 + .../pip/_vendor/rich/protocol.py | 42 + .../site-packages/pip/_vendor/rich/region.py | 10 + .../site-packages/pip/_vendor/rich/repr.py | 149 + .../site-packages/pip/_vendor/rich/rule.py | 130 + .../site-packages/pip/_vendor/rich/scope.py | 86 + .../site-packages/pip/_vendor/rich/screen.py | 54 + .../site-packages/pip/_vendor/rich/segment.py | 739 ++ .../site-packages/pip/_vendor/rich/spinner.py | 137 + .../site-packages/pip/_vendor/rich/status.py | 132 + .../site-packages/pip/_vendor/rich/style.py | 796 ++ .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 948 ++ .../site-packages/pip/_vendor/rich/table.py | 1002 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1307 +++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 756 ++ .../site-packages/pip/_vendor/rich/tree.py | 251 + .../site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 608 ++ .../pip/_vendor/tenacity/_asyncio.py | 94 + .../pip/_vendor/tenacity/_utils.py | 76 + .../pip/_vendor/tenacity/after.py | 51 + .../pip/_vendor/tenacity/before.py | 46 + .../pip/_vendor/tenacity/before_sleep.py | 71 + .../site-packages/pip/_vendor/tenacity/nap.py | 43 + .../pip/_vendor/tenacity/retry.py | 272 + .../pip/_vendor/tenacity/stop.py | 103 + .../pip/_vendor/tenacity/tornadoweb.py | 59 + .../pip/_vendor/tenacity/wait.py | 228 + .../pip/_vendor/tomli/__init__.py | 11 + .../pip/_vendor/tomli/_parser.py | 691 ++ .../site-packages/pip/_vendor/tomli/_re.py | 107 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../pip/_vendor/typing_extensions.py | 3072 ++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../pip/_vendor/urllib3/_collections.py | 355 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 ++ .../pip/_vendor/urllib3/connectionpool.py | 1137 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 518 + .../urllib3/contrib/securetransport.py | 921 ++ .../pip/_vendor/urllib3/contrib/socks.py | 216 + .../pip/_vendor/urllib3/exceptions.py | 323 + .../pip/_vendor/urllib3/fields.py | 274 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 0 .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 51 + .../packages/backports/weakref_finalize.py | 155 + .../pip/_vendor/urllib3/packages/six.py | 1076 +++ .../pip/_vendor/urllib3/poolmanager.py | 540 ++ .../pip/_vendor/urllib3/request.py | 170 + .../pip/_vendor/urllib3/response.py | 879 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../pip/_vendor/urllib3/util/connection.py | 149 + .../pip/_vendor/urllib3/util/proxy.py | 57 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 137 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 620 ++ .../pip/_vendor/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssl_match_hostname.py | 159 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 271 + .../pip/_vendor/urllib3/util/url.py | 435 + .../pip/_vendor/urllib3/util/wait.py | 152 + .../site-packages/pip/_vendor/vendor.txt | 23 + .../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 + .../lib/python3.11/site-packages/pip/py.typed | 4 + .../site-packages/pkg_resources/__init__.py | 3361 +++++++ .../pkg_resources/_vendor/__init__.py | 0 .../_vendor/importlib_resources/__init__.py | 36 + .../_vendor/importlib_resources/_adapters.py | 170 + .../_vendor/importlib_resources/_common.py | 207 + .../_vendor/importlib_resources/_compat.py | 108 + .../_vendor/importlib_resources/_itertools.py | 35 + .../_vendor/importlib_resources/_legacy.py | 120 + .../_vendor/importlib_resources/abc.py | 170 + .../_vendor/importlib_resources/readers.py | 120 + .../_vendor/importlib_resources/simple.py | 106 + .../pkg_resources/_vendor/jaraco/__init__.py | 0 .../pkg_resources/_vendor/jaraco/context.py | 288 + .../pkg_resources/_vendor/jaraco/functools.py | 556 ++ .../_vendor/jaraco/text/__init__.py | 599 ++ .../_vendor/more_itertools/__init__.py | 6 + .../_vendor/more_itertools/more.py | 4391 +++++++++ .../_vendor/more_itertools/recipes.py | 930 ++ .../_vendor/packaging/__init__.py | 15 + .../_vendor/packaging/_elffile.py | 108 + .../_vendor/packaging/_manylinux.py | 240 + .../_vendor/packaging/_musllinux.py | 80 + .../_vendor/packaging/_parser.py | 353 + .../_vendor/packaging/_structures.py | 61 + .../_vendor/packaging/_tokenizer.py | 192 + .../_vendor/packaging/markers.py | 252 + .../_vendor/packaging/metadata.py | 408 + .../_vendor/packaging/requirements.py | 95 + .../_vendor/packaging/specifiers.py | 1008 ++ .../pkg_resources/_vendor/packaging/tags.py | 546 ++ .../pkg_resources/_vendor/packaging/utils.py | 141 + .../_vendor/packaging/version.py | 564 ++ .../_vendor/platformdirs/__init__.py | 342 + .../_vendor/platformdirs/__main__.py | 46 + .../_vendor/platformdirs/android.py | 120 + .../pkg_resources/_vendor/platformdirs/api.py | 156 + .../_vendor/platformdirs/macos.py | 64 + .../_vendor/platformdirs/unix.py | 181 + .../_vendor/platformdirs/version.py | 4 + .../_vendor/platformdirs/windows.py | 184 + .../_vendor/typing_extensions.py | 2209 +++++ .../pkg_resources/_vendor/zipp.py | 329 + .../pkg_resources/extern/__init__.py | 80 + .../setuptools-68.1.2.dist-info/INSTALLER | 1 + .../setuptools-68.1.2.dist-info/LICENSE | 17 + .../setuptools-68.1.2.dist-info/METADATA | 132 + .../setuptools-68.1.2.dist-info/RECORD | 454 + .../setuptools-68.1.2.dist-info/REQUESTED | 0 .../setuptools-68.1.2.dist-info/WHEEL | 5 + .../entry_points.txt | 56 + .../setuptools-68.1.2.dist-info/top_level.txt | 3 + .../site-packages/setuptools/__init__.py | 270 + .../setuptools/_distutils/__init__.py | 14 + .../setuptools/_distutils/_collections.py | 194 + .../setuptools/_distutils/_functools.py | 20 + .../setuptools/_distutils/_log.py | 4 + .../setuptools/_distutils/_macos_compat.py | 12 + .../setuptools/_distutils/_msvccompiler.py | 568 ++ .../setuptools/_distutils/archive_util.py | 280 + .../setuptools/_distutils/bcppcompiler.py | 401 + .../setuptools/_distutils/ccompiler.py | 1254 +++ .../setuptools/_distutils/cmd.py | 435 + .../setuptools/_distutils/command/__init__.py | 25 + .../_distutils/command/_framework_compat.py | 55 + .../setuptools/_distutils/command/bdist.py | 156 + .../_distutils/command/bdist_dumb.py | 143 + .../_distutils/command/bdist_rpm.py | 614 ++ .../setuptools/_distutils/command/build.py | 152 + .../_distutils/command/build_clib.py | 207 + .../_distutils/command/build_ext.py | 788 ++ .../setuptools/_distutils/command/build_py.py | 406 + .../_distutils/command/build_scripts.py | 172 + .../setuptools/_distutils/command/check.py | 151 + .../setuptools/_distutils/command/clean.py | 75 + .../setuptools/_distutils/command/config.py | 376 + .../setuptools/_distutils/command/install.py | 813 ++ .../_distutils/command/install_data.py | 83 + .../_distutils/command/install_egg_info.py | 92 + .../_distutils/command/install_headers.py | 44 + .../_distutils/command/install_lib.py | 237 + .../_distutils/command/install_scripts.py | 60 + .../_distutils/command/py37compat.py | 31 + .../setuptools/_distutils/command/register.py | 320 + .../setuptools/_distutils/command/sdist.py | 530 + .../setuptools/_distutils/command/upload.py | 206 + .../setuptools/_distutils/config.py | 139 + .../setuptools/_distutils/core.py | 291 + .../setuptools/_distutils/cygwinccompiler.py | 356 + .../setuptools/_distutils/debug.py | 5 + .../setuptools/_distutils/dep_util.py | 96 + .../setuptools/_distutils/dir_util.py | 243 + .../setuptools/_distutils/dist.py | 1287 +++ .../setuptools/_distutils/errors.py | 127 + .../setuptools/_distutils/extension.py | 248 + .../setuptools/_distutils/fancy_getopt.py | 470 + .../setuptools/_distutils/file_util.py | 248 + .../setuptools/_distutils/filelist.py | 371 + .../setuptools/_distutils/log.py | 57 + .../setuptools/_distutils/msvc9compiler.py | 829 ++ .../setuptools/_distutils/msvccompiler.py | 692 ++ .../setuptools/_distutils/py38compat.py | 8 + .../setuptools/_distutils/py39compat.py | 22 + .../setuptools/_distutils/spawn.py | 109 + .../setuptools/_distutils/sysconfig.py | 559 ++ .../setuptools/_distutils/text_file.py | 286 + .../setuptools/_distutils/unixccompiler.py | 400 + .../setuptools/_distutils/util.py | 513 + .../setuptools/_distutils/version.py | 357 + .../setuptools/_distutils/versionpredicate.py | 175 + .../site-packages/setuptools/_entry_points.py | 88 + .../site-packages/setuptools/_imp.py | 88 + .../site-packages/setuptools/_importlib.py | 51 + .../site-packages/setuptools/_itertools.py | 23 + .../setuptools/_normalization.py | 114 + .../site-packages/setuptools/_path.py | 37 + .../site-packages/setuptools/_reqs.py | 33 + .../setuptools/_vendor/__init__.py | 0 .../_vendor/importlib_metadata/__init__.py | 904 ++ .../_vendor/importlib_metadata/_adapters.py | 90 + .../importlib_metadata/_collections.py | 30 + .../_vendor/importlib_metadata/_compat.py | 72 + .../_vendor/importlib_metadata/_functools.py | 104 + .../_vendor/importlib_metadata/_itertools.py | 73 + .../_vendor/importlib_metadata/_meta.py | 49 + .../_vendor/importlib_metadata/_py39compat.py | 35 + .../_vendor/importlib_metadata/_text.py | 99 + .../_vendor/importlib_resources/__init__.py | 36 + .../_vendor/importlib_resources/_adapters.py | 170 + .../_vendor/importlib_resources/_common.py | 207 + .../_vendor/importlib_resources/_compat.py | 108 + .../_vendor/importlib_resources/_itertools.py | 35 + .../_vendor/importlib_resources/_legacy.py | 120 + .../_vendor/importlib_resources/abc.py | 170 + .../_vendor/importlib_resources/readers.py | 120 + .../_vendor/importlib_resources/simple.py | 106 + .../setuptools/_vendor/jaraco/__init__.py | 0 .../setuptools/_vendor/jaraco/context.py | 288 + .../setuptools/_vendor/jaraco/functools.py | 556 ++ .../_vendor/jaraco/text/__init__.py | 599 ++ .../_vendor/more_itertools/__init__.py | 4 + .../setuptools/_vendor/more_itertools/more.py | 3824 ++++++++ .../_vendor/more_itertools/recipes.py | 620 ++ .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__init__.py | 15 + .../setuptools/_vendor/packaging/_elffile.py | 108 + .../_vendor/packaging/_manylinux.py | 240 + .../_vendor/packaging/_musllinux.py | 80 + .../setuptools/_vendor/packaging/_parser.py | 353 + .../_vendor/packaging/_structures.py | 61 + .../_vendor/packaging/_tokenizer.py | 192 + .../setuptools/_vendor/packaging/markers.py | 252 + .../setuptools/_vendor/packaging/metadata.py | 408 + .../_vendor/packaging/requirements.py | 95 + .../_vendor/packaging/specifiers.py | 1008 ++ .../setuptools/_vendor/packaging/tags.py | 546 ++ .../setuptools/_vendor/packaging/utils.py | 141 + .../setuptools/_vendor/packaging/version.py | 564 ++ .../setuptools/_vendor/tomli/__init__.py | 11 + .../setuptools/_vendor/tomli/_parser.py | 691 ++ .../setuptools/_vendor/tomli/_re.py | 107 + .../setuptools/_vendor/tomli/_types.py | 10 + .../setuptools/_vendor/typing_extensions.py | 2296 +++++ .../site-packages/setuptools/_vendor/zipp.py | 329 + .../site-packages/setuptools/archive_util.py | 216 + .../site-packages/setuptools/build_meta.py | 534 + .../site-packages/setuptools/cli-32.exe | Bin 0 -> 11776 bytes .../site-packages/setuptools/cli-64.exe | Bin 0 -> 14336 bytes .../site-packages/setuptools/cli-arm64.exe | Bin 0 -> 13824 bytes .../site-packages/setuptools/cli.exe | Bin 0 -> 11776 bytes .../setuptools/command/__init__.py | 12 + .../site-packages/setuptools/command/alias.py | 78 + .../setuptools/command/bdist_egg.py | 464 + .../setuptools/command/bdist_rpm.py | 40 + .../site-packages/setuptools/command/build.py | 149 + .../setuptools/command/build_clib.py | 99 + .../setuptools/command/build_ext.py | 456 + .../setuptools/command/build_py.py | 389 + .../setuptools/command/develop.py | 188 + .../setuptools/command/dist_info.py | 127 + .../setuptools/command/easy_install.py | 2420 +++++ .../setuptools/command/editable_wheel.py | 882 ++ .../setuptools/command/egg_info.py | 758 ++ .../setuptools/command/install.py | 147 + .../setuptools/command/install_egg_info.py | 77 + .../setuptools/command/install_lib.py | 151 + .../setuptools/command/install_scripts.py | 66 + .../setuptools/command/launcher manifest.xml | 15 + .../setuptools/command/register.py | 18 + .../setuptools/command/rotate.py | 62 + .../setuptools/command/saveopts.py | 21 + .../site-packages/setuptools/command/sdist.py | 215 + .../setuptools/command/setopt.py | 138 + .../site-packages/setuptools/command/test.py | 250 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 222 + .../setuptools/config/__init__.py | 42 + .../setuptools/config/_apply_pyprojecttoml.py | 416 + .../config/_validate_pyproject/__init__.py | 34 + .../_validate_pyproject/error_reporting.py | 318 + .../_validate_pyproject/extra_validations.py | 36 + .../fastjsonschema_exceptions.py | 51 + .../fastjsonschema_validations.py | 1052 ++ .../config/_validate_pyproject/formats.py | 275 + .../site-packages/setuptools/config/expand.py | 463 + .../setuptools/config/pyprojecttoml.py | 441 + .../setuptools/config/setupcfg.py | 789 ++ .../site-packages/setuptools/dep_util.py | 24 + .../site-packages/setuptools/depends.py | 178 + .../site-packages/setuptools/discovery.py | 614 ++ .../site-packages/setuptools/dist.py | 1238 +++ .../site-packages/setuptools/errors.py | 58 + .../site-packages/setuptools/extension.py | 148 + .../setuptools/extern/__init__.py | 84 + .../site-packages/setuptools/glob.py | 166 + .../site-packages/setuptools/gui-32.exe | Bin 0 -> 11776 bytes .../site-packages/setuptools/gui-64.exe | Bin 0 -> 14336 bytes .../site-packages/setuptools/gui-arm64.exe | Bin 0 -> 13824 bytes .../site-packages/setuptools/gui.exe | Bin 0 -> 11776 bytes .../site-packages/setuptools/installer.py | 145 + .../site-packages/setuptools/launch.py | 36 + .../site-packages/setuptools/logging.py | 38 + .../site-packages/setuptools/monkey.py | 158 + .../site-packages/setuptools/msvc.py | 1739 ++++ .../site-packages/setuptools/namespaces.py | 101 + .../site-packages/setuptools/package_index.py | 1131 +++ .../site-packages/setuptools/py312compat.py | 12 + .../site-packages/setuptools/sandbox.py | 530 + .../setuptools/script (dev).tmpl | 6 + .../site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/unicode_utils.py | 42 + .../site-packages/setuptools/version.py | 6 + .../site-packages/setuptools/warnings.py | 105 + .../site-packages/setuptools/wheel.py | 234 + .../setuptools/windows_support.py | 30 + .../site-packages/sqlalchemy/__init__.py | 294 + .../sqlalchemy/connectors/__init__.py | 18 + .../sqlalchemy/connectors/aioodbc.py | 174 + .../sqlalchemy/connectors/asyncio.py | 208 + .../sqlalchemy/connectors/pyodbc.py | 249 + .../sqlalchemy/cyextension/__init__.py | 6 + ...ollections.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 2019496 bytes .../sqlalchemy/cyextension/collections.pyx | 409 + ...utabledict.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 703720 bytes .../sqlalchemy/cyextension/immutabledict.pxd | 8 + .../sqlalchemy/cyextension/immutabledict.pyx | 133 + ...processors.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 509544 bytes .../sqlalchemy/cyextension/processors.pyx | 68 + ...esultproxy.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 586752 bytes .../sqlalchemy/cyextension/resultproxy.pyx | 102 + .../util.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 870136 bytes .../sqlalchemy/cyextension/util.pyx | 91 + .../sqlalchemy/dialects/__init__.py | 61 + .../sqlalchemy/dialects/_typing.py | 25 + .../sqlalchemy/dialects/mssql/__init__.py | 88 + .../sqlalchemy/dialects/mssql/aioodbc.py | 64 + .../sqlalchemy/dialects/mssql/base.py | 4038 ++++++++ .../dialects/mssql/information_schema.py | 254 + .../sqlalchemy/dialects/mssql/json.py | 133 + .../sqlalchemy/dialects/mssql/provision.py | 155 + .../sqlalchemy/dialects/mssql/pymssql.py | 125 + .../sqlalchemy/dialects/mssql/pyodbc.py | 745 ++ .../sqlalchemy/dialects/mysql/__init__.py | 101 + .../sqlalchemy/dialects/mysql/aiomysql.py | 332 + .../sqlalchemy/dialects/mysql/asyncmy.py | 337 + .../sqlalchemy/dialects/mysql/base.py | 3447 +++++++ .../sqlalchemy/dialects/mysql/cymysql.py | 84 + .../sqlalchemy/dialects/mysql/dml.py | 219 + .../sqlalchemy/dialects/mysql/enumerated.py | 244 + .../sqlalchemy/dialects/mysql/expression.py | 141 + .../sqlalchemy/dialects/mysql/json.py | 81 + .../sqlalchemy/dialects/mysql/mariadb.py | 32 + .../dialects/mysql/mariadbconnector.py | 282 + .../dialects/mysql/mysqlconnector.py | 179 + .../sqlalchemy/dialects/mysql/mysqldb.py | 308 + .../sqlalchemy/dialects/mysql/provision.py | 107 + .../sqlalchemy/dialects/mysql/pymysql.py | 137 + .../sqlalchemy/dialects/mysql/pyodbc.py | 138 + .../sqlalchemy/dialects/mysql/reflection.py | 677 ++ .../dialects/mysql/reserved_words.py | 567 ++ .../sqlalchemy/dialects/mysql/types.py | 773 ++ .../sqlalchemy/dialects/oracle/__init__.py | 67 + .../sqlalchemy/dialects/oracle/base.py | 3240 +++++++ .../sqlalchemy/dialects/oracle/cx_oracle.py | 1492 +++ .../sqlalchemy/dialects/oracle/dictionary.py | 507 + .../sqlalchemy/dialects/oracle/oracledb.py | 311 + .../sqlalchemy/dialects/oracle/provision.py | 220 + .../sqlalchemy/dialects/oracle/types.py | 287 + .../dialects/postgresql/__init__.py | 167 + .../dialects/postgresql/_psycopg_common.py | 187 + .../sqlalchemy/dialects/postgresql/array.py | 424 + .../sqlalchemy/dialects/postgresql/asyncpg.py | 1262 +++ .../sqlalchemy/dialects/postgresql/base.py | 4920 ++++++++++ .../sqlalchemy/dialects/postgresql/dml.py | 310 + .../sqlalchemy/dialects/postgresql/ext.py | 496 + .../sqlalchemy/dialects/postgresql/hstore.py | 397 + .../sqlalchemy/dialects/postgresql/json.py | 325 + .../dialects/postgresql/named_types.py | 495 + .../dialects/postgresql/operators.py | 129 + .../sqlalchemy/dialects/postgresql/pg8000.py | 662 ++ .../dialects/postgresql/pg_catalog.py | 294 + .../dialects/postgresql/provision.py | 175 + .../sqlalchemy/dialects/postgresql/psycopg.py | 749 ++ .../dialects/postgresql/psycopg2.py | 876 ++ .../dialects/postgresql/psycopg2cffi.py | 61 + .../sqlalchemy/dialects/postgresql/ranges.py | 1029 ++ .../sqlalchemy/dialects/postgresql/types.py | 303 + .../sqlalchemy/dialects/sqlite/__init__.py | 57 + .../sqlalchemy/dialects/sqlite/aiosqlite.py | 396 + .../sqlalchemy/dialects/sqlite/base.py | 2782 ++++++ .../sqlalchemy/dialects/sqlite/dml.py | 240 + .../sqlalchemy/dialects/sqlite/json.py | 92 + .../sqlalchemy/dialects/sqlite/provision.py | 198 + .../sqlalchemy/dialects/sqlite/pysqlcipher.py | 155 + .../sqlalchemy/dialects/sqlite/pysqlite.py | 753 ++ .../dialects/type_migration_guidelines.txt | 145 + .../sqlalchemy/engine/__init__.py | 62 + .../sqlalchemy/engine/_py_processors.py | 136 + .../sqlalchemy/engine/_py_row.py | 128 + .../sqlalchemy/engine/_py_util.py | 74 + .../site-packages/sqlalchemy/engine/base.py | 3355 +++++++ .../sqlalchemy/engine/characteristics.py | 81 + .../site-packages/sqlalchemy/engine/create.py | 864 ++ .../site-packages/sqlalchemy/engine/cursor.py | 2150 +++++ .../sqlalchemy/engine/default.py | 2339 +++++ .../site-packages/sqlalchemy/engine/events.py | 951 ++ .../sqlalchemy/engine/interfaces.py | 3391 +++++++ .../site-packages/sqlalchemy/engine/mock.py | 131 + .../sqlalchemy/engine/processors.py | 61 + .../sqlalchemy/engine/reflection.py | 2089 ++++ .../site-packages/sqlalchemy/engine/result.py | 2382 +++++ .../site-packages/sqlalchemy/engine/row.py | 401 + .../sqlalchemy/engine/strategies.py | 19 + .../site-packages/sqlalchemy/engine/url.py | 910 ++ .../site-packages/sqlalchemy/engine/util.py | 166 + .../sqlalchemy/event/__init__.py | 25 + .../site-packages/sqlalchemy/event/api.py | 225 + .../site-packages/sqlalchemy/event/attr.py | 655 ++ .../site-packages/sqlalchemy/event/base.py | 462 + .../site-packages/sqlalchemy/event/legacy.py | 246 + .../sqlalchemy/event/registry.py | 386 + .../site-packages/sqlalchemy/events.py | 17 + .../site-packages/sqlalchemy/exc.py | 830 ++ .../site-packages/sqlalchemy/ext/__init__.py | 11 + .../sqlalchemy/ext/associationproxy.py | 2005 ++++ .../sqlalchemy/ext/asyncio/__init__.py | 25 + .../sqlalchemy/ext/asyncio/base.py | 279 + .../sqlalchemy/ext/asyncio/engine.py | 1457 +++ .../sqlalchemy/ext/asyncio/exc.py | 21 + .../sqlalchemy/ext/asyncio/result.py | 961 ++ .../sqlalchemy/ext/asyncio/scoping.py | 1614 ++++ .../sqlalchemy/ext/asyncio/session.py | 1927 ++++ .../site-packages/sqlalchemy/ext/automap.py | 1652 ++++ .../site-packages/sqlalchemy/ext/baked.py | 574 ++ .../site-packages/sqlalchemy/ext/compiler.py | 555 ++ .../sqlalchemy/ext/declarative/__init__.py | 65 + .../sqlalchemy/ext/declarative/extensions.py | 548 ++ .../sqlalchemy/ext/horizontal_shard.py | 481 + .../site-packages/sqlalchemy/ext/hybrid.py | 1514 +++ .../site-packages/sqlalchemy/ext/indexable.py | 341 + .../sqlalchemy/ext/instrumentation.py | 450 + .../site-packages/sqlalchemy/ext/mutable.py | 1073 ++ .../sqlalchemy/ext/mypy/__init__.py | 6 + .../sqlalchemy/ext/mypy/apply.py | 320 + .../sqlalchemy/ext/mypy/decl_class.py | 515 + .../sqlalchemy/ext/mypy/infer.py | 590 ++ .../sqlalchemy/ext/mypy/names.py | 342 + .../sqlalchemy/ext/mypy/plugin.py | 303 + .../site-packages/sqlalchemy/ext/mypy/util.py | 338 + .../sqlalchemy/ext/orderinglist.py | 416 + .../sqlalchemy/ext/serializer.py | 185 + .../sqlalchemy/future/__init__.py | 16 + .../site-packages/sqlalchemy/future/engine.py | 15 + .../site-packages/sqlalchemy/inspection.py | 174 + .../site-packages/sqlalchemy/log.py | 288 + .../site-packages/sqlalchemy/orm/__init__.py | 170 + .../sqlalchemy/orm/_orm_constructors.py | 2468 +++++ .../site-packages/sqlalchemy/orm/_typing.py | 179 + .../sqlalchemy/orm/attributes.py | 2835 ++++++ .../site-packages/sqlalchemy/orm/base.py | 970 ++ .../sqlalchemy/orm/bulk_persistence.py | 2048 ++++ .../sqlalchemy/orm/clsregistry.py | 570 ++ .../sqlalchemy/orm/collections.py | 1618 ++++ .../site-packages/sqlalchemy/orm/context.py | 3243 +++++++ .../site-packages/sqlalchemy/orm/decl_api.py | 1875 ++++ .../site-packages/sqlalchemy/orm/decl_base.py | 2152 +++++ .../sqlalchemy/orm/dependency.py | 1304 +++ .../sqlalchemy/orm/descriptor_props.py | 1074 ++ .../site-packages/sqlalchemy/orm/dynamic.py | 298 + .../site-packages/sqlalchemy/orm/evaluator.py | 368 + .../site-packages/sqlalchemy/orm/events.py | 3259 +++++++ .../site-packages/sqlalchemy/orm/exc.py | 227 + .../site-packages/sqlalchemy/orm/identity.py | 302 + .../sqlalchemy/orm/instrumentation.py | 754 ++ .../sqlalchemy/orm/interfaces.py | 1464 +++ .../site-packages/sqlalchemy/orm/loading.py | 1665 ++++ .../sqlalchemy/orm/mapped_collection.py | 560 ++ .../site-packages/sqlalchemy/orm/mapper.py | 4420 +++++++++ .../sqlalchemy/orm/path_registry.py | 808 ++ .../sqlalchemy/orm/persistence.py | 1782 ++++ .../sqlalchemy/orm/properties.py | 880 ++ .../site-packages/sqlalchemy/orm/query.py | 3393 +++++++ .../sqlalchemy/orm/relationships.py | 3468 +++++++ .../site-packages/sqlalchemy/orm/scoping.py | 2165 +++++ .../site-packages/sqlalchemy/orm/session.py | 5238 ++++++++++ .../site-packages/sqlalchemy/orm/state.py | 1136 +++ .../sqlalchemy/orm/state_changes.py | 198 + .../sqlalchemy/orm/strategies.py | 3344 +++++++ .../sqlalchemy/orm/strategy_options.py | 2530 +++++ .../site-packages/sqlalchemy/orm/sync.py | 164 + .../sqlalchemy/orm/unitofwork.py | 796 ++ .../site-packages/sqlalchemy/orm/util.py | 2405 +++++ .../site-packages/sqlalchemy/orm/writeonly.py | 678 ++ .../site-packages/sqlalchemy/pool/__init__.py | 44 + .../site-packages/sqlalchemy/pool/base.py | 1515 +++ .../site-packages/sqlalchemy/pool/events.py | 370 + .../site-packages/sqlalchemy/pool/impl.py | 547 ++ .../site-packages/sqlalchemy/py.typed | 0 .../site-packages/sqlalchemy/schema.py | 70 + .../site-packages/sqlalchemy/sql/__init__.py | 145 + .../sqlalchemy/sql/_dml_constructors.py | 140 + .../sqlalchemy/sql/_elements_constructors.py | 1836 ++++ .../sqlalchemy/sql/_orm_types.py | 20 + .../site-packages/sqlalchemy/sql/_py_util.py | 75 + .../sql/_selectable_constructors.py | 635 ++ .../site-packages/sqlalchemy/sql/_typing.py | 446 + .../sqlalchemy/sql/annotation.py | 585 ++ .../site-packages/sqlalchemy/sql/base.py | 2179 +++++ .../site-packages/sqlalchemy/sql/cache_key.py | 1057 ++ .../site-packages/sqlalchemy/sql/coercions.py | 1389 +++ .../site-packages/sqlalchemy/sql/compiler.py | 7723 +++++++++++++++ .../site-packages/sqlalchemy/sql/crud.py | 1669 ++++ .../site-packages/sqlalchemy/sql/ddl.py | 1378 +++ .../sqlalchemy/sql/default_comparator.py | 552 ++ .../site-packages/sqlalchemy/sql/dml.py | 1817 ++++ .../site-packages/sqlalchemy/sql/elements.py | 5352 ++++++++++ .../site-packages/sqlalchemy/sql/events.py | 455 + .../sqlalchemy/sql/expression.py | 162 + .../site-packages/sqlalchemy/sql/functions.py | 2052 ++++ .../site-packages/sqlalchemy/sql/lambdas.py | 1449 +++ .../site-packages/sqlalchemy/sql/naming.py | 212 + .../site-packages/sqlalchemy/sql/operators.py | 2573 +++++ .../site-packages/sqlalchemy/sql/roles.py | 323 + .../site-packages/sqlalchemy/sql/schema.py | 6115 ++++++++++++ .../sqlalchemy/sql/selectable.py | 6913 +++++++++++++ .../site-packages/sqlalchemy/sql/sqltypes.py | 3811 ++++++++ .../sqlalchemy/sql/traversals.py | 1022 ++ .../site-packages/sqlalchemy/sql/type_api.py | 2323 +++++ .../site-packages/sqlalchemy/sql/util.py | 1486 +++ .../site-packages/sqlalchemy/sql/visitors.py | 1165 +++ .../sqlalchemy/testing/__init__.py | 95 + .../sqlalchemy/testing/assertions.py | 989 ++ .../sqlalchemy/testing/assertsql.py | 516 + .../sqlalchemy/testing/asyncio.py | 130 + .../sqlalchemy/testing/config.py | 427 + .../sqlalchemy/testing/engines.py | 467 + .../sqlalchemy/testing/entities.py | 117 + .../sqlalchemy/testing/exclusions.py | 435 + .../sqlalchemy/testing/fixtures/__init__.py | 28 + .../sqlalchemy/testing/fixtures/base.py | 366 + .../sqlalchemy/testing/fixtures/mypy.py | 312 + .../sqlalchemy/testing/fixtures/orm.py | 227 + .../sqlalchemy/testing/fixtures/sql.py | 492 + .../sqlalchemy/testing/pickleable.py | 155 + .../sqlalchemy/testing/plugin/__init__.py | 6 + .../sqlalchemy/testing/plugin/bootstrap.py | 51 + .../sqlalchemy/testing/plugin/plugin_base.py | 779 ++ .../sqlalchemy/testing/plugin/pytestplugin.py | 862 ++ .../sqlalchemy/testing/profiling.py | 324 + .../sqlalchemy/testing/provision.py | 496 + .../sqlalchemy/testing/requirements.py | 1783 ++++ .../sqlalchemy/testing/schema.py | 224 + .../sqlalchemy/testing/suite/__init__.py | 19 + .../sqlalchemy/testing/suite/test_cte.py | 211 + .../sqlalchemy/testing/suite/test_ddl.py | 389 + .../testing/suite/test_deprecations.py | 153 + .../sqlalchemy/testing/suite/test_dialect.py | 740 ++ .../sqlalchemy/testing/suite/test_insert.py | 630 ++ .../testing/suite/test_reflection.py | 3128 ++++++ .../sqlalchemy/testing/suite/test_results.py | 468 + .../sqlalchemy/testing/suite/test_rowcount.py | 258 + .../sqlalchemy/testing/suite/test_select.py | 1888 ++++ .../sqlalchemy/testing/suite/test_sequence.py | 317 + .../sqlalchemy/testing/suite/test_types.py | 2071 ++++ .../testing/suite/test_unicode_ddl.py | 189 + .../testing/suite/test_update_delete.py | 139 + .../site-packages/sqlalchemy/testing/util.py | 519 + .../sqlalchemy/testing/warnings.py | 52 + .../site-packages/sqlalchemy/types.py | 76 + .../site-packages/sqlalchemy/util/__init__.py | 159 + .../sqlalchemy/util/_collections.py | 715 ++ .../sqlalchemy/util/_concurrency_py3k.py | 267 + .../site-packages/sqlalchemy/util/_has_cy.py | 40 + .../sqlalchemy/util/_py_collections.py | 541 ++ .../site-packages/sqlalchemy/util/compat.py | 300 + .../sqlalchemy/util/concurrency.py | 73 + .../sqlalchemy/util/deprecations.py | 401 + .../sqlalchemy/util/langhelpers.py | 2210 +++++ .../sqlalchemy/util/preloaded.py | 150 + .../site-packages/sqlalchemy/util/queue.py | 322 + .../sqlalchemy/util/tool_support.py | 201 + .../sqlalchemy/util/topological.py | 120 + .../site-packages/sqlalchemy/util/typing.py | 580 ++ .../sqlalchemy_utils/__init__.py | 104 + .../sqlalchemy_utils/aggregates.py | 576 ++ .../site-packages/sqlalchemy_utils/asserts.py | 182 + .../site-packages/sqlalchemy_utils/compat.py | 86 + .../sqlalchemy_utils/exceptions.py | 10 + .../sqlalchemy_utils/expressions.py | 60 + .../sqlalchemy_utils/functions/__init__.py | 42 + .../sqlalchemy_utils/functions/database.py | 659 ++ .../functions/foreign_keys.py | 350 + .../sqlalchemy_utils/functions/mock.py | 112 + .../sqlalchemy_utils/functions/orm.py | 904 ++ .../sqlalchemy_utils/functions/render.py | 75 + .../sqlalchemy_utils/functions/sort_query.py | 74 + .../site-packages/sqlalchemy_utils/generic.py | 185 + .../site-packages/sqlalchemy_utils/i18n.py | 119 + .../sqlalchemy_utils/listeners.py | 277 + .../site-packages/sqlalchemy_utils/models.py | 96 + .../sqlalchemy_utils/observer.py | 376 + .../sqlalchemy_utils/operators.py | 74 + .../site-packages/sqlalchemy_utils/path.py | 152 + .../sqlalchemy_utils/primitives/__init__.py | 5 + .../sqlalchemy_utils/primitives/country.py | 110 + .../sqlalchemy_utils/primitives/currency.py | 109 + .../sqlalchemy_utils/primitives/ltree.py | 220 + .../sqlalchemy_utils/primitives/weekday.py | 54 + .../sqlalchemy_utils/primitives/weekdays.py | 57 + .../sqlalchemy_utils/proxy_dict.py | 84 + .../sqlalchemy_utils/query_chain.py | 173 + .../relationships/__init__.py | 128 + .../relationships/chained_join.py | 31 + .../sqlalchemy_utils/types/__init__.py | 63 + .../sqlalchemy_utils/types/arrow.py | 62 + .../sqlalchemy_utils/types/bit.py | 24 + .../sqlalchemy_utils/types/choice.py | 225 + .../sqlalchemy_utils/types/color.py | 79 + .../sqlalchemy_utils/types/country.py | 64 + .../sqlalchemy_utils/types/currency.py | 74 + .../sqlalchemy_utils/types/email.py | 48 + .../types/encrypted/__init__.py | 1 + .../types/encrypted/encrypted_type.py | 508 + .../types/encrypted/padding.py | 142 + .../types/enriched_datetime/__init__.py | 4 + .../types/enriched_datetime/arrow_datetime.py | 39 + .../enriched_datetime/enriched_date_type.py | 50 + .../enriched_datetime_type.py | 51 + .../types/enriched_datetime/pendulum_date.py | 32 + .../enriched_datetime/pendulum_datetime.py | 49 + .../sqlalchemy_utils/types/ip_address.py | 52 + .../sqlalchemy_utils/types/json.py | 77 + .../sqlalchemy_utils/types/locale.py | 76 + .../sqlalchemy_utils/types/ltree.py | 121 + .../sqlalchemy_utils/types/password.py | 259 + .../sqlalchemy_utils/types/pg_composite.py | 390 + .../sqlalchemy_utils/types/phone_number.py | 204 + .../sqlalchemy_utils/types/range.py | 480 + .../types/scalar_coercible.py | 6 + .../sqlalchemy_utils/types/scalar_list.py | 97 + .../sqlalchemy_utils/types/timezone.py | 102 + .../sqlalchemy_utils/types/ts_vector.py | 108 + .../sqlalchemy_utils/types/url.py | 68 + .../sqlalchemy_utils/types/uuid.py | 113 + .../sqlalchemy_utils/types/weekdays.py | 82 + .../site-packages/sqlalchemy_utils/utils.py | 22 + .../site-packages/sqlalchemy_utils/view.py | 210 + .../INSTALLER | 1 + .../typing_extensions-4.9.0.dist-info/LICENSE | 279 + .../METADATA | 66 + .../typing_extensions-4.9.0.dist-info/RECORD | 8 + .../REQUESTED | 0 .../typing_extensions-4.9.0.dist-info/WHEEL | 4 + .../site-packages/typing_extensions.py | 3053 ++++++ .../python3.11/site-packages/yaml/__init__.py | 390 + .../_yaml.cpython-311-x86_64-linux-gnu.so | Bin 0 -> 2504120 bytes .../python3.11/site-packages/yaml/composer.py | 139 + .../site-packages/yaml/constructor.py | 748 ++ .../python3.11/site-packages/yaml/cyaml.py | 101 + .../python3.11/site-packages/yaml/dumper.py | 62 + .../python3.11/site-packages/yaml/emitter.py | 1137 +++ .../python3.11/site-packages/yaml/error.py | 75 + .../python3.11/site-packages/yaml/events.py | 86 + .../python3.11/site-packages/yaml/loader.py | 63 + .../python3.11/site-packages/yaml/nodes.py | 49 + .../python3.11/site-packages/yaml/parser.py | 589 ++ .../python3.11/site-packages/yaml/reader.py | 185 + .../site-packages/yaml/representer.py | 389 + .../python3.11/site-packages/yaml/resolver.py | 227 + .../python3.11/site-packages/yaml/scanner.py | 1435 +++ .../site-packages/yaml/serializer.py | 111 + .../python3.11/site-packages/yaml/tokens.py | 104 + elitebot/lib64 | 1 + elitebot/pyvenv.cfg | 5 + logs/elitebot.log | 6818 ------------- plugins/__pycache__/__init__.cpython-310.pyc | Bin 151 -> 0 bytes plugins/__pycache__/__init__.cpython-311.pyc | Bin 167 -> 0 bytes plugins/__pycache__/commands.cpython-310.pyc | Bin 1782 -> 0 bytes plugins/__pycache__/commands.cpython-311.pyc | Bin 4174 -> 0 bytes plugins/hello.py | 25 + src/__pycache__/__init__.cpython-310.pyc | Bin 145 -> 0 bytes src/__pycache__/__init__.cpython-311.pyc | Bin 161 -> 0 bytes src/__pycache__/bot.cpython-310.pyc | Bin 5774 -> 0 bytes src/__pycache__/bot.cpython-311.pyc | Bin 13961 -> 0 bytes .../channel_manager.cpython-310.pyc | Bin 2050 -> 0 bytes .../channel_manager.cpython-311.pyc | Bin 3849 -> 0 bytes .../event_handlers.cpython-310.pyc | Bin 1873 -> 0 bytes src/__pycache__/logger.cpython-310.pyc | Bin 1448 -> 0 bytes src/__pycache__/logger.cpython-311.pyc | Bin 2628 -> 0 bytes src/__pycache__/plugin_base.cpython-310.pyc | Bin 1349 -> 0 bytes src/__pycache__/plugin_base.cpython-311.pyc | Bin 1538 -> 0 bytes src/__pycache__/sasl.cpython-310.pyc | Bin 1475 -> 0 bytes src/__pycache__/sasl.cpython-311.pyc | Bin 2084 -> 0 bytes test.json | 18 - 1340 files changed, 554582 insertions(+), 6840 deletions(-) delete mode 100644 data/channels.json create mode 100644 elitebot/bin/Activate.ps1 create mode 100644 elitebot/bin/activate create mode 100644 elitebot/bin/activate.csh create mode 100644 elitebot/bin/activate.fish create mode 100755 elitebot/bin/pip create mode 100755 elitebot/bin/pip3 create mode 100755 elitebot/bin/pip3.11 create mode 120000 elitebot/bin/python create mode 120000 elitebot/bin/python3 create mode 120000 elitebot/bin/python3.11 create mode 100644 elitebot/include/site/python3.11/greenlet/greenlet.h create mode 100644 elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/LICENSE create mode 100644 elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/top_level.txt create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/LICENSE create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/top_level.txt create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/LICENSE create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/top_level.txt create mode 100644 elitebot/lib/python3.11/site-packages/_distutils_hack/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/_distutils_hack/override.py create mode 100644 elitebot/lib/python3.11/site-packages/_yaml/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt create mode 100644 elitebot/lib/python3.11/site-packages/colorama/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/ansi.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/ansitowin32.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/initialise.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/tests/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/tests/ansi_test.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/tests/ansitowin32_test.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/tests/initialise_test.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/tests/isatty_test.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/tests/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/tests/winterm_test.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/win32.py create mode 100644 elitebot/lib/python3.11/site-packages/colorama/winterm.py create mode 100644 elitebot/lib/python3.11/site-packages/distutils-precedence.pth create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/AUTHORS create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE.PSF create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/top_level.txt create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TBrokenGreenlet.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TExceptionState.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TGreenlet.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TGreenletGlobals.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TMainGreenlet.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TPythonState.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TStackState.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TThreadStateDestroy.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/TUserGreenlet.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/__init__.py create mode 100755 elitebot/lib/python3.11/site-packages/greenlet/_greenlet.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet.cpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_allocator.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_compiler_compat.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_add_pending.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_compat.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_exceptions.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_internal.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_slp_switch.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_support.hpp create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/setup_switch_x64_masm.cmd create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_aarch64_gcc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_alpha_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_amd64_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_gcc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_ios.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.asm create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.obj create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_msvc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_csky_gcc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_loongarch64_linux.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_m68k_gcc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_mips_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_aix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_linux.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_aix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_linux.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_macosx.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_riscv_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_s390_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_sparc_sun_gcc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x32_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.asm create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.obj create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_msvc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_msvc.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_unix.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/slp_platformselect.h create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension.c create mode 100755 elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp create mode 100755 elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/leakcheck.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_cpp.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_gc.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_leaks.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_throw.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_tracing.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_version.py create mode 100644 elitebot/lib/python3.11/site-packages/greenlet/tests/test_weakref.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/abstracts.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/authentication.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/catch23.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/charsets.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/connection.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/connection_cext.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/constants.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/conversion.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/cursor.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/cursor_cext.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/custom_types.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/dbapi.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/base.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/client.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/compiler.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/creation.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/features.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/introspection.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/operations.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/schema.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/django/validation.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/errorcode.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/errors.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/fabric/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/fabric/balancing.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/fabric/caching.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/fabric/connection.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/locales/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/client_error.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/network.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/optionfiles.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/pooling.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/protocol.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql/connector/version.py create mode 100644 elitebot/lib/python3.11/site-packages/mysql_connector-2.2.9.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/mysql_connector-2.2.9.dist-info/LICENSE.txt create mode 100644 elitebot/lib/python3.11/site-packages/mysql_connector-2.2.9.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/mysql_connector-2.2.9.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/mysql_connector-2.2.9.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/mysql_connector-2.2.9.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/mysql_connector-2.2.9.dist-info/top_level.txt create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/authentication.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/charsets.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/connection.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/constants.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/crud.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/dbdoc.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/errorcode.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/errors.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/expr.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/expr_unparser.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/locales/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/locales/eng/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/locales/eng/client_error.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_connection_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_crud_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_datatypes_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_expect_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_expr_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_notice_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_resultset_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_session_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/mysqlx_sql_pb2.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protobuf/t.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/protocol.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/result.py create mode 100644 elitebot/lib/python3.11/site-packages/mysqlx/statement.py create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/AUTHORS.txt create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/LICENSE.txt create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/entry_points.txt create mode 100644 elitebot/lib/python3.11/site-packages/pip-23.2.dist-info/top_level.txt create mode 100644 elitebot/lib/python3.11/site-packages/pip/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/__main__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/__pip-runner__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/build_env.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cache.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/base_command.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/command_context.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/main.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/main_parser.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/parser.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/req_command.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/spinners.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/cli/status_codes.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/cache.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/check.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/completion.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/configuration.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/debug.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/download.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/freeze.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/hash.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/help.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/index.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/inspect.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/install.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/list.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/search.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/show.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/uninstall.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/commands/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/configuration.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/distributions/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/distributions/base.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/distributions/installed.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/distributions/sdist.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/distributions/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/exceptions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/index/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/index/collector.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/index/package_finder.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/index/sources.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/locations/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/locations/_distutils.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/locations/base.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/main.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/_json.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/base.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/candidate.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/direct_url.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/format_control.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/index.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/installation_report.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/link.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/scheme.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/search_scope.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/target_python.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/models/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/auth.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/cache.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/download.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/session.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/check.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/freeze.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/operations/prepare.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/pyproject.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/req/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/req/constructors.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/req/req_file.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/req/req_install.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/req/req_set.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/base.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/self_outdated_check.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/_jaraco_text.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/_log.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/appdirs.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/datetime.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/deprecation.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/egg_link.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/encoding.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/filesystem.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/filetypes.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/glibc.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/hashes.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/logging.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/misc.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/models.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/packaging.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/subprocess.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/unpacking.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/urls.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/utils/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/vcs/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/vcs/git.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/vcs/subversion.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_internal/wheel_builder.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/certifi/core.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/codingstatemachinedict.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/enums.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/johabfreq.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/johabprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/macromanprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/resultdict.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/utf1632prober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/chardet/version.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/tests/ansi_test.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/tests/initialise_test.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/tests/isatty_test.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/tests/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/tests/winterm_test.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/win32.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/database.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/index.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/locators.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/markers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/resources.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/util.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/version.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distro/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distro/__main__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/distro/distro.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/codec.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/core.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/intranges.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/package_data.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/markers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/tags.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/packaging/version.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/console.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/filter.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/style.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/token.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pygments/util.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/actions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/common.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/core.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/diagram/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/exceptions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/helpers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/results.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/testing.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/unicode.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/util.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__version__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/adapters.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/api.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/auth.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/certs.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/cookies.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/help.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/hooks.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/models.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/packages.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/sessions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/structures.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/requests/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__main__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_extension.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_fileno.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_loop.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_null_file.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_pick.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_stack.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_timer.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/abc.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/align.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/ansi.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/bar.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/box.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/cells.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/columns.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/console.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/constrain.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/containers.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/control.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/emoji.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/errors.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/filesize.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/json.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/layout.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/live.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/live_render.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/logging.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/markup.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/measure.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/padding.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/pager.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/palette.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/panel.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/pretty.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/progress.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/prompt.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/protocol.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/region.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/repr.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/rule.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/scope.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/screen.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/segment.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/spinner.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/status.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/style.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/styled.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/syntax.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/table.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/text.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/theme.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/themes.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/traceback.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/rich/tree.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/six.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/after.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/before.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tomli/_re.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/tomli/_types.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/typing_extensions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/request.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/response.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/vendor.txt create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 elitebot/lib/python3.11/site-packages/pip/py.typed create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/_adapters.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/_common.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/_compat.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/_itertools.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/_legacy.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/abc.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/readers.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/importlib_resources/simple.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/jaraco/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/jaraco/context.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/jaraco/functools.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/jaraco/text/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/more_itertools/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/more_itertools/more.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/more_itertools/recipes.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/_elffile.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/_manylinux.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/_musllinux.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/_parser.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/_tokenizer.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/metadata.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/tags.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/__main__.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/android.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/api.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/macos.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/unix.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/version.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/platformdirs/windows.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/typing_extensions.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/_vendor/zipp.py create mode 100644 elitebot/lib/python3.11/site-packages/pkg_resources/extern/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/LICENSE create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/entry_points.txt create mode 100644 elitebot/lib/python3.11/site-packages/setuptools-68.1.2.dist-info/top_level.txt create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/_collections.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/_functools.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/_log.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/_macos_compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/_msvccompiler.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/archive_util.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/bcppcompiler.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/ccompiler.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/cmd.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/_framework_compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/bdist.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/bdist_dumb.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/bdist_rpm.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/build.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/build_clib.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/build_ext.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/build_py.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/build_scripts.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/check.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/clean.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/config.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/install.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/install_data.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/install_egg_info.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/install_headers.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/install_lib.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/install_scripts.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/py37compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/register.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/sdist.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/command/upload.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/config.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/core.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/cygwinccompiler.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/debug.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/dep_util.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/dir_util.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/dist.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/errors.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/extension.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/fancy_getopt.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/file_util.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/filelist.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/log.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/msvc9compiler.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/msvccompiler.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/py38compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/py39compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/spawn.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/sysconfig.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/text_file.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/unixccompiler.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/util.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/version.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_distutils/versionpredicate.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_entry_points.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_imp.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_importlib.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_itertools.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_normalization.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_path.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_reqs.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_adapters.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_collections.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_functools.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_itertools.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_meta.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_py39compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_metadata/_text.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/_adapters.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/_common.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/_compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/_itertools.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/_legacy.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/abc.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/readers.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/importlib_resources/simple.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/jaraco/context.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/jaraco/functools.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/jaraco/text/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/more_itertools/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/more_itertools/more.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/more_itertools/recipes.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/_elffile.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/_parser.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/_tokenizer.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/metadata.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/tomli/_parser.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/_vendor/zipp.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/archive_util.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/build_meta.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/cli-32.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/cli-64.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/cli-arm64.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/cli.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/alias.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/bdist_egg.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/build.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/build_clib.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/build_ext.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/build_py.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/develop.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/dist_info.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/easy_install.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/editable_wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/egg_info.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/install.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/install_egg_info.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/install_lib.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/install_scripts.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/register.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/rotate.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/saveopts.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/sdist.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/setopt.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/test.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/upload.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/command/upload_docs.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/_apply_pyprojecttoml.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/expand.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/config/setupcfg.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/dep_util.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/depends.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/discovery.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/dist.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/errors.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/extension.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/extern/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/glob.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/gui-32.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/gui-64.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/gui-arm64.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/gui.exe create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/installer.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/launch.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/logging.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/monkey.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/msvc.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/namespaces.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/package_index.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/py312compat.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/sandbox.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/script (dev).tmpl create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/script.tmpl create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/unicode_utils.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/version.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/warnings.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/wheel.py create mode 100644 elitebot/lib/python3.11/site-packages/setuptools/windows_support.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/connectors/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/connectors/aioodbc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/connectors/asyncio.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/connectors/pyodbc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/__init__.py create mode 100755 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/collections.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/collections.pyx create mode 100755 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/immutabledict.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/immutabledict.pxd create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/immutabledict.pyx create mode 100755 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/processors.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/processors.pyx create mode 100755 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/resultproxy.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/resultproxy.pyx create mode 100755 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/util.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/cyextension/util.pyx create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/_typing.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/aioodbc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/information_schema.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/json.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/provision.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/pymssql.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mssql/pyodbc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/aiomysql.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/asyncmy.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/cymysql.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/dml.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/enumerated.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/expression.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/json.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/mariadb.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/mariadbconnector.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/mysqlconnector.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/mysqldb.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/provision.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/pymysql.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/pyodbc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/reflection.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/reserved_words.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/mysql/types.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/oracle/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/oracle/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/oracle/cx_oracle.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/oracle/dictionary.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/oracle/oracledb.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/oracle/provision.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/oracle/types.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/_psycopg_common.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/array.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/dml.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/ext.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/hstore.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/json.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/named_types.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/operators.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/pg8000.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/pg_catalog.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/provision.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/psycopg.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/psycopg2cffi.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/ranges.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/postgresql/types.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/aiosqlite.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/dml.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/json.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/provision.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/pysqlcipher.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/sqlite/pysqlite.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/dialects/type_migration_guidelines.txt create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/_py_processors.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/_py_row.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/_py_util.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/characteristics.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/create.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/cursor.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/default.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/events.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/interfaces.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/mock.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/processors.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/reflection.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/result.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/row.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/strategies.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/url.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/engine/util.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/event/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/event/api.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/event/attr.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/event/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/event/legacy.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/event/registry.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/events.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/exc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/associationproxy.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/asyncio/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/asyncio/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/asyncio/engine.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/asyncio/exc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/asyncio/result.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/asyncio/scoping.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/asyncio/session.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/automap.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/baked.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/compiler.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/declarative/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/declarative/extensions.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/horizontal_shard.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/hybrid.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/indexable.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/instrumentation.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mutable.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mypy/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mypy/apply.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mypy/decl_class.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mypy/infer.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mypy/names.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mypy/plugin.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/mypy/util.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/orderinglist.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/ext/serializer.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/future/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/future/engine.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/inspection.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/log.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/_orm_constructors.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/_typing.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/attributes.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/bulk_persistence.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/clsregistry.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/collections.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/context.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/decl_api.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/decl_base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/dependency.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/descriptor_props.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/dynamic.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/evaluator.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/events.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/exc.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/identity.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/instrumentation.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/interfaces.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/loading.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/mapped_collection.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/mapper.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/path_registry.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/persistence.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/properties.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/query.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/relationships.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/scoping.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/session.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/state.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/state_changes.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/strategies.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/strategy_options.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/sync.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/unitofwork.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/util.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/orm/writeonly.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/pool/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/pool/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/pool/events.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/pool/impl.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/py.typed create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/schema.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/_dml_constructors.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/_elements_constructors.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/_orm_types.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/_py_util.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/_selectable_constructors.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/_typing.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/annotation.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/cache_key.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/coercions.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/compiler.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/crud.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/ddl.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/default_comparator.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/dml.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/elements.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/events.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/expression.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/functions.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/lambdas.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/naming.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/operators.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/roles.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/schema.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/selectable.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/sqltypes.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/traversals.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/type_api.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/util.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/assertions.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/assertsql.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/asyncio.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/config.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/engines.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/entities.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/exclusions.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/fixtures/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/fixtures/base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/fixtures/mypy.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/fixtures/orm.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/fixtures/sql.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/pickleable.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/plugin/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/plugin/bootstrap.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/plugin/plugin_base.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/plugin/pytestplugin.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/profiling.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/provision.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/requirements.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/schema.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_cte.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_ddl.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_deprecations.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_dialect.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_insert.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_reflection.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_results.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_rowcount.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_select.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_sequence.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_types.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_unicode_ddl.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/suite/test_update_delete.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/util.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/testing/warnings.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/types.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/_collections.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/_concurrency_py3k.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/_has_cy.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/_py_collections.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/concurrency.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/deprecations.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/preloaded.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/queue.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/tool_support.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/topological.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy/util/typing.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/aggregates.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/asserts.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/compat.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/exceptions.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/expressions.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/functions/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/functions/database.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/functions/foreign_keys.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/functions/mock.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/functions/orm.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/functions/render.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/functions/sort_query.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/generic.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/i18n.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/listeners.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/models.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/observer.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/operators.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/path.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/primitives/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/primitives/country.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/primitives/currency.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/primitives/ltree.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/primitives/weekday.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/primitives/weekdays.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/proxy_dict.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/query_chain.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/relationships/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/relationships/chained_join.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/arrow.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/bit.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/choice.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/color.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/country.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/currency.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/email.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/encrypted/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/encrypted/encrypted_type.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/encrypted/padding.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/enriched_datetime/__init__.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/enriched_datetime/pendulum_date.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/ip_address.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/json.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/locale.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/ltree.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/password.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/pg_composite.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/phone_number.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/range.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/scalar_coercible.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/scalar_list.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/timezone.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/ts_vector.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/url.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/uuid.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/types/weekdays.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/utils.py create mode 100644 elitebot/lib/python3.11/site-packages/sqlalchemy_utils/view.py create mode 100644 elitebot/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/INSTALLER create mode 100644 elitebot/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/LICENSE create mode 100644 elitebot/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/METADATA create mode 100644 elitebot/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/RECORD create mode 100644 elitebot/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/REQUESTED create mode 100644 elitebot/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/WHEEL create mode 100644 elitebot/lib/python3.11/site-packages/typing_extensions.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/__init__.py create mode 100755 elitebot/lib/python3.11/site-packages/yaml/_yaml.cpython-311-x86_64-linux-gnu.so create mode 100644 elitebot/lib/python3.11/site-packages/yaml/composer.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/constructor.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/cyaml.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/dumper.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/emitter.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/error.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/events.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/loader.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/nodes.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/parser.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/reader.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/representer.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/resolver.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/scanner.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/serializer.py create mode 100644 elitebot/lib/python3.11/site-packages/yaml/tokens.py create mode 120000 elitebot/lib64 create mode 100644 elitebot/pyvenv.cfg delete mode 100644 logs/elitebot.log delete mode 100644 plugins/__pycache__/__init__.cpython-310.pyc delete mode 100644 plugins/__pycache__/__init__.cpython-311.pyc delete mode 100644 plugins/__pycache__/commands.cpython-310.pyc delete mode 100644 plugins/__pycache__/commands.cpython-311.pyc create mode 100644 plugins/hello.py delete mode 100644 src/__pycache__/__init__.cpython-310.pyc delete mode 100644 src/__pycache__/__init__.cpython-311.pyc delete mode 100644 src/__pycache__/bot.cpython-310.pyc delete mode 100644 src/__pycache__/bot.cpython-311.pyc delete mode 100644 src/__pycache__/channel_manager.cpython-310.pyc delete mode 100644 src/__pycache__/channel_manager.cpython-311.pyc delete mode 100644 src/__pycache__/event_handlers.cpython-310.pyc delete mode 100644 src/__pycache__/logger.cpython-310.pyc delete mode 100644 src/__pycache__/logger.cpython-311.pyc delete mode 100644 src/__pycache__/plugin_base.cpython-310.pyc delete mode 100644 src/__pycache__/plugin_base.cpython-311.pyc delete mode 100644 src/__pycache__/sasl.cpython-310.pyc delete mode 100644 src/__pycache__/sasl.cpython-311.pyc delete mode 100644 test.json diff --git a/config.yaml b/config.yaml index 041bd69..34c5ac2 100644 --- a/config.yaml +++ b/config.yaml @@ -6,10 +6,10 @@ Connection: Name: EliteBot BindHost: 0.0.0.0 SASL: - UseSASL: false + UseSASL: true SASLNick: EliteBot - SASLPassword: password + SASLPassword: 789abc// Logging: Console: true Database: - ConnectionString: mysql://user:password@host:port/database \ No newline at end of file + ConnectionString: mysql://user:password@host:port/database diff --git a/data/channels.json b/data/channels.json deleted file mode 100644 index 307193f..0000000 --- a/data/channels.json +++ /dev/null @@ -1 +0,0 @@ -["#EliteBot"] \ No newline at end of file diff --git a/elitebot/bin/Activate.ps1 b/elitebot/bin/Activate.ps1 new file mode 100644 index 0000000..b49d77b --- /dev/null +++ b/elitebot/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.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 VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # 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 virtual 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 + } + $env:VIRTUAL_ENV_PROMPT = $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/elitebot/bin/activate b/elitebot/bin/activate new file mode 100644 index 0000000..1597d21 --- /dev/null +++ b/elitebot/bin/activate @@ -0,0 +1,69 @@ +# 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 + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/home/colby/Documents/stuff/EliteBot/elitebot" +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="(elitebot) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(elitebot) " + export VIRTUAL_ENV_PROMPT +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/elitebot/bin/activate.csh b/elitebot/bin/activate.csh new file mode 100644 index 0000000..fe67370 --- /dev/null +++ b/elitebot/bin/activate.csh @@ -0,0 +1,26 @@ +# 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; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/colby/Documents/stuff/EliteBot/elitebot" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(elitebot) $prompt" + setenv VIRTUAL_ENV_PROMPT "(elitebot) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/elitebot/bin/activate.fish b/elitebot/bin/activate.fish new file mode 100644 index 0000000..285b55e --- /dev/null +++ b/elitebot/bin/activate.fish @@ -0,0 +1,69 @@ +# 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" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/colby/Documents/stuff/EliteBot/elitebot" + +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) "(elitebot) " (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" + set -gx VIRTUAL_ENV_PROMPT "(elitebot) " +end diff --git a/elitebot/bin/pip b/elitebot/bin/pip new file mode 100755 index 0000000..4b9d691 --- /dev/null +++ b/elitebot/bin/pip @@ -0,0 +1,8 @@ +#!/home/colby/Documents/stuff/EliteBot/elitebot/bin/python3 +# -*- 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/elitebot/bin/pip3 b/elitebot/bin/pip3 new file mode 100755 index 0000000..4b9d691 --- /dev/null +++ b/elitebot/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/colby/Documents/stuff/EliteBot/elitebot/bin/python3 +# -*- 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/elitebot/bin/pip3.11 b/elitebot/bin/pip3.11 new file mode 100755 index 0000000..4b9d691 --- /dev/null +++ b/elitebot/bin/pip3.11 @@ -0,0 +1,8 @@ +#!/home/colby/Documents/stuff/EliteBot/elitebot/bin/python3 +# -*- 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/elitebot/bin/python b/elitebot/bin/python new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/elitebot/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/elitebot/bin/python3 b/elitebot/bin/python3 new file mode 120000 index 0000000..ae65fda --- /dev/null +++ b/elitebot/bin/python3 @@ -0,0 +1 @@ +/usr/bin/python3 \ No newline at end of file diff --git a/elitebot/bin/python3.11 b/elitebot/bin/python3.11 new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/elitebot/bin/python3.11 @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/elitebot/include/site/python3.11/greenlet/greenlet.h b/elitebot/include/site/python3.11/greenlet/greenlet.h new file mode 100644 index 0000000..d02a16e --- /dev/null +++ b/elitebot/include/site/python3.11/greenlet/greenlet.h @@ -0,0 +1,164 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ + +/* Greenlet object interface */ + +#ifndef Py_GREENLETOBJECT_H +#define Py_GREENLETOBJECT_H + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is deprecated and undocumented. It does not change. */ +#define GREENLET_VERSION "1.0.0" + +#ifndef GREENLET_MODULE +#define implementation_ptr_t void* +#endif + +typedef struct _greenlet { + PyObject_HEAD + PyObject* weakreflist; + PyObject* dict; + implementation_ptr_t pimpl; +} PyGreenlet; + +#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) + + +/* C API functions */ + +/* Total number of symbols that are exported */ +#define PyGreenlet_API_pointers 12 + +#define PyGreenlet_Type_NUM 0 +#define PyExc_GreenletError_NUM 1 +#define PyExc_GreenletExit_NUM 2 + +#define PyGreenlet_New_NUM 3 +#define PyGreenlet_GetCurrent_NUM 4 +#define PyGreenlet_Throw_NUM 5 +#define PyGreenlet_Switch_NUM 6 +#define PyGreenlet_SetParent_NUM 7 + +#define PyGreenlet_MAIN_NUM 8 +#define PyGreenlet_STARTED_NUM 9 +#define PyGreenlet_ACTIVE_NUM 10 +#define PyGreenlet_GET_PARENT_NUM 11 + +#ifndef GREENLET_MODULE +/* This section is used by modules that uses the greenlet C API */ +static void** _PyGreenlet_API = NULL; + +# define PyGreenlet_Type \ + (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) + +# define PyExc_GreenletError \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) + +# define PyExc_GreenletExit \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) + +/* + * PyGreenlet_New(PyObject *args) + * + * greenlet.greenlet(run, parent=None) + */ +# define PyGreenlet_New \ + (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ + _PyGreenlet_API[PyGreenlet_New_NUM]) + +/* + * PyGreenlet_GetCurrent(void) + * + * greenlet.getcurrent() + */ +# define PyGreenlet_GetCurrent \ + (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) + +/* + * PyGreenlet_Throw( + * PyGreenlet *greenlet, + * PyObject *typ, + * PyObject *val, + * PyObject *tb) + * + * g.throw(...) + */ +# define PyGreenlet_Throw \ + (*(PyObject * (*)(PyGreenlet * self, \ + PyObject * typ, \ + PyObject * val, \ + PyObject * tb)) \ + _PyGreenlet_API[PyGreenlet_Throw_NUM]) + +/* + * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) + * + * g.switch(*args, **kwargs) + */ +# define PyGreenlet_Switch \ + (*(PyObject * \ + (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ + _PyGreenlet_API[PyGreenlet_Switch_NUM]) + +/* + * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) + * + * g.parent = new_parent + */ +# define PyGreenlet_SetParent \ + (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ + _PyGreenlet_API[PyGreenlet_SetParent_NUM]) + +/* + * PyGreenlet_GetParent(PyObject* greenlet) + * + * return greenlet.parent; + * + * This could return NULL even if there is no exception active. + * If it does not return NULL, you are responsible for decrementing the + * reference count. + */ +# define PyGreenlet_GetParent \ + (*(PyGreenlet* (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) + +/* + * deprecated, undocumented alias. + */ +# define PyGreenlet_GET_PARENT PyGreenlet_GetParent + +# define PyGreenlet_MAIN \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_MAIN_NUM]) + +# define PyGreenlet_STARTED \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_STARTED_NUM]) + +# define PyGreenlet_ACTIVE \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) + + + + +/* Macro that imports greenlet and initializes C API */ +/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we + keep the older definition to be sure older code that might have a copy of + the header still works. */ +# define PyGreenlet_Import() \ + { \ + _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ + } + +#endif /* GREENLET_MODULE */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GREENLETOBJECT_H */ diff --git a/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/INSTALLER b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/LICENSE b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/LICENSE new file mode 100644 index 0000000..2f1b8e1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.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/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/METADATA b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/METADATA new file mode 100644 index 0000000..c890598 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/METADATA @@ -0,0 +1,46 @@ +Metadata-Version: 2.1 +Name: PyYAML +Version: 6.0.1 +Summary: YAML parser and emitter for Python +Home-page: https://pyyaml.org/ +Download-URL: https://pypi.org/project/PyYAML/ +Author: Kirill Simonov +Author-email: xi@resolvent.net +License: MIT +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 :: 3.11 +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/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/RECORD b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/RECORD new file mode 100644 index 0000000..365419b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/RECORD @@ -0,0 +1,44 @@ +PyYAML-6.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +PyYAML-6.0.1.dist-info/LICENSE,sha256=jTko-dxEkP1jVwfLiOsmvXZBAqcoKVQwfT5RZ6V36KQ,1101 +PyYAML-6.0.1.dist-info/METADATA,sha256=UNNF8-SzzwOKXVo-kV5lXUGH2_wDWMBmGxqISpp5HQk,2058 +PyYAML-6.0.1.dist-info/RECORD,, +PyYAML-6.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +PyYAML-6.0.1.dist-info/WHEEL,sha256=8KU227XctfdX2qUwyjQUO-ciQuZtmyPUCKmeGV6Byto,152 +PyYAML-6.0.1.dist-info/top_level.txt,sha256=rpj0IVMTisAjh_1vG3Ccf9v5jpCQwAz6cD1IVU5ZdhQ,11 +_yaml/__init__.py,sha256=04Ae_5osxahpJHa3XBZUAf4wi6XX32gR8D6X6p64GEA,1402 +_yaml/__pycache__/__init__.cpython-311.pyc,, +yaml/__init__.py,sha256=bhl05qSeO-1ZxlSRjGrvl2m9nrXb1n9-GQatTN0Mrqc,12311 +yaml/__pycache__/__init__.cpython-311.pyc,, +yaml/__pycache__/composer.cpython-311.pyc,, +yaml/__pycache__/constructor.cpython-311.pyc,, +yaml/__pycache__/cyaml.cpython-311.pyc,, +yaml/__pycache__/dumper.cpython-311.pyc,, +yaml/__pycache__/emitter.cpython-311.pyc,, +yaml/__pycache__/error.cpython-311.pyc,, +yaml/__pycache__/events.cpython-311.pyc,, +yaml/__pycache__/loader.cpython-311.pyc,, +yaml/__pycache__/nodes.cpython-311.pyc,, +yaml/__pycache__/parser.cpython-311.pyc,, +yaml/__pycache__/reader.cpython-311.pyc,, +yaml/__pycache__/representer.cpython-311.pyc,, +yaml/__pycache__/resolver.cpython-311.pyc,, +yaml/__pycache__/scanner.cpython-311.pyc,, +yaml/__pycache__/serializer.cpython-311.pyc,, +yaml/__pycache__/tokens.cpython-311.pyc,, +yaml/_yaml.cpython-311-x86_64-linux-gnu.so,sha256=ls52EONnCPWCytU6wojl6RE4BhAUdu8LH3XIYfgpH0k,2504120 +yaml/composer.py,sha256=_Ko30Wr6eDWUeUpauUGT3Lcg9QPBnOPVlTnIMRGJ9FM,4883 +yaml/constructor.py,sha256=kNgkfaeLUkwQYY_Q6Ff1Tz2XVw_pG1xVE9Ak7z-viLA,28639 +yaml/cyaml.py,sha256=6ZrAG9fAYvdVe2FK_w0hmXoG7ZYsoYUwapG8CiC72H0,3851 +yaml/dumper.py,sha256=PLctZlYwZLp7XmeUdwRuv4nYOZ2UBnDIUy8-lKfLF-o,2837 +yaml/emitter.py,sha256=jghtaU7eFwg31bG0B7RZea_29Adi9CKmXq_QjgQpCkQ,43006 +yaml/error.py,sha256=Ah9z-toHJUbE9j-M8YpxgSRM5CgLCcwVzJgLLRF2Fxo,2533 +yaml/events.py,sha256=50_TksgQiE4up-lKo_V-nBy-tAIxkIPQxY5qDhKCeHw,2445 +yaml/loader.py,sha256=UVa-zIqmkFSCIYq_PgSGm4NSJttHY2Rf_zQ4_b1fHN0,2061 +yaml/nodes.py,sha256=gPKNj8pKCdh2d4gr3gIYINnPOaOxGhJAUiYhGRnPE84,1440 +yaml/parser.py,sha256=ilWp5vvgoHFGzvOZDItFoGjD6D42nhlZrZyjAwa0oJo,25495 +yaml/reader.py,sha256=0dmzirOiDG4Xo41RnuQS7K9rkY3xjHiVasfDMNTqCNw,6794 +yaml/representer.py,sha256=IuWP-cAW9sHKEnS0gCqSa894k1Bg4cgTxaDwIcbRQ-Y,14190 +yaml/resolver.py,sha256=9L-VYfm4mWHxUD1Vg4X7rjDRK_7VZd6b92wzq7Y2IKY,9004 +yaml/scanner.py,sha256=YEM3iLZSaQwXcQRg2l2R4MdT0zGP2F9eHkKGKnHyWQY,51279 +yaml/serializer.py,sha256=ChuFgmhU01hj4xgI8GaKv6vfM2Bujwa9i7d2FAHj7cA,4165 +yaml/tokens.py,sha256=lTQIzSVw8Mg9wv459-TjiOQe6wVziqaRlqX2_89rp54,2573 diff --git a/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/REQUESTED b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/WHEEL b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/WHEEL new file mode 100644 index 0000000..3bed0cb --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: false +Tag: cp311-cp311-manylinux_2_17_x86_64 +Tag: cp311-cp311-manylinux2014_x86_64 + diff --git a/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/top_level.txt b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/top_level.txt new file mode 100644 index 0000000..e6475e9 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/PyYAML-6.0.1.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_yaml +yaml diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/INSTALLER b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/LICENSE b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/LICENSE new file mode 100644 index 0000000..967cdc5 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright 2005-2024 SQLAlchemy authors and contributors . + +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/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/METADATA b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/METADATA new file mode 100644 index 0000000..e43a459 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/METADATA @@ -0,0 +1,242 @@ +Metadata-Version: 2.1 +Name: SQLAlchemy +Version: 2.0.27 +Summary: Database Abstraction Library +Home-page: https://www.sqlalchemy.org +Author: Mike Bayer +Author-email: mike_mp@zzzcomputing.com +License: MIT +Project-URL: Documentation, https://docs.sqlalchemy.org +Project-URL: Issue Tracker, https://github.com/sqlalchemy/sqlalchemy/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +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 :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Database :: Front-Ends +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: typing-extensions >=4.6.0 +Requires-Dist: greenlet !=0.4.17 ; platform_machine == "aarch64" or (platform_machine == "ppc64le" or (platform_machine == "x86_64" or (platform_machine == "amd64" or (platform_machine == "AMD64" or (platform_machine == "win32" or platform_machine == "WIN32"))))) +Requires-Dist: importlib-metadata ; python_version < "3.8" +Provides-Extra: aiomysql +Requires-Dist: greenlet !=0.4.17 ; extra == 'aiomysql' +Requires-Dist: aiomysql >=0.2.0 ; extra == 'aiomysql' +Provides-Extra: aioodbc +Requires-Dist: greenlet !=0.4.17 ; extra == 'aioodbc' +Requires-Dist: aioodbc ; extra == 'aioodbc' +Provides-Extra: aiosqlite +Requires-Dist: greenlet !=0.4.17 ; extra == 'aiosqlite' +Requires-Dist: aiosqlite ; extra == 'aiosqlite' +Requires-Dist: typing-extensions !=3.10.0.1 ; extra == 'aiosqlite' +Provides-Extra: asyncio +Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncio' +Provides-Extra: asyncmy +Requires-Dist: greenlet !=0.4.17 ; extra == 'asyncmy' +Requires-Dist: asyncmy !=0.2.4,!=0.2.6,>=0.2.3 ; extra == 'asyncmy' +Provides-Extra: mariadb_connector +Requires-Dist: mariadb !=1.1.2,!=1.1.5,>=1.0.1 ; extra == 'mariadb_connector' +Provides-Extra: mssql +Requires-Dist: pyodbc ; extra == 'mssql' +Provides-Extra: mssql_pymssql +Requires-Dist: pymssql ; extra == 'mssql_pymssql' +Provides-Extra: mssql_pyodbc +Requires-Dist: pyodbc ; extra == 'mssql_pyodbc' +Provides-Extra: mypy +Requires-Dist: mypy >=0.910 ; extra == 'mypy' +Provides-Extra: mysql +Requires-Dist: mysqlclient >=1.4.0 ; extra == 'mysql' +Provides-Extra: mysql_connector +Requires-Dist: mysql-connector-python ; extra == 'mysql_connector' +Provides-Extra: oracle +Requires-Dist: cx-oracle >=8 ; extra == 'oracle' +Provides-Extra: oracle_oracledb +Requires-Dist: oracledb >=1.0.1 ; extra == 'oracle_oracledb' +Provides-Extra: postgresql +Requires-Dist: psycopg2 >=2.7 ; extra == 'postgresql' +Provides-Extra: postgresql_asyncpg +Requires-Dist: greenlet !=0.4.17 ; extra == 'postgresql_asyncpg' +Requires-Dist: asyncpg ; extra == 'postgresql_asyncpg' +Provides-Extra: postgresql_pg8000 +Requires-Dist: pg8000 >=1.29.1 ; extra == 'postgresql_pg8000' +Provides-Extra: postgresql_psycopg +Requires-Dist: psycopg >=3.0.7 ; extra == 'postgresql_psycopg' +Provides-Extra: postgresql_psycopg2binary +Requires-Dist: psycopg2-binary ; extra == 'postgresql_psycopg2binary' +Provides-Extra: postgresql_psycopg2cffi +Requires-Dist: psycopg2cffi ; extra == 'postgresql_psycopg2cffi' +Provides-Extra: postgresql_psycopgbinary +Requires-Dist: psycopg[binary] >=3.0.7 ; extra == 'postgresql_psycopgbinary' +Provides-Extra: pymysql +Requires-Dist: pymysql ; extra == 'pymysql' +Provides-Extra: sqlcipher +Requires-Dist: sqlcipher3-binary ; extra == 'sqlcipher' + +SQLAlchemy +========== + +|PyPI| |Python| |Downloads| + +.. |PyPI| image:: https://img.shields.io/pypi/v/sqlalchemy + :target: https://pypi.org/project/sqlalchemy + :alt: PyPI + +.. |Python| image:: https://img.shields.io/pypi/pyversions/sqlalchemy + :target: https://pypi.org/project/sqlalchemy + :alt: PyPI - Python Version + +.. |Downloads| image:: https://static.pepy.tech/badge/sqlalchemy/month + :target: https://pepy.tech/project/sqlalchemy + :alt: PyPI - Downloads + + +The Python SQL Toolkit and Object Relational Mapper + +Introduction +------------- + +SQLAlchemy is the Python SQL toolkit and Object Relational Mapper +that gives application developers the full power and +flexibility of SQL. SQLAlchemy provides a full suite +of well known enterprise-level persistence patterns, +designed for efficient and high-performing database +access, adapted into a simple and Pythonic domain +language. + +Major SQLAlchemy features include: + +* An industrial strength ORM, built + from the core on the identity map, unit of work, + and data mapper patterns. These patterns + allow transparent persistence of objects + using a declarative configuration system. + Domain models + can be constructed and manipulated naturally, + and changes are synchronized with the + current transaction automatically. +* A relationally-oriented query system, exposing + the full range of SQL's capabilities + explicitly, including joins, subqueries, + correlation, and most everything else, + in terms of the object model. + Writing queries with the ORM uses the same + techniques of relational composition you use + when writing SQL. While you can drop into + literal SQL at any time, it's virtually never + needed. +* A comprehensive and flexible system + of eager loading for related collections and objects. + Collections are cached within a session, + and can be loaded on individual access, all + at once using joins, or by query per collection + across the full result set. +* A Core SQL construction system and DBAPI + interaction layer. The SQLAlchemy Core is + separate from the ORM and is a full database + abstraction layer in its own right, and includes + an extensible Python-based SQL expression + language, schema metadata, connection pooling, + type coercion, and custom types. +* All primary and foreign key constraints are + assumed to be composite and natural. Surrogate + integer primary keys are of course still the + norm, but SQLAlchemy never assumes or hardcodes + to this model. +* Database introspection and generation. Database + schemas can be "reflected" in one step into + Python structures representing database metadata; + those same structures can then generate + CREATE statements right back out - all within + the Core, independent of the ORM. + +SQLAlchemy's philosophy: + +* SQL databases behave less and less like object + collections the more size and performance start to + matter; object collections behave less and less like + tables and rows the more abstraction starts to matter. + SQLAlchemy aims to accommodate both of these + principles. +* An ORM doesn't need to hide the "R". A relational + database provides rich, set-based functionality + that should be fully exposed. SQLAlchemy's + ORM provides an open-ended set of patterns + that allow a developer to construct a custom + mediation layer between a domain model and + a relational schema, turning the so-called + "object relational impedance" issue into + a distant memory. +* The developer, in all cases, makes all decisions + regarding the design, structure, and naming conventions + of both the object model as well as the relational + schema. SQLAlchemy only provides the means + to automate the execution of these decisions. +* With SQLAlchemy, there's no such thing as + "the ORM generated a bad query" - you + retain full control over the structure of + queries, including how joins are organized, + how subqueries and correlation is used, what + columns are requested. Everything SQLAlchemy + does is ultimately the result of a developer-initiated + decision. +* Don't use an ORM if the problem doesn't need one. + SQLAlchemy consists of a Core and separate ORM + component. The Core offers a full SQL expression + language that allows Pythonic construction + of SQL constructs that render directly to SQL + strings for a target database, returning + result sets that are essentially enhanced DBAPI + cursors. +* Transactions should be the norm. With SQLAlchemy's + ORM, nothing goes to permanent storage until + commit() is called. SQLAlchemy encourages applications + to create a consistent means of delineating + the start and end of a series of operations. +* Never render a literal value in a SQL statement. + Bound parameters are used to the greatest degree + possible, allowing query optimizers to cache + query plans effectively and making SQL injection + attacks a non-issue. + +Documentation +------------- + +Latest documentation is at: + +https://www.sqlalchemy.org/docs/ + +Installation / Requirements +--------------------------- + +Full documentation for installation is at +`Installation `_. + +Getting Help / Development / Bug reporting +------------------------------------------ + +Please refer to the `SQLAlchemy Community Guide `_. + +Code of Conduct +--------------- + +Above all, SQLAlchemy places great emphasis on polite, thoughtful, and +constructive communication between users and developers. +Please see our current Code of Conduct at +`Code of Conduct `_. + +License +------- + +SQLAlchemy is distributed under the `MIT license +`_. + diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/RECORD b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/RECORD new file mode 100644 index 0000000..87edbb3 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/RECORD @@ -0,0 +1,530 @@ +SQLAlchemy-2.0.27.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +SQLAlchemy-2.0.27.dist-info/LICENSE,sha256=PA9Zq4h9BB3mpOUv_j6e212VIt6Qn66abNettue-MpM,1100 +SQLAlchemy-2.0.27.dist-info/METADATA,sha256=fZGrNxgSqoY_vLjP6pXy7Ax_9Fvpy6P0SN_Qmjpaf8M,9602 +SQLAlchemy-2.0.27.dist-info/RECORD,, +SQLAlchemy-2.0.27.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +SQLAlchemy-2.0.27.dist-info/WHEEL,sha256=AI1yqBLEPcVKWn5Ls2uPawjbqPXPFTYdQLSdN8WFCJw,152 +SQLAlchemy-2.0.27.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11 +sqlalchemy/__init__.py,sha256=s94qQVe-QqqRL9xhlih382KZikm_5rCLehCmTVeMkxo,13033 +sqlalchemy/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/__pycache__/events.cpython-311.pyc,, +sqlalchemy/__pycache__/exc.cpython-311.pyc,, +sqlalchemy/__pycache__/inspection.cpython-311.pyc,, +sqlalchemy/__pycache__/log.cpython-311.pyc,, +sqlalchemy/__pycache__/schema.cpython-311.pyc,, +sqlalchemy/__pycache__/types.cpython-311.pyc,, +sqlalchemy/connectors/__init__.py,sha256=PzXPqZqi3BzEnrs1eW0DcsR4lyknAzhhN9rWcQ97hb4,476 +sqlalchemy/connectors/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/connectors/__pycache__/aioodbc.cpython-311.pyc,, +sqlalchemy/connectors/__pycache__/asyncio.cpython-311.pyc,, +sqlalchemy/connectors/__pycache__/pyodbc.cpython-311.pyc,, +sqlalchemy/connectors/aioodbc.py,sha256=GSTiNMO9h0qjPxgqaxDwWZ8HvhWMFNVR6MJQnN1oc40,5288 +sqlalchemy/connectors/asyncio.py,sha256=6s4hDYfuMjJ9KbJ4s7bF1fp5DmcgV77ozgZ5-bwZ0wc,5955 +sqlalchemy/connectors/pyodbc.py,sha256=t7AjyxIOnaWg3CrlUEpBs4Y5l0HFdNt3P_cSSKhbi0Y,8501 +sqlalchemy/cyextension/__init__.py,sha256=GzhhN8cjMnDTE0qerlUlpbrNmFPHQWCZ4Gk74OAxl04,244 +sqlalchemy/cyextension/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/cyextension/collections.cpython-311-x86_64-linux-gnu.so,sha256=mMzAZiy3Z3NaEHsP_Ad-IvLCkvjbOZQCRwvS9PryJF4,2019496 +sqlalchemy/cyextension/collections.pyx,sha256=L7DZ3DGKpgw2MT2ZZRRxCnrcyE5pU1NAFowWgAzQPEc,12571 +sqlalchemy/cyextension/immutabledict.cpython-311-x86_64-linux-gnu.so,sha256=61zeVLfZ5ylDwnXZE8stoYcWJ1EcqMFiZid-L6Ihpss,703720 +sqlalchemy/cyextension/immutabledict.pxd,sha256=3x3-rXG5eRQ7bBnktZ-OJ9-6ft8zToPmTDOd92iXpB0,291 +sqlalchemy/cyextension/immutabledict.pyx,sha256=KfDTYbTfebstE8xuqAtuXsHNAK0_b5q_ymUiinUe_xs,3535 +sqlalchemy/cyextension/processors.cpython-311-x86_64-linux-gnu.so,sha256=1kmZ0XQH06gEr1jQNF3PGAhFFd_5K4N4IAzyNTvce78,509544 +sqlalchemy/cyextension/processors.pyx,sha256=R1rHsGLEaGeBq5VeCydjClzYlivERIJ9B-XLOJlf2MQ,1792 +sqlalchemy/cyextension/resultproxy.cpython-311-x86_64-linux-gnu.so,sha256=EZDMIii55WxmoXp6I2QV0zAOaFYVQuglOfTZtTxUxCU,586752 +sqlalchemy/cyextension/resultproxy.pyx,sha256=eWLdyBXiBy_CLQrF5ScfWJm7X0NeelscSXedtj1zv9Q,2725 +sqlalchemy/cyextension/util.cpython-311-x86_64-linux-gnu.so,sha256=ArvZ5z3oRLSMODlTRYQ4LrPMyyBpf3SJ5py9jD_0QII,870136 +sqlalchemy/cyextension/util.pyx,sha256=B85orxa9LddLuQEaDoVSq1XmAXIbLKxrxpvuB8ogV_o,2530 +sqlalchemy/dialects/__init__.py,sha256=Kos9Gf5JZg1Vg6GWaCqEbD6e0r1jCwCmcnJIfcxDdcY,1770 +sqlalchemy/dialects/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/__pycache__/_typing.cpython-311.pyc,, +sqlalchemy/dialects/_typing.py,sha256=hyv0nKucX2gI8ispB1IsvaUgrEPn9zEcq9hS7kfstEw,888 +sqlalchemy/dialects/mssql/__init__.py,sha256=r5t8wFRNtBQoiUWh0WfIEWzXZW6f3D0uDt6NZTW_7Cc,1880 +sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-311.pyc,, +sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-311.pyc,, +sqlalchemy/dialects/mssql/aioodbc.py,sha256=UQd9ecSMIML713TDnLAviuBVJle7P7i1FtqGZZePk2Y,2022 +sqlalchemy/dialects/mssql/base.py,sha256=2Tx9sC5bOd0JbweaMaqnjGOgESur7ZaaN1S66KMTwHk,133298 +sqlalchemy/dialects/mssql/information_schema.py,sha256=HswjDc6y0mPXCf_x6VyylHlBdBa4PSY6Evxmmlch700,8084 +sqlalchemy/dialects/mssql/json.py,sha256=evUACW2O62TAPq8B7QIPagz7jfc664ql9ms68JqiYzg,4816 +sqlalchemy/dialects/mssql/provision.py,sha256=RTVbgYLFAHzEnpVQDJroU8ji_10MqBTiZfyP9_-QNT4,5362 +sqlalchemy/dialects/mssql/pymssql.py,sha256=eZRLz7HGt3SdoZUjFBmA9BS43N7AhIASw7VPBPEJuG0,4038 +sqlalchemy/dialects/mssql/pyodbc.py,sha256=vwM-vBlmRwrqxOc73P0sFOrBSwn24wzc5IkEOpalbXQ,27056 +sqlalchemy/dialects/mysql/__init__.py,sha256=bxbi4hkysUK2OOVvr1F49akUj1cky27kKb07tgFzI9U,2153 +sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/expression.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-311.pyc,, +sqlalchemy/dialects/mysql/__pycache__/types.cpython-311.pyc,, +sqlalchemy/dialects/mysql/aiomysql.py,sha256=67JrSUD1BmN88k_ASk6GvrttZFQiFjDY0wBiwdllxMk,9964 +sqlalchemy/dialects/mysql/asyncmy.py,sha256=CGILIRKf_2Ut9Ng2yBlmdg62laL-ockEm6GMuN7xlKE,10033 +sqlalchemy/dialects/mysql/base.py,sha256=KA7tvRxKUw0KwHwMth2rz-NWV0xMkVbYvPoBM9wrAFw,120850 +sqlalchemy/dialects/mysql/cymysql.py,sha256=eXT1ry0w_qRxjiO24M980c-8PZ9qSsbhqBHntjEiKB0,2300 +sqlalchemy/dialects/mysql/dml.py,sha256=HXJMAvimJsqvhj3UZO4vW_6LkF5RqaKbHvklAjor7yU,7645 +sqlalchemy/dialects/mysql/enumerated.py,sha256=ipEPPQqoXfFwcywNdcLlZCEzHBtnitHRah1Gn6nItcg,8448 +sqlalchemy/dialects/mysql/expression.py,sha256=lsmQCHKwfPezUnt27d2kR6ohk4IRFCA64KBS16kx5dc,4097 +sqlalchemy/dialects/mysql/json.py,sha256=l6MEZ0qp8FgiRrIQvOMhyEJq0q6OqiEnvDTx5Cbt9uQ,2269 +sqlalchemy/dialects/mysql/mariadb.py,sha256=kTfBLioLKk4JFFst4TY_iWqPtnvvQXFHknLfm89H2N8,853 +sqlalchemy/dialects/mysql/mariadbconnector.py,sha256=VVRwKLb6GzDmitOM4wLNvmZw6RdhnIwkLl7IZfAmUy8,8734 +sqlalchemy/dialects/mysql/mysqlconnector.py,sha256=qiQdfLPze3QHuASAZ9iqRzD0hDW8FbKoQnfAEQCF7tM,5675 +sqlalchemy/dialects/mysql/mysqldb.py,sha256=9x_JiY4hj4tykG1ckuEGPyH4jCtsh4fgBhNukVnjUos,9658 +sqlalchemy/dialects/mysql/provision.py,sha256=4oGkClQ8jC3YLPF54sB4kCjFc8HRTwf5zl5zftAAXGo,3474 +sqlalchemy/dialects/mysql/pymysql.py,sha256=GUnSHd2M2uKjmN46Hheymtm26g7phEgwYOXrX0zLY8M,4083 +sqlalchemy/dialects/mysql/pyodbc.py,sha256=072crI4qVyPhajYvHnsfFeSrNjLFVPIjBQKo5uyz5yk,4297 +sqlalchemy/dialects/mysql/reflection.py,sha256=XXM8AGpaRTqDvuObg89Bzn_4h2ETG03viYBpWZJM3vc,22822 +sqlalchemy/dialects/mysql/reserved_words.py,sha256=Dm7FINIAkrKLoXmdu26SpE6V8LDCGyp734nmHV2tMd0,9154 +sqlalchemy/dialects/mysql/types.py,sha256=aPzx7hqqZ21aGwByEC-yWZUl6OpMvkbxwTqdN3OUGGI,24267 +sqlalchemy/dialects/oracle/__init__.py,sha256=p4-2gw7TT0bX_MoJXTGD4i8WHctYsK9kCRbkpzykBrc,1493 +sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/oracle/__pycache__/types.cpython-311.pyc,, +sqlalchemy/dialects/oracle/base.py,sha256=-7b5iubFPxJyDRoLXlxj8rk8eBRN2_IdZlB2zzzrrbw,118246 +sqlalchemy/dialects/oracle/cx_oracle.py,sha256=t5yH4svVz7xoDSITF958blgZ01hbCUEWUKrAXwiCiAE,55566 +sqlalchemy/dialects/oracle/dictionary.py,sha256=7WMrbPkqo8ZdGjaEZyQr-5f2pajSOF1OTGb8P97z8-g,19519 +sqlalchemy/dialects/oracle/oracledb.py,sha256=UFcZwrrk0pWfAp_SKJZ1B5rIQHtNhOvuu73_JaSnTbI,9487 +sqlalchemy/dialects/oracle/provision.py,sha256=O9ZpF4OG6Cx4mMzLRfZwhs8dZjrJETWR402n9c7726A,8304 +sqlalchemy/dialects/oracle/types.py,sha256=QK3hJvWzKnnCe3oD3rItwEEIwcoBze8qGg7VFOvVlIk,8231 +sqlalchemy/dialects/postgresql/__init__.py,sha256=kwgzMhtZKDHD12HMGo5MtdKCnDdy6wLezDGZPOEoU3Q,3895 +sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/array.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/__pycache__/types.cpython-311.pyc,, +sqlalchemy/dialects/postgresql/_psycopg_common.py,sha256=7TudtgsPiSB8O5kX8W8KxcNYR8t5h_UHb86b_ChL0P8,5696 +sqlalchemy/dialects/postgresql/array.py,sha256=9dJ_1WjWSBX1-MGDZtJACJ38vtRO3da7d4UId79WsnQ,13713 +sqlalchemy/dialects/postgresql/asyncpg.py,sha256=12DN8hlK-Na_bEFmQ5kXK7MRqu87ze2IMX8aDyiSddU,40183 +sqlalchemy/dialects/postgresql/base.py,sha256=ogY8rcQvT9jjYdtStxZ_nhTl8LmhB_zeJyhZIaUyMLk,176486 +sqlalchemy/dialects/postgresql/dml.py,sha256=Pc69Le6qzmUHHb1FT5zeUSD31dWm6SBgdCAGW89cs3s,11212 +sqlalchemy/dialects/postgresql/ext.py,sha256=1bZ--iNh2O9ym7l2gXZX48yP3yMO4dqb9RpYro2Mj2Q,16262 +sqlalchemy/dialects/postgresql/hstore.py,sha256=otAx-RTDfpi_tcXkMuQV0JOIXtYgevgnsikLKKOkI6U,11541 +sqlalchemy/dialects/postgresql/json.py,sha256=-ffnp85fQBOyt0Bjb7XAupmOxloUdzFZZgixUG3Wj5w,11212 +sqlalchemy/dialects/postgresql/named_types.py,sha256=SFhs9_l108errKNuAMPl761RQ2imTO9PbUAnSv-WtRg,17100 +sqlalchemy/dialects/postgresql/operators.py,sha256=NsAaWun_tL3d_be0fs9YL6T4LPKK6crnmFxxIJHgyeY,2808 +sqlalchemy/dialects/postgresql/pg8000.py,sha256=3yoekiWSF-xnaWMqG76XrYPMqerg-42TdmfsW_ivK9E,18640 +sqlalchemy/dialects/postgresql/pg_catalog.py,sha256=nAKavWTE_4cqxiDKDTdo-ivkCxxRIlzD5GO9Wl1yrG4,8884 +sqlalchemy/dialects/postgresql/provision.py,sha256=yqyx-aDFO9l2YcL9f4T5HBP_Lnt5dHsMjpuXUG8mi7A,5762 +sqlalchemy/dialects/postgresql/psycopg.py,sha256=TF53axr1EkTBAZD85JCq6wA7XTcJTzXueSz26txDbgc,22364 +sqlalchemy/dialects/postgresql/psycopg2.py,sha256=gAP3poHDUxEB6iut6sxe9PhBiOrV_iIMvnP0NUlC-Rw,31607 +sqlalchemy/dialects/postgresql/psycopg2cffi.py,sha256=M7wAYSL6Pvt-4nbfacAHGyyw4XMKJ_bQZ1tc1pBtIdg,1756 +sqlalchemy/dialects/postgresql/ranges.py,sha256=6CgV7qkxEMJ9AQsiibo_XBLJYzGh-2ZxpG83sRaesVY,32949 +sqlalchemy/dialects/postgresql/types.py,sha256=Jfxqw9JaKNOq29JRWBublywgb3lLMyzx8YZI7CXpS2s,7300 +sqlalchemy/dialects/sqlite/__init__.py,sha256=lp9DIggNn349M-7IYhUA8et8--e8FRExWD2V_r1LJk4,1182 +sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/base.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/json.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-311.pyc,, +sqlalchemy/dialects/sqlite/aiosqlite.py,sha256=OMvxP2eWyqk5beF-sHhzxRmjzO4VCQp55q7NH2XPVTE,12305 +sqlalchemy/dialects/sqlite/base.py,sha256=lUtigjn7NdPBq831zQsLcBwdwRJqdgKM_tUaDrMElOE,96794 +sqlalchemy/dialects/sqlite/dml.py,sha256=9GE55WvwoktKy2fHeT-Wbc9xPHgsbh5oBfd_fckMH5Q,8443 +sqlalchemy/dialects/sqlite/json.py,sha256=Eoplbb_4dYlfrtmQaI8Xddd2suAIHA-IdbDQYM-LIhs,2777 +sqlalchemy/dialects/sqlite/provision.py,sha256=UCpmwxf4IWlrpb2eLHGbPTpCFVbdI_KAh2mKtjiLYao,5632 +sqlalchemy/dialects/sqlite/pysqlcipher.py,sha256=OL2S_05DK9kllZj6DOz7QtEl7jI7syxjW6woS725ii4,5356 +sqlalchemy/dialects/sqlite/pysqlite.py,sha256=TAOqsHIjhbUZOF_Qk7UooiekkVZNhYJNduxlGQjokeA,27900 +sqlalchemy/dialects/type_migration_guidelines.txt,sha256=-uHNdmYFGB7bzUNT6i8M5nb4j6j9YUKAtW4lcBZqsMg,8239 +sqlalchemy/engine/__init__.py,sha256=Stb2oV6l8w65JvqEo6J4qtKoApcmOpXy3AAxQud4C1o,2818 +sqlalchemy/engine/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/_py_processors.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/_py_row.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/_py_util.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/base.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/characteristics.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/create.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/cursor.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/default.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/events.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/interfaces.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/mock.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/processors.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/reflection.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/result.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/row.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/strategies.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/url.cpython-311.pyc,, +sqlalchemy/engine/__pycache__/util.cpython-311.pyc,, +sqlalchemy/engine/_py_processors.py,sha256=j9i_lcYYQOYJMcsDerPxI0sVFBIlX5sqoYMdMJlgWPI,3744 +sqlalchemy/engine/_py_row.py,sha256=wSqoUFzLOJ1f89kgDb6sJm9LUrF5LMFpXPcK1vUsKcs,3787 +sqlalchemy/engine/_py_util.py,sha256=f2DI3AN1kv6EplelowesCVpwS8hSXNufRkZoQmJtSH8,2484 +sqlalchemy/engine/base.py,sha256=NGD1iokXsJBw_6sBOpX4STo_05fQFd52qUl1YiJZsdU,122038 +sqlalchemy/engine/characteristics.py,sha256=Qbvt4CPrggJ3GfxHl0hOAxopjnCQy-W_pjtwLIe-Q1g,2590 +sqlalchemy/engine/create.py,sha256=5Me7rgLvmZVJM6QzoH8aBHz0lIratA2vXN8cW6kUgdY,32872 +sqlalchemy/engine/cursor.py,sha256=jSjpGM5DiwX1pwEHGx3wyqgHrgj8rwU5ZpVvMv5GaJs,74443 +sqlalchemy/engine/default.py,sha256=VSqSm-juosz-5WqZPWjgDQf8Fra27M-YsrVVcs7RwPU,84672 +sqlalchemy/engine/events.py,sha256=c0unNFFiHzTAvkUtXoJaxzMFMDwurBkHiiUhuN8qluc,37381 +sqlalchemy/engine/interfaces.py,sha256=gktNzgLjNK-KrYMU__Lk0h85SXQI8LCjDakkuLxagNE,112688 +sqlalchemy/engine/mock.py,sha256=yvpxgFmRw5G4QsHeF-ZwQGHKES-HqQOucTxFtN1uzdk,4179 +sqlalchemy/engine/processors.py,sha256=XyfINKbo-2fjN-mW55YybvFyQMOil50_kVqsunahkNs,2379 +sqlalchemy/engine/reflection.py,sha256=FlT5kPpKm7Lah50GNt5XcnlJWojTL3LD_x0SoCF9kfY,75127 +sqlalchemy/engine/result.py,sha256=j6BI4Wj2bziQNQG5OlG_Cm4KcNWY9AoYvTXVlJUU-D8,77603 +sqlalchemy/engine/row.py,sha256=9AAQo9zYDL88GcZ3bjcQTwMT-YIcuGTSMAyTfmBJ_yM,12032 +sqlalchemy/engine/strategies.py,sha256=DqFSWaXJPL-29Omot9O0aOcuGL8KmCGyOvnPGDkAJoE,442 +sqlalchemy/engine/url.py,sha256=8eWkUaIUyDExOcJ2D4xJXRcn4OY1GQJ3Q2duSX6UGAg,30784 +sqlalchemy/engine/util.py,sha256=hkEql1t19WHl6uzR55-F-Fs_VMCJ7p02KKQVNUDSXTk,5667 +sqlalchemy/event/__init__.py,sha256=KBrp622xojnC3FFquxa2JsMamwAbfkvzfv6Op0NKiYc,997 +sqlalchemy/event/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/event/__pycache__/api.cpython-311.pyc,, +sqlalchemy/event/__pycache__/attr.cpython-311.pyc,, +sqlalchemy/event/__pycache__/base.cpython-311.pyc,, +sqlalchemy/event/__pycache__/legacy.cpython-311.pyc,, +sqlalchemy/event/__pycache__/registry.cpython-311.pyc,, +sqlalchemy/event/api.py,sha256=BUTAZjSlzvq4Hn2v2pihP_P1yo3lvCVDczK8lV_XJ80,8227 +sqlalchemy/event/attr.py,sha256=X8QeHGK4ioSYht1vkhc11f606_mq_t91jMNIT314ubs,20751 +sqlalchemy/event/base.py,sha256=3n9FmUkcXYHHyGzfpjKDsrIUVCNST_hq4zOtrNm0_a4,14954 +sqlalchemy/event/legacy.py,sha256=teMPs00fO-4g8a_z2omcVKkYce5wj_1uvJO2n2MIeuo,8227 +sqlalchemy/event/registry.py,sha256=nfTSSyhjZZXc5wseWB4sXn-YibSc0LKX8mg17XlWmAo,10835 +sqlalchemy/events.py,sha256=k-ZD38aSPD29LYhED7CBqttp5MDVVx_YSaWC2-cu9ec,525 +sqlalchemy/exc.py,sha256=M_8-O1hd8i6gbyx-TapV400p_Lxq2QqTGMXUAO-YgCc,23976 +sqlalchemy/ext/__init__.py,sha256=S1fGKAbycnQDV01gs-JWGaFQ9GCD4QHwKcU2wnugg_o,322 +sqlalchemy/ext/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/associationproxy.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/automap.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/baked.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/compiler.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/horizontal_shard.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/hybrid.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/indexable.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/instrumentation.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/mutable.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/orderinglist.cpython-311.pyc,, +sqlalchemy/ext/__pycache__/serializer.cpython-311.pyc,, +sqlalchemy/ext/associationproxy.py,sha256=5O5ANHARO8jytvqBQmOu-QjNVE4Hh3tfYquqKAj5ajs,65771 +sqlalchemy/ext/asyncio/__init__.py,sha256=1OqSxEyIUn7RWLGyO12F-jAUIvk1I6DXlVy80-Gvkds,1317 +sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/base.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/engine.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/exc.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/result.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-311.pyc,, +sqlalchemy/ext/asyncio/__pycache__/session.cpython-311.pyc,, +sqlalchemy/ext/asyncio/base.py,sha256=fl7wxZD9KjgFiCtG3WXrYjHEvanamcsodCqq9pH9lOk,8905 +sqlalchemy/ext/asyncio/engine.py,sha256=vQRdpBnGuyzyG48ZssDZvFlcS6Y6ZXUYI0GEOQqdDxk,47941 +sqlalchemy/ext/asyncio/exc.py,sha256=8sII7VMXzs2TrhizhFQMzSfcroRtiesq8o3UwLfXSgQ,639 +sqlalchemy/ext/asyncio/result.py,sha256=ID2eh-NHW-lnNFTxbKhje8fr-tnsucUsiw_jcpGcSPc,30409 +sqlalchemy/ext/asyncio/scoping.py,sha256=BmE1UbFV_C4BXB4WngJc523DeMH-nTchNb8ORiSPYfE,52597 +sqlalchemy/ext/asyncio/session.py,sha256=Zhkrwwc4rqZJntUpzbgruQNgpuOwaRmjrBQb8ol19z0,62894 +sqlalchemy/ext/automap.py,sha256=hBlKAfZn2fgAAQh7vh4f2kClbb5ryOgV59tzVHEObQM,61389 +sqlalchemy/ext/baked.py,sha256=H6T1il7GY84BhzPFj49UECSpZh_eBuiHomA-QIsYOYQ,17807 +sqlalchemy/ext/compiler.py,sha256=ONPoxoKD2yUS9R2-oOhmPsA7efm-Bs0BXo7HE1dGlsU,20391 +sqlalchemy/ext/declarative/__init__.py,sha256=20psLdFQbbOWfpdXHZ0CTY6I1k4UqXvKemNVu1LvPOI,1818 +sqlalchemy/ext/declarative/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/declarative/__pycache__/extensions.cpython-311.pyc,, +sqlalchemy/ext/declarative/extensions.py,sha256=uCjN1GisQt54AjqYnKYzJdUjnGd2pZBW47WWdPlS7FE,19547 +sqlalchemy/ext/horizontal_shard.py,sha256=wuwAPnHymln0unSBnyx-cpX0AfESKSsypaSQTYCvzDk,16750 +sqlalchemy/ext/hybrid.py,sha256=LXph2NOtBQj6rZMi5ar-WCxkY7qaFp-o-UFIvCy-ep0,52432 +sqlalchemy/ext/indexable.py,sha256=UkTelbydKCdKelzbv3HWFFavoET9WocKaGRPGEOVfN8,11032 +sqlalchemy/ext/instrumentation.py,sha256=sg8ghDjdHSODFXh_jAmpgemnNX1rxCeeXEG3-PMdrNk,15707 +sqlalchemy/ext/mutable.py,sha256=L5ZkHBGYhMaqO75Xtyrk2DBR44RDk0g6Rz2HzHH0F8Q,37355 +sqlalchemy/ext/mypy/__init__.py,sha256=0WebDIZmqBD0OTq5JLtd_PmfF9JGxe4d4Qv3Ml3PKUg,241 +sqlalchemy/ext/mypy/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/apply.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/infer.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/names.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/plugin.cpython-311.pyc,, +sqlalchemy/ext/mypy/__pycache__/util.cpython-311.pyc,, +sqlalchemy/ext/mypy/apply.py,sha256=Aek_-XA1eXihT4attxhfE43yBKtCgsxBSb--qgZKUqc,10550 +sqlalchemy/ext/mypy/decl_class.py,sha256=1vVJRII2apnLTUbc5HkJS6Z2GueaUv_eKvhbqh7Wik4,17384 +sqlalchemy/ext/mypy/infer.py,sha256=KVnmLFEVS33Al8pUKI7MJbJQu3KeveBUMl78EluBORw,19369 +sqlalchemy/ext/mypy/names.py,sha256=IQ16GLZFqKxfYxIZxkbTurBqOUYbUV-64V_DSRns1tc,10630 +sqlalchemy/ext/mypy/plugin.py,sha256=74ML8LI9xar0V86oCxnPFv5FQGEEfUzK64vOay4BKFs,9750 +sqlalchemy/ext/mypy/util.py,sha256=1zuDQG8ezmF-XhJmAQU_lcBHiD--sL-lq20clg8t4lE,9448 +sqlalchemy/ext/orderinglist.py,sha256=TGYbsGH72wEZcFNQDYDsZg9OSPuzf__P8YX8_2HtYUo,14384 +sqlalchemy/ext/serializer.py,sha256=YemanWdeMVUDweHCnQc-iMO6mVVXNo2qQ5NK0Eb2_Es,6178 +sqlalchemy/future/__init__.py,sha256=q2mw-gxk_xoxJLEvRoyMha3vO1xSRHrslcExOHZwmPA,512 +sqlalchemy/future/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/future/__pycache__/engine.cpython-311.pyc,, +sqlalchemy/future/engine.py,sha256=AgIw6vMsef8W6tynOTkxsjd6o_OQDwGjLdbpoMD8ue8,495 +sqlalchemy/inspection.py,sha256=MF-LE358wZDUEl1IH8-Uwt2HI65EsQpQW5o5udHkZwA,5063 +sqlalchemy/log.py,sha256=8x9UR3nj0uFm6or6bQF-JWb4fYv2zOeQjG_w-0wOJFA,8607 +sqlalchemy/orm/__init__.py,sha256=ZYys5nL3RFUDCMOLFDBrRI52F6er3S1U1OY9TeORuKs,8463 +sqlalchemy/orm/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/_orm_constructors.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/_typing.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/attributes.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/base.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/bulk_persistence.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/clsregistry.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/collections.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/context.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/decl_api.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/decl_base.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/dependency.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/descriptor_props.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/dynamic.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/evaluator.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/events.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/exc.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/identity.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/instrumentation.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/interfaces.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/loading.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/mapped_collection.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/mapper.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/path_registry.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/persistence.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/properties.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/query.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/relationships.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/scoping.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/session.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/state.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/state_changes.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/strategies.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/strategy_options.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/sync.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/unitofwork.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/util.cpython-311.pyc,, +sqlalchemy/orm/__pycache__/writeonly.cpython-311.pyc,, +sqlalchemy/orm/_orm_constructors.py,sha256=VWY_MotbcQlECGx2uwEu3IcRkZ4RgLM_ufPad3IA9ZM,99354 +sqlalchemy/orm/_typing.py,sha256=DVBfpHmDVK4x1zxaGJPY2GoTrAsyR6uexv20Lzf1afc,4973 +sqlalchemy/orm/attributes.py,sha256=-IGg2RFjOPwAEr-boohvlZfitz7OtaXz1v8-7uG8ekw,92520 +sqlalchemy/orm/base.py,sha256=HhuarpRU-BpKSHE1LeeBaG8CpdkwwLrvTkUVRK-ofjg,27424 +sqlalchemy/orm/bulk_persistence.py,sha256=SSSR0Omv8A8BzpsOdSo4x75XICoqGpO1sUkyEWUVGso,70022 +sqlalchemy/orm/clsregistry.py,sha256=29LyYiuj0qbebOpgW6DbBPNB2ikTweFQar1byCst7I0,17958 +sqlalchemy/orm/collections.py,sha256=jpMsJGVixmrW9kfT8wevm9kpatKRqyDLcqWd7CjKPxE,52179 +sqlalchemy/orm/context.py,sha256=Wjx0d1Rkxd-wsX1mP2V2_4VbOxdNY6S_HijdXJ-TtKg,112001 +sqlalchemy/orm/decl_api.py,sha256=0gCZWM2sOXb_4OzUXfevVUisZWOUrErQTAHyaSQQL5k,63674 +sqlalchemy/orm/decl_base.py,sha256=Tq6I3Jm3bkM01mmoiHfdFXLE94YDk1ik2u2dXL1RxLc,81601 +sqlalchemy/orm/dependency.py,sha256=hgjksUWhgbmgHK5GdJdiDCBgDAIGQXIrY-Tj79tbL2k,47631 +sqlalchemy/orm/descriptor_props.py,sha256=pKtpP7H1LB_YuHRVrEYpfFZybEnUUdPwQXxduYFe2hA,37180 +sqlalchemy/orm/dynamic.py,sha256=jksBDCOsm6EBMVParcNGuMeaAv12hX4IzouKspC-HPA,9786 +sqlalchemy/orm/evaluator.py,sha256=q292K5vdpP69G7Z9y1RqI5GFAk2diUPwnsXE8De_Wgw,11925 +sqlalchemy/orm/events.py,sha256=_Ttun_bCSGgvsfg-VzAeEcsGpacf8p4c5z12JkSQkjM,127697 +sqlalchemy/orm/exc.py,sha256=w7MZkJMGGlu5J6jOFSmi9XXzc02ctnTv34jrEWpI-eM,7356 +sqlalchemy/orm/identity.py,sha256=jHdCxCpCyda_8mFOfGmN_Pr0XZdKiU-2hFZshlNxbHs,9249 +sqlalchemy/orm/instrumentation.py,sha256=M-kZmkUvHUxtf-0mCA8RIM5QmMH1hWlYR_pKMwaidjA,24321 +sqlalchemy/orm/interfaces.py,sha256=1yyppjMHcP5NPXjxfOlSeFNmc-3_T_o2upeF3KFZtc0,48378 +sqlalchemy/orm/loading.py,sha256=JN2zLnPjNnk7K9DERbyerxESCXin7m7X1XP0gfdWLOE,57537 +sqlalchemy/orm/mapped_collection.py,sha256=3cneB1dfPTLrsTvKoo9_oCY2xtq4UAHfe5WSXPyqIS4,19690 +sqlalchemy/orm/mapper.py,sha256=8SVHr7tO-DDNpNGi68usc7PLQ7mTwzkZNEJu1aMb6dQ,171059 +sqlalchemy/orm/path_registry.py,sha256=bIXllBRevK7Ic5irajYnZgl2iazJ0rKNRkhXJSlfxjY,25850 +sqlalchemy/orm/persistence.py,sha256=dzyB2JOXNwQgaCbN8kh0sEz00WFePr48qf8NWVCUZH8,61701 +sqlalchemy/orm/properties.py,sha256=81I-PIF7f7bB0qdH4BCYMWzCzRpe57yUiEIPv2tzBoA,29127 +sqlalchemy/orm/query.py,sha256=UVNWn_Rq4a8agh5UUWNeu0DJQtPceCWVpXx1-uW7A4E,117555 +sqlalchemy/orm/relationships.py,sha256=DqD3WBKpeVQ59ldh6eCxar_sIToA3tc2-bJPtp3zfpM,127709 +sqlalchemy/orm/scoping.py,sha256=gFYywLeMmd5qjFdVPzeuCX727mTaChrCv8aqn4wPke0,78677 +sqlalchemy/orm/session.py,sha256=yiKyoJBARQj4I1ZBjsIxc6ecCpt2Upjvlxruo2A5HRc,193181 +sqlalchemy/orm/state.py,sha256=mW2f1hMSNeTJ89foutOE1EqLLD6DZkrSeO-pgagZweg,37520 +sqlalchemy/orm/state_changes.py,sha256=qKYg7NxwrDkuUY3EPygAztym6oAVUFcP2wXn7QD3Mz4,6815 +sqlalchemy/orm/strategies.py,sha256=OtmMtWpCDk4ZiaM_ipzGn80sPOi6Opwj3Co4lUHpd_w,114206 +sqlalchemy/orm/strategy_options.py,sha256=RbFl-79Lrh8XIVUnZFmQ5GVvR586SG_szs3prw5DZLQ,84204 +sqlalchemy/orm/sync.py,sha256=g7iZfSge1HgxMk9SKRgUgtHEbpbZ1kP_CBqOIdTOXqc,5779 +sqlalchemy/orm/unitofwork.py,sha256=fiVaqcymbDDHRa1NjS90N9Z466nd5pkJOEi1dHO6QLY,27033 +sqlalchemy/orm/util.py,sha256=MSLKAWZNw3FzFTH094xpfrhoA2Ov5pJQinK_dU_M0zo,80351 +sqlalchemy/orm/writeonly.py,sha256=SYu2sAaHZONk2pW4PmtE871LG-O0P_bjidvKzY1H_zI,22305 +sqlalchemy/pool/__init__.py,sha256=qiDdq4r4FFAoDrK6ncugF_i6usi_X1LeJt-CuBHey0s,1804 +sqlalchemy/pool/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/pool/__pycache__/base.cpython-311.pyc,, +sqlalchemy/pool/__pycache__/events.cpython-311.pyc,, +sqlalchemy/pool/__pycache__/impl.cpython-311.pyc,, +sqlalchemy/pool/base.py,sha256=WF4az4ZKuzQGuKeSJeyexaYjmWZUvYdC6KIi8zTGodw,52236 +sqlalchemy/pool/events.py,sha256=xGjkIUZl490ZDtCHqnQF9ZCwe2Jv93eGXmnQxftB11E,13147 +sqlalchemy/pool/impl.py,sha256=2k2YMY9AepEoqGD_ClP_sUodSoa6atkt3GLPPWI49i4,17717 +sqlalchemy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sqlalchemy/schema.py,sha256=dKiWmgHYjcKQ4TiiD6vD0UMmIsD8u0Fsor1M9AAeGUs,3194 +sqlalchemy/sql/__init__.py,sha256=UNa9EUiYWoPayf-FzNcwVgQvpsBdInPZfpJesAStN9o,5820 +sqlalchemy/sql/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_dml_constructors.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_elements_constructors.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_orm_types.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_py_util.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/_typing.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/annotation.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/base.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/cache_key.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/coercions.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/compiler.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/crud.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/ddl.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/default_comparator.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/dml.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/elements.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/events.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/expression.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/functions.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/lambdas.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/naming.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/operators.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/roles.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/schema.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/selectable.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/sqltypes.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/traversals.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/type_api.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/util.cpython-311.pyc,, +sqlalchemy/sql/__pycache__/visitors.cpython-311.pyc,, +sqlalchemy/sql/_dml_constructors.py,sha256=YdBJex0MCVACv4q2nl_ii3uhxzwU6aDB8zAsratX5UQ,3867 +sqlalchemy/sql/_elements_constructors.py,sha256=rrxq5Nzyo7GbLaGxb8VRZxko2nW0z7SYEli8ArfMIXI,62550 +sqlalchemy/sql/_orm_types.py,sha256=T-vjcry4C1y0GToFKVxQCnmly_-Zsq4IO4SHN6bvUF4,625 +sqlalchemy/sql/_py_util.py,sha256=hiM9ePbRSGs60bAMxPFuJCIC_p9SQ1VzqXGiPchiYwE,2173 +sqlalchemy/sql/_selectable_constructors.py,sha256=wjE6HrLm9cR7bxvZXT8sFLUqT6t_J9G1XyQCnYmBDl0,18780 +sqlalchemy/sql/_typing.py,sha256=Z3tBzapYRP0sKL7IwqnzPE9b8Bbq9vQtc4iV9tvxDoU,12494 +sqlalchemy/sql/annotation.py,sha256=aqbbVz9kfbCT3_66CZ9GEirVN197Cukoqt8rq48FgkQ,18245 +sqlalchemy/sql/base.py,sha256=2MVQnIL0b8xuzp1Fcv0NAye6h_OcgYpsUgLB4sy8Ahk,73756 +sqlalchemy/sql/cache_key.py,sha256=sJhAA-2jovIteeIU7mw9hSL1liPP9Ez89CZZJFC3h6E,33548 +sqlalchemy/sql/coercions.py,sha256=1xzN_9U5BCJGgokdc5iYj5o2cMAfEEZkr1Oa9Q-JYj8,40493 +sqlalchemy/sql/compiler.py,sha256=aDD100xmz8WpBq8oe7PJ5ar8lk9emd54gEE5K2Hr76g,271187 +sqlalchemy/sql/crud.py,sha256=g9xcol2KRGjZi1qsb2-bVz8zgVy_53gfMtJcnNO2vyQ,56521 +sqlalchemy/sql/ddl.py,sha256=CIqMilCKfuQnF0lrZsQdTxgrbXqcTauKr0Ojzj77PFQ,45602 +sqlalchemy/sql/default_comparator.py,sha256=utXWsZVGEjflhFfCT4ywa6RnhORc1Rryo87Hga71Rps,16707 +sqlalchemy/sql/dml.py,sha256=pn0Lm1ofC5qVZzwGWFW73lPCiNba8OsTeemurJgwRyg,65614 +sqlalchemy/sql/elements.py,sha256=kGRUilpx-rr6TTZgZpC5b71OnxxmCgDJRF2fYjDtxh8,172025 +sqlalchemy/sql/events.py,sha256=iC_Q1Htm1Aobt5tOYxWfHHqNpoytrULORmUKcusH_-E,18290 +sqlalchemy/sql/expression.py,sha256=VMX-dLpsZYnVRJpYNDozDUgaj7iQ0HuewUKVefD57PE,7586 +sqlalchemy/sql/functions.py,sha256=MjXK0IVv45Y4n96_TMDZGJ7fwAhGHPRbFP8hOJgaplQ,63689 +sqlalchemy/sql/lambdas.py,sha256=6P__bsWsFnrD7M18FPiBXI0L0OdWZOEV25FAijT4bwo,49289 +sqlalchemy/sql/naming.py,sha256=ZHs1qSV3ou8TYmZ92uvU3sfdklUQlIz4uhe330n05SU,6858 +sqlalchemy/sql/operators.py,sha256=r4oQp4h5zTMFFOpiFNV56joIK-QIjJCobatsmaZ-724,75935 +sqlalchemy/sql/roles.py,sha256=pOsVn_OZD7mF2gJByHf24Rjopt0_Hu3dUCEOK5t4KS8,7662 +sqlalchemy/sql/schema.py,sha256=WOIBaDVdg-zahrP95CPYgY4--3OQN56DH6xm28JDF-Y,228262 +sqlalchemy/sql/selectable.py,sha256=7lxe79hZvnHyzHe1DobodI1lZ1eo8quSLZ6phw10Zj4,232848 +sqlalchemy/sql/sqltypes.py,sha256=UV46KTkgxSin48oPckPOqk3Gx0tZT1l60qXwk7SbKlo,127101 +sqlalchemy/sql/traversals.py,sha256=NFgJrVJzInO3HrnG90CklxrDXhFydZohPs2vRJkh3Bo,33589 +sqlalchemy/sql/type_api.py,sha256=5DzdVquCJomFfpfMyLYbCb66PWxjxbSRdjh6UYB1Yv4,83841 +sqlalchemy/sql/util.py,sha256=qGHQF-tPCj-m1FBerzT7weCanGcXU7dK5m-W7NHio-4,48077 +sqlalchemy/sql/visitors.py,sha256=71wdVvhhZL4nJvVwFAs6ssaW-qZgNRSmKjpAcOzF_TA,36317 +sqlalchemy/testing/__init__.py,sha256=VsrEHrORpAF5n7Vfl43YQgABh6EP1xBx_gHxs7pSXeE,3126 +sqlalchemy/testing/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/assertions.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/assertsql.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/asyncio.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/config.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/engines.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/entities.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/exclusions.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/pickleable.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/profiling.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/provision.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/requirements.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/schema.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/util.cpython-311.pyc,, +sqlalchemy/testing/__pycache__/warnings.cpython-311.pyc,, +sqlalchemy/testing/assertions.py,sha256=gL0rA7CCZJbcVgvWOPV91tTZTRwQc1_Ta0-ykBn83Ew,31439 +sqlalchemy/testing/assertsql.py,sha256=IgQG7l94WaiRP8nTbilJh1ZHZl125g7GPq-S5kmQZN0,16817 +sqlalchemy/testing/asyncio.py,sha256=fkdRz-E37d5OrQKw5hdjmglOTJyXGnJzaJpvNXOBLxg,3728 +sqlalchemy/testing/config.py,sha256=AqyH1qub_gDqX0BvlL-JBQe7N-t2wo8655FtwblUNOY,12090 +sqlalchemy/testing/engines.py,sha256=UnH-8--3zLlYz4IbbCPwC375Za_DC61Spz-oKulbs9Q,13347 +sqlalchemy/testing/entities.py,sha256=IphFegPKbff3Un47jY6bi7_MQXy6qkx_50jX2tHZJR4,3354 +sqlalchemy/testing/exclusions.py,sha256=T8B01hmm8WVs-EKcUOQRzabahPqblWJfOidi6bHJ6GA,12460 +sqlalchemy/testing/fixtures/__init__.py,sha256=dMClrIoxqlYIFpk2ia4RZpkbfxsS_3EBigr9QsPJ66g,1198 +sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/testing/fixtures/__pycache__/base.cpython-311.pyc,, +sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-311.pyc,, +sqlalchemy/testing/fixtures/__pycache__/orm.cpython-311.pyc,, +sqlalchemy/testing/fixtures/__pycache__/sql.cpython-311.pyc,, +sqlalchemy/testing/fixtures/base.py,sha256=9r_J2ksiTzClpUxW0TczICHrWR7Ny8PV8IsBz6TsGFI,12256 +sqlalchemy/testing/fixtures/mypy.py,sha256=gdxiwNFIzDlNGSOdvM3gbwDceVCC9t8oM5kKbwyhGBk,11973 +sqlalchemy/testing/fixtures/orm.py,sha256=8EFbnaBbXX_Bf4FcCzBUaAHgyVpsLGBHX16SGLqE3Fg,6095 +sqlalchemy/testing/fixtures/sql.py,sha256=MFOuYBUyPIpHJzjRCHL9vU-IT4bD6LXGGMvsp0v1FY8,15704 +sqlalchemy/testing/pickleable.py,sha256=U9mIqk-zaxq9Xfy7HErP7UrKgTov-A3QFnhZh-NiOjI,2833 +sqlalchemy/testing/plugin/__init__.py,sha256=79F--BIY_NTBzVRIlJGgAY5LNJJ3cD19XvrAo4X0W9A,247 +sqlalchemy/testing/plugin/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-311.pyc,, +sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-311.pyc,, +sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-311.pyc,, +sqlalchemy/testing/plugin/bootstrap.py,sha256=oYScMbEW4pCnWlPEAq1insFruCXFQeEVBwo__i4McpU,1685 +sqlalchemy/testing/plugin/plugin_base.py,sha256=BgNzWNEmgpK4CwhyblQQKnH-7FDKVi_Uul5vw8fFjBU,21578 +sqlalchemy/testing/plugin/pytestplugin.py,sha256=Jtj073ArTcAmetv81sHmrUhlH0SblcSK4wyN8S4hmvo,27554 +sqlalchemy/testing/profiling.py,sha256=PbuPhRFbauFilUONeY3tV_Y_5lBkD7iCa8VVyH2Sk9Y,10148 +sqlalchemy/testing/provision.py,sha256=zXsw2D2Xpmw_chmYLsE1GXQqKQ-so3V8xU_joTcKan0,14619 +sqlalchemy/testing/requirements.py,sha256=N9pSj7z2wVMkBif-DQfPVa_cl9k6p9g_J5FY1OsWtrY,51817 +sqlalchemy/testing/schema.py,sha256=lr4GkGrGwagaHMuSGzWdzkMaj3HnS7dgfLLWfxt__-U,6513 +sqlalchemy/testing/suite/__init__.py,sha256=Y5DRNG0Yl1u3ypt9zVF0Z9suPZeuO_UQGLl-wRgvTjU,722 +sqlalchemy/testing/suite/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_cte.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_insert.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_results.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_select.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_types.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-311.pyc,, +sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-311.pyc,, +sqlalchemy/testing/suite/test_cte.py,sha256=6zBC3W2OwX1Xs-HedzchcKN2S7EaLNkgkvV_JSZ_Pq0,6451 +sqlalchemy/testing/suite/test_ddl.py,sha256=1Npkf0C_4UNxphthAGjG078n0vPEgnSIHpDu5MfokxQ,12031 +sqlalchemy/testing/suite/test_deprecations.py,sha256=BcJxZTcjYqeOAENVElCg3hVvU6fkGEW3KGBMfnW8bng,5337 +sqlalchemy/testing/suite/test_dialect.py,sha256=EH4ZQWbnGdtjmx5amZtTyhYmrkXJCvW1SQoLahoE7uk,22923 +sqlalchemy/testing/suite/test_insert.py,sha256=9azifj6-OCD7s8h_tAO1uPw100ibQv8YoKc_VA3hn3c,18824 +sqlalchemy/testing/suite/test_reflection.py,sha256=tJSbJFg5fw0sSUv3I_FPmhN7rWWeJtq3YyxmylWJUlM,106466 +sqlalchemy/testing/suite/test_results.py,sha256=NQ23m8FDVd0ub751jN4PswGoAhk5nrqvjHvpYULZXnc,15937 +sqlalchemy/testing/suite/test_rowcount.py,sha256=3KDTlRgjpQ1OVfp__1cv8Hvq4CsDKzmrhJQ_WIJWoJg,7900 +sqlalchemy/testing/suite/test_select.py,sha256=FvMFYQW9IJpDWGYZiJk46is6YrtmdSghBdTjZCG8T0Y,58574 +sqlalchemy/testing/suite/test_sequence.py,sha256=66bCoy4xo99GBSaX6Hxb88foANAykLGRz1YEKbvpfuA,9923 +sqlalchemy/testing/suite/test_types.py,sha256=rFmTOg6XuMch9L2-XthfLJRCTTwpZbMfrNss2g09gmc,65677 +sqlalchemy/testing/suite/test_unicode_ddl.py,sha256=c3_eIxLyORuSOhNDP0jWKxPyUf3SwMFpdalxtquwqlM,6141 +sqlalchemy/testing/suite/test_update_delete.py,sha256=yTiM2unnfOK9rK8ZkqeTTU_MkT-RsKFLmdYliniZfAY,3994 +sqlalchemy/testing/util.py,sha256=BFiSp3CEX95Dr-vv4l_7ZRu5vjZi9hjjnp-JKNfuS5E,14080 +sqlalchemy/testing/warnings.py,sha256=fJ-QJUY2zY2PPxZJKv9medW-BKKbCNbA4Ns_V3YwFXM,1546 +sqlalchemy/types.py,sha256=cQFM-hFRmaf1GErun1qqgEs6QxufvzMuwKqj9tuMPpE,3168 +sqlalchemy/util/__init__.py,sha256=B3bedg-LSQEscwqgmYYU-VENUX8_zAE3q9vb7tkfJNY,8277 +sqlalchemy/util/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_collections.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_has_cy.cpython-311.pyc,, +sqlalchemy/util/__pycache__/_py_collections.cpython-311.pyc,, +sqlalchemy/util/__pycache__/compat.cpython-311.pyc,, +sqlalchemy/util/__pycache__/concurrency.cpython-311.pyc,, +sqlalchemy/util/__pycache__/deprecations.cpython-311.pyc,, +sqlalchemy/util/__pycache__/langhelpers.cpython-311.pyc,, +sqlalchemy/util/__pycache__/preloaded.cpython-311.pyc,, +sqlalchemy/util/__pycache__/queue.cpython-311.pyc,, +sqlalchemy/util/__pycache__/tool_support.cpython-311.pyc,, +sqlalchemy/util/__pycache__/topological.cpython-311.pyc,, +sqlalchemy/util/__pycache__/typing.cpython-311.pyc,, +sqlalchemy/util/_collections.py,sha256=NE9dGJo8UNXIMbY3l3k8AO9BdPW04DlKTYraKCinchI,20063 +sqlalchemy/util/_concurrency_py3k.py,sha256=v8VVoBfFvFHe4j8mMkVLfdUrTbV897p8RWGAm73Ue9U,8574 +sqlalchemy/util/_has_cy.py,sha256=wCQmeSjT3jaH_oxfCEtGk-1g0gbSpt5MCK5UcWdMWqk,1247 +sqlalchemy/util/_py_collections.py,sha256=U6L5AoyLdgSv7cdqB4xxQbw1rpeJjyOZVXffgxgga8I,16714 +sqlalchemy/util/compat.py,sha256=R6bpBydldtbr6h7oJePihQxFb7jKiI-YDsK465MSOzk,8714 +sqlalchemy/util/concurrency.py,sha256=mhwHm0utriD14DRqxTBWgIW7QuwdSEiLgLiJdUjiR3w,2427 +sqlalchemy/util/deprecations.py,sha256=YBwvvYhSB8LhasIZRKvg_-WNoVhPUcaYI1ZrnjDn868,11971 +sqlalchemy/util/langhelpers.py,sha256=khoFN05HjHiWY9ddeehCYxYG2u8LDzuiIKLOGLSAihU,64905 +sqlalchemy/util/preloaded.py,sha256=az7NmLJLsqs0mtM9uBkIu10-841RYDq8wOyqJ7xXvqE,5904 +sqlalchemy/util/queue.py,sha256=CaeSEaYZ57YwtmLdNdOIjT5PK_LCuwMFiO0mpp39ybM,10185 +sqlalchemy/util/tool_support.py,sha256=9braZyidaiNrZVsWtGmkSmus50-byhuYrlAqvhjcmnA,6135 +sqlalchemy/util/topological.py,sha256=N3M3Le7KzGHCmqPGg0ZBqixTDGwmFLhOZvBtc4rHL_g,3458 +sqlalchemy/util/typing.py,sha256=FqH6WjV3p-8rz68YaXktpiZrPu3kmug2-gktJxBQSnI,16641 diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/REQUESTED b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/WHEEL b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/WHEEL new file mode 100644 index 0000000..4497ba5 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: false +Tag: cp311-cp311-manylinux_2_17_x86_64 +Tag: cp311-cp311-manylinux2014_x86_64 + diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/top_level.txt b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/top_level.txt new file mode 100644 index 0000000..39fb2be --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy-2.0.27.dist-info/top_level.txt @@ -0,0 +1 @@ +sqlalchemy diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/INSTALLER b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/LICENSE b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/LICENSE new file mode 100644 index 0000000..d604ce8 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012, Konsta Vesterinen + +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. + +* The names of the contributors may not 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 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/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/METADATA b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/METADATA new file mode 100644 index 0000000..053c3ca --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/METADATA @@ -0,0 +1,97 @@ +Metadata-Version: 2.1 +Name: SQLAlchemy-Utils +Version: 0.41.1 +Summary: Various utility functions for SQLAlchemy. +Home-page: https://github.com/kvesteri/sqlalchemy-utils +Author: Konsta Vesterinen, Ryan Leckey, Janne Vanhala, Vesa Uimonen +Author-email: konsta@fastmonkeys.com +License: BSD +Platform: any +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.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 :: 3.11 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.6 +License-File: LICENSE +Requires-Dist: SQLAlchemy (>=1.3) +Requires-Dist: importlib-metadata ; python_version < "3.8" +Provides-Extra: arrow +Requires-Dist: arrow (>=0.3.4) ; extra == 'arrow' +Provides-Extra: babel +Requires-Dist: Babel (>=1.3) ; extra == 'babel' +Provides-Extra: color +Requires-Dist: colour (>=0.0.4) ; extra == 'color' +Provides-Extra: encrypted +Requires-Dist: cryptography (>=0.6) ; extra == 'encrypted' +Provides-Extra: intervals +Requires-Dist: intervals (>=0.7.1) ; extra == 'intervals' +Provides-Extra: password +Requires-Dist: passlib (<2.0,>=1.6) ; extra == 'password' +Provides-Extra: pendulum +Requires-Dist: pendulum (>=2.0.5) ; extra == 'pendulum' +Provides-Extra: phone +Requires-Dist: phonenumbers (>=5.9.2) ; extra == 'phone' +Provides-Extra: test +Requires-Dist: pytest (>=2.7.1) ; extra == 'test' +Requires-Dist: Pygments (>=1.2) ; extra == 'test' +Requires-Dist: Jinja2 (>=2.3) ; extra == 'test' +Requires-Dist: docutils (>=0.10) ; extra == 'test' +Requires-Dist: flexmock (>=0.9.7) ; extra == 'test' +Requires-Dist: psycopg (>=3.1.8) ; extra == 'test' +Requires-Dist: psycopg2 (>=2.5.1) ; extra == 'test' +Requires-Dist: psycopg2cffi (>=2.8.1) ; extra == 'test' +Requires-Dist: pg8000 (>=1.12.4) ; extra == 'test' +Requires-Dist: pytz (>=2014.2) ; extra == 'test' +Requires-Dist: python-dateutil (>=2.6) ; extra == 'test' +Requires-Dist: pymysql ; extra == 'test' +Requires-Dist: flake8 (>=2.4.0) ; extra == 'test' +Requires-Dist: isort (>=4.2.2) ; extra == 'test' +Requires-Dist: pyodbc ; extra == 'test' +Requires-Dist: backports.zoneinfo ; (python_version < "3.9") and extra == 'test' +Provides-Extra: test_all +Requires-Dist: Babel (>=1.3) ; extra == 'test_all' +Requires-Dist: Jinja2 (>=2.3) ; extra == 'test_all' +Requires-Dist: Pygments (>=1.2) ; extra == 'test_all' +Requires-Dist: arrow (>=0.3.4) ; extra == 'test_all' +Requires-Dist: colour (>=0.0.4) ; extra == 'test_all' +Requires-Dist: cryptography (>=0.6) ; extra == 'test_all' +Requires-Dist: docutils (>=0.10) ; extra == 'test_all' +Requires-Dist: flake8 (>=2.4.0) ; extra == 'test_all' +Requires-Dist: flexmock (>=0.9.7) ; extra == 'test_all' +Requires-Dist: furl (>=0.4.1) ; extra == 'test_all' +Requires-Dist: intervals (>=0.7.1) ; extra == 'test_all' +Requires-Dist: isort (>=4.2.2) ; extra == 'test_all' +Requires-Dist: passlib (<2.0,>=1.6) ; extra == 'test_all' +Requires-Dist: pendulum (>=2.0.5) ; extra == 'test_all' +Requires-Dist: pg8000 (>=1.12.4) ; extra == 'test_all' +Requires-Dist: phonenumbers (>=5.9.2) ; extra == 'test_all' +Requires-Dist: psycopg2 (>=2.5.1) ; extra == 'test_all' +Requires-Dist: psycopg2cffi (>=2.8.1) ; extra == 'test_all' +Requires-Dist: psycopg (>=3.1.8) ; extra == 'test_all' +Requires-Dist: pymysql ; extra == 'test_all' +Requires-Dist: pyodbc ; extra == 'test_all' +Requires-Dist: pytest (>=2.7.1) ; extra == 'test_all' +Requires-Dist: python-dateutil ; extra == 'test_all' +Requires-Dist: python-dateutil (>=2.6) ; extra == 'test_all' +Requires-Dist: pytz (>=2014.2) ; extra == 'test_all' +Requires-Dist: backports.zoneinfo ; (python_version < "3.9") and extra == 'test_all' +Provides-Extra: timezone +Requires-Dist: python-dateutil ; extra == 'timezone' +Provides-Extra: url +Requires-Dist: furl (>=0.4.1) ; extra == 'url' + + +SQLAlchemy-Utils +---------------- + +Various utility functions and custom data types for SQLAlchemy. diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/RECORD b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/RECORD new file mode 100644 index 0000000..23399ed --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/RECORD @@ -0,0 +1,135 @@ +SQLAlchemy_Utils-0.41.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +SQLAlchemy_Utils-0.41.1.dist-info/LICENSE,sha256=aKpRvWCrOmo-gm2RyB2KhgP4FtG6tTWi_xi_fWmqmwo,1437 +SQLAlchemy_Utils-0.41.1.dist-info/METADATA,sha256=L2ExcVhOidADc4LVJvw1RuF3ScQx3YMnaGGbkBlN-Ok,4341 +SQLAlchemy_Utils-0.41.1.dist-info/RECORD,, +SQLAlchemy_Utils-0.41.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +SQLAlchemy_Utils-0.41.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92 +SQLAlchemy_Utils-0.41.1.dist-info/top_level.txt,sha256=C1ORFCU1fhRUCHEe-ZcUkfSkafW8gtZgCEAFeXZeaLc,17 +sqlalchemy_utils/__init__.py,sha256=lQkpRiVlMTX8GuH5M6FIyntqMXlB2LcWBD1zK4x-c60,2363 +sqlalchemy_utils/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/aggregates.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/asserts.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/compat.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/exceptions.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/expressions.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/generic.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/i18n.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/listeners.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/models.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/observer.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/operators.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/path.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/proxy_dict.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/query_chain.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/utils.cpython-311.pyc,, +sqlalchemy_utils/__pycache__/view.cpython-311.pyc,, +sqlalchemy_utils/aggregates.py,sha256=sdzDxpQDZgHmHMuEJ82vzMh8DDQEw7_vqaLBeRwn9ik,15420 +sqlalchemy_utils/asserts.py,sha256=w37lkU4hgzlLkr3GalUMkGVRFrB4E65gi8vVeDNW5tE,5376 +sqlalchemy_utils/compat.py,sha256=BYEgwN_tu-1yfjYSjVJEtK2R_WC57R7okXHoCv6aD4k,2241 +sqlalchemy_utils/exceptions.py,sha256=iZW-TQSZDtCge4pzDDpYug4tKmpEM8coaplYiPJ8UPw,229 +sqlalchemy_utils/expressions.py,sha256=ab-7JXJbuf9nNaSIEHGeUK9mkI__UpLrsAxgXYHZjCA,1610 +sqlalchemy_utils/functions/__init__.py,sha256=R6TU8WdVGFrYOcA_76rW8CH8AvZeBR_SL6pJFdHa0g8,950 +sqlalchemy_utils/functions/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy_utils/functions/__pycache__/database.cpython-311.pyc,, +sqlalchemy_utils/functions/__pycache__/foreign_keys.cpython-311.pyc,, +sqlalchemy_utils/functions/__pycache__/mock.cpython-311.pyc,, +sqlalchemy_utils/functions/__pycache__/orm.cpython-311.pyc,, +sqlalchemy_utils/functions/__pycache__/render.cpython-311.pyc,, +sqlalchemy_utils/functions/__pycache__/sort_query.cpython-311.pyc,, +sqlalchemy_utils/functions/database.py,sha256=eH2pTTRbCPrXFIsHcEjaH5SHugfKl-1SFQF_M7xyfcw,19986 +sqlalchemy_utils/functions/foreign_keys.py,sha256=oHVJoB037tpa-xc3eVnhJPKT6YhkTDETVgQ5RIdIchg,10440 +sqlalchemy_utils/functions/mock.py,sha256=g8PrPh7W2NFIyklSzKoL4s2cErvJXrAxMzGfvdif_48,3145 +sqlalchemy_utils/functions/orm.py,sha256=sg9PfWFefRLGeMT_B8vcVDdLmn5EJjuUj9ImW-MNGqM,24628 +sqlalchemy_utils/functions/render.py,sha256=aCAtzQicivrCMbCvaT-CdHhQvztr2yzAVFXHImzakH8,2057 +sqlalchemy_utils/functions/sort_query.py,sha256=4O2vMDAwrPA2FsOY62xTirVmhqsfaDBGkRV_ReM7F4A,2332 +sqlalchemy_utils/generic.py,sha256=LK11XwZa0gc8YEkykXVqVT48rYd6A2qCSsbc6asNJQM,6354 +sqlalchemy_utils/i18n.py,sha256=bPJziNDTzIaSdNZntlgL0MlI3frQgf8M-yvyjmS_XoQ,3905 +sqlalchemy_utils/listeners.py,sha256=p1nxzGnEWNspueH27iFG21D9_O-PX95wIWbgiNx5pHM,7805 +sqlalchemy_utils/models.py,sha256=z87KGdLmwSRGeQBzEJ4w3jj5eEL3heEZPIfQYRPYniw,2877 +sqlalchemy_utils/observer.py,sha256=11E_n4NwgRcqes0N6A1G8MKCTCGcznSvla2VkJdREPE,12220 +sqlalchemy_utils/operators.py,sha256=nItfRvJbYcreLjCkJd7t1zckfidkvoiF-tMXNVUJz04,1966 +sqlalchemy_utils/path.py,sha256=ulyUFuG5BAHIKr_ttJoa2s5NTzUKH27YYPrMLsy1Pew,4121 +sqlalchemy_utils/primitives/__init__.py,sha256=Ubo8i8HJr2TIcA94y0I822FninJyxKSmHY676wZWT14,185 +sqlalchemy_utils/primitives/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy_utils/primitives/__pycache__/country.cpython-311.pyc,, +sqlalchemy_utils/primitives/__pycache__/currency.cpython-311.pyc,, +sqlalchemy_utils/primitives/__pycache__/ltree.cpython-311.pyc,, +sqlalchemy_utils/primitives/__pycache__/weekday.cpython-311.pyc,, +sqlalchemy_utils/primitives/__pycache__/weekdays.cpython-311.pyc,, +sqlalchemy_utils/primitives/country.py,sha256=U8eayWirlksN2ZnCTLE4PFYnLU5DSnxs51m4FU2rVFM,2740 +sqlalchemy_utils/primitives/currency.py,sha256=RdI-TIxhO90VCmzxnuOAd9ZvHkuw2XrzFJPvD5ZgfE8,2733 +sqlalchemy_utils/primitives/ltree.py,sha256=4Hs6xjZKdNVMLiVppSCA37RoidfOQZWi7FlUWPuujHA,5261 +sqlalchemy_utils/primitives/weekday.py,sha256=AMAe1km6iOKLlHghWUr8enj8J2jWNvf5Dox4LrneJJg,1259 +sqlalchemy_utils/primitives/weekdays.py,sha256=K4tIOHv6EvYR3IUwCEqKT1DEiVgsBMpOty8xRym0Kcc,1764 +sqlalchemy_utils/proxy_dict.py,sha256=t0-VwgrTcAAsUhOFCE2JdIhTy5Yv-71GebhwQC3xNIU,2369 +sqlalchemy_utils/query_chain.py,sha256=GN6pWesgac5LtPTvUSecbciR9XbfBAG6qxdQiNFA38s,3963 +sqlalchemy_utils/relationships/__init__.py,sha256=vyGb2Opfv-ZM0pw5JOpv9kdWr4_Q2foSHSp8Ho_cBik,3587 +sqlalchemy_utils/relationships/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy_utils/relationships/__pycache__/chained_join.cpython-311.pyc,, +sqlalchemy_utils/relationships/chained_join.py,sha256=VUMZh5gwGf8qypkM-ZzNz3OtHY7mP7Hi0QoijQM6OpA,880 +sqlalchemy_utils/types/__init__.py,sha256=LUMa5FZq7dFuzatd_Dl993hPHc8lQXSnHX4QlW0wG7E,1919 +sqlalchemy_utils/types/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/arrow.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/bit.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/choice.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/color.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/country.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/currency.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/email.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/ip_address.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/json.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/locale.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/ltree.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/password.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/pg_composite.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/phone_number.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/range.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/scalar_coercible.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/scalar_list.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/timezone.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/ts_vector.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/url.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/uuid.cpython-311.pyc,, +sqlalchemy_utils/types/__pycache__/weekdays.cpython-311.pyc,, +sqlalchemy_utils/types/arrow.py,sha256=zpklt2Bh2rFPyjI2HBjMWWmbm83o6iiksp4yj9j1z-g,1535 +sqlalchemy_utils/types/bit.py,sha256=V9TU63GCuPJGAjlDskK15kBwi2F2y_E9On34QQAY1Zs,756 +sqlalchemy_utils/types/choice.py,sha256=3GNGs0qNgO3eR0xOlYEhbMjumTKGjMB1wAi-p5UuI5k,5882 +sqlalchemy_utils/types/color.py,sha256=X5ogyU5s21wJYFhE9v_SttyYElV1BlnNFaZ2M0kTvJk,2121 +sqlalchemy_utils/types/country.py,sha256=VQpj_5zL04u1mW6g9HKPp5pQlZoHmSXwW--wjj7DGtY,1579 +sqlalchemy_utils/types/currency.py,sha256=7jab_GdPTZvaYjvsWwh8pyMj69iU2lpUwDsJy4_3YTo,1933 +sqlalchemy_utils/types/email.py,sha256=93fleQPJrvdxZH9pjdPXtYnci96qwTIwdx3sJbvZNWk,1259 +sqlalchemy_utils/types/encrypted/__init__.py,sha256=54Yf-Bd-HekcoRTJnHc5q0YVbAlJh8XMcPctgKTJGJo,28 +sqlalchemy_utils/types/encrypted/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy_utils/types/encrypted/__pycache__/encrypted_type.cpython-311.pyc,, +sqlalchemy_utils/types/encrypted/__pycache__/padding.cpython-311.pyc,, +sqlalchemy_utils/types/encrypted/encrypted_type.py,sha256=Z7f48H-4JX1ngv2jmmfUPbYLIKoedZTCmmr73bm7plg,16646 +sqlalchemy_utils/types/encrypted/padding.py,sha256=roNnoiCelBV-N1-UpOrBHZpL9tA7pkokcPeSNUrhfA8,4483 +sqlalchemy_utils/types/enriched_datetime/__init__.py,sha256=OmaPAmpYTRsySUrf5V6YboLtq5cGMzjSkixzXg0g3fs,196 +sqlalchemy_utils/types/enriched_datetime/__pycache__/__init__.cpython-311.pyc,, +sqlalchemy_utils/types/enriched_datetime/__pycache__/arrow_datetime.cpython-311.pyc,, +sqlalchemy_utils/types/enriched_datetime/__pycache__/enriched_date_type.cpython-311.pyc,, +sqlalchemy_utils/types/enriched_datetime/__pycache__/enriched_datetime_type.cpython-311.pyc,, +sqlalchemy_utils/types/enriched_datetime/__pycache__/pendulum_date.cpython-311.pyc,, +sqlalchemy_utils/types/enriched_datetime/__pycache__/pendulum_datetime.cpython-311.pyc,, +sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py,sha256=FsBohjRv800aIRIt-HCs_Hy7yV_MXYfS6fGzc9VdP2k,1038 +sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py,sha256=ZcqeUk_2MqQR91pHvh0r4-bZmdeFnf49zVEIcSRnspQ,1367 +sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py,sha256=N4BNnx4dqwbdltgxxm3GMNXvd744E2rSuTG-Iu2IKs8,1446 +sqlalchemy_utils/types/enriched_datetime/pendulum_date.py,sha256=4gWAowdqxXWxkci5iKG6UrtYdAQ7ZbM4S4Br4Su7clA,868 +sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py,sha256=FWGq--aTUDEOsjcmvSOYf3mpvQuwtUua4UFO2guJ8As,1451 +sqlalchemy_utils/types/ip_address.py,sha256=d0W5H9ICIchWfGi76hkwOCZVVBsUiFS5ZE3HzJoHZwU,1327 +sqlalchemy_utils/types/json.py,sha256=R_B-GkUwsqjsN0ncat9siWiTgITb-AS9LfLYZa5ilgQ,2123 +sqlalchemy_utils/types/locale.py,sha256=4wJJ--wNUz_4Zj7u1-QSSRk_1VaF9fN6AjEmq-EL7sM,1797 +sqlalchemy_utils/types/ltree.py,sha256=uS5Ry3GdXQzcXmYE57kCq_Orq22j_vIUSDtZLDi5UgA,3386 +sqlalchemy_utils/types/password.py,sha256=GxfkBcnndSy-ihmqoECAY2YsgGJUpqGYzILg3x9gSD4,7875 +sqlalchemy_utils/types/pg_composite.py,sha256=k6iPw3znq6U2fVhCUNykSTN4lrGpx5evxEwAfKcDQxA,10524 +sqlalchemy_utils/types/phone_number.py,sha256=RTUiZbpw06e8Rt_N6Smgkh-lSNa27GidXysYx3ODFQ8,6707 +sqlalchemy_utils/types/range.py,sha256=_nMDA-xL9rhYJby1gdLshZ8E9q2aR_rYd_8-3OrIT2A,12002 +sqlalchemy_utils/types/scalar_coercible.py,sha256=cIG3kQKMPy6tktOQmexFZ_iDYzWzz3ky_x4jRZ38VFU,192 +sqlalchemy_utils/types/scalar_list.py,sha256=ioi-hEIz6lC4E8ohQ_4SCTqvWYIHiNGxugzB3g1CeS8,2701 +sqlalchemy_utils/types/timezone.py,sha256=RvtXS8OVoQvLvJVKpN5YjID7FcURwMJ9Vouh-lxO2Bk,3408 +sqlalchemy_utils/types/ts_vector.py,sha256=WSOOGr8FXUIVe0HXhP-CSFAtCLDCyF07gMimfXQx8Rs,3148 +sqlalchemy_utils/types/url.py,sha256=Gwa05HTM1ZKOBVWVk4AZ2WcydaQTAbwwANO8jp-SFmQ,1525 +sqlalchemy_utils/types/uuid.py,sha256=NDkGm_NOcKyluKYT_tKgIWJX6WIk2kY8em-Md8a7Zc4,3297 +sqlalchemy_utils/types/weekdays.py,sha256=u0AEc_sNnRNFKBYBfupby-7j7iBC3CWo5S2JDVC8mDE,2129 +sqlalchemy_utils/utils.py,sha256=xFL2j2MxNiaKGFMrXOZsK8wMmqMItgtgSEgCExzsaIQ,452 +sqlalchemy_utils/view.py,sha256=JPCxu4x74qIRDzIDahNJprE7sIYCJJ9P99Z9MNjsAOU,6468 diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/REQUESTED b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/WHEEL b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/WHEEL new file mode 100644 index 0000000..1f37c02 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/top_level.txt b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/top_level.txt new file mode 100644 index 0000000..3244027 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/SQLAlchemy_Utils-0.41.1.dist-info/top_level.txt @@ -0,0 +1 @@ +sqlalchemy_utils diff --git a/elitebot/lib/python3.11/site-packages/_distutils_hack/__init__.py b/elitebot/lib/python3.11/site-packages/_distutils_hack/__init__.py new file mode 100644 index 0000000..b951c2d --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/_distutils_hack/__init__.py @@ -0,0 +1,227 @@ +# don't import any costly modules +import sys +import os + + +is_pypy = '__pypy__' in sys.builtin_module_names + + +def warn_distutils_present(): + if 'distutils' not in sys.modules: + return + if is_pypy and sys.version_info < (3, 7): + # PyPy for 3.6 unconditionally imports distutils, so bypass the warning + # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250 + return + import warnings + + warnings.warn( + "Distutils was imported before Setuptools, but importing Setuptools " + "also replaces the `distutils` module in `sys.modules`. This may lead " + "to undesirable behaviors or errors. To avoid these issues, avoid " + "using distutils directly, ensure that setuptools is installed in the " + "traditional way (e.g. not an editable install), and/or make sure " + "that setuptools is always imported before distutils." + ) + + +def clear_distutils(): + if 'distutils' not in sys.modules: + return + import warnings + + warnings.warn("Setuptools is replacing distutils.") + mods = [ + name + for name in sys.modules + if name == "distutils" or name.startswith("distutils.") + ] + for name in mods: + del sys.modules[name] + + +def enabled(): + """ + Allow selection of distutils by environment variable. + """ + which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local') + return which == 'local' + + +def ensure_local_distutils(): + import importlib + + clear_distutils() + + # With the DistutilsMetaFinder in place, + # perform an import to cause distutils to be + # loaded from setuptools._distutils. Ref #2906. + with shim(): + importlib.import_module('distutils') + + # check that submodules load as expected + core = importlib.import_module('distutils.core') + assert '_distutils' in core.__file__, core.__file__ + assert 'setuptools._distutils.log' not in sys.modules + + +def do_override(): + """ + Ensure that the local copy of distutils is preferred over stdlib. + + See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 + for more motivation. + """ + if enabled(): + warn_distutils_present() + ensure_local_distutils() + + +class _TrivialRe: + def __init__(self, *patterns): + self._patterns = patterns + + def match(self, string): + return all(pat in string for pat in self._patterns) + + +class DistutilsMetaFinder: + def find_spec(self, fullname, path, target=None): + # optimization: only consider top level modules and those + # found in the CPython test suite. + if path is not None and not fullname.startswith('test.'): + return + + method_name = 'spec_for_{fullname}'.format(**locals()) + method = getattr(self, method_name, lambda: None) + return method() + + def spec_for_distutils(self): + if self.is_cpython(): + return + + import importlib + import importlib.abc + import importlib.util + + try: + mod = importlib.import_module('setuptools._distutils') + except Exception: + # There are a couple of cases where setuptools._distutils + # may not be present: + # - An older Setuptools without a local distutils is + # taking precedence. Ref #2957. + # - Path manipulation during sitecustomize removes + # setuptools from the path but only after the hook + # has been loaded. Ref #2980. + # In either case, fall back to stdlib behavior. + return + + class DistutilsLoader(importlib.abc.Loader): + def create_module(self, spec): + mod.__name__ = 'distutils' + return mod + + def exec_module(self, module): + pass + + return importlib.util.spec_from_loader( + 'distutils', DistutilsLoader(), origin=mod.__file__ + ) + + @staticmethod + def is_cpython(): + """ + Suppress supplying distutils for CPython (build and tests). + Ref #2965 and #3007. + """ + return os.path.isfile('pybuilddir.txt') + + def spec_for_pip(self): + """ + Ensure stdlib distutils when running under pip. + See pypa/pip#8761 for rationale. + """ + if sys.version_info >= (3, 12) or self.pip_imported_during_build(): + return + clear_distutils() + self.spec_for_distutils = lambda: None + + @classmethod + def pip_imported_during_build(cls): + """ + Detect if pip is being imported in a build script. Ref #2355. + """ + import traceback + + return any( + cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None) + ) + + @staticmethod + def frame_file_is_setup(frame): + """ + Return True if the indicated frame suggests a setup.py file. + """ + # some frames may not have __file__ (#2940) + return frame.f_globals.get('__file__', '').endswith('setup.py') + + def spec_for_sensitive_tests(self): + """ + Ensure stdlib distutils when running select tests under CPython. + + python/cpython#91169 + """ + clear_distutils() + self.spec_for_distutils = lambda: None + + sensitive_tests = ( + [ + 'test.test_distutils', + 'test.test_peg_generator', + 'test.test_importlib', + ] + if sys.version_info < (3, 10) + else [ + 'test.test_distutils', + ] + ) + + +for name in DistutilsMetaFinder.sensitive_tests: + setattr( + DistutilsMetaFinder, + f'spec_for_{name}', + DistutilsMetaFinder.spec_for_sensitive_tests, + ) + + +DISTUTILS_FINDER = DistutilsMetaFinder() + + +def add_shim(): + DISTUTILS_FINDER in sys.meta_path or insert_shim() + + +class shim: + def __enter__(self): + insert_shim() + + def __exit__(self, exc, value, tb): + _remove_shim() + + +def insert_shim(): + sys.meta_path.insert(0, DISTUTILS_FINDER) + + +def _remove_shim(): + try: + sys.meta_path.remove(DISTUTILS_FINDER) + except ValueError: + pass + + +if sys.version_info < (3, 12): + # DistutilsMetaFinder can only be disabled in Python < 3.12 (PEP 632) + remove_shim = _remove_shim diff --git a/elitebot/lib/python3.11/site-packages/_distutils_hack/override.py b/elitebot/lib/python3.11/site-packages/_distutils_hack/override.py new file mode 100644 index 0000000..2cc433a --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/_distutils_hack/override.py @@ -0,0 +1 @@ +__import__('_distutils_hack').do_override() diff --git a/elitebot/lib/python3.11/site-packages/_yaml/__init__.py b/elitebot/lib/python3.11/site-packages/_yaml/__init__.py new file mode 100644 index 0000000..7baa8c4 --- /dev/null +++ b/elitebot/lib/python3.11/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/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/INSTALLER b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/METADATA b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/METADATA new file mode 100644 index 0000000..a1b5c57 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/METADATA @@ -0,0 +1,441 @@ +Metadata-Version: 2.1 +Name: colorama +Version: 0.4.6 +Summary: Cross-platform colored terminal text. +Project-URL: Homepage, https://github.com/tartley/colorama +Author-email: Jonathan Hartley +License-File: LICENSE.txt +Keywords: ansi,color,colour,crossplatform,terminal,text,windows,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.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: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7 +Description-Content-Type: text/x-rst + +.. 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.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.8. + +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.just_fix_windows_console()`` (since v0.4.6) or ``colorama.init()`` +(all versions, but may have other side-effects – see below). + +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 +.............. + +If the only thing you want from Colorama is to get ANSI escapes to work on +Windows, then run: + +.. code-block:: python + + from colorama import just_fix_windows_console + just_fix_windows_console() + +If you're on a recent version of Windows 10 or better, and your stdout/stderr +are pointing to a Windows console, then this will flip the magic configuration +switch to enable Windows' built-in ANSI support. + +If you're on an older version of Windows, and your stdout/stderr are pointing to +a Windows console, then this will wrap ``sys.stdout`` and/or ``sys.stderr`` in a +magic file object that intercepts ANSI escape sequences and issues the +appropriate Win32 calls to emulate them. + +In all other circumstances, it does nothing whatsoever. Basically the idea is +that this makes Windows act like Unix with respect to ANSI escape handling. + +It's safe to call this function multiple times. It's safe to call this function +on non-Windows platforms, but it won't do anything. It's safe to call this +function when one or both of your stdout/stderr are redirected to a file – it +won't do anything to those streams. + +Alternatively, you can use the older interface with more features (but also more +potential footguns): + +.. code-block:: python + + from colorama import init + init() + +This does the same thing as ``just_fix_windows_console``, except for the +following differences: + +- It's not safe to call ``init`` multiple times; you can end up with multiple + layers of wrapping and broken ANSI support. + +- Colorama will apply a heuristic to guess whether stdout/stderr support ANSI, + and if it thinks they don't, then it will wrap ``sys.stdout`` and + ``sys.stderr`` in a magic file object that strips out ANSI escape sequences + before printing them. This happens on all platforms, and can be convenient if + you want to write your code to emit ANSI escape sequences unconditionally, and + let Colorama decide whether they should actually be output. But note that + Colorama's heuristic is not particularly clever. + +- ``init`` also accepts explicit keyword args to enable/disable various + functionality – see below. + +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). + +Most users should depend on ``colorama >= 0.4.6``, and use +``just_fix_windows_console``. The old ``init`` interface will be supported +indefinitely for backwards compatibility, but we don't plan to fix any issues +with it, also for backwards compatibility. + +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: + +SIMILARLY, do not send PRs adding the generation of new ANSI types to Colorama. +We are only interested in converting ANSI codes to win32 API calls, not +shortcuts like the above to generate ANSI characters. + +.. code-block:: python + + from colorama import just_fix_windows_console + from termcolor import colored + + # use Colorama to make Termcolor work on Windows too + just_fix_windows_console() + + # 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 valid ANSI sequences aren't recognised. + +If you're hacking on the code, see `README-hacking.md`_. ESPECIALLY, see the +explanation there of why we do not want PRs that allow Colorama to generate new +types of ANSI codes. + +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. + +.. _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 +------ + +See the CHANGELOG for more 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/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/RECORD b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/RECORD new file mode 100644 index 0000000..0e0eb30 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/RECORD @@ -0,0 +1,32 @@ +colorama-0.4.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +colorama-0.4.6.dist-info/METADATA,sha256=e67SnrUMOym9sz_4TjF3vxvAV4T3aF7NyqRHHH3YEMw,17158 +colorama-0.4.6.dist-info/RECORD,, +colorama-0.4.6.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +colorama-0.4.6.dist-info/WHEEL,sha256=cdcF4Fbd0FPtw2EMIOwH-3rSOTUdTCeOSXRMD1iLUb8,105 +colorama-0.4.6.dist-info/licenses/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 +colorama/__init__.py,sha256=wePQA4U20tKgYARySLEC047ucNX-g8pRLpYBuiHlLb8,266 +colorama/__pycache__/__init__.cpython-311.pyc,, +colorama/__pycache__/ansi.cpython-311.pyc,, +colorama/__pycache__/ansitowin32.cpython-311.pyc,, +colorama/__pycache__/initialise.cpython-311.pyc,, +colorama/__pycache__/win32.cpython-311.pyc,, +colorama/__pycache__/winterm.cpython-311.pyc,, +colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522 +colorama/ansitowin32.py,sha256=vPNYa3OZbxjbuFyaVo0Tmhmy1FZ1lKMWCnT7odXpItk,11128 +colorama/initialise.py,sha256=-hIny86ClXo39ixh5iSCfUIa2f_h_bgKRDW7gqs-KLU,3325 +colorama/tests/__init__.py,sha256=MkgPAEzGQd-Rq0w0PZXSX2LadRWhUECcisJY8lSrm4Q,75 +colorama/tests/__pycache__/__init__.cpython-311.pyc,, +colorama/tests/__pycache__/ansi_test.cpython-311.pyc,, +colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc,, +colorama/tests/__pycache__/initialise_test.cpython-311.pyc,, +colorama/tests/__pycache__/isatty_test.cpython-311.pyc,, +colorama/tests/__pycache__/utils.cpython-311.pyc,, +colorama/tests/__pycache__/winterm_test.cpython-311.pyc,, +colorama/tests/ansi_test.py,sha256=FeViDrUINIZcr505PAxvU4AjXz1asEiALs9GXMhwRaE,2839 +colorama/tests/ansitowin32_test.py,sha256=RN7AIhMJ5EqDsYaCjVo-o4u8JzDD4ukJbmevWKS70rY,10678 +colorama/tests/initialise_test.py,sha256=BbPy-XfyHwJ6zKozuQOvNvQZzsx9vdb_0bYXn7hsBTc,6741 +colorama/tests/isatty_test.py,sha256=Pg26LRpv0yQDB5Ac-sxgVXG7hsA1NYvapFgApZfYzZg,1866 +colorama/tests/utils.py,sha256=1IIRylG39z5-dzq09R_ngufxyPZxgldNbrxKxUGwGKE,1079 +colorama/tests/winterm_test.py,sha256=qoWFPEjym5gm2RuMwpf3pOis3a5r_PJZFCzK254JL8A,3709 +colorama/win32.py,sha256=YQOKwMTwtGBbsY4dL5HYTvwTeP9wIQra5MvPNddpxZs,6181 +colorama/winterm.py,sha256=XCQFDHjPi6AHYNdZwy0tA02H-Jh48Jp-HvCjeLeLp3U,7134 diff --git a/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/REQUESTED b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/WHEEL b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/WHEEL new file mode 100644 index 0000000..d79189f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.11.1 +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any diff --git a/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..3105888 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama-0.4.6.dist-info/licenses/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/elitebot/lib/python3.11/site-packages/colorama/__init__.py b/elitebot/lib/python3.11/site-packages/colorama/__init__.py new file mode 100644 index 0000000..383101c --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/__init__.py @@ -0,0 +1,7 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text, just_fix_windows_console +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.4.6' + diff --git a/elitebot/lib/python3.11/site-packages/colorama/ansi.py b/elitebot/lib/python3.11/site-packages/colorama/ansi.py new file mode 100644 index 0000000..11ec695 --- /dev/null +++ b/elitebot/lib/python3.11/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/elitebot/lib/python3.11/site-packages/colorama/ansitowin32.py b/elitebot/lib/python3.11/site-packages/colorama/ansitowin32.py new file mode 100644 index 0000000..abf209e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/ansitowin32.py @@ -0,0 +1,277 @@ +# 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 enable_vt_processing, 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() + try: + fd = wrapped.fileno() + except Exception: + fd = -1 + system_has_native_ansi = not on_windows or enable_vt_processing(fd) + have_tty = not self.stream.closed and self.stream.isatty() + need_conversion = conversion_supported and not system_has_native_ansi + + # should we strip ANSI sequences from our output? + if strip is None: + strip = need_conversion or not have_tty + self.strip = strip + + # should we should convert ANSI sequences into win32 calls? + if convert is None: + convert = need_conversion and have_tty + 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 + + + def flush(self): + self.wrapped.flush() diff --git a/elitebot/lib/python3.11/site-packages/colorama/initialise.py b/elitebot/lib/python3.11/site-packages/colorama/initialise.py new file mode 100644 index 0000000..d5fd4b7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/initialise.py @@ -0,0 +1,121 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import atexit +import contextlib +import sys + +from .ansitowin32 import AnsiToWin32 + + +def _wipe_internal_state_for_tests(): + global orig_stdout, orig_stderr + orig_stdout = None + orig_stderr = None + + global wrapped_stdout, wrapped_stderr + wrapped_stdout = None + wrapped_stderr = None + + global atexit_done + atexit_done = False + + global fixed_windows_console + fixed_windows_console = False + + try: + # no-op if it wasn't registered + atexit.unregister(reset_all) + except AttributeError: + # python 2: no atexit.unregister. Oh well, we did our best. + pass + + +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 + + +def just_fix_windows_console(): + global fixed_windows_console + + if sys.platform != "win32": + return + if fixed_windows_console: + return + if wrapped_stdout is not None or wrapped_stderr is not None: + # Someone already ran init() and it did stuff, so we won't second-guess them + return + + # On newer versions of Windows, AnsiToWin32.__init__ will implicitly enable the + # native ANSI support in the console as a side-effect. We only need to actually + # replace sys.stdout/stderr if we're in the old-style conversion mode. + new_stdout = AnsiToWin32(sys.stdout, convert=None, strip=None, autoreset=False) + if new_stdout.convert: + sys.stdout = new_stdout + new_stderr = AnsiToWin32(sys.stderr, convert=None, strip=None, autoreset=False) + if new_stderr.convert: + sys.stderr = new_stderr + + fixed_windows_console = True + +@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 + + +# Use this for initial setup as well, to reduce code duplication +_wipe_internal_state_for_tests() diff --git a/elitebot/lib/python3.11/site-packages/colorama/tests/__init__.py b/elitebot/lib/python3.11/site-packages/colorama/tests/__init__.py new file mode 100644 index 0000000..8c5661e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/tests/__init__.py @@ -0,0 +1 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. diff --git a/elitebot/lib/python3.11/site-packages/colorama/tests/ansi_test.py b/elitebot/lib/python3.11/site-packages/colorama/tests/ansi_test.py new file mode 100644 index 0000000..0a20c80 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/tests/ansi_test.py @@ -0,0 +1,76 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main + +from ..ansi import Back, Fore, Style +from ..ansitowin32 import AnsiToWin32 + +stdout_orig = sys.stdout +stderr_orig = sys.stderr + + +class AnsiTest(TestCase): + + def setUp(self): + # sanity check: stdout should be a file or StringIO object. + # It will only be AnsiToWin32 if init() has previously wrapped it + self.assertNotEqual(type(sys.stdout), AnsiToWin32) + self.assertNotEqual(type(sys.stderr), AnsiToWin32) + + def tearDown(self): + sys.stdout = stdout_orig + sys.stderr = stderr_orig + + + def testForeAttributes(self): + self.assertEqual(Fore.BLACK, '\033[30m') + self.assertEqual(Fore.RED, '\033[31m') + self.assertEqual(Fore.GREEN, '\033[32m') + self.assertEqual(Fore.YELLOW, '\033[33m') + self.assertEqual(Fore.BLUE, '\033[34m') + self.assertEqual(Fore.MAGENTA, '\033[35m') + self.assertEqual(Fore.CYAN, '\033[36m') + self.assertEqual(Fore.WHITE, '\033[37m') + self.assertEqual(Fore.RESET, '\033[39m') + + # Check the light, extended versions. + self.assertEqual(Fore.LIGHTBLACK_EX, '\033[90m') + self.assertEqual(Fore.LIGHTRED_EX, '\033[91m') + self.assertEqual(Fore.LIGHTGREEN_EX, '\033[92m') + self.assertEqual(Fore.LIGHTYELLOW_EX, '\033[93m') + self.assertEqual(Fore.LIGHTBLUE_EX, '\033[94m') + self.assertEqual(Fore.LIGHTMAGENTA_EX, '\033[95m') + self.assertEqual(Fore.LIGHTCYAN_EX, '\033[96m') + self.assertEqual(Fore.LIGHTWHITE_EX, '\033[97m') + + + def testBackAttributes(self): + self.assertEqual(Back.BLACK, '\033[40m') + self.assertEqual(Back.RED, '\033[41m') + self.assertEqual(Back.GREEN, '\033[42m') + self.assertEqual(Back.YELLOW, '\033[43m') + self.assertEqual(Back.BLUE, '\033[44m') + self.assertEqual(Back.MAGENTA, '\033[45m') + self.assertEqual(Back.CYAN, '\033[46m') + self.assertEqual(Back.WHITE, '\033[47m') + self.assertEqual(Back.RESET, '\033[49m') + + # Check the light, extended versions. + self.assertEqual(Back.LIGHTBLACK_EX, '\033[100m') + self.assertEqual(Back.LIGHTRED_EX, '\033[101m') + self.assertEqual(Back.LIGHTGREEN_EX, '\033[102m') + self.assertEqual(Back.LIGHTYELLOW_EX, '\033[103m') + self.assertEqual(Back.LIGHTBLUE_EX, '\033[104m') + self.assertEqual(Back.LIGHTMAGENTA_EX, '\033[105m') + self.assertEqual(Back.LIGHTCYAN_EX, '\033[106m') + self.assertEqual(Back.LIGHTWHITE_EX, '\033[107m') + + + def testStyleAttributes(self): + self.assertEqual(Style.DIM, '\033[2m') + self.assertEqual(Style.NORMAL, '\033[22m') + self.assertEqual(Style.BRIGHT, '\033[1m') + + +if __name__ == '__main__': + main() diff --git a/elitebot/lib/python3.11/site-packages/colorama/tests/ansitowin32_test.py b/elitebot/lib/python3.11/site-packages/colorama/tests/ansitowin32_test.py new file mode 100644 index 0000000..91ca551 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/tests/ansitowin32_test.py @@ -0,0 +1,294 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from io import StringIO, TextIOWrapper +from unittest import TestCase, main +try: + from contextlib import ExitStack +except ImportError: + # python 2 + from contextlib2 import ExitStack + +try: + from unittest.mock import MagicMock, Mock, patch +except ImportError: + from mock import MagicMock, Mock, patch + +from ..ansitowin32 import AnsiToWin32, StreamWrapper +from ..win32 import ENABLE_VIRTUAL_TERMINAL_PROCESSING +from .utils import osname + + +class StreamWrapperTest(TestCase): + + def testIsAProxy(self): + mockStream = Mock() + wrapper = StreamWrapper(mockStream, None) + self.assertTrue( wrapper.random_attr is mockStream.random_attr ) + + def testDelegatesWrite(self): + mockStream = Mock() + mockConverter = Mock() + wrapper = StreamWrapper(mockStream, mockConverter) + wrapper.write('hello') + self.assertTrue(mockConverter.write.call_args, (('hello',), {})) + + def testDelegatesContext(self): + mockConverter = Mock() + s = StringIO() + with StreamWrapper(s, mockConverter) as fp: + fp.write(u'hello') + self.assertTrue(s.closed) + + def testProxyNoContextManager(self): + mockStream = MagicMock() + mockStream.__enter__.side_effect = AttributeError() + mockConverter = Mock() + with self.assertRaises(AttributeError) as excinfo: + with StreamWrapper(mockStream, mockConverter) as wrapper: + wrapper.write('hello') + + def test_closed_shouldnt_raise_on_closed_stream(self): + stream = StringIO() + stream.close() + wrapper = StreamWrapper(stream, None) + self.assertEqual(wrapper.closed, True) + + def test_closed_shouldnt_raise_on_detached_stream(self): + stream = TextIOWrapper(StringIO()) + stream.detach() + wrapper = StreamWrapper(stream, None) + self.assertEqual(wrapper.closed, True) + +class AnsiToWin32Test(TestCase): + + def testInit(self): + mockStdout = Mock() + auto = Mock() + stream = AnsiToWin32(mockStdout, autoreset=auto) + self.assertEqual(stream.wrapped, mockStdout) + self.assertEqual(stream.autoreset, auto) + + @patch('colorama.ansitowin32.winterm', None) + @patch('colorama.ansitowin32.winapi_test', lambda *_: True) + def testStripIsTrueOnWindows(self): + with osname('nt'): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout) + self.assertTrue(stream.strip) + + def testStripIsFalseOffWindows(self): + with osname('posix'): + mockStdout = Mock(closed=False) + stream = AnsiToWin32(mockStdout) + self.assertFalse(stream.strip) + + def testWriteStripsAnsi(self): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout) + stream.wrapped = Mock() + stream.write_and_convert = Mock() + stream.strip = True + + stream.write('abc') + + self.assertFalse(stream.wrapped.write.called) + self.assertEqual(stream.write_and_convert.call_args, (('abc',), {})) + + def testWriteDoesNotStripAnsi(self): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout) + stream.wrapped = Mock() + stream.write_and_convert = Mock() + stream.strip = False + stream.convert = False + + stream.write('abc') + + self.assertFalse(stream.write_and_convert.called) + self.assertEqual(stream.wrapped.write.call_args, (('abc',), {})) + + def assert_autoresets(self, convert, autoreset=True): + stream = AnsiToWin32(Mock()) + stream.convert = convert + stream.reset_all = Mock() + stream.autoreset = autoreset + stream.winterm = Mock() + + stream.write('abc') + + self.assertEqual(stream.reset_all.called, autoreset) + + def testWriteAutoresets(self): + self.assert_autoresets(convert=True) + self.assert_autoresets(convert=False) + self.assert_autoresets(convert=True, autoreset=False) + self.assert_autoresets(convert=False, autoreset=False) + + def testWriteAndConvertWritesPlainText(self): + stream = AnsiToWin32(Mock()) + stream.write_and_convert( 'abc' ) + self.assertEqual( stream.wrapped.write.call_args, (('abc',), {}) ) + + def testWriteAndConvertStripsAllValidAnsi(self): + stream = AnsiToWin32(Mock()) + stream.call_win32 = Mock() + data = [ + 'abc\033[mdef', + 'abc\033[0mdef', + 'abc\033[2mdef', + 'abc\033[02mdef', + 'abc\033[002mdef', + 'abc\033[40mdef', + 'abc\033[040mdef', + 'abc\033[0;1mdef', + 'abc\033[40;50mdef', + 'abc\033[50;30;40mdef', + 'abc\033[Adef', + 'abc\033[0Gdef', + 'abc\033[1;20;128Hdef', + ] + for datum in data: + stream.wrapped.write.reset_mock() + stream.write_and_convert( datum ) + self.assertEqual( + [args[0] for args in stream.wrapped.write.call_args_list], + [ ('abc',), ('def',) ] + ) + + def testWriteAndConvertSkipsEmptySnippets(self): + stream = AnsiToWin32(Mock()) + stream.call_win32 = Mock() + stream.write_and_convert( '\033[40m\033[41m' ) + self.assertFalse( stream.wrapped.write.called ) + + def testWriteAndConvertCallsWin32WithParamsAndCommand(self): + stream = AnsiToWin32(Mock()) + stream.convert = True + stream.call_win32 = Mock() + stream.extract_params = Mock(return_value='params') + data = { + 'abc\033[adef': ('a', 'params'), + 'abc\033[;;bdef': ('b', 'params'), + 'abc\033[0cdef': ('c', 'params'), + 'abc\033[;;0;;Gdef': ('G', 'params'), + 'abc\033[1;20;128Hdef': ('H', 'params'), + } + for datum, expected in data.items(): + stream.call_win32.reset_mock() + stream.write_and_convert( datum ) + self.assertEqual( stream.call_win32.call_args[0], expected ) + + def test_reset_all_shouldnt_raise_on_closed_orig_stdout(self): + stream = StringIO() + converter = AnsiToWin32(stream) + stream.close() + + converter.reset_all() + + def test_wrap_shouldnt_raise_on_closed_orig_stdout(self): + stream = StringIO() + stream.close() + with \ + patch("colorama.ansitowin32.os.name", "nt"), \ + patch("colorama.ansitowin32.winapi_test", lambda: True): + converter = AnsiToWin32(stream) + self.assertTrue(converter.strip) + self.assertFalse(converter.convert) + + def test_wrap_shouldnt_raise_on_missing_closed_attr(self): + with \ + patch("colorama.ansitowin32.os.name", "nt"), \ + patch("colorama.ansitowin32.winapi_test", lambda: True): + converter = AnsiToWin32(object()) + self.assertTrue(converter.strip) + self.assertFalse(converter.convert) + + def testExtractParams(self): + stream = AnsiToWin32(Mock()) + data = { + '': (0,), + ';;': (0,), + '2': (2,), + ';;002;;': (2,), + '0;1': (0, 1), + ';;003;;456;;': (3, 456), + '11;22;33;44;55': (11, 22, 33, 44, 55), + } + for datum, expected in data.items(): + self.assertEqual(stream.extract_params('m', datum), expected) + + def testCallWin32UsesLookup(self): + listener = Mock() + stream = AnsiToWin32(listener) + stream.win32_calls = { + 1: (lambda *_, **__: listener(11),), + 2: (lambda *_, **__: listener(22),), + 3: (lambda *_, **__: listener(33),), + } + stream.call_win32('m', (3, 1, 99, 2)) + self.assertEqual( + [a[0][0] for a in listener.call_args_list], + [33, 11, 22] ) + + def test_osc_codes(self): + mockStdout = Mock() + stream = AnsiToWin32(mockStdout, convert=True) + with patch('colorama.ansitowin32.winterm') as winterm: + data = [ + '\033]0\x07', # missing arguments + '\033]0;foo\x08', # wrong OSC command + '\033]0;colorama_test_title\x07', # should work + '\033]1;colorama_test_title\x07', # wrong set command + '\033]2;colorama_test_title\x07', # should work + '\033]' + ';' * 64 + '\x08', # see issue #247 + ] + for code in data: + stream.write(code) + self.assertEqual(winterm.set_title.call_count, 2) + + def test_native_windows_ansi(self): + with ExitStack() as stack: + def p(a, b): + stack.enter_context(patch(a, b, create=True)) + # Pretend to be on Windows + p("colorama.ansitowin32.os.name", "nt") + p("colorama.ansitowin32.winapi_test", lambda: True) + p("colorama.win32.winapi_test", lambda: True) + p("colorama.winterm.win32.windll", "non-None") + p("colorama.winterm.get_osfhandle", lambda _: 1234) + + # Pretend that our mock stream has native ANSI support + p( + "colorama.winterm.win32.GetConsoleMode", + lambda _: ENABLE_VIRTUAL_TERMINAL_PROCESSING, + ) + SetConsoleMode = Mock() + p("colorama.winterm.win32.SetConsoleMode", SetConsoleMode) + + stdout = Mock() + stdout.closed = False + stdout.isatty.return_value = True + stdout.fileno.return_value = 1 + + # Our fake console says it has native vt support, so AnsiToWin32 should + # enable that support and do nothing else. + stream = AnsiToWin32(stdout) + SetConsoleMode.assert_called_with(1234, ENABLE_VIRTUAL_TERMINAL_PROCESSING) + self.assertFalse(stream.strip) + self.assertFalse(stream.convert) + self.assertFalse(stream.should_wrap()) + + # Now let's pretend we're on an old Windows console, that doesn't have + # native ANSI support. + p("colorama.winterm.win32.GetConsoleMode", lambda _: 0) + SetConsoleMode = Mock() + p("colorama.winterm.win32.SetConsoleMode", SetConsoleMode) + + stream = AnsiToWin32(stdout) + SetConsoleMode.assert_called_with(1234, ENABLE_VIRTUAL_TERMINAL_PROCESSING) + self.assertTrue(stream.strip) + self.assertTrue(stream.convert) + self.assertTrue(stream.should_wrap()) + + +if __name__ == '__main__': + main() diff --git a/elitebot/lib/python3.11/site-packages/colorama/tests/initialise_test.py b/elitebot/lib/python3.11/site-packages/colorama/tests/initialise_test.py new file mode 100644 index 0000000..89f9b07 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/tests/initialise_test.py @@ -0,0 +1,189 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main, skipUnless + +try: + from unittest.mock import patch, Mock +except ImportError: + from mock import patch, Mock + +from ..ansitowin32 import StreamWrapper +from ..initialise import init, just_fix_windows_console, _wipe_internal_state_for_tests +from .utils import osname, replace_by + +orig_stdout = sys.stdout +orig_stderr = sys.stderr + + +class InitTest(TestCase): + + @skipUnless(sys.stdout.isatty(), "sys.stdout is not a tty") + def setUp(self): + # sanity check + self.assertNotWrapped() + + def tearDown(self): + _wipe_internal_state_for_tests() + sys.stdout = orig_stdout + sys.stderr = orig_stderr + + def assertWrapped(self): + self.assertIsNot(sys.stdout, orig_stdout, 'stdout should be wrapped') + self.assertIsNot(sys.stderr, orig_stderr, 'stderr should be wrapped') + self.assertTrue(isinstance(sys.stdout, StreamWrapper), + 'bad stdout wrapper') + self.assertTrue(isinstance(sys.stderr, StreamWrapper), + 'bad stderr wrapper') + + def assertNotWrapped(self): + self.assertIs(sys.stdout, orig_stdout, 'stdout should not be wrapped') + self.assertIs(sys.stderr, orig_stderr, 'stderr should not be wrapped') + + @patch('colorama.initialise.reset_all') + @patch('colorama.ansitowin32.winapi_test', lambda *_: True) + @patch('colorama.ansitowin32.enable_vt_processing', lambda *_: False) + def testInitWrapsOnWindows(self, _): + with osname("nt"): + init() + self.assertWrapped() + + @patch('colorama.initialise.reset_all') + @patch('colorama.ansitowin32.winapi_test', lambda *_: False) + def testInitDoesntWrapOnEmulatedWindows(self, _): + with osname("nt"): + init() + self.assertNotWrapped() + + def testInitDoesntWrapOnNonWindows(self): + with osname("posix"): + init() + self.assertNotWrapped() + + def testInitDoesntWrapIfNone(self): + with replace_by(None): + init() + # We can't use assertNotWrapped here because replace_by(None) + # changes stdout/stderr already. + self.assertIsNone(sys.stdout) + self.assertIsNone(sys.stderr) + + def testInitAutoresetOnWrapsOnAllPlatforms(self): + with osname("posix"): + init(autoreset=True) + self.assertWrapped() + + def testInitWrapOffDoesntWrapOnWindows(self): + with osname("nt"): + init(wrap=False) + self.assertNotWrapped() + + def testInitWrapOffIncompatibleWithAutoresetOn(self): + self.assertRaises(ValueError, lambda: init(autoreset=True, wrap=False)) + + @patch('colorama.win32.SetConsoleTextAttribute') + @patch('colorama.initialise.AnsiToWin32') + def testAutoResetPassedOn(self, mockATW32, _): + with osname("nt"): + init(autoreset=True) + self.assertEqual(len(mockATW32.call_args_list), 2) + self.assertEqual(mockATW32.call_args_list[1][1]['autoreset'], True) + self.assertEqual(mockATW32.call_args_list[0][1]['autoreset'], True) + + @patch('colorama.initialise.AnsiToWin32') + def testAutoResetChangeable(self, mockATW32): + with osname("nt"): + init() + + init(autoreset=True) + self.assertEqual(len(mockATW32.call_args_list), 4) + self.assertEqual(mockATW32.call_args_list[2][1]['autoreset'], True) + self.assertEqual(mockATW32.call_args_list[3][1]['autoreset'], True) + + init() + self.assertEqual(len(mockATW32.call_args_list), 6) + self.assertEqual( + mockATW32.call_args_list[4][1]['autoreset'], False) + self.assertEqual( + mockATW32.call_args_list[5][1]['autoreset'], False) + + + @patch('colorama.initialise.atexit.register') + def testAtexitRegisteredOnlyOnce(self, mockRegister): + init() + self.assertTrue(mockRegister.called) + mockRegister.reset_mock() + init() + self.assertFalse(mockRegister.called) + + +class JustFixWindowsConsoleTest(TestCase): + def _reset(self): + _wipe_internal_state_for_tests() + sys.stdout = orig_stdout + sys.stderr = orig_stderr + + def tearDown(self): + self._reset() + + @patch("colorama.ansitowin32.winapi_test", lambda: True) + def testJustFixWindowsConsole(self): + if sys.platform != "win32": + # just_fix_windows_console should be a no-op + just_fix_windows_console() + self.assertIs(sys.stdout, orig_stdout) + self.assertIs(sys.stderr, orig_stderr) + else: + def fake_std(): + # Emulate stdout=not a tty, stderr=tty + # to check that we handle both cases correctly + stdout = Mock() + stdout.closed = False + stdout.isatty.return_value = False + stdout.fileno.return_value = 1 + sys.stdout = stdout + + stderr = Mock() + stderr.closed = False + stderr.isatty.return_value = True + stderr.fileno.return_value = 2 + sys.stderr = stderr + + for native_ansi in [False, True]: + with patch( + 'colorama.ansitowin32.enable_vt_processing', + lambda *_: native_ansi + ): + self._reset() + fake_std() + + # Regular single-call test + prev_stdout = sys.stdout + prev_stderr = sys.stderr + just_fix_windows_console() + self.assertIs(sys.stdout, prev_stdout) + if native_ansi: + self.assertIs(sys.stderr, prev_stderr) + else: + self.assertIsNot(sys.stderr, prev_stderr) + + # second call without resetting is always a no-op + prev_stdout = sys.stdout + prev_stderr = sys.stderr + just_fix_windows_console() + self.assertIs(sys.stdout, prev_stdout) + self.assertIs(sys.stderr, prev_stderr) + + self._reset() + fake_std() + + # If init() runs first, just_fix_windows_console should be a no-op + init() + prev_stdout = sys.stdout + prev_stderr = sys.stderr + just_fix_windows_console() + self.assertIs(prev_stdout, sys.stdout) + self.assertIs(prev_stderr, sys.stderr) + + +if __name__ == '__main__': + main() diff --git a/elitebot/lib/python3.11/site-packages/colorama/tests/isatty_test.py b/elitebot/lib/python3.11/site-packages/colorama/tests/isatty_test.py new file mode 100644 index 0000000..0f84e4b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/tests/isatty_test.py @@ -0,0 +1,57 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main + +from ..ansitowin32 import StreamWrapper, AnsiToWin32 +from .utils import pycharm, replace_by, replace_original_by, StreamTTY, StreamNonTTY + + +def is_a_tty(stream): + return StreamWrapper(stream, None).isatty() + +class IsattyTest(TestCase): + + def test_TTY(self): + tty = StreamTTY() + self.assertTrue(is_a_tty(tty)) + with pycharm(): + self.assertTrue(is_a_tty(tty)) + + def test_nonTTY(self): + non_tty = StreamNonTTY() + self.assertFalse(is_a_tty(non_tty)) + with pycharm(): + self.assertFalse(is_a_tty(non_tty)) + + def test_withPycharm(self): + with pycharm(): + self.assertTrue(is_a_tty(sys.stderr)) + self.assertTrue(is_a_tty(sys.stdout)) + + def test_withPycharmTTYOverride(self): + tty = StreamTTY() + with pycharm(), replace_by(tty): + self.assertTrue(is_a_tty(tty)) + + def test_withPycharmNonTTYOverride(self): + non_tty = StreamNonTTY() + with pycharm(), replace_by(non_tty): + self.assertFalse(is_a_tty(non_tty)) + + def test_withPycharmNoneOverride(self): + with pycharm(): + with replace_by(None), replace_original_by(None): + self.assertFalse(is_a_tty(None)) + self.assertFalse(is_a_tty(StreamNonTTY())) + self.assertTrue(is_a_tty(StreamTTY())) + + def test_withPycharmStreamWrapped(self): + with pycharm(): + self.assertTrue(AnsiToWin32(StreamTTY()).stream.isatty()) + self.assertFalse(AnsiToWin32(StreamNonTTY()).stream.isatty()) + self.assertTrue(AnsiToWin32(sys.stdout).stream.isatty()) + self.assertTrue(AnsiToWin32(sys.stderr).stream.isatty()) + + +if __name__ == '__main__': + main() diff --git a/elitebot/lib/python3.11/site-packages/colorama/tests/utils.py b/elitebot/lib/python3.11/site-packages/colorama/tests/utils.py new file mode 100644 index 0000000..472fafb --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/tests/utils.py @@ -0,0 +1,49 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from contextlib import contextmanager +from io import StringIO +import sys +import os + + +class StreamTTY(StringIO): + def isatty(self): + return True + +class StreamNonTTY(StringIO): + def isatty(self): + return False + +@contextmanager +def osname(name): + orig = os.name + os.name = name + yield + os.name = orig + +@contextmanager +def replace_by(stream): + orig_stdout = sys.stdout + orig_stderr = sys.stderr + sys.stdout = stream + sys.stderr = stream + yield + sys.stdout = orig_stdout + sys.stderr = orig_stderr + +@contextmanager +def replace_original_by(stream): + orig_stdout = sys.__stdout__ + orig_stderr = sys.__stderr__ + sys.__stdout__ = stream + sys.__stderr__ = stream + yield + sys.__stdout__ = orig_stdout + sys.__stderr__ = orig_stderr + +@contextmanager +def pycharm(): + os.environ["PYCHARM_HOSTED"] = "1" + non_tty = StreamNonTTY() + with replace_by(non_tty), replace_original_by(non_tty): + yield + del os.environ["PYCHARM_HOSTED"] diff --git a/elitebot/lib/python3.11/site-packages/colorama/tests/winterm_test.py b/elitebot/lib/python3.11/site-packages/colorama/tests/winterm_test.py new file mode 100644 index 0000000..d0955f9 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/tests/winterm_test.py @@ -0,0 +1,131 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import sys +from unittest import TestCase, main, skipUnless + +try: + from unittest.mock import Mock, patch +except ImportError: + from mock import Mock, patch + +from ..winterm import WinColor, WinStyle, WinTerm + + +class WinTermTest(TestCase): + + @patch('colorama.winterm.win32') + def testInit(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 7 + 6 * 16 + 8 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + self.assertEqual(term._fore, 7) + self.assertEqual(term._back, 6) + self.assertEqual(term._style, 8) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testGetAttrs(self): + term = WinTerm() + + term._fore = 0 + term._back = 0 + term._style = 0 + self.assertEqual(term.get_attrs(), 0) + + term._fore = WinColor.YELLOW + self.assertEqual(term.get_attrs(), WinColor.YELLOW) + + term._back = WinColor.MAGENTA + self.assertEqual( + term.get_attrs(), + WinColor.YELLOW + WinColor.MAGENTA * 16) + + term._style = WinStyle.BRIGHT + self.assertEqual( + term.get_attrs(), + WinColor.YELLOW + WinColor.MAGENTA * 16 + WinStyle.BRIGHT) + + @patch('colorama.winterm.win32') + def testResetAll(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 1 + 2 * 16 + 8 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + + term.set_console = Mock() + term._fore = -1 + term._back = -1 + term._style = -1 + + term.reset_all() + + self.assertEqual(term._fore, 1) + self.assertEqual(term._back, 2) + self.assertEqual(term._style, 8) + self.assertEqual(term.set_console.called, True) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testFore(self): + term = WinTerm() + term.set_console = Mock() + term._fore = 0 + + term.fore(5) + + self.assertEqual(term._fore, 5) + self.assertEqual(term.set_console.called, True) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testBack(self): + term = WinTerm() + term.set_console = Mock() + term._back = 0 + + term.back(5) + + self.assertEqual(term._back, 5) + self.assertEqual(term.set_console.called, True) + + @skipUnless(sys.platform.startswith("win"), "requires Windows") + def testStyle(self): + term = WinTerm() + term.set_console = Mock() + term._style = 0 + + term.style(22) + + self.assertEqual(term._style, 22) + self.assertEqual(term.set_console.called, True) + + @patch('colorama.winterm.win32') + def testSetConsole(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 0 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + term.windll = Mock() + + term.set_console() + + self.assertEqual( + mockWin32.SetConsoleTextAttribute.call_args, + ((mockWin32.STDOUT, term.get_attrs()), {}) + ) + + @patch('colorama.winterm.win32') + def testSetConsoleOnStderr(self, mockWin32): + mockAttr = Mock() + mockAttr.wAttributes = 0 + mockWin32.GetConsoleScreenBufferInfo.return_value = mockAttr + term = WinTerm() + term.windll = Mock() + + term.set_console(on_stderr=True) + + self.assertEqual( + mockWin32.SetConsoleTextAttribute.call_args, + ((mockWin32.STDERR, term.get_attrs()), {}) + ) + + +if __name__ == '__main__': + main() diff --git a/elitebot/lib/python3.11/site-packages/colorama/win32.py b/elitebot/lib/python3.11/site-packages/colorama/win32.py new file mode 100644 index 0000000..841b0e2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/win32.py @@ -0,0 +1,180 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + +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 + + _GetConsoleMode = windll.kernel32.GetConsoleMode + _GetConsoleMode.argtypes = [ + wintypes.HANDLE, + POINTER(wintypes.DWORD) + ] + _GetConsoleMode.restype = wintypes.BOOL + + _SetConsoleMode = windll.kernel32.SetConsoleMode + _SetConsoleMode.argtypes = [ + wintypes.HANDLE, + wintypes.DWORD + ] + _SetConsoleMode.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) + + def GetConsoleMode(handle): + mode = wintypes.DWORD() + success = _GetConsoleMode(handle, byref(mode)) + if not success: + raise ctypes.WinError() + return mode.value + + def SetConsoleMode(handle, mode): + success = _SetConsoleMode(handle, mode) + if not success: + raise ctypes.WinError() diff --git a/elitebot/lib/python3.11/site-packages/colorama/winterm.py b/elitebot/lib/python3.11/site-packages/colorama/winterm.py new file mode 100644 index 0000000..aad867e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/colorama/winterm.py @@ -0,0 +1,195 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +try: + from msvcrt import get_osfhandle +except ImportError: + def get_osfhandle(_): + raise OSError("This isn't windows!") + + +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) + + +def enable_vt_processing(fd): + if win32.windll is None or not win32.winapi_test(): + return False + + try: + handle = get_osfhandle(fd) + mode = win32.GetConsoleMode(handle) + win32.SetConsoleMode( + handle, + mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING, + ) + + mode = win32.GetConsoleMode(handle) + if mode & win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING: + return True + # Can get TypeError in testsuite where 'fd' is a Mock() + except (OSError, TypeError): + return False diff --git a/elitebot/lib/python3.11/site-packages/distutils-precedence.pth b/elitebot/lib/python3.11/site-packages/distutils-precedence.pth new file mode 100644 index 0000000..7f009fe --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/distutils-precedence.pth @@ -0,0 +1 @@ +import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'local') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/AUTHORS b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/AUTHORS new file mode 100644 index 0000000..42a5c22 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/AUTHORS @@ -0,0 +1,51 @@ +Original Authors +---------------- +* Armin Rigo +* Christian Tismer + +Contributors +------------ +* Al Stone +* Alexander Schmidt +* Alexey Borzenkov +* Andreas Schwab +* Armin Ronacher +* Bin Wang +* Bob Ippolito +* ChangBo Guo +* Christoph Gohlke +* Denis Bilenko +* Dirk Mueller +* Donovan Preston +* Fantix King +* Floris Bruynooghe +* Fredrik Fornwall +* Gerd Woetzel +* Giel van Schijndel +* Gökhan Karabulut +* Gustavo Niemeyer +* Guy Rozendorn +* Hye-Shik Chang +* Jared Kuolt +* Jason Madden +* Josh Snyder +* Kyle Ambroff +* Laszlo Boszormenyi +* Mao Han +* Marc Abramowitz +* Marc Schlaich +* Marcin Bachry +* Matt Madison +* Matt Turner +* Michael Ellerman +* Michael Matz +* Ralf Schmitt +* Robie Basak +* Ronny Pfannschmidt +* Samual M. Rushing +* Tony Bowles +* Tony Breeds +* Trevor Bowen +* Tulio Magno Quites Machado Filho +* Ulrich Weigand +* Victor Stinner diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/INSTALLER b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE new file mode 100644 index 0000000..b73a4a1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE @@ -0,0 +1,30 @@ +The following files are derived from Stackless Python and are subject to the +same license as Stackless Python: + + src/greenlet/slp_platformselect.h + files in src/greenlet/platform/ directory + +See LICENSE.PSF and http://www.stackless.com/ for details. + +Unless otherwise noted, the files in greenlet have been released under the +following MIT license: + +Copyright (c) Armin Rigo, Christian Tismer and contributors + +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/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE.PSF b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE.PSF new file mode 100644 index 0000000..d3b509a --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/LICENSE.PSF @@ -0,0 +1,47 @@ +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") 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 alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011 Python Software Foundation; All Rights Reserved" are retained in Python +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 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. + +4. PSF is making Python 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 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +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, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/METADATA b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/METADATA new file mode 100644 index 0000000..e87d0ab --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/METADATA @@ -0,0 +1,102 @@ +Metadata-Version: 2.1 +Name: greenlet +Version: 3.0.3 +Summary: Lightweight in-process concurrent programming +Home-page: https://greenlet.readthedocs.io/ +Author: Alexey Borzenkov +Author-email: snaury@gmail.com +Maintainer: Jason Madden +Maintainer-email: jason@seecoresoftware.com +License: MIT License +Project-URL: Bug Tracker, https://github.com/python-greenlet/greenlet/issues +Project-URL: Source Code, https://github.com/python-greenlet/greenlet/ +Project-URL: Documentation, https://greenlet.readthedocs.io/ +Keywords: greenlet coroutine concurrency threads cooperative +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Natural Language :: English +Classifier: Programming Language :: C +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: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Operating System :: OS Independent +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: LICENSE.PSF +License-File: AUTHORS +Provides-Extra: docs +Requires-Dist: Sphinx ; extra == 'docs' +Requires-Dist: furo ; extra == 'docs' +Provides-Extra: test +Requires-Dist: objgraph ; extra == 'test' +Requires-Dist: psutil ; extra == 'test' + +.. This file is included into docs/history.rst + + +Greenlets are lightweight coroutines for in-process concurrent +programming. + +The "greenlet" package is a spin-off of `Stackless`_, a version of +CPython that supports micro-threads called "tasklets". Tasklets run +pseudo-concurrently (typically in a single or a few OS-level threads) +and are synchronized with data exchanges on "channels". + +A "greenlet", on the other hand, is a still more primitive notion of +micro-thread with no implicit scheduling; coroutines, in other words. +This is useful when you want to control exactly when your code runs. +You can build custom scheduled micro-threads on top of greenlet; +however, it seems that greenlets are useful on their own as a way to +make advanced control flow structures. For example, we can recreate +generators; the difference with Python's own generators is that our +generators can call nested functions and the nested functions can +yield values too. (Additionally, you don't need a "yield" keyword. See +the example in `test_generator.py +`_). + +Greenlets are provided as a C extension module for the regular unmodified +interpreter. + +.. _`Stackless`: http://www.stackless.com + + +Who is using Greenlet? +====================== + +There are several libraries that use Greenlet as a more flexible +alternative to Python's built in coroutine support: + + - `Concurrence`_ + - `Eventlet`_ + - `Gevent`_ + +.. _Concurrence: http://opensource.hyves.org/concurrence/ +.. _Eventlet: http://eventlet.net/ +.. _Gevent: http://www.gevent.org/ + +Getting Greenlet +================ + +The easiest way to get Greenlet is to install it with pip:: + + pip install greenlet + + +Source code archives and binary distributions are available on the +python package index at https://pypi.org/project/greenlet + +The source code repository is hosted on github: +https://github.com/python-greenlet/greenlet + +Documentation is available on readthedocs.org: +https://greenlet.readthedocs.io diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/RECORD b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/RECORD new file mode 100644 index 0000000..dbfc94f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/RECORD @@ -0,0 +1,117 @@ +../../../include/site/python3.11/greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 +greenlet-3.0.3.dist-info/AUTHORS,sha256=swW28t2knVRxRkaEQNZtO7MP9Sgnompb7B6cNgJM8Gk,849 +greenlet-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +greenlet-3.0.3.dist-info/LICENSE,sha256=dpgx1uXfrywggC-sz_H6-0wgJd2PYlPfpH_K1Z1NCXk,1434 +greenlet-3.0.3.dist-info/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424 +greenlet-3.0.3.dist-info/METADATA,sha256=CHtHlitUM_AS9hKoJfYLF3Vz-UFJlqRnhbRl2-1JrjU,3779 +greenlet-3.0.3.dist-info/RECORD,, +greenlet-3.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +greenlet-3.0.3.dist-info/WHEEL,sha256=xlJUan517virathN2lKmlOcMObJx20JZaCR_iv23glU,153 +greenlet-3.0.3.dist-info/top_level.txt,sha256=YSnRsCRoO61JGlP57o8iKL6rdLWDWuiyKD8ekpWUsDc,9 +greenlet/TBrokenGreenlet.cpp,sha256=YgKaHkQV6_dKBrgS0HKDSqZroskv0IwSZDo4bsiwz3w,1029 +greenlet/TExceptionState.cpp,sha256=Ctg2YfyEYNjOYbteRB_oIJa9lNGyC7N1F3h4XqqQdg8,1367 +greenlet/TGreenlet.cpp,sha256=1xwAzGNqO68AZ4D5lD5DHmGPBohM6nv4BYnLatgIL68,25637 +greenlet/TGreenletGlobals.cpp,sha256=qLi1icS1UDSbefTkolz9TycEi_GOUblsEznMp0HFywQ,3268 +greenlet/TMainGreenlet.cpp,sha256=FvWtGJDKb64DLy0n-ddcTF6xJDwczPMKSm9mXSsHJKg,3365 +greenlet/TPythonState.cpp,sha256=QUoIQzF0HYmAJO_nwX5gXSSlMNL1mkxlN24KJCXIrIQ,14861 +greenlet/TStackState.cpp,sha256=VclDR-qiMeJjuiJxL9_u24MJiTgdSaYvr8bWQdTEZjY,7389 +greenlet/TThreadStateDestroy.cpp,sha256=EqZ-GjksrWNC20CY_P0yXN43wVRMYEh659SmRRqBaI4,7214 +greenlet/TUserGreenlet.cpp,sha256=b_Bmh4WZdS6I1yM2AfHRtd535WovtpYMkpfu2GQpaDs,23618 +greenlet/__init__.py,sha256=Dw4tovn18bpPaWQ4SK7jDJe24uV4ao264UfaT0uufxU,1723 +greenlet/__pycache__/__init__.cpython-311.pyc,, +greenlet/_greenlet.cpython-311-x86_64-linux-gnu.so,sha256=89kThwDfvkHXs3GXeuXnnZb-wShF60h1XyHXZYmkymU,1506232 +greenlet/greenlet.cpp,sha256=k9RZolayY79WgjPXwcA3Vcv48MuW7TAtogIZPaDD3gM,48815 +greenlet/greenlet.h,sha256=sz5pYRSQqedgOt2AMgxLZdTjO-qcr_JMvgiEJR9IAJ8,4755 +greenlet/greenlet_allocator.hpp,sha256=kxyWW4Qdwlrc7ufgdb5vd6Y7jhauQ699Kod0mqiO1iM,1582 +greenlet/greenlet_compiler_compat.hpp,sha256=m7wvwrZqBoCQpDMTP-Z7whdXIES7e3AuXBgvPHSsfxg,4140 +greenlet/greenlet_cpython_add_pending.hpp,sha256=apAwIhGlgYrnYn03zWL6Sxy68kltDeb1e0QupZfb3DQ,6043 +greenlet/greenlet_cpython_compat.hpp,sha256=ZpN8gewZeOtd6T-mLidA7zteQ_P4vG8T1za_KPvCijg,3621 +greenlet/greenlet_exceptions.hpp,sha256=Dt8YdaQn8AK9nBfwU9rrDoMlR2Lw5aLTQV6ZAsHmfsw,3683 +greenlet/greenlet_greenlet.hpp,sha256=Ct_EAx4OJL6FvF5g3jV1ybSxnqzLVaRdPi2EcYT1iq4,27728 +greenlet/greenlet_internal.hpp,sha256=ZXH5zemWCN8wH8zAqMUGycvz_3IulRL6Gf2hZA6CknE,2703 +greenlet/greenlet_refs.hpp,sha256=ECkHKV1CVamtzmWWGKXXMpw8lXLeIzastXM9tfqlsNI,33864 +greenlet/greenlet_slp_switch.hpp,sha256=kM1QHA2iV-gH4cFyN6lfIagHQxvJZjWOVJdIxRE3TlQ,3198 +greenlet/greenlet_thread_state.hpp,sha256=0UwJCNd86ifwM2yDd3QrNmHAECL-eNADHubwiB_XGA4,20614 +greenlet/greenlet_thread_state_dict_cleanup.hpp,sha256=tEN0rI1pZiEsdtr7Oda24gr52fGiHnYTLyM8Vme3Gns,3831 +greenlet/greenlet_thread_support.hpp,sha256=XUJ6ljWjf9OYyuOILiz8e_yHvT3fbaUiHdhiPNQUV4s,867 +greenlet/platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +greenlet/platform/__pycache__/__init__.cpython-311.pyc,, +greenlet/platform/setup_switch_x64_masm.cmd,sha256=ZpClUJeU0ujEPSTWNSepP0W2f9XiYQKA8QKSoVou8EU,143 +greenlet/platform/switch_aarch64_gcc.h,sha256=GKC0yWNXnbK2X--X6aguRCMj2Tg7hDU1Zkl3RljDvC8,4307 +greenlet/platform/switch_alpha_unix.h,sha256=Z-SvF8JQV3oxWT8JRbL9RFu4gRFxPdJ7cviM8YayMmw,671 +greenlet/platform/switch_amd64_unix.h,sha256=EcSFCBlodEBhqhKjcJqY_5Dn_jn7pKpkJlOvp7gFXLI,2748 +greenlet/platform/switch_arm32_gcc.h,sha256=Z3KkHszdgq6uU4YN3BxvKMG2AdDnovwCCNrqGWZ1Lyo,2479 +greenlet/platform/switch_arm32_ios.h,sha256=mm5_R9aXB92hyxzFRwB71M60H6AlvHjrpTrc72Pz3l8,1892 +greenlet/platform/switch_arm64_masm.asm,sha256=4kpTtfy7rfcr8j1CpJLAK21EtZpGDAJXWRU68HEy5A8,1245 +greenlet/platform/switch_arm64_masm.obj,sha256=DmLnIB_icoEHAz1naue_pJPTZgR9ElM7-Nmztr-o9_U,746 +greenlet/platform/switch_arm64_msvc.h,sha256=RqK5MHLmXI3Q-FQ7tm32KWnbDNZKnkJdq8CR89cz640,398 +greenlet/platform/switch_csky_gcc.h,sha256=kDikyiPpewP71KoBZQO_MukDTXTXBiC7x-hF0_2DL0w,1331 +greenlet/platform/switch_loongarch64_linux.h,sha256=7M-Dhc4Q8tRbJCJhalDLwU6S9Mx8MjmN1RbTDgIvQTM,779 +greenlet/platform/switch_m68k_gcc.h,sha256=VSa6NpZhvyyvF-Q58CTIWSpEDo4FKygOyTz00whctlw,928 +greenlet/platform/switch_mips_unix.h,sha256=E0tYsqc5anDY1BhenU1l8DW-nVHC_BElzLgJw3TGtPk,1426 +greenlet/platform/switch_ppc64_aix.h,sha256=_BL0iyRr3ZA5iPlr3uk9SJ5sNRWGYLrXcZ5z-CE9anE,3860 +greenlet/platform/switch_ppc64_linux.h,sha256=0rriT5XyxPb0GqsSSn_bP9iQsnjsPbBmu0yqo5goSyQ,3815 +greenlet/platform/switch_ppc_aix.h,sha256=pHA4slEjUFP3J3SYm1TAlNPhgb2G_PAtax5cO8BEe1A,2941 +greenlet/platform/switch_ppc_linux.h,sha256=YwrlKUzxlXuiKMQqr6MFAV1bPzWnmvk6X1AqJZEpOWU,2759 +greenlet/platform/switch_ppc_macosx.h,sha256=L8sB0c00V4G2_5cQCG3zX-23DKq3le_Dcj0sUDcACos,2624 +greenlet/platform/switch_ppc_unix.h,sha256=POy4bRBcH74Chfw4viFE9bVlZ-7BaNsFC0NnXr1L2tg,2652 +greenlet/platform/switch_riscv_unix.h,sha256=jX3vC_xZXiUho8tz4J6Ai8BNQB80yLn03fxkoMztVCU,740 +greenlet/platform/switch_s390_unix.h,sha256=RRlGu957ybmq95qNNY4Qw1mcaoT3eBnW5KbVwu48KX8,2763 +greenlet/platform/switch_sparc_sun_gcc.h,sha256=xZish9GsMHBienUbUMsX1-ZZ-as7hs36sVhYIE3ew8Y,2797 +greenlet/platform/switch_x32_unix.h,sha256=nM98PKtzTWc1lcM7TRMUZJzskVdR1C69U1UqZRWX0GE,1509 +greenlet/platform/switch_x64_masm.asm,sha256=nu6n2sWyXuXfpPx40d9YmLfHXUc1sHgeTvX1kUzuvEM,1841 +greenlet/platform/switch_x64_masm.obj,sha256=GNtTNxYdo7idFUYsQv-mrXWgyT5EJ93-9q90lN6svtQ,1078 +greenlet/platform/switch_x64_msvc.h,sha256=LIeasyKo_vHzspdMzMHbosRhrBfKI4BkQOh4qcTHyJw,1805 +greenlet/platform/switch_x86_msvc.h,sha256=TtGOwinbFfnn6clxMNkCz8i6OmgB6kVRrShoF5iT9to,12838 +greenlet/platform/switch_x86_unix.h,sha256=VplW9H0FF0cZHw1DhJdIUs5q6YLS4cwb2nYwjF83R1s,3059 +greenlet/slp_platformselect.h,sha256=JEnia_2HsTwdqvnnEsDxHQqalYvFJqx_CDsqvNUQYe8,3600 +greenlet/tests/__init__.py,sha256=F282jaIavKrhsYgHJEXtIQXKHdHpe9OJOPTK7R40JzI,9022 +greenlet/tests/__pycache__/__init__.cpython-311.pyc,, +greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-311.pyc,, +greenlet/tests/__pycache__/fail_cpp_exception.cpython-311.pyc,, +greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-311.pyc,, +greenlet/tests/__pycache__/fail_slp_switch.cpython-311.pyc,, +greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-311.pyc,, +greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-311.pyc,, +greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-311.pyc,, +greenlet/tests/__pycache__/leakcheck.cpython-311.pyc,, +greenlet/tests/__pycache__/test_contextvars.cpython-311.pyc,, +greenlet/tests/__pycache__/test_cpp.cpython-311.pyc,, +greenlet/tests/__pycache__/test_extension_interface.cpython-311.pyc,, +greenlet/tests/__pycache__/test_gc.cpython-311.pyc,, +greenlet/tests/__pycache__/test_generator.cpython-311.pyc,, +greenlet/tests/__pycache__/test_generator_nested.cpython-311.pyc,, +greenlet/tests/__pycache__/test_greenlet.cpython-311.pyc,, +greenlet/tests/__pycache__/test_greenlet_trash.cpython-311.pyc,, +greenlet/tests/__pycache__/test_leaks.cpython-311.pyc,, +greenlet/tests/__pycache__/test_stack_saved.cpython-311.pyc,, +greenlet/tests/__pycache__/test_throw.cpython-311.pyc,, +greenlet/tests/__pycache__/test_tracing.cpython-311.pyc,, +greenlet/tests/__pycache__/test_version.cpython-311.pyc,, +greenlet/tests/__pycache__/test_weakref.cpython-311.pyc,, +greenlet/tests/_test_extension.c,sha256=vkeGA-6oeJcGILsD7oIrT1qZop2GaTOHXiNT7mcSl-0,5773 +greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so,sha256=cYvKKnDFhjTDjM_mYc_4l53g44Iz-CJR5woKXR6Ddqg,36624 +greenlet/tests/_test_extension_cpp.cpp,sha256=e0kVnaB8CCaEhE9yHtNyfqTjevsPDKKx-zgxk7PPK48,6565 +greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so,sha256=de1fYlFMrBJRAwPKHWl-OMuBy8AmSXsh14FYYyLj6dI,57288 +greenlet/tests/fail_clearing_run_switches.py,sha256=o433oA_nUCtOPaMEGc8VEhZIKa71imVHXFw7TsXaP8M,1263 +greenlet/tests/fail_cpp_exception.py,sha256=o_ZbipWikok8Bjc-vjiQvcb5FHh2nVW-McGKMLcMzh0,985 +greenlet/tests/fail_initialstub_already_started.py,sha256=txENn5IyzGx2p-XR1XB7qXmC8JX_4mKDEA8kYBXUQKc,1961 +greenlet/tests/fail_slp_switch.py,sha256=rJBZcZfTWR3e2ERQtPAud6YKShiDsP84PmwOJbp4ey0,524 +greenlet/tests/fail_switch_three_greenlets.py,sha256=zSitV7rkNnaoHYVzAGGLnxz-yPtohXJJzaE8ehFDQ0M,956 +greenlet/tests/fail_switch_three_greenlets2.py,sha256=FPJensn2EJxoropl03JSTVP3kgP33k04h6aDWWozrOk,1285 +greenlet/tests/fail_switch_two_greenlets.py,sha256=1CaI8s3504VbbF1vj1uBYuy-zxBHVzHPIAd1LIc8ONg,817 +greenlet/tests/leakcheck.py,sha256=inbfM7_oVzd8jIKGxCgo4JqpFZaDAnWPkSULJ8vIE1s,11964 +greenlet/tests/test_contextvars.py,sha256=0n5pR_lbpAppc5wFfK0e1SwYLM-fsSFp72B5_ArLPGE,10348 +greenlet/tests/test_cpp.py,sha256=hpxhFAdKJTpAVZP8CBGs1ZcrKdscI9BaDZk4btkI5d4,2736 +greenlet/tests/test_extension_interface.py,sha256=eJ3cwLacdK2WbsrC-4DgeyHdwLRcG4zx7rrkRtqSzC4,3829 +greenlet/tests/test_gc.py,sha256=PCOaRpIyjNnNlDogGL3FZU_lrdXuM-pv1rxeE5TP5mc,2923 +greenlet/tests/test_generator.py,sha256=tONXiTf98VGm347o1b-810daPiwdla5cbpFg6QI1R1g,1240 +greenlet/tests/test_generator_nested.py,sha256=7v4HOYrf1XZP39dk5IUMubdZ8yc3ynwZcqj9GUJyMSA,3718 +greenlet/tests/test_greenlet.py,sha256=95qgDR-xtB0jzEFLirNx7HPUdwHikVMvDdyUoCvyjOo,45354 +greenlet/tests/test_greenlet_trash.py,sha256=P6r-3K4fmXX8foW8BVgthuqVKjicHMDvxfK7Al4x028,7508 +greenlet/tests/test_leaks.py,sha256=wskLqCAvqZ3qTZkam_wXzd-E5zelUjlXS5Ss8KshtZY,17465 +greenlet/tests/test_stack_saved.py,sha256=eyzqNY2VCGuGlxhT_In6TvZ6Okb0AXFZVyBEnK1jDwA,446 +greenlet/tests/test_throw.py,sha256=u2TQ_WvvCd6N6JdXWIxVEcXkKu5fepDlz9dktYdmtng,3712 +greenlet/tests/test_tracing.py,sha256=VlwzMU0C1noospZhuUMyB7MHw200emIvGCN_6G2p2ZU,8250 +greenlet/tests/test_version.py,sha256=O9DpAITsOFgiRcjd4odQ7ejmwx_N9Q1zQENVcbtFHIc,1339 +greenlet/tests/test_weakref.py,sha256=F8M23btEF87bIbpptLNBORosbQqNZGiYeKMqYjWrsak,883 diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/REQUESTED b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/WHEEL b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/WHEEL new file mode 100644 index 0000000..cc43dbf --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: false +Tag: cp311-cp311-manylinux_2_24_x86_64 +Tag: cp311-cp311-manylinux_2_28_x86_64 + diff --git a/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/top_level.txt b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/top_level.txt new file mode 100644 index 0000000..46725be --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet-3.0.3.dist-info/top_level.txt @@ -0,0 +1 @@ +greenlet diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TBrokenGreenlet.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TBrokenGreenlet.cpp new file mode 100644 index 0000000..11a3bea --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TBrokenGreenlet.cpp @@ -0,0 +1,45 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::UserGreenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ + +#include "greenlet_greenlet.hpp" + +namespace greenlet { + +void* BrokenGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void BrokenGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + +greenlet::PythonAllocator greenlet::BrokenGreenlet::allocator; + +bool +BrokenGreenlet::force_slp_switch_error() const noexcept +{ + return this->_force_slp_switch_error; +} + +UserGreenlet::switchstack_result_t BrokenGreenlet::g_switchstack(void) +{ + if (this->_force_switch_error) { + return switchstack_result_t(-1); + } + return UserGreenlet::g_switchstack(); +} + +}; //namespace greenlet diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TExceptionState.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TExceptionState.cpp new file mode 100644 index 0000000..ee6b191 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TExceptionState.cpp @@ -0,0 +1,62 @@ +#ifndef GREENLET_EXCEPTION_STATE_CPP +#define GREENLET_EXCEPTION_STATE_CPP + +#include +#include "greenlet_greenlet.hpp" + +namespace greenlet { + + +ExceptionState::ExceptionState() +{ + this->clear(); +} + +void ExceptionState::operator<<(const PyThreadState *const tstate) noexcept +{ + this->exc_info = tstate->exc_info; + this->exc_state = tstate->exc_state; +} + +void ExceptionState::operator>>(PyThreadState *const tstate) noexcept +{ + tstate->exc_state = this->exc_state; + tstate->exc_info = + this->exc_info ? this->exc_info : &tstate->exc_state; + this->clear(); +} + +void ExceptionState::clear() noexcept +{ + this->exc_info = nullptr; + this->exc_state.exc_value = nullptr; +#if !GREENLET_PY311 + this->exc_state.exc_type = nullptr; + this->exc_state.exc_traceback = nullptr; +#endif + this->exc_state.previous_item = nullptr; +} + +int ExceptionState::tp_traverse(visitproc visit, void* arg) noexcept +{ + Py_VISIT(this->exc_state.exc_value); +#if !GREENLET_PY311 + Py_VISIT(this->exc_state.exc_type); + Py_VISIT(this->exc_state.exc_traceback); +#endif + return 0; +} + +void ExceptionState::tp_clear() noexcept +{ + Py_CLEAR(this->exc_state.exc_value); +#if !GREENLET_PY311 + Py_CLEAR(this->exc_state.exc_type); + Py_CLEAR(this->exc_state.exc_traceback); +#endif +} + + +}; // namespace greenlet + +#endif // GREENLET_EXCEPTION_STATE_CPP diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TGreenlet.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TGreenlet.cpp new file mode 100644 index 0000000..51f8995 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TGreenlet.cpp @@ -0,0 +1,714 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::Greenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ + +#include "greenlet_internal.hpp" +#include "greenlet_greenlet.hpp" +#include "greenlet_thread_state.hpp" + +#include "TGreenletGlobals.cpp" +#include "TThreadStateDestroy.cpp" + +namespace greenlet { + +Greenlet::Greenlet(PyGreenlet* p) +{ + p ->pimpl = this; +} + +Greenlet::~Greenlet() +{ + // XXX: Can't do this. tp_clear is a virtual function, and by the + // time we're here, we've sliced off our child classes. + //this->tp_clear(); +} + +Greenlet::Greenlet(PyGreenlet* p, const StackState& initial_stack) + : stack_state(initial_stack) +{ + // can't use a delegating constructor because of + // MSVC for Python 2.7 + p->pimpl = this; +} + +bool +Greenlet::force_slp_switch_error() const noexcept +{ + return false; +} + +void +Greenlet::release_args() +{ + this->switch_args.CLEAR(); +} + +/** + * CAUTION: This will allocate memory and may trigger garbage + * collection and arbitrary Python code. + */ +OwnedObject +Greenlet::throw_GreenletExit_during_dealloc(const ThreadState& UNUSED(current_thread_state)) +{ + // If we're killed because we lost all references in the + // middle of a switch, that's ok. Don't reset the args/kwargs, + // we still want to pass them to the parent. + PyErr_SetString(mod_globs->PyExc_GreenletExit, + "Killing the greenlet because all references have vanished."); + // To get here it had to have run before + return this->g_switch(); +} + +inline void +Greenlet::slp_restore_state() noexcept +{ +#ifdef SLP_BEFORE_RESTORE_STATE + SLP_BEFORE_RESTORE_STATE(); +#endif + this->stack_state.copy_heap_to_stack( + this->thread_state()->borrow_current()->stack_state); +} + + +inline int +Greenlet::slp_save_state(char *const stackref) noexcept +{ + // XXX: This used to happen in the middle, before saving, but + // after finding the next owner. Does that matter? This is + // only defined for Sparc/GCC where it flushes register + // windows to the stack (I think) +#ifdef SLP_BEFORE_SAVE_STATE + SLP_BEFORE_SAVE_STATE(); +#endif + return this->stack_state.copy_stack_to_heap(stackref, + this->thread_state()->borrow_current()->stack_state); +} + +/** + * CAUTION: This will allocate memory and may trigger garbage + * collection and arbitrary Python code. + */ +OwnedObject +Greenlet::on_switchstack_or_initialstub_failure( + Greenlet* target, + const Greenlet::switchstack_result_t& err, + const bool target_was_me, + const bool was_initial_stub) +{ + // If we get here, either g_initialstub() + // failed, or g_switchstack() failed. Either one of those + // cases SHOULD leave us in the original greenlet with a valid stack. + if (!PyErr_Occurred()) { + PyErr_SetString( + PyExc_SystemError, + was_initial_stub + ? "Failed to switch stacks into a greenlet for the first time." + : "Failed to switch stacks into a running greenlet."); + } + this->release_args(); + + if (target && !target_was_me) { + target->murder_in_place(); + } + + assert(!err.the_new_current_greenlet); + assert(!err.origin_greenlet); + return OwnedObject(); + +} + +OwnedGreenlet +Greenlet::g_switchstack_success() noexcept +{ + PyThreadState* tstate = PyThreadState_GET(); + // restore the saved state + this->python_state >> tstate; + this->exception_state >> tstate; + + // The thread state hasn't been changed yet. + ThreadState* thread_state = this->thread_state(); + OwnedGreenlet result(thread_state->get_current()); + thread_state->set_current(this->self()); + //assert(thread_state->borrow_current().borrow() == this->_self); + return result; +} + +Greenlet::switchstack_result_t +Greenlet::g_switchstack(void) +{ + // if any of these assertions fail, it's likely because we + // switched away and tried to switch back to us. Early stages of + // switching are not reentrant because we re-use ``this->args()``. + // Switching away would happen if we trigger a garbage collection + // (by just using some Python APIs that happen to allocate Python + // objects) and some garbage had weakref callbacks or __del__ that + // switches (people don't write code like that by hand, but with + // gevent it's possible without realizing it) + assert(this->args() || PyErr_Occurred()); + { /* save state */ + if (this->thread_state()->is_current(this->self())) { + // Hmm, nothing to do. + // TODO: Does this bypass trace events that are + // important? + return switchstack_result_t(0, + this, this->thread_state()->borrow_current()); + } + BorrowedGreenlet current = this->thread_state()->borrow_current(); + PyThreadState* tstate = PyThreadState_GET(); + + current->python_state << tstate; + current->exception_state << tstate; + this->python_state.will_switch_from(tstate); + switching_thread_state = this; + current->expose_frames(); + } + assert(this->args() || PyErr_Occurred()); + // If this is the first switch into a greenlet, this will + // return twice, once with 1 in the new greenlet, once with 0 + // in the origin. + int err; + if (this->force_slp_switch_error()) { + err = -1; + } + else { + err = slp_switch(); + } + + if (err < 0) { /* error */ + // Tested by + // test_greenlet.TestBrokenGreenlets.test_failed_to_slp_switch_into_running + // + // It's not clear if it's worth trying to clean up and + // continue here. Failing to switch stacks is a big deal which + // may not be recoverable (who knows what state the stack is in). + // Also, we've stolen references in preparation for calling + // ``g_switchstack_success()`` and we don't have a clean + // mechanism for backing that all out. + Py_FatalError("greenlet: Failed low-level slp_switch(). The stack is probably corrupt."); + } + + // No stack-based variables are valid anymore. + + // But the global is volatile so we can reload it without the + // compiler caching it from earlier. + Greenlet* greenlet_that_switched_in = switching_thread_state; // aka this + switching_thread_state = nullptr; + // except that no stack variables are valid, we would: + // assert(this == greenlet_that_switched_in); + + // switchstack success is where we restore the exception state, + // etc. It returns the origin greenlet because its convenient. + + OwnedGreenlet origin = greenlet_that_switched_in->g_switchstack_success(); + assert(greenlet_that_switched_in->args() || PyErr_Occurred()); + return switchstack_result_t(err, greenlet_that_switched_in, origin); +} + + +inline void +Greenlet::check_switch_allowed() const +{ + // TODO: Make this take a parameter of the current greenlet, + // or current main greenlet, to make the check for + // cross-thread switching cheaper. Surely somewhere up the + // call stack we've already accessed the thread local variable. + + // We expect to always have a main greenlet now; accessing the thread state + // created it. However, if we get here and cleanup has already + // begun because we're a greenlet that was running in a + // (now dead) thread, these invariants will not hold true. In + // fact, accessing `this->thread_state` may not even be possible. + + // If the thread this greenlet was running in is dead, + // we'll still have a reference to a main greenlet, but the + // thread state pointer we have is bogus. + // TODO: Give the objects an API to determine if they belong + // to a dead thread. + + const BorrowedMainGreenlet main_greenlet = this->find_main_greenlet_in_lineage(); + + if (!main_greenlet) { + throw PyErrOccurred(mod_globs->PyExc_GreenletError, + "cannot switch to a garbage collected greenlet"); + } + + if (!main_greenlet->thread_state()) { + throw PyErrOccurred(mod_globs->PyExc_GreenletError, + "cannot switch to a different thread (which happens to have exited)"); + } + + // The main greenlet we found was from the .parent lineage. + // That may or may not have any relationship to the main + // greenlet of the running thread. We can't actually access + // our this->thread_state members to try to check that, + // because it could be in the process of getting destroyed, + // but setting the main_greenlet->thread_state member to NULL + // may not be visible yet. So we need to check against the + // current thread state (once the cheaper checks are out of + // the way) + const BorrowedMainGreenlet current_main_greenlet = GET_THREAD_STATE().state().borrow_main_greenlet(); + if ( + // lineage main greenlet is not this thread's greenlet + current_main_greenlet != main_greenlet + || ( + // atteched to some thread + this->main_greenlet() + // XXX: Same condition as above. Was this supposed to be + // this->main_greenlet()? + && current_main_greenlet != main_greenlet) + // switching into a known dead thread (XXX: which, if we get here, + // is bad, because we just accessed the thread state, which is + // gone!) + || (!current_main_greenlet->thread_state())) { + // CAUTION: This may trigger memory allocations, gc, and + // arbitrary Python code. + throw PyErrOccurred(mod_globs->PyExc_GreenletError, + "cannot switch to a different thread"); + } +} + +const OwnedObject +Greenlet::context() const +{ + using greenlet::PythonStateContext; + OwnedObject result; + + if (this->is_currently_running_in_some_thread()) { + /* Currently running greenlet: context is stored in the thread state, + not the greenlet object. */ + if (GET_THREAD_STATE().state().is_current(this->self())) { + result = PythonStateContext::context(PyThreadState_GET()); + } + else { + throw ValueError( + "cannot get context of a " + "greenlet that is running in a different thread"); + } + } + else { + /* Greenlet is not running: just return context. */ + result = this->python_state.context(); + } + if (!result) { + result = OwnedObject::None(); + } + return result; +} + + +void +Greenlet::context(BorrowedObject given) +{ + using greenlet::PythonStateContext; + if (!given) { + throw AttributeError("can't delete context attribute"); + } + if (given.is_None()) { + /* "Empty context" is stored as NULL, not None. */ + given = nullptr; + } + + //checks type, incrs refcnt + greenlet::refs::OwnedContext context(given); + PyThreadState* tstate = PyThreadState_GET(); + + if (this->is_currently_running_in_some_thread()) { + if (!GET_THREAD_STATE().state().is_current(this->self())) { + throw ValueError("cannot set context of a greenlet" + " that is running in a different thread"); + } + + /* Currently running greenlet: context is stored in the thread state, + not the greenlet object. */ + OwnedObject octx = OwnedObject::consuming(PythonStateContext::context(tstate)); + PythonStateContext::context(tstate, context.relinquish_ownership()); + } + else { + /* Greenlet is not running: just set context. Note that the + greenlet may be dead.*/ + this->python_state.context() = context; + } +} + +/** + * CAUTION: May invoke arbitrary Python code. + * + * Figure out what the result of ``greenlet.switch(arg, kwargs)`` + * should be and transfers ownership of it to the left-hand-side. + * + * If switch() was just passed an arg tuple, then we'll just return that. + * If only keyword arguments were passed, then we'll pass the keyword + * argument dict. Otherwise, we'll create a tuple of (args, kwargs) and + * return both. + * + * CAUTION: This may allocate a new tuple object, which may + * cause the Python garbage collector to run, which in turn may + * run arbitrary Python code that switches. + */ +OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept +{ + // Because this may invoke arbitrary Python code, which could + // result in switching back to us, we need to get the + // arguments locally on the stack. + assert(rhs); + OwnedObject args = rhs.args(); + OwnedObject kwargs = rhs.kwargs(); + rhs.CLEAR(); + // We shouldn't be called twice for the same switch. + assert(args || kwargs); + assert(!rhs); + + if (!kwargs) { + lhs = args; + } + else if (!PyDict_Size(kwargs.borrow())) { + lhs = args; + } + else if (!PySequence_Length(args.borrow())) { + lhs = kwargs; + } + else { + // PyTuple_Pack allocates memory, may GC, may run arbitrary + // Python code. + lhs = OwnedObject::consuming(PyTuple_Pack(2, args.borrow(), kwargs.borrow())); + } + return lhs; +} + +static OwnedObject +g_handle_exit(const OwnedObject& greenlet_result) +{ + if (!greenlet_result && mod_globs->PyExc_GreenletExit.PyExceptionMatches()) { + /* catch and ignore GreenletExit */ + PyErrFetchParam val; + PyErr_Fetch(PyErrFetchParam(), val, PyErrFetchParam()); + if (!val) { + return OwnedObject::None(); + } + return OwnedObject(val); + } + + if (greenlet_result) { + // package the result into a 1-tuple + // PyTuple_Pack increments the reference of its arguments, + // so we always need to decref the greenlet result; + // the owner will do that. + return OwnedObject::consuming(PyTuple_Pack(1, greenlet_result.borrow())); + } + + return OwnedObject(); +} + + + +/** + * May run arbitrary Python code. + */ +OwnedObject +Greenlet::g_switch_finish(const switchstack_result_t& err) +{ + assert(err.the_new_current_greenlet == this); + + ThreadState& state = *this->thread_state(); + // Because calling the trace function could do arbitrary things, + // including switching away from this greenlet and then maybe + // switching back, we need to capture the arguments now so that + // they don't change. + OwnedObject result; + if (this->args()) { + result <<= this->args(); + } + else { + assert(PyErr_Occurred()); + } + assert(!this->args()); + try { + // Our only caller handles the bad error case + assert(err.status >= 0); + assert(state.borrow_current() == this->self()); + if (OwnedObject tracefunc = state.get_tracefunc()) { + assert(result || PyErr_Occurred()); + g_calltrace(tracefunc, + result ? mod_globs->event_switch : mod_globs->event_throw, + err.origin_greenlet, + this->self()); + } + // The above could have invoked arbitrary Python code, but + // it couldn't switch back to this object and *also* + // throw an exception, so the args won't have changed. + + if (PyErr_Occurred()) { + // We get here if we fell of the end of the run() function + // raising an exception. The switch itself was + // successful, but the function raised. + // valgrind reports that memory allocated here can still + // be reached after a test run. + throw PyErrOccurred::from_current(); + } + return result; + } + catch (const PyErrOccurred&) { + /* Turn switch errors into switch throws */ + /* Turn trace errors into switch throws */ + this->release_args(); + throw; + } +} + +void +Greenlet::g_calltrace(const OwnedObject& tracefunc, + const greenlet::refs::ImmortalEventName& event, + const BorrowedGreenlet& origin, + const BorrowedGreenlet& target) +{ + PyErrPieces saved_exc; + try { + TracingGuard tracing_guard; + // TODO: We have saved the active exception (if any) that's + // about to be raised. In the 'throw' case, we could provide + // the exception to the tracefunction, which seems very helpful. + tracing_guard.CallTraceFunction(tracefunc, event, origin, target); + } + catch (const PyErrOccurred&) { + // In case of exceptions trace function is removed, + // and any existing exception is replaced with the tracing + // exception. + GET_THREAD_STATE().state().set_tracefunc(Py_None); + throw; + } + + saved_exc.PyErrRestore(); + assert( + (event == mod_globs->event_throw && PyErr_Occurred()) + || (event == mod_globs->event_switch && !PyErr_Occurred()) + ); +} + +void +Greenlet::murder_in_place() +{ + if (this->active()) { + assert(!this->is_currently_running_in_some_thread()); + this->deactivate_and_free(); + } +} + +inline void +Greenlet::deactivate_and_free() +{ + if (!this->active()) { + return; + } + // Throw away any saved stack. + this->stack_state = StackState(); + assert(!this->stack_state.active()); + // Throw away any Python references. + // We're holding a borrowed reference to the last + // frame we executed. Since we borrowed it, the + // normal traversal, clear, and dealloc functions + // ignore it, meaning it leaks. (The thread state + // object can't find it to clear it when that's + // deallocated either, because by definition if we + // got an object on this list, it wasn't + // running and the thread state doesn't have + // this frame.) + // So here, we *do* clear it. + this->python_state.tp_clear(true); +} + +bool +Greenlet::belongs_to_thread(const ThreadState* thread_state) const +{ + if (!this->thread_state() // not running anywhere, or thread + // exited + || !thread_state) { // same, or there is no thread state. + return false; + } + return true; +} + + +void +Greenlet::deallocing_greenlet_in_thread(const ThreadState* current_thread_state) +{ + /* Cannot raise an exception to kill the greenlet if + it is not running in the same thread! */ + if (this->belongs_to_thread(current_thread_state)) { + assert(current_thread_state); + // To get here it had to have run before + /* Send the greenlet a GreenletExit exception. */ + + // We don't care about the return value, only whether an + // exception happened. + this->throw_GreenletExit_during_dealloc(*current_thread_state); + return; + } + + // Not the same thread! Temporarily save the greenlet + // into its thread's deleteme list, *if* it exists. + // If that thread has already exited, and processed its pending + // cleanup, we'll never be able to clean everything up: we won't + // be able to raise an exception. + // That's mostly OK! Since we can't add it to a list, our refcount + // won't increase, and we'll go ahead with the DECREFs later. + ThreadState *const thread_state = this->thread_state(); + if (thread_state) { + thread_state->delete_when_thread_running(this->self()); + } + else { + // The thread is dead, we can't raise an exception. + // We need to make it look non-active, though, so that dealloc + // finishes killing it. + this->deactivate_and_free(); + } + return; +} + + +int +Greenlet::tp_traverse(visitproc visit, void* arg) +{ + + int result; + if ((result = this->exception_state.tp_traverse(visit, arg)) != 0) { + return result; + } + //XXX: This is ugly. But so is handling everything having to do + //with the top frame. + bool visit_top_frame = this->was_running_in_dead_thread(); + // When true, the thread is dead. Our implicit weak reference to the + // frame is now all that's left; we consider ourselves to + // strongly own it now. + if ((result = this->python_state.tp_traverse(visit, arg, visit_top_frame)) != 0) { + return result; + } + return 0; +} + +int +Greenlet::tp_clear() +{ + bool own_top_frame = this->was_running_in_dead_thread(); + this->exception_state.tp_clear(); + this->python_state.tp_clear(own_top_frame); + return 0; +} + +bool Greenlet::is_currently_running_in_some_thread() const +{ + return this->stack_state.active() && !this->python_state.top_frame(); +} + +#if GREENLET_PY312 +void GREENLET_NOINLINE(Greenlet::expose_frames)() +{ + if (!this->python_state.top_frame()) { + return; + } + + _PyInterpreterFrame* last_complete_iframe = nullptr; + _PyInterpreterFrame* iframe = this->python_state.top_frame()->f_frame; + while (iframe) { + // We must make a copy before looking at the iframe contents, + // since iframe might point to a portion of the greenlet's C stack + // that was spilled when switching greenlets. + _PyInterpreterFrame iframe_copy; + this->stack_state.copy_from_stack(&iframe_copy, iframe, sizeof(*iframe)); + if (!_PyFrame_IsIncomplete(&iframe_copy)) { + // If the iframe were OWNED_BY_CSTACK then it would always be + // incomplete. Since it's not incomplete, it's not on the C stack + // and we can access it through the original `iframe` pointer + // directly. This is important since GetFrameObject might + // lazily _create_ the frame object and we don't want the + // interpreter to lose track of it. + assert(iframe_copy.owner != FRAME_OWNED_BY_CSTACK); + + // We really want to just write: + // PyFrameObject* frame = _PyFrame_GetFrameObject(iframe); + // but _PyFrame_GetFrameObject calls _PyFrame_MakeAndSetFrameObject + // which is not a visible symbol in libpython. The easiest + // way to get a public function to call it is using + // PyFrame_GetBack, which is defined as follows: + // assert(frame != NULL); + // assert(!_PyFrame_IsIncomplete(frame->f_frame)); + // PyFrameObject *back = frame->f_back; + // if (back == NULL) { + // _PyInterpreterFrame *prev = frame->f_frame->previous; + // prev = _PyFrame_GetFirstComplete(prev); + // if (prev) { + // back = _PyFrame_GetFrameObject(prev); + // } + // } + // return (PyFrameObject*)Py_XNewRef(back); + if (!iframe->frame_obj) { + PyFrameObject dummy_frame; + _PyInterpreterFrame dummy_iframe; + dummy_frame.f_back = nullptr; + dummy_frame.f_frame = &dummy_iframe; + // force the iframe to be considered complete without + // needing to check its code object: + dummy_iframe.owner = FRAME_OWNED_BY_GENERATOR; + dummy_iframe.previous = iframe; + assert(!_PyFrame_IsIncomplete(&dummy_iframe)); + // Drop the returned reference immediately; the iframe + // continues to hold a strong reference + Py_XDECREF(PyFrame_GetBack(&dummy_frame)); + assert(iframe->frame_obj); + } + + // This is a complete frame, so make the last one of those we saw + // point at it, bypassing any incomplete frames (which may have + // been on the C stack) in between the two. We're overwriting + // last_complete_iframe->previous and need that to be reversible, + // so we store the original previous ptr in the frame object + // (which we must have created on a previous iteration through + // this loop). The frame object has a bunch of storage that is + // only used when its iframe is OWNED_BY_FRAME_OBJECT, which only + // occurs when the frame object outlives the frame's execution, + // which can't have happened yet because the frame is currently + // executing as far as the interpreter is concerned. So, we can + // reuse it for our own purposes. + assert(iframe->owner == FRAME_OWNED_BY_THREAD + || iframe->owner == FRAME_OWNED_BY_GENERATOR); + if (last_complete_iframe) { + assert(last_complete_iframe->frame_obj); + memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], + &last_complete_iframe->previous, sizeof(void *)); + last_complete_iframe->previous = iframe; + } + last_complete_iframe = iframe; + } + // Frames that are OWNED_BY_FRAME_OBJECT are linked via the + // frame's f_back while all others are linked via the iframe's + // previous ptr. Since all the frames we traverse are running + // as far as the interpreter is concerned, we don't have to + // worry about the OWNED_BY_FRAME_OBJECT case. + iframe = iframe_copy.previous; + } + + // Give the outermost complete iframe a null previous pointer to + // account for any potential incomplete/C-stack iframes between it + // and the actual top-of-stack + if (last_complete_iframe) { + assert(last_complete_iframe->frame_obj); + memcpy(&last_complete_iframe->frame_obj->_f_frame_data[0], + &last_complete_iframe->previous, sizeof(void *)); + last_complete_iframe->previous = nullptr; + } +} +#else +void Greenlet::expose_frames() +{ + +} +#endif + +}; // namespace greenlet diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TGreenletGlobals.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TGreenletGlobals.cpp new file mode 100644 index 0000000..c71c963 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TGreenletGlobals.cpp @@ -0,0 +1,94 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of GreenletGlobals. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#ifndef T_GREENLET_GLOBALS +#define T_GREENLET_GLOBALS + +#include "greenlet_refs.hpp" +#include "greenlet_exceptions.hpp" +#include "greenlet_thread_support.hpp" +#include "greenlet_thread_state.hpp" + +namespace greenlet { + +// This encapsulates what were previously module global "constants" +// established at init time. +// This is a step towards Python3 style module state that allows +// reloading. +// +// In an earlier iteration of this code, we used placement new to be +// able to allocate this object statically still, so that references +// to its members don't incur an extra pointer indirection. +// But under some scenarios, that could result in crashes at +// shutdown because apparently the destructor was getting run twice? +class GreenletGlobals +{ + +public: + const greenlet::refs::ImmortalEventName event_switch; + const greenlet::refs::ImmortalEventName event_throw; + const greenlet::refs::ImmortalException PyExc_GreenletError; + const greenlet::refs::ImmortalException PyExc_GreenletExit; + const greenlet::refs::ImmortalObject empty_tuple; + const greenlet::refs::ImmortalObject empty_dict; + const greenlet::refs::ImmortalString str_run; + Mutex* const thread_states_to_destroy_lock; + greenlet::cleanup_queue_t thread_states_to_destroy; + + GreenletGlobals() : + event_switch("switch"), + event_throw("throw"), + PyExc_GreenletError("greenlet.error"), + PyExc_GreenletExit("greenlet.GreenletExit", PyExc_BaseException), + empty_tuple(Require(PyTuple_New(0))), + empty_dict(Require(PyDict_New())), + str_run("run"), + thread_states_to_destroy_lock(new Mutex()) + {} + + ~GreenletGlobals() + { + // This object is (currently) effectively immortal, and not + // just because of those placement new tricks; if we try to + // deallocate the static object we allocated, and overwrote, + // we would be doing so at C++ teardown time, which is after + // the final Python GIL is released, and we can't use the API + // then. + // (The members will still be destructed, but they also don't + // do any deallocation.) + } + + void queue_to_destroy(ThreadState* ts) const + { + // we're currently accessed through a static const object, + // implicitly marking our members as const, so code can't just + // call push_back (or pop_back) without casting away the + // const. + // + // Do that for callers. + greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); + q.push_back(ts); + } + + ThreadState* take_next_to_destroy() const + { + greenlet::cleanup_queue_t& q = const_cast(this->thread_states_to_destroy); + ThreadState* result = q.back(); + q.pop_back(); + return result; + } +}; + +}; // namespace greenlet + +static const greenlet::GreenletGlobals* mod_globs; + +#endif // T_GREENLET_GLOBALS diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TMainGreenlet.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TMainGreenlet.cpp new file mode 100644 index 0000000..c33aadb --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TMainGreenlet.cpp @@ -0,0 +1,155 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::MainGreenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ + +#include "greenlet_greenlet.hpp" +#include "greenlet_thread_state.hpp" + + +// Protected by the GIL. Incremented when we create a main greenlet, +// in a new thread, decremented when it is destroyed. +static Py_ssize_t G_TOTAL_MAIN_GREENLETS; + +namespace greenlet { +greenlet::PythonAllocator MainGreenlet::allocator; + +void* MainGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void MainGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + + +MainGreenlet::MainGreenlet(PyGreenlet* p, ThreadState* state) + : Greenlet(p, StackState::make_main()), + _self(p), + _thread_state(state) +{ + G_TOTAL_MAIN_GREENLETS++; +} + +MainGreenlet::~MainGreenlet() +{ + G_TOTAL_MAIN_GREENLETS--; + this->tp_clear(); +} + +ThreadState* +MainGreenlet::thread_state() const noexcept +{ + return this->_thread_state; +} + +void +MainGreenlet::thread_state(ThreadState* t) noexcept +{ + assert(!t); + this->_thread_state = t; +} + +BorrowedGreenlet +MainGreenlet::self() const noexcept +{ + return BorrowedGreenlet(this->_self.borrow()); +} + + +const BorrowedMainGreenlet +MainGreenlet::main_greenlet() const +{ + return this->_self; +} + +BorrowedMainGreenlet +MainGreenlet::find_main_greenlet_in_lineage() const +{ + return BorrowedMainGreenlet(this->_self); +} + +bool +MainGreenlet::was_running_in_dead_thread() const noexcept +{ + return !this->_thread_state; +} + +OwnedObject +MainGreenlet::g_switch() +{ + try { + this->check_switch_allowed(); + } + catch (const PyErrOccurred&) { + this->release_args(); + throw; + } + + switchstack_result_t err = this->g_switchstack(); + if (err.status < 0) { + // XXX: This code path is untested, but it is shared + // with the UserGreenlet path that is tested. + return this->on_switchstack_or_initialstub_failure( + this, + err, + true, // target was me + false // was initial stub + ); + } + + return err.the_new_current_greenlet->g_switch_finish(err); +} + +int +MainGreenlet::tp_traverse(visitproc visit, void* arg) +{ + if (this->_thread_state) { + // we've already traversed main, (self), don't do it again. + int result = this->_thread_state->tp_traverse(visit, arg, false); + if (result) { + return result; + } + } + return Greenlet::tp_traverse(visit, arg); +} + +const OwnedObject& +MainGreenlet::run() const +{ + throw AttributeError("Main greenlets do not have a run attribute."); +} + +void +MainGreenlet::run(const BorrowedObject UNUSED(nrun)) +{ + throw AttributeError("Main greenlets do not have a run attribute."); +} + +void +MainGreenlet::parent(const BorrowedObject raw_new_parent) +{ + if (!raw_new_parent) { + throw AttributeError("can't delete attribute"); + } + throw AttributeError("cannot set the parent of a main greenlet"); +} + +const OwnedGreenlet +MainGreenlet::parent() const +{ + return OwnedGreenlet(); // null becomes None +} + +}; // namespace greenlet diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TPythonState.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TPythonState.cpp new file mode 100644 index 0000000..465d417 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TPythonState.cpp @@ -0,0 +1,375 @@ +#ifndef GREENLET_PYTHON_STATE_CPP +#define GREENLET_PYTHON_STATE_CPP + +#include +#include "greenlet_greenlet.hpp" + +namespace greenlet { + +PythonState::PythonState() + : _top_frame() +#if GREENLET_USE_CFRAME + ,cframe(nullptr) + ,use_tracing(0) +#endif +#if GREENLET_PY312 + ,py_recursion_depth(0) + ,c_recursion_depth(0) +#else + ,recursion_depth(0) +#endif + ,trash_delete_nesting(0) +#if GREENLET_PY311 + ,current_frame(nullptr) + ,datastack_chunk(nullptr) + ,datastack_top(nullptr) + ,datastack_limit(nullptr) +#endif +{ +#if GREENLET_USE_CFRAME + /* + The PyThreadState->cframe pointer usually points to memory on + the stack, alloceted in a call into PyEval_EvalFrameDefault. + + Initially, before any evaluation begins, it points to the + initial PyThreadState object's ``root_cframe`` object, which is + statically allocated for the lifetime of the thread. + + A greenlet can last for longer than a call to + PyEval_EvalFrameDefault, so we can't set its ``cframe`` pointer + to be the current ``PyThreadState->cframe``; nor could we use + one from the greenlet parent for the same reason. Yet a further + no: we can't allocate one scoped to the greenlet and then + destroy it when the greenlet is deallocated, because inside the + interpreter the _PyCFrame objects form a linked list, and that too + can result in accessing memory beyond its dynamic lifetime (if + the greenlet doesn't actually finish before it dies, its entry + could still be in the list). + + Using the ``root_cframe`` is problematic, though, because its + members are never modified by the interpreter and are set to 0, + meaning that its ``use_tracing`` flag is never updated. We don't + want to modify that value in the ``root_cframe`` ourself: it + *shouldn't* matter much because we should probably never get + back to the point where that's the only cframe on the stack; + even if it did matter, the major consequence of an incorrect + value for ``use_tracing`` is that if its true the interpreter + does some extra work --- however, it's just good code hygiene. + + Our solution: before a greenlet runs, after its initial + creation, it uses the ``root_cframe`` just to have something to + put there. However, once the greenlet is actually switched to + for the first time, ``g_initialstub`` (which doesn't actually + "return" while the greenlet is running) stores a new _PyCFrame on + its local stack, and copies the appropriate values from the + currently running _PyCFrame; this is then made the _PyCFrame for the + newly-minted greenlet. ``g_initialstub`` then proceeds to call + ``glet.run()``, which results in ``PyEval_...`` adding the + _PyCFrame to the list. Switches continue as normal. Finally, when + the greenlet finishes, the call to ``glet.run()`` returns and + the _PyCFrame is taken out of the linked list and the stack value + is now unused and free to expire. + + XXX: I think we can do better. If we're deallocing in the same + thread, can't we traverse the list and unlink our frame? + Can we just keep a reference to the thread state in case we + dealloc in another thread? (Is that even possible if we're still + running and haven't returned from g_initialstub?) + */ + this->cframe = &PyThreadState_GET()->root_cframe; +#endif +} + + +inline void PythonState::may_switch_away() noexcept +{ +#if GREENLET_PY311 + // PyThreadState_GetFrame is probably going to have to allocate a + // new frame object. That may trigger garbage collection. Because + // we call this during the early phases of a switch (it doesn't + // matter to which greenlet, as this has a global effect), if a GC + // triggers a switch away, two things can happen, both bad: + // - We might not get switched back to, halting forward progress. + // this is pathological, but possible. + // - We might get switched back to with a different set of + // arguments or a throw instead of a switch. That would corrupt + // our state (specifically, PyErr_Occurred() and this->args() + // would no longer agree). + // + // Thus, when we call this API, we need to have GC disabled. + // This method serves as a bottleneck we call when maybe beginning + // a switch. In this way, it is always safe -- no risk of GC -- to + // use ``_GetFrame()`` whenever we need to, just as it was in + // <=3.10 (because subsequent calls will be cached and not + // allocate memory). + + GCDisabledGuard no_gc; + Py_XDECREF(PyThreadState_GetFrame(PyThreadState_GET())); +#endif +} + +void PythonState::operator<<(const PyThreadState *const tstate) noexcept +{ + this->_context.steal(tstate->context); +#if GREENLET_USE_CFRAME + /* + IMPORTANT: ``cframe`` is a pointer into the STACK. Thus, because + the call to ``slp_switch()`` changes the contents of the stack, + you cannot read from ``ts_current->cframe`` after that call and + necessarily get the same values you get from reading it here. + Anything you need to restore from now to then must be saved in a + global/threadlocal variable (because we can't use stack + variables here either). For things that need to persist across + the switch, use `will_switch_from`. + */ + this->cframe = tstate->cframe; + #if !GREENLET_PY312 + this->use_tracing = tstate->cframe->use_tracing; + #endif +#endif // GREENLET_USE_CFRAME +#if GREENLET_PY311 + #if GREENLET_PY312 + this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; + this->c_recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; + #else // not 312 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; + #endif // GREENLET_PY312 + this->current_frame = tstate->cframe->current_frame; + this->datastack_chunk = tstate->datastack_chunk; + this->datastack_top = tstate->datastack_top; + this->datastack_limit = tstate->datastack_limit; + + PyFrameObject *frame = PyThreadState_GetFrame((PyThreadState *)tstate); + Py_XDECREF(frame); // PyThreadState_GetFrame gives us a new + // reference. + this->_top_frame.steal(frame); + #if GREENLET_PY312 + this->trash_delete_nesting = tstate->trash.delete_nesting; + #else // not 312 + this->trash_delete_nesting = tstate->trash_delete_nesting; + #endif // GREENLET_PY312 +#else // Not 311 + this->recursion_depth = tstate->recursion_depth; + this->_top_frame.steal(tstate->frame); + this->trash_delete_nesting = tstate->trash_delete_nesting; +#endif // GREENLET_PY311 +} + +#if GREENLET_PY312 +void GREENLET_NOINLINE(PythonState::unexpose_frames)() +{ + if (!this->top_frame()) { + return; + } + + // See GreenletState::expose_frames() and the comment on frames_were_exposed + // for more information about this logic. + _PyInterpreterFrame *iframe = this->_top_frame->f_frame; + while (iframe != nullptr) { + _PyInterpreterFrame *prev_exposed = iframe->previous; + assert(iframe->frame_obj); + memcpy(&iframe->previous, &iframe->frame_obj->_f_frame_data[0], + sizeof(void *)); + iframe = prev_exposed; + } +} +#else +void PythonState::unexpose_frames() +{} +#endif + +void PythonState::operator>>(PyThreadState *const tstate) noexcept +{ + tstate->context = this->_context.relinquish_ownership(); + /* Incrementing this value invalidates the contextvars cache, + which would otherwise remain valid across switches */ + tstate->context_ver++; +#if GREENLET_USE_CFRAME + tstate->cframe = this->cframe; + /* + If we were tracing, we need to keep tracing. + There should never be the possibility of hitting the + root_cframe here. See note above about why we can't + just copy this from ``origin->cframe->use_tracing``. + */ + #if !GREENLET_PY312 + tstate->cframe->use_tracing = this->use_tracing; + #endif +#endif // GREENLET_USE_CFRAME +#if GREENLET_PY311 + #if GREENLET_PY312 + tstate->py_recursion_remaining = tstate->py_recursion_limit - this->py_recursion_depth; + tstate->c_recursion_remaining = C_RECURSION_LIMIT - this->c_recursion_depth; + this->unexpose_frames(); + #else // \/ 3.11 + tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth; + #endif // GREENLET_PY312 + tstate->cframe->current_frame = this->current_frame; + tstate->datastack_chunk = this->datastack_chunk; + tstate->datastack_top = this->datastack_top; + tstate->datastack_limit = this->datastack_limit; + this->_top_frame.relinquish_ownership(); + #if GREENLET_PY312 + tstate->trash.delete_nesting = this->trash_delete_nesting; + #else // not 3.12 + tstate->trash_delete_nesting = this->trash_delete_nesting; + #endif // GREENLET_PY312 +#else // not 3.11 + tstate->frame = this->_top_frame.relinquish_ownership(); + tstate->recursion_depth = this->recursion_depth; + tstate->trash_delete_nesting = this->trash_delete_nesting; +#endif // GREENLET_PY311 +} + +inline void PythonState::will_switch_from(PyThreadState *const origin_tstate) noexcept +{ +#if GREENLET_USE_CFRAME && !GREENLET_PY312 + // The weird thing is, we don't actually save this for an + // effect on the current greenlet, it's saved for an + // effect on the target greenlet. That is, we want + // continuity of this setting across the greenlet switch. + this->use_tracing = origin_tstate->cframe->use_tracing; +#endif +} + +void PythonState::set_initial_state(const PyThreadState* const tstate) noexcept +{ + this->_top_frame = nullptr; +#if GREENLET_PY312 + this->py_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; + // XXX: TODO: Comment from a reviewer: + // Should this be ``C_RECURSION_LIMIT - tstate->c_recursion_remaining``? + // But to me it looks more like that might not be the right + // initialization either? + this->c_recursion_depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; +#elif GREENLET_PY311 + this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining; +#else + this->recursion_depth = tstate->recursion_depth; +#endif +} +// TODO: Better state management about when we own the top frame. +int PythonState::tp_traverse(visitproc visit, void* arg, bool own_top_frame) noexcept +{ + Py_VISIT(this->_context.borrow()); + if (own_top_frame) { + Py_VISIT(this->_top_frame.borrow()); + } + return 0; +} + +void PythonState::tp_clear(bool own_top_frame) noexcept +{ + PythonStateContext::tp_clear(); + // If we get here owning a frame, + // we got dealloc'd without being finished. We may or may not be + // in the same thread. + if (own_top_frame) { + this->_top_frame.CLEAR(); + } +} + +#if GREENLET_USE_CFRAME +void PythonState::set_new_cframe(_PyCFrame& frame) noexcept +{ + frame = *PyThreadState_GET()->cframe; + /* Make the target greenlet refer to the stack value. */ + this->cframe = &frame; + /* + And restore the link to the previous frame so this one gets + unliked appropriately. + */ + this->cframe->previous = &PyThreadState_GET()->root_cframe; +} +#endif + +const PythonState::OwnedFrame& PythonState::top_frame() const noexcept +{ + return this->_top_frame; +} + +void PythonState::did_finish(PyThreadState* tstate) noexcept +{ +#if GREENLET_PY311 + // See https://github.com/gevent/gevent/issues/1924 and + // https://github.com/python-greenlet/greenlet/issues/328. In + // short, Python 3.11 allocates memory for frames as a sort of + // linked list that's kept as part of PyThreadState in the + // ``datastack_chunk`` member and friends. These are saved and + // restored as part of switching greenlets. + // + // When we initially switch to a greenlet, we set those to NULL. + // That causes the frame management code to treat this like a + // brand new thread and start a fresh list of chunks, beginning + // with a new "root" chunk. As we make calls in this greenlet, + // those chunks get added, and as calls return, they get popped. + // But the frame code (pystate.c) is careful to make sure that the + // root chunk never gets popped. + // + // Thus, when a greenlet exits for the last time, there will be at + // least a single root chunk that we must be responsible for + // deallocating. + // + // The complex part is that these chunks are allocated and freed + // using ``_PyObject_VirtualAlloc``/``Free``. Those aren't public + // functions, and they aren't exported for linking. It so happens + // that we know they are just thin wrappers around the Arena + // allocator, so we can use that directly to deallocate in a + // compatible way. + // + // CAUTION: Check this implementation detail on every major version. + // + // It might be nice to be able to do this in our destructor, but + // can we be sure that no one else is using that memory? Plus, as + // described below, our pointers may not even be valid anymore. As + // a special case, there is one time that we know we can do this, + // and that's from the destructor of the associated UserGreenlet + // (NOT main greenlet) + PyObjectArenaAllocator alloc; + _PyStackChunk* chunk = nullptr; + if (tstate) { + // We really did finish, we can never be switched to again. + chunk = tstate->datastack_chunk; + // Unfortunately, we can't do much sanity checking. Our + // this->datastack_chunk pointer is out of date (evaluation may + // have popped down through it already) so we can't verify that + // we deallocate it. I don't think we can even check datastack_top + // for the same reason. + + PyObject_GetArenaAllocator(&alloc); + tstate->datastack_chunk = nullptr; + tstate->datastack_limit = nullptr; + tstate->datastack_top = nullptr; + + } + else if (this->datastack_chunk) { + // The UserGreenlet (NOT the main greenlet!) is being deallocated. If we're + // still holding a stack chunk, it's garbage because we know + // we can never switch back to let cPython clean it up. + // Because the last time we got switched away from, and we + // haven't run since then, we know our chain is valid and can + // be dealloced. + chunk = this->datastack_chunk; + PyObject_GetArenaAllocator(&alloc); + } + + if (alloc.free && chunk) { + // In case the arena mechanism has been torn down already. + while (chunk) { + _PyStackChunk *prev = chunk->previous; + chunk->previous = nullptr; + alloc.free(alloc.ctx, chunk, chunk->size); + chunk = prev; + } + } + + this->datastack_chunk = nullptr; + this->datastack_limit = nullptr; + this->datastack_top = nullptr; +#endif +} + + +}; // namespace greenlet + +#endif // GREENLET_PYTHON_STATE_CPP diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TStackState.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TStackState.cpp new file mode 100644 index 0000000..9aab596 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TStackState.cpp @@ -0,0 +1,265 @@ +#ifndef GREENLET_STACK_STATE_CPP +#define GREENLET_STACK_STATE_CPP + +#include "greenlet_greenlet.hpp" + +namespace greenlet { + +#ifdef GREENLET_USE_STDIO +#include +using std::cerr; +using std::endl; + +std::ostream& operator<<(std::ostream& os, const StackState& s) +{ + os << "StackState(stack_start=" << (void*)s._stack_start + << ", stack_stop=" << (void*)s.stack_stop + << ", stack_copy=" << (void*)s.stack_copy + << ", stack_saved=" << s._stack_saved + << ", stack_prev=" << s.stack_prev + << ", addr=" << &s + << ")"; + return os; +} +#endif + +StackState::StackState(void* mark, StackState& current) + : _stack_start(nullptr), + stack_stop((char*)mark), + stack_copy(nullptr), + _stack_saved(0), + /* Skip a dying greenlet */ + stack_prev(current._stack_start + ? ¤t + : current.stack_prev) +{ +} + +StackState::StackState() + : _stack_start(nullptr), + stack_stop(nullptr), + stack_copy(nullptr), + _stack_saved(0), + stack_prev(nullptr) +{ +} + +StackState::StackState(const StackState& other) +// can't use a delegating constructor because of +// MSVC for Python 2.7 + : _stack_start(nullptr), + stack_stop(nullptr), + stack_copy(nullptr), + _stack_saved(0), + stack_prev(nullptr) +{ + this->operator=(other); +} + +StackState& StackState::operator=(const StackState& other) +{ + if (&other == this) { + return *this; + } + if (other._stack_saved) { + throw std::runtime_error("Refusing to steal memory."); + } + + //If we have memory allocated, dispose of it + this->free_stack_copy(); + + this->_stack_start = other._stack_start; + this->stack_stop = other.stack_stop; + this->stack_copy = other.stack_copy; + this->_stack_saved = other._stack_saved; + this->stack_prev = other.stack_prev; + return *this; +} + +inline void StackState::free_stack_copy() noexcept +{ + PyMem_Free(this->stack_copy); + this->stack_copy = nullptr; + this->_stack_saved = 0; +} + +inline void StackState::copy_heap_to_stack(const StackState& current) noexcept +{ + + /* Restore the heap copy back into the C stack */ + if (this->_stack_saved != 0) { + memcpy(this->_stack_start, this->stack_copy, this->_stack_saved); + this->free_stack_copy(); + } + StackState* owner = const_cast(¤t); + if (!owner->_stack_start) { + owner = owner->stack_prev; /* greenlet is dying, skip it */ + } + while (owner && owner->stack_stop <= this->stack_stop) { + // cerr << "\tOwner: " << owner << endl; + owner = owner->stack_prev; /* find greenlet with more stack */ + } + this->stack_prev = owner; + // cerr << "\tFinished with: " << *this << endl; +} + +inline int StackState::copy_stack_to_heap_up_to(const char* const stop) noexcept +{ + /* Save more of g's stack into the heap -- at least up to 'stop' + g->stack_stop |________| + | | + | __ stop . . . . . + | | ==> . . + |________| _______ + | | | | + | | | | + g->stack_start | | |_______| g->stack_copy + */ + intptr_t sz1 = this->_stack_saved; + intptr_t sz2 = stop - this->_stack_start; + assert(this->_stack_start); + if (sz2 > sz1) { + char* c = (char*)PyMem_Realloc(this->stack_copy, sz2); + if (!c) { + PyErr_NoMemory(); + return -1; + } + memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1); + this->stack_copy = c; + this->_stack_saved = sz2; + } + return 0; +} + +inline int StackState::copy_stack_to_heap(char* const stackref, + const StackState& current) noexcept +{ + /* must free all the C stack up to target_stop */ + const char* const target_stop = this->stack_stop; + + StackState* owner = const_cast(¤t); + assert(owner->_stack_saved == 0); // everything is present on the stack + if (!owner->_stack_start) { + owner = owner->stack_prev; /* not saved if dying */ + } + else { + owner->_stack_start = stackref; + } + + while (owner->stack_stop < target_stop) { + /* ts_current is entierely within the area to free */ + if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) { + return -1; /* XXX */ + } + owner = owner->stack_prev; + } + if (owner != this) { + if (owner->copy_stack_to_heap_up_to(target_stop)) { + return -1; /* XXX */ + } + } + return 0; +} + +inline bool StackState::started() const noexcept +{ + return this->stack_stop != nullptr; +} + +inline bool StackState::main() const noexcept +{ + return this->stack_stop == (char*)-1; +} + +inline bool StackState::active() const noexcept +{ + return this->_stack_start != nullptr; +} + +inline void StackState::set_active() noexcept +{ + assert(this->_stack_start == nullptr); + this->_stack_start = (char*)1; +} + +inline void StackState::set_inactive() noexcept +{ + this->_stack_start = nullptr; + // XXX: What if we still have memory out there? + // That case is actually triggered by + // test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks) + // and + // test_issue251_issue252_need_to_collect_in_background + // (greenlet.tests.test_leaks.TestLeaks) + // + // Those objects never get deallocated, so the destructor never + // runs. + // It *seems* safe to clean up the memory here? + if (this->_stack_saved) { + this->free_stack_copy(); + } +} + +inline intptr_t StackState::stack_saved() const noexcept +{ + return this->_stack_saved; +} + +inline char* StackState::stack_start() const noexcept +{ + return this->_stack_start; +} + + +inline StackState StackState::make_main() noexcept +{ + StackState s; + s._stack_start = (char*)1; + s.stack_stop = (char*)-1; + return s; +} + +StackState::~StackState() +{ + if (this->_stack_saved != 0) { + this->free_stack_copy(); + } +} + +void StackState::copy_from_stack(void* vdest, const void* vsrc, size_t n) const +{ + char* dest = static_cast(vdest); + const char* src = static_cast(vsrc); + if (src + n <= this->_stack_start + || src >= this->_stack_start + this->_stack_saved + || this->_stack_saved == 0) { + // Nothing we're copying was spilled from the stack + memcpy(dest, src, n); + return; + } + + if (src < this->_stack_start) { + // Copy the part before the saved stack. + // We know src + n > _stack_start due to the test above. + const size_t nbefore = this->_stack_start - src; + memcpy(dest, src, nbefore); + dest += nbefore; + src += nbefore; + n -= nbefore; + } + // We know src >= _stack_start after the before-copy, and + // src < _stack_start + _stack_saved due to the first if condition + size_t nspilled = std::min(n, this->_stack_start + this->_stack_saved - src); + memcpy(dest, this->stack_copy + (src - this->_stack_start), nspilled); + dest += nspilled; + src += nspilled; + n -= nspilled; + if (n > 0) { + // Copy the part after the saved stack + memcpy(dest, src, n); + } +} + +}; // namespace greenlet + +#endif // GREENLET_STACK_STATE_CPP diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TThreadStateDestroy.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TThreadStateDestroy.cpp new file mode 100644 index 0000000..a149a1a --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TThreadStateDestroy.cpp @@ -0,0 +1,195 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of the ThreadState destructors. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#ifndef T_THREADSTATE_DESTROY +#define T_THREADSTATE_DESTROY + +#include "greenlet_greenlet.hpp" +#include "greenlet_thread_state.hpp" +#include "greenlet_thread_support.hpp" +#include "greenlet_cpython_add_pending.hpp" +#include "TGreenletGlobals.cpp" + +namespace greenlet { + +struct ThreadState_DestroyWithGIL +{ + ThreadState_DestroyWithGIL(ThreadState* state) + { + if (state && state->has_main_greenlet()) { + DestroyWithGIL(state); + } + } + + static int + DestroyWithGIL(ThreadState* state) + { + // Holding the GIL. + // Passed a non-shared pointer to the actual thread state. + // state -> main greenlet + assert(state->has_main_greenlet()); + PyGreenlet* main(state->borrow_main_greenlet()); + // When we need to do cross-thread operations, we check this. + // A NULL value means the thread died some time ago. + // We do this here, rather than in a Python dealloc function + // for the greenlet, in case there's still a reference out + // there. + static_cast(main->pimpl)->thread_state(nullptr); + + delete state; // Deleting this runs the destructor, DECREFs the main greenlet. + return 0; + } +}; + + + +struct ThreadState_DestroyNoGIL +{ + // ensure this is actually defined. + static_assert(GREENLET_BROKEN_PY_ADD_PENDING == 1 || GREENLET_BROKEN_PY_ADD_PENDING == 0, + "GREENLET_BROKEN_PY_ADD_PENDING not defined correctly."); + +#if GREENLET_BROKEN_PY_ADD_PENDING + static int _push_pending_call(struct _pending_calls *pending, + int (*func)(void *), void *arg) + { + int i = pending->last; + int j = (i + 1) % NPENDINGCALLS; + if (j == pending->first) { + return -1; /* Queue full */ + } + pending->calls[i].func = func; + pending->calls[i].arg = arg; + pending->last = j; + return 0; + } + + static int AddPendingCall(int (*func)(void *), void *arg) + { + _PyRuntimeState *runtime = &_PyRuntime; + if (!runtime) { + // obviously impossible + return 0; + } + struct _pending_calls *pending = &runtime->ceval.pending; + if (!pending->lock) { + return 0; + } + int result = 0; + PyThread_acquire_lock(pending->lock, WAIT_LOCK); + if (!pending->finishing) { + result = _push_pending_call(pending, func, arg); + } + PyThread_release_lock(pending->lock); + SIGNAL_PENDING_CALLS(&runtime->ceval); + return result; + } +#else + // Python < 3.8 or >= 3.9 + static int AddPendingCall(int (*func)(void*), void* arg) + { + return Py_AddPendingCall(func, arg); + } +#endif + + ThreadState_DestroyNoGIL(ThreadState* state) + { + // We are *NOT* holding the GIL. Our thread is in the middle + // of its death throes and the Python thread state is already + // gone so we can't use most Python APIs. One that is safe is + // ``Py_AddPendingCall``, unless the interpreter itself has + // been torn down. There is a limited number of calls that can + // be queued: 32 (NPENDINGCALLS) in CPython 3.10, so we + // coalesce these calls using our own queue. + if (state && state->has_main_greenlet()) { + // mark the thread as dead ASAP. + // this is racy! If we try to throw or switch to a + // greenlet from this thread from some other thread before + // we clear the state pointer, it won't realize the state + // is dead which can crash the process. + PyGreenlet* p = state->borrow_main_greenlet(); + assert(p->pimpl->thread_state() == state || p->pimpl->thread_state() == nullptr); + static_cast(p->pimpl)->thread_state(nullptr); + } + + // NOTE: Because we're not holding the GIL here, some other + // Python thread could run and call ``os.fork()``, which would + // be bad if that happenend while we are holding the cleanup + // lock (it wouldn't function in the child process). + // Make a best effort to try to keep the duration we hold the + // lock short. + // TODO: On platforms that support it, use ``pthread_atfork`` to + // drop this lock. + LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); + + if (state && state->has_main_greenlet()) { + // Because we don't have the GIL, this is a race condition. + if (!PyInterpreterState_Head()) { + // We have to leak the thread state, if the + // interpreter has shut down when we're getting + // deallocated, we can't run the cleanup code that + // deleting it would imply. + return; + } + + mod_globs->queue_to_destroy(state); + if (mod_globs->thread_states_to_destroy.size() == 1) { + // We added the first item to the queue. We need to schedule + // the cleanup. + int result = ThreadState_DestroyNoGIL::AddPendingCall( + ThreadState_DestroyNoGIL::DestroyQueueWithGIL, + NULL); + if (result < 0) { + // Hmm, what can we do here? + fprintf(stderr, + "greenlet: WARNING: failed in call to Py_AddPendingCall; " + "expect a memory leak.\n"); + } + } + } + } + + static int + DestroyQueueWithGIL(void* UNUSED(arg)) + { + // We're holding the GIL here, so no Python code should be able to + // run to call ``os.fork()``. + while (1) { + ThreadState* to_destroy; + { + LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); + if (mod_globs->thread_states_to_destroy.empty()) { + break; + } + to_destroy = mod_globs->take_next_to_destroy(); + } + // Drop the lock while we do the actual deletion. + ThreadState_DestroyWithGIL::DestroyWithGIL(to_destroy); + } + return 0; + } + +}; + +}; // namespace greenlet + +// The intent when GET_THREAD_STATE() is needed multiple times in a +// function is to take a reference to its return value in a local +// variable, to avoid the thread-local indirection. On some platforms +// (macOS), accessing a thread-local involves a function call (plus an +// initial function call in each function that uses a thread local); +// in contrast, static volatile variables are at some pre-computed +// offset. +typedef greenlet::ThreadStateCreator ThreadStateCreator; +static thread_local ThreadStateCreator g_thread_state_global; +#define GET_THREAD_STATE() g_thread_state_global + +#endif //T_THREADSTATE_DESTROY diff --git a/elitebot/lib/python3.11/site-packages/greenlet/TUserGreenlet.cpp b/elitebot/lib/python3.11/site-packages/greenlet/TUserGreenlet.cpp new file mode 100644 index 0000000..495a794 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/TUserGreenlet.cpp @@ -0,0 +1,667 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/** + * Implementation of greenlet::UserGreenlet. + * + * Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ + +#include "greenlet_internal.hpp" +#include "greenlet_greenlet.hpp" +#include "greenlet_thread_state.hpp" +#include "TThreadStateDestroy.cpp" + + +namespace greenlet { +using greenlet::refs::BorrowedMainGreenlet; +greenlet::PythonAllocator UserGreenlet::allocator; + +void* UserGreenlet::operator new(size_t UNUSED(count)) +{ + return allocator.allocate(1); +} + + +void UserGreenlet::operator delete(void* ptr) +{ + return allocator.deallocate(static_cast(ptr), + 1); +} + + +UserGreenlet::UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent) + : Greenlet(p), _parent(the_parent) +{ + this->_self = p; +} + +UserGreenlet::~UserGreenlet() +{ + // Python 3.11: If we don't clear out the raw frame datastack + // when deleting an unfinished greenlet, + // TestLeaks.test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main fails. + this->python_state.did_finish(nullptr); + this->tp_clear(); +} + +BorrowedGreenlet +UserGreenlet::self() const noexcept +{ + return this->_self; +} + + + +const BorrowedMainGreenlet +UserGreenlet::main_greenlet() const +{ + return this->_main_greenlet; +} + + +BorrowedMainGreenlet +UserGreenlet::find_main_greenlet_in_lineage() const +{ + if (this->started()) { + assert(this->_main_greenlet); + return BorrowedMainGreenlet(this->_main_greenlet); + } + + if (!this->_parent) { + /* garbage collected greenlet in chain */ + // XXX: WHAT? + return BorrowedMainGreenlet(nullptr); + } + + return this->_parent->find_main_greenlet_in_lineage(); +} + + +/** + * CAUTION: This will allocate memory and may trigger garbage + * collection and arbitrary Python code. + */ +OwnedObject +UserGreenlet::throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state) +{ + /* The dying greenlet cannot be a parent of ts_current + because the 'parent' field chain would hold a + reference */ + UserGreenlet::ParentIsCurrentGuard with_current_parent(this, current_thread_state); + + // We don't care about the return value, only whether an + // exception happened. Whether or not an exception happens, + // we need to restore the parent in case the greenlet gets + // resurrected. + return Greenlet::throw_GreenletExit_during_dealloc(current_thread_state); +} + +ThreadState* +UserGreenlet::thread_state() const noexcept +{ + // TODO: maybe make this throw, if the thread state isn't there? + // if (!this->main_greenlet) { + // throw std::runtime_error("No thread state"); // TODO: Better exception + // } + if (!this->_main_greenlet) { + return nullptr; + } + return this->_main_greenlet->thread_state(); +} + + +bool +UserGreenlet::was_running_in_dead_thread() const noexcept +{ + return this->_main_greenlet && !this->thread_state(); +} + +OwnedObject +UserGreenlet::g_switch() +{ + assert(this->args() || PyErr_Occurred()); + + try { + this->check_switch_allowed(); + } + catch (const PyErrOccurred&) { + this->release_args(); + throw; + } + + // Switching greenlets used to attempt to clean out ones that need + // deleted *if* we detected a thread switch. Should it still do + // that? + // An issue is that if we delete a greenlet from another thread, + // it gets queued to this thread, and ``kill_greenlet()`` switches + // back into the greenlet + + /* find the real target by ignoring dead greenlets, + and if necessary starting a greenlet. */ + switchstack_result_t err; + Greenlet* target = this; + // TODO: probably cleaner to handle the case where we do + // switch to ourself separately from the other cases. + // This can probably even further be simplified if we keep + // track of the switching_state we're going for and just call + // into g_switch() if it's not ourself. The main problem with that + // is that we would be using more stack space. + bool target_was_me = true; + bool was_initial_stub = false; + while (target) { + if (target->active()) { + if (!target_was_me) { + target->args() <<= this->args(); + assert(!this->args()); + } + err = target->g_switchstack(); + break; + } + if (!target->started()) { + // We never encounter a main greenlet that's not started. + assert(!target->main()); + UserGreenlet* real_target = static_cast(target); + assert(real_target); + void* dummymarker; + was_initial_stub = true; + if (!target_was_me) { + target->args() <<= this->args(); + assert(!this->args()); + } + try { + // This can only throw back to us while we're + // still in this greenlet. Once the new greenlet + // is bootstrapped, it has its own exception state. + err = real_target->g_initialstub(&dummymarker); + } + catch (const PyErrOccurred&) { + this->release_args(); + throw; + } + catch (const GreenletStartedWhileInPython&) { + // The greenlet was started sometime before this + // greenlet actually switched to it, i.e., + // "concurrent" calls to switch() or throw(). + // We need to retry the switch. + // Note that the current greenlet has been reset + // to this one (or we wouldn't be running!) + continue; + } + break; + } + + target = target->parent(); + target_was_me = false; + } + // The ``this`` pointer and all other stack or register based + // variables are invalid now, at least where things succeed + // above. + // But this one, probably not so much? It's not clear if it's + // safe to throw an exception at this point. + + if (err.status < 0) { + // If we get here, either g_initialstub() + // failed, or g_switchstack() failed. Either one of those + // cases SHOULD leave us in the original greenlet with a valid + // stack. + return this->on_switchstack_or_initialstub_failure(target, err, target_was_me, was_initial_stub); + } + + // err.the_new_current_greenlet would be the same as ``target``, + // if target wasn't probably corrupt. + return err.the_new_current_greenlet->g_switch_finish(err); +} + + + +Greenlet::switchstack_result_t +UserGreenlet::g_initialstub(void* mark) +{ + OwnedObject run; + + // We need to grab a reference to the current switch arguments + // in case we're entered concurrently during the call to + // GetAttr() and have to try again. + // We'll restore them when we return in that case. + // Scope them tightly to avoid ref leaks. + { + SwitchingArgs args(this->args()); + + /* save exception in case getattr clears it */ + PyErrPieces saved; + + /* + self.run is the object to call in the new greenlet. + This could run arbitrary python code and switch greenlets! + */ + run = this->_self.PyRequireAttr(mod_globs->str_run); + /* restore saved exception */ + saved.PyErrRestore(); + + + /* recheck that it's safe to switch in case greenlet reparented anywhere above */ + this->check_switch_allowed(); + + /* by the time we got here another start could happen elsewhere, + * that means it should now be a regular switch. + * This can happen if the Python code is a subclass that implements + * __getattribute__ or __getattr__, or makes ``run`` a descriptor; + * all of those can run arbitrary code that switches back into + * this greenlet. + */ + if (this->stack_state.started()) { + // the successful switch cleared these out, we need to + // restore our version. They will be copied on up to the + // next target. + assert(!this->args()); + this->args() <<= args; + throw GreenletStartedWhileInPython(); + } + } + + // Sweet, if we got here, we have the go-ahead and will switch + // greenlets. + // Nothing we do from here on out should allow for a thread or + // greenlet switch: No arbitrary calls to Python, including + // decref'ing + +#if GREENLET_USE_CFRAME + /* OK, we need it, we're about to switch greenlets, save the state. */ + /* + See green_new(). This is a stack-allocated variable used + while *self* is in PyObject_Call(). + We want to defer copying the state info until we're sure + we need it and are in a stable place to do so. + */ + _PyCFrame trace_info; + + this->python_state.set_new_cframe(trace_info); +#endif + /* start the greenlet */ + ThreadState& thread_state = GET_THREAD_STATE().state(); + this->stack_state = StackState(mark, + thread_state.borrow_current()->stack_state); + this->python_state.set_initial_state(PyThreadState_GET()); + this->exception_state.clear(); + this->_main_greenlet = thread_state.get_main_greenlet(); + + /* perform the initial switch */ + switchstack_result_t err = this->g_switchstack(); + /* returns twice! + The 1st time with ``err == 1``: we are in the new greenlet. + This one owns a greenlet that used to be current. + The 2nd time with ``err <= 0``: back in the caller's + greenlet; this happens if the child finishes or switches + explicitly to us. Either way, the ``err`` variable is + created twice at the same memory location, but possibly + having different ``origin`` values. Note that it's not + constructed for the second time until the switch actually happens. + */ + if (err.status == 1) { + // In the new greenlet. + + // This never returns! Calling inner_bootstrap steals + // the contents of our run object within this stack frame, so + // it is not valid to do anything with it. + try { + this->inner_bootstrap(err.origin_greenlet.relinquish_ownership(), + run.relinquish_ownership()); + } + // Getting a C++ exception here isn't good. It's probably a + // bug in the underlying greenlet, meaning it's probably a + // C++ extension. We're going to abort anyway, but try to + // display some nice information *if* possible. Some obscure + // platforms don't properly support this (old 32-bit Arm, see see + // https://github.com/python-greenlet/greenlet/issues/385); that's not + // great, but should usually be OK because, as mentioned above, we're + // terminating anyway. + // + // The catching is tested by + // ``test_cpp.CPPTests.test_unhandled_exception_in_greenlet_aborts``. + // + // PyErrOccurred can theoretically be thrown by + // inner_bootstrap() -> g_switch_finish(), but that should + // never make it back to here. It is a std::exception and + // would be caught if it is. + catch (const std::exception& e) { + std::string base = "greenlet: Unhandled C++ exception: "; + base += e.what(); + Py_FatalError(base.c_str()); + } + catch (...) { + // Some compilers/runtimes use exceptions internally. + // It appears that GCC on Linux with libstdc++ throws an + // exception internally at process shutdown time to unwind + // stacks and clean up resources. Depending on exactly + // where we are when the process exits, that could result + // in an unknown exception getting here. If we + // Py_FatalError() or abort() here, we interfere with + // orderly process shutdown. Throwing the exception on up + // is the right thing to do. + // + // gevent's ``examples/dns_mass_resolve.py`` demonstrates this. +#ifndef NDEBUG + fprintf(stderr, + "greenlet: inner_bootstrap threw unknown exception; " + "is the process terminating?\n"); +#endif + throw; + } + Py_FatalError("greenlet: inner_bootstrap returned with no exception.\n"); + } + + + // In contrast, notice that we're keeping the origin greenlet + // around as an owned reference; we need it to call the trace + // function for the switch back into the parent. It was only + // captured at the time the switch actually happened, though, + // so we haven't been keeping an extra reference around this + // whole time. + + /* back in the parent */ + if (err.status < 0) { + /* start failed badly, restore greenlet state */ + this->stack_state = StackState(); + this->_main_greenlet.CLEAR(); + // CAUTION: This may run arbitrary Python code. + run.CLEAR(); // inner_bootstrap didn't run, we own the reference. + } + + // In the success case, the spawned code (inner_bootstrap) will + // take care of decrefing this, so we relinquish ownership so as + // to not double-decref. + + run.relinquish_ownership(); + + return err; +} + + +void +UserGreenlet::inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run) +{ + // The arguments here would be another great place for move. + // As it is, we take them as a reference so that when we clear + // them we clear what's on the stack above us. Do that NOW, and + // without using a C++ RAII object, + // so there's no way that exiting the parent frame can clear it, + // or we clear it unexpectedly. This arises in the context of the + // interpreter shutting down. See https://github.com/python-greenlet/greenlet/issues/325 + //PyObject* run = _run.relinquish_ownership(); + + /* in the new greenlet */ + assert(this->thread_state()->borrow_current() == this->_self); + // C++ exceptions cannot propagate to the parent greenlet from + // here. (TODO: Do we need a catch(...) clause, perhaps on the + // function itself? ALl we could do is terminate the program.) + // NOTE: On 32-bit Windows, the call chain is extremely + // important here in ways that are subtle, having to do with + // the depth of the SEH list. The call to restore it MUST NOT + // add a new SEH handler to the list, or we'll restore it to + // the wrong thing. + this->thread_state()->restore_exception_state(); + /* stack variables from above are no good and also will not unwind! */ + // EXCEPT: That can't be true, we access run, among others, here. + + this->stack_state.set_active(); /* running */ + + // We're about to possibly run Python code again, which + // could switch back/away to/from us, so we need to grab the + // arguments locally. + SwitchingArgs args; + args <<= this->args(); + assert(!this->args()); + + // XXX: We could clear this much earlier, right? + // Or would that introduce the possibility of running Python + // code when we don't want to? + // CAUTION: This may run arbitrary Python code. + this->_run_callable.CLEAR(); + + + // The first switch we need to manually call the trace + // function here instead of in g_switch_finish, because we + // never return there. + if (OwnedObject tracefunc = this->thread_state()->get_tracefunc()) { + OwnedGreenlet trace_origin; + trace_origin = origin_greenlet; + try { + g_calltrace(tracefunc, + args ? mod_globs->event_switch : mod_globs->event_throw, + trace_origin, + this->_self); + } + catch (const PyErrOccurred&) { + /* Turn trace errors into switch throws */ + args.CLEAR(); + } + } + + // We no longer need the origin, it was only here for + // tracing. + // We may never actually exit this stack frame so we need + // to explicitly clear it. + // This could run Python code and switch. + Py_CLEAR(origin_greenlet); + + OwnedObject result; + if (!args) { + /* pending exception */ + result = NULL; + } + else { + /* call g.run(*args, **kwargs) */ + // This could result in further switches + try { + //result = run.PyCall(args.args(), args.kwargs()); + // CAUTION: Just invoking this, before the function even + // runs, may cause memory allocations, which may trigger + // GC, which may run arbitrary Python code. + result = OwnedObject::consuming(PyObject_Call(run, args.args().borrow(), args.kwargs().borrow())); + } + catch (...) { + // Unhandled C++ exception! + + // If we declare ourselves as noexcept, if we don't catch + // this here, most platforms will just abort() the + // process. But on 64-bit Windows with older versions of + // the C runtime, this can actually corrupt memory and + // just return. We see this when compiling with the + // Windows 7.0 SDK targeting Windows Server 2008, but not + // when using the Appveyor Visual Studio 2019 image. So + // this currently only affects Python 2.7 on Windows 64. + // That is, the tests pass and the runtime aborts + // everywhere else. + // + // However, if we catch it and try to continue with a + // Python error, then all Windows 64 bit platforms corrupt + // memory. So all we can do is manually abort, hopefully + // with a good error message. (Note that the above was + // tested WITHOUT the `/EHr` switch being used at compile + // time, so MSVC may have "optimized" out important + // checking. Using that switch, we may be in a better + // place in terms of memory corruption.) But sometimes it + // can't be caught here at all, which is confusing but not + // terribly surprising; so again, the G_NOEXCEPT_WIN32 + // plus "/EHr". + // + // Hopefully the basic C stdlib is still functional enough + // for us to at least print an error. + // + // It gets more complicated than that, though, on some + // platforms, specifically at least Linux/gcc/libstdc++. They use + // an exception to unwind the stack when a background + // thread exits. (See comments about noexcept.) So this + // may not actually represent anything untoward. On those + // platforms we allow throws of this to propagate, or + // attempt to anyway. +# if defined(WIN32) || defined(_WIN32) + Py_FatalError( + "greenlet: Unhandled C++ exception from a greenlet run function. " + "Because memory is likely corrupted, terminating process."); + std::abort(); +#else + throw; +#endif + } + } + // These lines may run arbitrary code + args.CLEAR(); + Py_CLEAR(run); + + if (!result + && mod_globs->PyExc_GreenletExit.PyExceptionMatches() + && (this->args())) { + // This can happen, for example, if our only reference + // goes away after we switch back to the parent. + // See test_dealloc_switch_args_not_lost + PyErrPieces clear_error; + result <<= this->args(); + result = single_result(result); + } + this->release_args(); + this->python_state.did_finish(PyThreadState_GET()); + + result = g_handle_exit(result); + assert(this->thread_state()->borrow_current() == this->_self); + + /* jump back to parent */ + this->stack_state.set_inactive(); /* dead */ + + + // TODO: Can we decref some things here? Release our main greenlet + // and maybe parent? + for (Greenlet* parent = this->_parent; + parent; + parent = parent->parent()) { + // We need to somewhere consume a reference to + // the result; in most cases we'll never have control + // back in this stack frame again. Calling + // green_switch actually adds another reference! + // This would probably be clearer with a specific API + // to hand results to the parent. + parent->args() <<= result; + assert(!result); + // The parent greenlet now owns the result; in the + // typical case we'll never get back here to assign to + // result and thus release the reference. + try { + result = parent->g_switch(); + } + catch (const PyErrOccurred&) { + // Ignore, keep passing the error on up. + } + + /* Return here means switch to parent failed, + * in which case we throw *current* exception + * to the next parent in chain. + */ + assert(!result); + } + /* We ran out of parents, cannot continue */ + PyErr_WriteUnraisable(this->self().borrow_o()); + Py_FatalError("greenlet: ran out of parent greenlets while propagating exception; " + "cannot continue"); + std::abort(); +} + +void +UserGreenlet::run(const BorrowedObject nrun) +{ + if (this->started()) { + throw AttributeError( + "run cannot be set " + "after the start of the greenlet"); + } + this->_run_callable = nrun; +} + +const OwnedGreenlet +UserGreenlet::parent() const +{ + return this->_parent; +} + +void +UserGreenlet::parent(const BorrowedObject raw_new_parent) +{ + if (!raw_new_parent) { + throw AttributeError("can't delete attribute"); + } + + BorrowedMainGreenlet main_greenlet_of_new_parent; + BorrowedGreenlet new_parent(raw_new_parent.borrow()); // could + // throw + // TypeError! + for (BorrowedGreenlet p = new_parent; p; p = p->parent()) { + if (p == this->_self) { + throw ValueError("cyclic parent chain"); + } + main_greenlet_of_new_parent = p->main_greenlet(); + } + + if (!main_greenlet_of_new_parent) { + throw ValueError("parent must not be garbage collected"); + } + + if (this->started() + && this->_main_greenlet != main_greenlet_of_new_parent) { + throw ValueError("parent cannot be on a different thread"); + } + + this->_parent = new_parent; +} + +void +UserGreenlet::murder_in_place() +{ + this->_main_greenlet.CLEAR(); + Greenlet::murder_in_place(); +} + +bool +UserGreenlet::belongs_to_thread(const ThreadState* thread_state) const +{ + return Greenlet::belongs_to_thread(thread_state) && this->_main_greenlet == thread_state->borrow_main_greenlet(); +} + + +int +UserGreenlet::tp_traverse(visitproc visit, void* arg) +{ + Py_VISIT(this->_parent.borrow_o()); + Py_VISIT(this->_main_greenlet.borrow_o()); + Py_VISIT(this->_run_callable.borrow_o()); + + return Greenlet::tp_traverse(visit, arg); +} + +int +UserGreenlet::tp_clear() +{ + Greenlet::tp_clear(); + this->_parent.CLEAR(); + this->_main_greenlet.CLEAR(); + this->_run_callable.CLEAR(); + return 0; +} + +UserGreenlet::ParentIsCurrentGuard::ParentIsCurrentGuard(UserGreenlet* p, + const ThreadState& thread_state) + : oldparent(p->_parent), + greenlet(p) +{ + p->_parent = thread_state.get_current(); +} + +UserGreenlet::ParentIsCurrentGuard::~ParentIsCurrentGuard() +{ + this->greenlet->_parent = oldparent; + oldparent.CLEAR(); +} + +}; //namespace greenlet diff --git a/elitebot/lib/python3.11/site-packages/greenlet/__init__.py b/elitebot/lib/python3.11/site-packages/greenlet/__init__.py new file mode 100644 index 0000000..298a19d --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/__init__.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +""" +The root of the greenlet package. +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +__all__ = [ + '__version__', + '_C_API', + + 'GreenletExit', + 'error', + + 'getcurrent', + 'greenlet', + + 'gettrace', + 'settrace', +] + +# pylint:disable=no-name-in-module + +### +# Metadata +### +__version__ = '3.0.3' +from ._greenlet import _C_API # pylint:disable=no-name-in-module + +### +# Exceptions +### +from ._greenlet import GreenletExit +from ._greenlet import error + +### +# greenlets +### +from ._greenlet import getcurrent +from ._greenlet import greenlet + +### +# tracing +### +try: + from ._greenlet import gettrace + from ._greenlet import settrace +except ImportError: + # Tracing wasn't supported. + # XXX: The option to disable it was removed in 1.0, + # so this branch should be dead code. + pass + +### +# Constants +# These constants aren't documented and aren't recommended. +# In 1.0, USE_GC and USE_TRACING are always true, and USE_CONTEXT_VARS +# is the same as ``sys.version_info[:2] >= 3.7`` +### +from ._greenlet import GREENLET_USE_CONTEXT_VARS # pylint:disable=unused-import +from ._greenlet import GREENLET_USE_GC # pylint:disable=unused-import +from ._greenlet import GREENLET_USE_TRACING # pylint:disable=unused-import + +# Controlling the use of the gc module. Provisional API for this greenlet +# implementation in 2.0. +from ._greenlet import CLOCKS_PER_SEC # pylint:disable=unused-import +from ._greenlet import enable_optional_cleanup # pylint:disable=unused-import +from ._greenlet import get_clocks_used_doing_optional_cleanup # pylint:disable=unused-import + +# Other APIS in the _greenlet module are for test support. diff --git a/elitebot/lib/python3.11/site-packages/greenlet/_greenlet.cpython-311-x86_64-linux-gnu.so b/elitebot/lib/python3.11/site-packages/greenlet/_greenlet.cpython-311-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..1d293a337023f3dda544e0071ed8cda4d9ff6948 GIT binary patch literal 1506232 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

qwhO8tTy6nD6tz!^F=bewH8KK-*Jk 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 z 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

l9f3V9IfvoV6NJQ~=z``@)-PA1V6w%~ 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 z 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 il0tTG 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%0DFL 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 Z8z8-P+sf`Ssr<+H>+;t-1)PuG{|6)b%7 literal 0 HcmV?d00001 diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet.cpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet.cpp new file mode 100644 index 0000000..5a9818e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet.cpp @@ -0,0 +1,1494 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +/* Format with: + * clang-format -i --style=file src/greenlet/greenlet.c + * + * + * Fix missing braces with: + * clang-tidy src/greenlet/greenlet.c -fix -checks="readability-braces-around-statements" +*/ +#include +#include +#include +#include + + +#define PY_SSIZE_T_CLEAN +#include +#include "structmember.h" // PyMemberDef + +#include "greenlet_internal.hpp" +// Code after this point can assume access to things declared in stdint.h, +// including the fixed-width types. This goes for the platform-specific switch functions +// as well. +#include "greenlet_refs.hpp" +#include "greenlet_slp_switch.hpp" +#include "greenlet_thread_state.hpp" +#include "greenlet_thread_support.hpp" +#include "greenlet_greenlet.hpp" + +#include "TGreenletGlobals.cpp" +#include "TThreadStateDestroy.cpp" +#include "TGreenlet.cpp" +#include "TMainGreenlet.cpp" +#include "TUserGreenlet.cpp" +#include "TBrokenGreenlet.cpp" +#include "TExceptionState.cpp" +#include "TPythonState.cpp" +#include "TStackState.cpp" + + +using greenlet::LockGuard; +using greenlet::LockInitError; +using greenlet::PyErrOccurred; +using greenlet::Require; + +using greenlet::g_handle_exit; +using greenlet::single_result; + +using greenlet::Greenlet; +using greenlet::UserGreenlet; +using greenlet::MainGreenlet; +using greenlet::BrokenGreenlet; +using greenlet::ThreadState; +using greenlet::PythonState; + + + +// ******* Implementation of things from included files +template +greenlet::refs::_BorrowedGreenlet& greenlet::refs::_BorrowedGreenlet::operator=(const greenlet::refs::BorrowedObject& other) +{ + this->_set_raw_pointer(static_cast(other)); + return *this; +} + +template +inline greenlet::refs::_BorrowedGreenlet::operator Greenlet*() const noexcept +{ + if (!this->p) { + return nullptr; + } + return reinterpret_cast(this->p)->pimpl; +} + +template +greenlet::refs::_BorrowedGreenlet::_BorrowedGreenlet(const BorrowedObject& p) + : BorrowedReference(nullptr) +{ + + this->_set_raw_pointer(p.borrow()); +} + +template +inline greenlet::refs::_OwnedGreenlet::operator Greenlet*() const noexcept +{ + if (!this->p) { + return nullptr; + } + return reinterpret_cast(this->p)->pimpl; +} + + + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmissing-field-initializers" +# pragma clang diagnostic ignored "-Wwritable-strings" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +// warning: ISO C++ forbids converting a string constant to ‘char*’ +// (The python APIs aren't const correct and accept writable char*) +# pragma GCC diagnostic ignored "-Wwrite-strings" +#endif + + +/*********************************************************** + +A PyGreenlet is a range of C stack addresses that must be +saved and restored in such a way that the full range of the +stack contains valid data when we switch to it. + +Stack layout for a greenlet: + + | ^^^ | + | older data | + | | + stack_stop . |_______________| + . | | + . | greenlet data | + . | in stack | + . * |_______________| . . _____________ stack_copy + stack_saved + . | | | | + . | data | |greenlet data| + . | unrelated | | saved | + . | to | | in heap | + stack_start . | this | . . |_____________| stack_copy + | greenlet | + | | + | newer data | + | vvv | + + +Note that a greenlet's stack data is typically partly at its correct +place in the stack, and partly saved away in the heap, but always in +the above configuration: two blocks, the more recent one in the heap +and the older one still in the stack (either block may be empty). + +Greenlets are chained: each points to the previous greenlet, which is +the one that owns the data currently in the C stack above my +stack_stop. The currently running greenlet is the first element of +this chain. The main (initial) greenlet is the last one. Greenlets +whose stack is entirely in the heap can be skipped from the chain. + +The chain is not related to execution order, but only to the order +in which bits of C stack happen to belong to greenlets at a particular +point in time. + +The main greenlet doesn't have a stack_stop: it is responsible for the +complete rest of the C stack, and we don't know where it begins. We +use (char*) -1, the largest possible address. + +States: + stack_stop == NULL && stack_start == NULL: did not start yet + stack_stop != NULL && stack_start == NULL: already finished + stack_stop != NULL && stack_start != NULL: active + +The running greenlet's stack_start is undefined but not NULL. + + ***********************************************************/ + +static PyGreenlet* +green_create_main(ThreadState* state) +{ + PyGreenlet* gmain; + + /* create the main greenlet for this thread */ + gmain = (PyGreenlet*)PyType_GenericAlloc(&PyGreenlet_Type, 0); + if (gmain == NULL) { + Py_FatalError("green_create_main failed to alloc"); + return NULL; + } + new MainGreenlet(gmain, state); + + assert(Py_REFCNT(gmain) == 1); + return gmain; +} + + + +/***********************************************************/ + +/* Some functions must not be inlined: + * slp_restore_state, when inlined into slp_switch might cause + it to restore stack over its own local variables + * slp_save_state, when inlined would add its own local + variables to the saved stack, wasting space + * slp_switch, cannot be inlined for obvious reasons + * g_initialstub, when inlined would receive a pointer into its + own stack frame, leading to incomplete stack save/restore + +g_initialstub is a member function and declared virtual so that the +compiler always calls it through a vtable. + +slp_save_state and slp_restore_state are also member functions. They +are called from trampoline functions that themselves are declared as +not eligible for inlining. +*/ + +extern "C" { +static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref) +{ + return switching_thread_state->slp_save_state(stackref); +} +static void GREENLET_NOINLINE(slp_restore_state_trampoline)() +{ + switching_thread_state->slp_restore_state(); +} +} + + +/***********************************************************/ + +static PyGreenlet* +green_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) +{ + PyGreenlet* o = + (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); + if (o) { + new UserGreenlet(o, GET_THREAD_STATE().state().borrow_current()); + assert(Py_REFCNT(o) == 1); + } + return o; +} + +static PyGreenlet* +green_unswitchable_new(PyTypeObject* type, PyObject* UNUSED(args), PyObject* UNUSED(kwds)) +{ + PyGreenlet* o = + (PyGreenlet*)PyBaseObject_Type.tp_new(type, mod_globs->empty_tuple, mod_globs->empty_dict); + if (o) { + new BrokenGreenlet(o, GET_THREAD_STATE().state().borrow_current()); + assert(Py_REFCNT(o) == 1); + } + return o; +} + +static int +green_setrun(BorrowedGreenlet self, BorrowedObject nrun, void* c); +static int +green_setparent(BorrowedGreenlet self, BorrowedObject nparent, void* c); + +static int +green_init(BorrowedGreenlet self, BorrowedObject args, BorrowedObject kwargs) +{ + PyArgParseParam run; + PyArgParseParam nparent; + static const char* const kwlist[] = { + "run", + "parent", + NULL + }; + + // recall: The O specifier does NOT increase the reference count. + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OO:green", (char**)kwlist, &run, &nparent)) { + return -1; + } + + if (run) { + if (green_setrun(self, run, NULL)) { + return -1; + } + } + if (nparent && !nparent.is_None()) { + return green_setparent(self, nparent, NULL); + } + return 0; +} + + + +static int +green_traverse(PyGreenlet* self, visitproc visit, void* arg) +{ + // We must only visit referenced objects, i.e. only objects + // Py_INCREF'ed by this greenlet (directly or indirectly): + // + // - stack_prev is not visited: holds previous stack pointer, but it's not + // referenced + // - frames are not visited as we don't strongly reference them; + // alive greenlets are not garbage collected + // anyway. This can be a problem, however, if this greenlet is + // never allowed to finish, and is referenced from the frame: we + // have an uncollectible cycle in that case. Note that the + // frame object itself is also frequently not even tracked by the GC + // starting with Python 3.7 (frames are allocated by the + // interpreter untracked, and only become tracked when their + // evaluation is finished if they have a refcount > 1). All of + // this is to say that we should probably strongly reference + // the frame object. Doing so, while always allowing GC on a + // greenlet, solves several leaks for us. + + Py_VISIT(self->dict); + if (!self->pimpl) { + // Hmm. I have seen this at interpreter shutdown time, + // I think. That's very odd because this doesn't go away until + // we're ``green_dealloc()``, at which point we shouldn't be + // traversed anymore. + return 0; + } + + return self->pimpl->tp_traverse(visit, arg); +} + +static int +green_is_gc(BorrowedGreenlet self) +{ + int result = 0; + /* Main greenlet can be garbage collected since it can only + become unreachable if the underlying thread exited. + Active greenlets --- including those that are suspended --- + cannot be garbage collected, however. + */ + if (self->main() || !self->active()) { + result = 1; + } + // The main greenlet pointer will eventually go away after the thread dies. + if (self->was_running_in_dead_thread()) { + // Our thread is dead! We can never run again. Might as well + // GC us. Note that if a tuple containing only us and other + // immutable objects had been scanned before this, when we + // would have returned 0, the tuple will take itself out of GC + // tracking and never be investigated again. So that could + // result in both us and the tuple leaking due to an + // unreachable/uncollectible reference. The same goes for + // dictionaries. + // + // It's not a great idea to be changing our GC state on the + // fly. + result = 1; + } + return result; +} + + +static int +green_clear(PyGreenlet* self) +{ + /* Greenlet is only cleared if it is about to be collected. + Since active greenlets are not garbage collectable, we can + be sure that, even if they are deallocated during clear, + nothing they reference is in unreachable or finalizers, + so even if it switches we are relatively safe. */ + // XXX: Are we responsible for clearing weakrefs here? + Py_CLEAR(self->dict); + return self->pimpl->tp_clear(); +} + +/** + * Returns 0 on failure (the object was resurrected) or 1 on success. + **/ +static int +_green_dealloc_kill_started_non_main_greenlet(BorrowedGreenlet self) +{ + /* Hacks hacks hacks copied from instance_dealloc() */ + /* Temporarily resurrect the greenlet. */ + assert(self.REFCNT() == 0); + Py_SET_REFCNT(self.borrow(), 1); + /* Save the current exception, if any. */ + PyErrPieces saved_err; + try { + // BY THE TIME WE GET HERE, the state may actually be going + // away + // if we're shutting down the interpreter and freeing thread + // entries, + // this could result in freeing greenlets that were leaked. So + // we can't try to read the state. + self->deallocing_greenlet_in_thread( + self->thread_state() + ? static_cast(GET_THREAD_STATE()) + : nullptr); + } + catch (const PyErrOccurred&) { + PyErr_WriteUnraisable(self.borrow_o()); + /* XXX what else should we do? */ + } + /* Check for no resurrection must be done while we keep + * our internal reference, otherwise PyFile_WriteObject + * causes recursion if using Py_INCREF/Py_DECREF + */ + if (self.REFCNT() == 1 && self->active()) { + /* Not resurrected, but still not dead! + XXX what else should we do? we complain. */ + PyObject* f = PySys_GetObject("stderr"); + Py_INCREF(self.borrow_o()); /* leak! */ + if (f != NULL) { + PyFile_WriteString("GreenletExit did not kill ", f); + PyFile_WriteObject(self.borrow_o(), f, 0); + PyFile_WriteString("\n", f); + } + } + /* Restore the saved exception. */ + saved_err.PyErrRestore(); + /* Undo the temporary resurrection; can't use DECREF here, + * it would cause a recursive call. + */ + assert(self.REFCNT() > 0); + + Py_ssize_t refcnt = self.REFCNT() - 1; + Py_SET_REFCNT(self.borrow_o(), refcnt); + if (refcnt != 0) { + /* Resurrected! */ + _Py_NewReference(self.borrow_o()); + Py_SET_REFCNT(self.borrow_o(), refcnt); + /* Better to use tp_finalizer slot (PEP 442) + * and call ``PyObject_CallFinalizerFromDealloc``, + * but that's only supported in Python 3.4+; see + * Modules/_io/iobase.c for an example. + * + * The following approach is copied from iobase.c in CPython 2.7. + * (along with much of this function in general). Here's their + * comment: + * + * When called from a heap type's dealloc, the type will be + * decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ + if (PyType_HasFeature(self.TYPE(), Py_TPFLAGS_HEAPTYPE)) { + Py_INCREF(self.TYPE()); + } + + PyObject_GC_Track((PyObject*)self); + + _Py_DEC_REFTOTAL; +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif /* COUNT_ALLOCS */ + return 0; + } + return 1; +} + + +static void +green_dealloc(PyGreenlet* self) +{ + PyObject_GC_UnTrack(self); + BorrowedGreenlet me(self); + if (me->active() + && me->started() + && !me->main()) { + if (!_green_dealloc_kill_started_non_main_greenlet(me)) { + return; + } + } + + if (self->weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject*)self); + } + Py_CLEAR(self->dict); + + if (self->pimpl) { + // In case deleting this, which frees some memory, + // somehow winds up calling back into us. That's usually a + //bug in our code. + Greenlet* p = self->pimpl; + self->pimpl = nullptr; + delete p; + } + // and finally we're done. self is now invalid. + Py_TYPE(self)->tp_free((PyObject*)self); +} + + + +static OwnedObject +throw_greenlet(BorrowedGreenlet self, PyErrPieces& err_pieces) +{ + PyObject* result = nullptr; + err_pieces.PyErrRestore(); + assert(PyErr_Occurred()); + if (self->started() && !self->active()) { + /* dead greenlet: turn GreenletExit into a regular return */ + result = g_handle_exit(OwnedObject()).relinquish_ownership(); + } + self->args() <<= result; + + return single_result(self->g_switch()); +} + + + +PyDoc_STRVAR( + green_switch_doc, + "switch(*args, **kwargs)\n" + "\n" + "Switch execution to this greenlet.\n" + "\n" + "If this greenlet has never been run, then this greenlet\n" + "will be switched to using the body of ``self.run(*args, **kwargs)``.\n" + "\n" + "If the greenlet is active (has been run, but was switch()'ed\n" + "out before leaving its run function), then this greenlet will\n" + "be resumed and the return value to its switch call will be\n" + "None if no arguments are given, the given argument if one\n" + "argument is given, or the args tuple and keyword args dict if\n" + "multiple arguments are given.\n" + "\n" + "If the greenlet is dead, or is the current greenlet then this\n" + "function will simply return the arguments using the same rules as\n" + "above.\n"); + +static PyObject* +green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) +{ + using greenlet::SwitchingArgs; + SwitchingArgs switch_args(OwnedObject::owning(args), OwnedObject::owning(kwargs)); + self->pimpl->may_switch_away(); + self->pimpl->args() <<= switch_args; + + // If we're switching out of a greenlet, and that switch is the + // last thing the greenlet does, the greenlet ought to be able to + // go ahead and die at that point. Currently, someone else must + // manually switch back to the greenlet so that we "fall off the + // end" and can perform cleanup. You'd think we'd be able to + // figure out that this is happening using the frame's ``f_lasti`` + // member, which is supposed to be an index into + // ``frame->f_code->co_code``, the bytecode string. However, in + // recent interpreters, ``f_lasti`` tends not to be updated thanks + // to things like the PREDICT() macros in ceval.c. So it doesn't + // really work to do that in many cases. For example, the Python + // code: + // def run(): + // greenlet.getcurrent().parent.switch() + // produces bytecode of len 16, with the actual call to switch() + // being at index 10 (in Python 3.10). However, the reported + // ``f_lasti`` we actually see is...5! (Which happens to be the + // second byte of the CALL_METHOD op for ``getcurrent()``). + + try { + //OwnedObject result = single_result(self->pimpl->g_switch()); + OwnedObject result(single_result(self->pimpl->g_switch())); +#ifndef NDEBUG + // Note that the current greenlet isn't necessarily self. If self + // finished, we went to one of its parents. + assert(!self->pimpl->args()); + + const BorrowedGreenlet& current = GET_THREAD_STATE().state().borrow_current(); + // It's possible it's never been switched to. + assert(!current->args()); +#endif + PyObject* p = result.relinquish_ownership(); + + if (!p && !PyErr_Occurred()) { + // This shouldn't be happening anymore, so the asserts + // are there for debug builds. Non-debug builds + // crash "gracefully" in this case, although there is an + // argument to be made for killing the process in all + // cases --- for this to be the case, our switches + // probably nested in an incorrect way, so the state is + // suspicious. Nothing should be corrupt though, just + // confused at the Python level. Letting this propagate is + // probably good enough. + assert(p || PyErr_Occurred()); + throw PyErrOccurred( + mod_globs->PyExc_GreenletError, + "Greenlet.switch() returned NULL without an exception set." + ); + } + return p; + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + +PyDoc_STRVAR( + green_throw_doc, + "Switches execution to this greenlet, but immediately raises the\n" + "given exception in this greenlet. If no argument is provided, the " + "exception\n" + "defaults to `greenlet.GreenletExit`. The normal exception\n" + "propagation rules apply, as described for `switch`. Note that calling " + "this\n" + "method is almost equivalent to the following::\n" + "\n" + " def raiser():\n" + " raise typ, val, tb\n" + " g_raiser = greenlet(raiser, parent=g)\n" + " g_raiser.switch()\n" + "\n" + "except that this trick does not work for the\n" + "`greenlet.GreenletExit` exception, which would not propagate\n" + "from ``g_raiser`` to ``g``.\n"); + +static PyObject* +green_throw(PyGreenlet* self, PyObject* args) +{ + PyArgParseParam typ(mod_globs->PyExc_GreenletExit); + PyArgParseParam val; + PyArgParseParam tb; + + if (!PyArg_ParseTuple(args, "|OOO:throw", &typ, &val, &tb)) { + return nullptr; + } + + assert(typ.borrow() || val.borrow()); + + self->pimpl->may_switch_away(); + try { + // Both normalizing the error and the actual throw_greenlet + // could throw PyErrOccurred. + PyErrPieces err_pieces(typ.borrow(), val.borrow(), tb.borrow()); + + return throw_greenlet(self, err_pieces).relinquish_ownership(); + } + catch (const PyErrOccurred&) { + return nullptr; + } +} + +static int +green_bool(PyGreenlet* self) +{ + return self->pimpl->active(); +} + +/** + * CAUTION: Allocates memory, may run GC and arbitrary Python code. + */ +static PyObject* +green_getdict(PyGreenlet* self, void* UNUSED(context)) +{ + if (self->dict == NULL) { + self->dict = PyDict_New(); + if (self->dict == NULL) { + return NULL; + } + } + Py_INCREF(self->dict); + return self->dict; +} + +static int +green_setdict(PyGreenlet* self, PyObject* val, void* UNUSED(context)) +{ + PyObject* tmp; + + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); + return -1; + } + if (!PyDict_Check(val)) { + PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); + return -1; + } + tmp = self->dict; + Py_INCREF(val); + self->dict = val; + Py_XDECREF(tmp); + return 0; +} + +static bool +_green_not_dead(BorrowedGreenlet self) +{ + // XXX: Where else should we do this? + // Probably on entry to most Python-facing functions? + if (self->was_running_in_dead_thread()) { + self->deactivate_and_free(); + return false; + } + return self->active() || !self->started(); +} + + +static PyObject* +green_getdead(BorrowedGreenlet self, void* UNUSED(context)) +{ + if (_green_not_dead(self)) { + Py_RETURN_FALSE; + } + else { + Py_RETURN_TRUE; + } +} + +static PyObject* +green_get_stack_saved(PyGreenlet* self, void* UNUSED(context)) +{ + return PyLong_FromSsize_t(self->pimpl->stack_saved()); +} + + +static PyObject* +green_getrun(BorrowedGreenlet self, void* UNUSED(context)) +{ + try { + OwnedObject result(self->run()); + return result.relinquish_ownership(); + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + + + + + +static int +green_setrun(BorrowedGreenlet self, BorrowedObject nrun, void* UNUSED(context)) +{ + try { + self->run(nrun); + return 0; + } + catch(const PyErrOccurred&) { + return -1; + } +} + +static PyObject* +green_getparent(BorrowedGreenlet self, void* UNUSED(context)) +{ + return self->parent().acquire_or_None(); +} + + + +static int +green_setparent(BorrowedGreenlet self, BorrowedObject nparent, void* UNUSED(context)) +{ + try { + self->parent(nparent); + } + catch(const PyErrOccurred&) { + return -1; + } + return 0; +} + + +static PyObject* +green_getcontext(const PyGreenlet* self, void* UNUSED(context)) +{ + const Greenlet *const g = self->pimpl; + try { + OwnedObject result(g->context()); + return result.relinquish_ownership(); + } + catch(const PyErrOccurred&) { + return nullptr; + } +} + +static int +green_setcontext(BorrowedGreenlet self, PyObject* nctx, void* UNUSED(context)) +{ + try { + self->context(nctx); + return 0; + } + catch(const PyErrOccurred&) { + return -1; + } +} + + +static PyObject* +green_getframe(BorrowedGreenlet self, void* UNUSED(context)) +{ + const PythonState::OwnedFrame& top_frame = self->top_frame(); + return top_frame.acquire_or_None(); +} + + +static PyObject* +green_getstate(PyGreenlet* self) +{ + PyErr_Format(PyExc_TypeError, + "cannot serialize '%s' object", + Py_TYPE(self)->tp_name); + return nullptr; +} + +static PyObject* +green_repr(BorrowedGreenlet self) +{ + /* + Return a string like + + + The handling of greenlets across threads is not super good. + We mostly use the internal definitions of these terms, but they + generally should make sense to users as well. + */ + PyObject* result; + int never_started = !self->started() && !self->active(); + + const char* const tp_name = Py_TYPE(self)->tp_name; + + if (_green_not_dead(self)) { + /* XXX: The otid= is almost useless because you can't correlate it to + any thread identifier exposed to Python. We could use + PyThreadState_GET()->thread_id, but we'd need to save that in the + greenlet, or save the whole PyThreadState object itself. + + As it stands, its only useful for identifying greenlets from the same thread. + */ + const char* state_in_thread; + if (self->was_running_in_dead_thread()) { + // The thread it was running in is dead! + // This can happen, especially at interpreter shut down. + // It complicates debugging output because it may be + // impossible to access the current thread state at that + // time. Thus, don't access the current thread state. + state_in_thread = " (thread exited)"; + } + else { + state_in_thread = GET_THREAD_STATE().state().is_current(self) + ? " current" + : (self->started() ? " suspended" : ""); + } + result = PyUnicode_FromFormat( + "<%s object at %p (otid=%p)%s%s%s%s>", + tp_name, + self.borrow_o(), + self->thread_state(), + state_in_thread, + self->active() ? " active" : "", + never_started ? " pending" : " started", + self->main() ? " main" : "" + ); + } + else { + result = PyUnicode_FromFormat( + "<%s object at %p (otid=%p) %sdead>", + tp_name, + self.borrow_o(), + self->thread_state(), + self->was_running_in_dead_thread() + ? "(thread exited) " + : "" + ); + } + + return result; +} + +/***************************************************************************** + * C interface + * + * These are exported using the CObject API + */ +extern "C" { +static PyGreenlet* +PyGreenlet_GetCurrent(void) +{ + return GET_THREAD_STATE().state().get_current().relinquish_ownership(); +} + +static int +PyGreenlet_SetParent(PyGreenlet* g, PyGreenlet* nparent) +{ + return green_setparent((PyGreenlet*)g, (PyObject*)nparent, NULL); +} + +static PyGreenlet* +PyGreenlet_New(PyObject* run, PyGreenlet* parent) +{ + using greenlet::refs::NewDictReference; + // In the past, we didn't use green_new and green_init, but that + // was a maintenance issue because we duplicated code. This way is + // much safer, but slightly slower. If that's a problem, we could + // refactor green_init to separate argument parsing from initialization. + OwnedGreenlet g = OwnedGreenlet::consuming(green_new(&PyGreenlet_Type, nullptr, nullptr)); + if (!g) { + return NULL; + } + + try { + NewDictReference kwargs; + if (run) { + kwargs.SetItem(mod_globs->str_run, run); + } + if (parent) { + kwargs.SetItem("parent", (PyObject*)parent); + } + + Require(green_init(g, mod_globs->empty_tuple, kwargs)); + } + catch (const PyErrOccurred&) { + return nullptr; + } + + return g.relinquish_ownership(); +} + +static PyObject* +PyGreenlet_Switch(PyGreenlet* self, PyObject* args, PyObject* kwargs) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return NULL; + } + + if (args == NULL) { + args = mod_globs->empty_tuple; + } + + if (kwargs == NULL || !PyDict_Check(kwargs)) { + kwargs = NULL; + } + + return green_switch(self, args, kwargs); +} + +static PyObject* +PyGreenlet_Throw(PyGreenlet* self, PyObject* typ, PyObject* val, PyObject* tb) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return nullptr; + } + try { + PyErrPieces err_pieces(typ, val, tb); + return throw_greenlet(self, err_pieces).relinquish_ownership(); + } + catch (const PyErrOccurred&) { + return nullptr; + } +} + +static int +Extern_PyGreenlet_MAIN(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->main(); +} + +static int +Extern_PyGreenlet_ACTIVE(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->active(); +} + +static int +Extern_PyGreenlet_STARTED(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return -1; + } + return self->pimpl->started(); +} + +static PyGreenlet* +Extern_PyGreenlet_GET_PARENT(PyGreenlet* self) +{ + if (!PyGreenlet_Check(self)) { + PyErr_BadArgument(); + return NULL; + } + // This can return NULL even if there is no exception + return self->pimpl->parent().acquire(); +} +} // extern C. + +/** End C API ****************************************************************/ + +static PyMethodDef green_methods[] = { + {"switch", + reinterpret_cast(green_switch), + METH_VARARGS | METH_KEYWORDS, + green_switch_doc}, + {"throw", (PyCFunction)green_throw, METH_VARARGS, green_throw_doc}, + {"__getstate__", (PyCFunction)green_getstate, METH_NOARGS, NULL}, + {NULL, NULL} /* sentinel */ +}; + +static PyGetSetDef green_getsets[] = { + /* name, getter, setter, doc, context pointer */ + {"__dict__", (getter)green_getdict, (setter)green_setdict, /*XXX*/ NULL}, + {"run", (getter)green_getrun, (setter)green_setrun, /*XXX*/ NULL}, + {"parent", (getter)green_getparent, (setter)green_setparent, /*XXX*/ NULL}, + {"gr_frame", (getter)green_getframe, NULL, /*XXX*/ NULL}, + {"gr_context", + (getter)green_getcontext, + (setter)green_setcontext, + /*XXX*/ NULL}, + {"dead", (getter)green_getdead, NULL, /*XXX*/ NULL}, + {"_stack_saved", (getter)green_get_stack_saved, NULL, /*XXX*/ NULL}, + {NULL} +}; + +static PyMemberDef green_members[] = { + {NULL} +}; + +static PyNumberMethods green_as_number = { + NULL, /* nb_add */ + NULL, /* nb_subtract */ + NULL, /* nb_multiply */ + NULL, /* nb_remainder */ + NULL, /* nb_divmod */ + NULL, /* nb_power */ + NULL, /* nb_negative */ + NULL, /* nb_positive */ + NULL, /* nb_absolute */ + (inquiry)green_bool, /* nb_bool */ +}; + + +PyTypeObject PyGreenlet_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "greenlet.greenlet", /* tp_name */ + sizeof(PyGreenlet), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)green_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)green_repr, /* tp_repr */ + &green_as_number, /* tp_as _number*/ + 0, /* tp_as _sequence*/ + 0, /* tp_as _mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer*/ + G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "greenlet(run=None, parent=None) -> greenlet\n\n" + "Creates a new greenlet object (without running it).\n\n" + " - *run* -- The callable to invoke.\n" + " - *parent* -- The parent greenlet. The default is the current " + "greenlet.", /* tp_doc */ + (traverseproc)green_traverse, /* tp_traverse */ + (inquiry)green_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyGreenlet, weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + green_methods, /* tp_methods */ + green_members, /* tp_members */ + green_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(PyGreenlet, dict), /* tp_dictoffset */ + (initproc)green_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + (newfunc)green_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + (inquiry)green_is_gc, /* tp_is_gc */ +}; + + + +static PyObject* +green_unswitchable_getforce(PyGreenlet* self, void* UNUSED(context)) +{ + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + return PyBool_FromLong(broken->_force_switch_error); +} + +static int +green_unswitchable_setforce(PyGreenlet* self, BorrowedObject nforce, void* UNUSED(context)) +{ + if (!nforce) { + PyErr_SetString( + PyExc_AttributeError, + "Cannot delete force_switch_error" + ); + return -1; + } + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + int is_true = PyObject_IsTrue(nforce); + if (is_true == -1) { + return -1; + } + broken->_force_switch_error = is_true; + return 0; +} + +static PyObject* +green_unswitchable_getforceslp(PyGreenlet* self, void* UNUSED(context)) +{ + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + return PyBool_FromLong(broken->_force_slp_switch_error); +} + +static int +green_unswitchable_setforceslp(PyGreenlet* self, BorrowedObject nforce, void* UNUSED(context)) +{ + if (!nforce) { + PyErr_SetString( + PyExc_AttributeError, + "Cannot delete force_slp_switch_error" + ); + return -1; + } + BrokenGreenlet* broken = dynamic_cast(self->pimpl); + int is_true = PyObject_IsTrue(nforce); + if (is_true == -1) { + return -1; + } + broken->_force_slp_switch_error = is_true; + return 0; +} + +static PyGetSetDef green_unswitchable_getsets[] = { + /* name, getter, setter, doc, context pointer */ + {"force_switch_error", + (getter)green_unswitchable_getforce, + (setter)green_unswitchable_setforce, + /*XXX*/ NULL}, + {"force_slp_switch_error", + (getter)green_unswitchable_getforceslp, + (setter)green_unswitchable_setforceslp, + /*XXX*/ NULL}, + + {NULL} +}; + +PyTypeObject PyGreenletUnswitchable_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "greenlet._greenlet.UnswitchableGreenlet", + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)green_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as _number*/ + 0, /* tp_as _sequence*/ + 0, /* tp_as _mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer*/ + G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Undocumented internal class", /* tp_doc */ + (traverseproc)green_traverse, /* tp_traverse */ + (inquiry)green_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + green_unswitchable_getsets, /* tp_getset */ + &PyGreenlet_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)green_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + (newfunc)green_unswitchable_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + (inquiry)green_is_gc, /* tp_is_gc */ +}; + + +PyDoc_STRVAR(mod_getcurrent_doc, + "getcurrent() -> greenlet\n" + "\n" + "Returns the current greenlet (i.e. the one which called this " + "function).\n"); + +static PyObject* +mod_getcurrent(PyObject* UNUSED(module)) +{ + return GET_THREAD_STATE().state().get_current().relinquish_ownership_o(); +} + +PyDoc_STRVAR(mod_settrace_doc, + "settrace(callback) -> object\n" + "\n" + "Sets a new tracing function and returns the previous one.\n"); +static PyObject* +mod_settrace(PyObject* UNUSED(module), PyObject* args) +{ + PyArgParseParam tracefunc; + if (!PyArg_ParseTuple(args, "O", &tracefunc)) { + return NULL; + } + ThreadState& state = GET_THREAD_STATE(); + OwnedObject previous = state.get_tracefunc(); + if (!previous) { + previous = Py_None; + } + + state.set_tracefunc(tracefunc); + + return previous.relinquish_ownership(); +} + +PyDoc_STRVAR(mod_gettrace_doc, + "gettrace() -> object\n" + "\n" + "Returns the currently set tracing function, or None.\n"); + +static PyObject* +mod_gettrace(PyObject* UNUSED(module)) +{ + OwnedObject tracefunc = GET_THREAD_STATE().state().get_tracefunc(); + if (!tracefunc) { + tracefunc = Py_None; + } + return tracefunc.relinquish_ownership(); +} + +PyDoc_STRVAR(mod_set_thread_local_doc, + "set_thread_local(key, value) -> None\n" + "\n" + "Set a value in the current thread-local dictionary. Debbuging only.\n"); + +static PyObject* +mod_set_thread_local(PyObject* UNUSED(module), PyObject* args) +{ + PyArgParseParam key; + PyArgParseParam value; + PyObject* result = NULL; + + if (PyArg_UnpackTuple(args, "set_thread_local", 2, 2, &key, &value)) { + if(PyDict_SetItem( + PyThreadState_GetDict(), // borrow + key, + value) == 0 ) { + // success + Py_INCREF(Py_None); + result = Py_None; + } + } + return result; +} + +PyDoc_STRVAR(mod_get_pending_cleanup_count_doc, + "get_pending_cleanup_count() -> Integer\n" + "\n" + "Get the number of greenlet cleanup operations pending. Testing only.\n"); + + +static PyObject* +mod_get_pending_cleanup_count(PyObject* UNUSED(module)) +{ + LockGuard cleanup_lock(*mod_globs->thread_states_to_destroy_lock); + return PyLong_FromSize_t(mod_globs->thread_states_to_destroy.size()); +} + +PyDoc_STRVAR(mod_get_total_main_greenlets_doc, + "get_total_main_greenlets() -> Integer\n" + "\n" + "Quickly return the number of main greenlets that exist. Testing only.\n"); + +static PyObject* +mod_get_total_main_greenlets(PyObject* UNUSED(module)) +{ + return PyLong_FromSize_t(G_TOTAL_MAIN_GREENLETS); +} + +PyDoc_STRVAR(mod_get_clocks_used_doing_optional_cleanup_doc, + "get_clocks_used_doing_optional_cleanup() -> Integer\n" + "\n" + "Get the number of clock ticks the program has used doing optional " + "greenlet cleanup.\n" + "Beginning in greenlet 2.0, greenlet tries to find and dispose of greenlets\n" + "that leaked after a thread exited. This requires invoking Python's garbage collector,\n" + "which may have a performance cost proportional to the number of live objects.\n" + "This function returns the amount of processor time\n" + "greenlet has used to do this. In programs that run with very large amounts of live\n" + "objects, this metric can be used to decide whether the cost of doing this cleanup\n" + "is worth the memory leak being corrected. If not, you can disable the cleanup\n" + "using ``enable_optional_cleanup(False)``.\n" + "The units are arbitrary and can only be compared to themselves (similarly to ``time.clock()``);\n" + "for example, to see how it scales with your heap. You can attempt to convert them into seconds\n" + "by dividing by the value of CLOCKS_PER_SEC." + "If cleanup has been disabled, returns None." + "\n" + "This is an implementation specific, provisional API. It may be changed or removed\n" + "in the future.\n" + ".. versionadded:: 2.0" + ); +static PyObject* +mod_get_clocks_used_doing_optional_cleanup(PyObject* UNUSED(module)) +{ + std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); + + if (clocks == std::clock_t(-1)) { + Py_RETURN_NONE; + } + // This might not actually work on some implementations; clock_t + // is an opaque type. + return PyLong_FromSsize_t(clocks); +} + +PyDoc_STRVAR(mod_enable_optional_cleanup_doc, + "mod_enable_optional_cleanup(bool) -> None\n" + "\n" + "Enable or disable optional cleanup operations.\n" + "See ``get_clocks_used_doing_optional_cleanup()`` for details.\n" + ); +static PyObject* +mod_enable_optional_cleanup(PyObject* UNUSED(module), PyObject* flag) +{ + int is_true = PyObject_IsTrue(flag); + if (is_true == -1) { + return nullptr; + } + + std::clock_t& clocks = ThreadState::clocks_used_doing_gc(); + if (is_true) { + // If we already have a value, we don't want to lose it. + if (clocks == std::clock_t(-1)) { + clocks = 0; + } + } + else { + clocks = std::clock_t(-1); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(mod_get_tstate_trash_delete_nesting_doc, + "get_tstate_trash_delete_nesting() -> Integer\n" + "\n" + "Return the 'trash can' nesting level. Testing only.\n"); +static PyObject* +mod_get_tstate_trash_delete_nesting(PyObject* UNUSED(module)) +{ + PyThreadState* tstate = PyThreadState_GET(); + +#if GREENLET_PY312 + return PyLong_FromLong(tstate->trash.delete_nesting); +#else + return PyLong_FromLong(tstate->trash_delete_nesting); +#endif +} + +static PyMethodDef GreenMethods[] = { + {"getcurrent", + (PyCFunction)mod_getcurrent, + METH_NOARGS, + mod_getcurrent_doc}, + {"settrace", (PyCFunction)mod_settrace, METH_VARARGS, mod_settrace_doc}, + {"gettrace", (PyCFunction)mod_gettrace, METH_NOARGS, mod_gettrace_doc}, + {"set_thread_local", (PyCFunction)mod_set_thread_local, METH_VARARGS, mod_set_thread_local_doc}, + {"get_pending_cleanup_count", (PyCFunction)mod_get_pending_cleanup_count, METH_NOARGS, mod_get_pending_cleanup_count_doc}, + {"get_total_main_greenlets", (PyCFunction)mod_get_total_main_greenlets, METH_NOARGS, mod_get_total_main_greenlets_doc}, + {"get_clocks_used_doing_optional_cleanup", (PyCFunction)mod_get_clocks_used_doing_optional_cleanup, METH_NOARGS, mod_get_clocks_used_doing_optional_cleanup_doc}, + {"enable_optional_cleanup", (PyCFunction)mod_enable_optional_cleanup, METH_O, mod_enable_optional_cleanup_doc}, + {"get_tstate_trash_delete_nesting", (PyCFunction)mod_get_tstate_trash_delete_nesting, METH_NOARGS, mod_get_tstate_trash_delete_nesting_doc}, + {NULL, NULL} /* Sentinel */ +}; + +static const char* const copy_on_greentype[] = { + "getcurrent", + "error", + "GreenletExit", + "settrace", + "gettrace", + NULL +}; + +static struct PyModuleDef greenlet_module_def = { + PyModuleDef_HEAD_INIT, + "greenlet._greenlet", + NULL, + -1, + GreenMethods, +}; + + + +static PyObject* +greenlet_internal_mod_init() noexcept +{ + static void* _PyGreenlet_API[PyGreenlet_API_pointers]; + + try { + CreatedModule m(greenlet_module_def); + + Require(PyType_Ready(&PyGreenlet_Type)); + Require(PyType_Ready(&PyGreenletUnswitchable_Type)); + + mod_globs = new greenlet::GreenletGlobals; + ThreadState::init(); + + m.PyAddObject("greenlet", PyGreenlet_Type); + m.PyAddObject("UnswitchableGreenlet", PyGreenletUnswitchable_Type); + m.PyAddObject("error", mod_globs->PyExc_GreenletError); + m.PyAddObject("GreenletExit", mod_globs->PyExc_GreenletExit); + + m.PyAddObject("GREENLET_USE_GC", 1); + m.PyAddObject("GREENLET_USE_TRACING", 1); + m.PyAddObject("GREENLET_USE_CONTEXT_VARS", 1L); + m.PyAddObject("GREENLET_USE_STANDARD_THREADING", 1L); + + OwnedObject clocks_per_sec = OwnedObject::consuming(PyLong_FromSsize_t(CLOCKS_PER_SEC)); + m.PyAddObject("CLOCKS_PER_SEC", clocks_per_sec); + + /* also publish module-level data as attributes of the greentype. */ + // XXX: This is weird, and enables a strange pattern of + // confusing the class greenlet with the module greenlet; with + // the exception of (possibly) ``getcurrent()``, this + // shouldn't be encouraged so don't add new items here. + for (const char* const* p = copy_on_greentype; *p; p++) { + OwnedObject o = m.PyRequireAttr(*p); + PyDict_SetItemString(PyGreenlet_Type.tp_dict, *p, o.borrow()); + } + + /* + * Expose C API + */ + + /* types */ + _PyGreenlet_API[PyGreenlet_Type_NUM] = (void*)&PyGreenlet_Type; + + /* exceptions */ + _PyGreenlet_API[PyExc_GreenletError_NUM] = (void*)mod_globs->PyExc_GreenletError; + _PyGreenlet_API[PyExc_GreenletExit_NUM] = (void*)mod_globs->PyExc_GreenletExit; + + /* methods */ + _PyGreenlet_API[PyGreenlet_New_NUM] = (void*)PyGreenlet_New; + _PyGreenlet_API[PyGreenlet_GetCurrent_NUM] = (void*)PyGreenlet_GetCurrent; + _PyGreenlet_API[PyGreenlet_Throw_NUM] = (void*)PyGreenlet_Throw; + _PyGreenlet_API[PyGreenlet_Switch_NUM] = (void*)PyGreenlet_Switch; + _PyGreenlet_API[PyGreenlet_SetParent_NUM] = (void*)PyGreenlet_SetParent; + + /* Previously macros, but now need to be functions externally. */ + _PyGreenlet_API[PyGreenlet_MAIN_NUM] = (void*)Extern_PyGreenlet_MAIN; + _PyGreenlet_API[PyGreenlet_STARTED_NUM] = (void*)Extern_PyGreenlet_STARTED; + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM] = (void*)Extern_PyGreenlet_ACTIVE; + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM] = (void*)Extern_PyGreenlet_GET_PARENT; + + /* XXX: Note that our module name is ``greenlet._greenlet``, but for + backwards compatibility with existing C code, we need the _C_API to + be directly in greenlet. + */ + const NewReference c_api_object(Require( + PyCapsule_New( + (void*)_PyGreenlet_API, + "greenlet._C_API", + NULL))); + m.PyAddObject("_C_API", c_api_object); + assert(c_api_object.REFCNT() == 2); + + // cerr << "Sizes:" + // << "\n\tGreenlet : " << sizeof(Greenlet) + // << "\n\tUserGreenlet : " << sizeof(UserGreenlet) + // << "\n\tMainGreenlet : " << sizeof(MainGreenlet) + // << "\n\tExceptionState : " << sizeof(greenlet::ExceptionState) + // << "\n\tPythonState : " << sizeof(greenlet::PythonState) + // << "\n\tStackState : " << sizeof(greenlet::StackState) + // << "\n\tSwitchingArgs : " << sizeof(greenlet::SwitchingArgs) + // << "\n\tOwnedObject : " << sizeof(greenlet::refs::OwnedObject) + // << "\n\tBorrowedObject : " << sizeof(greenlet::refs::BorrowedObject) + // << "\n\tPyGreenlet : " << sizeof(PyGreenlet) + // << endl; + + return m.borrow(); // But really it's the main reference. + } + catch (const LockInitError& e) { + PyErr_SetString(PyExc_MemoryError, e.what()); + return NULL; + } + catch (const PyErrOccurred&) { + return NULL; + } + +} + +extern "C" { + +PyMODINIT_FUNC +PyInit__greenlet(void) +{ + return greenlet_internal_mod_init(); +} + +}; // extern C + +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet.h b/elitebot/lib/python3.11/site-packages/greenlet/greenlet.h new file mode 100644 index 0000000..d02a16e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet.h @@ -0,0 +1,164 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ + +/* Greenlet object interface */ + +#ifndef Py_GREENLETOBJECT_H +#define Py_GREENLETOBJECT_H + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is deprecated and undocumented. It does not change. */ +#define GREENLET_VERSION "1.0.0" + +#ifndef GREENLET_MODULE +#define implementation_ptr_t void* +#endif + +typedef struct _greenlet { + PyObject_HEAD + PyObject* weakreflist; + PyObject* dict; + implementation_ptr_t pimpl; +} PyGreenlet; + +#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type)) + + +/* C API functions */ + +/* Total number of symbols that are exported */ +#define PyGreenlet_API_pointers 12 + +#define PyGreenlet_Type_NUM 0 +#define PyExc_GreenletError_NUM 1 +#define PyExc_GreenletExit_NUM 2 + +#define PyGreenlet_New_NUM 3 +#define PyGreenlet_GetCurrent_NUM 4 +#define PyGreenlet_Throw_NUM 5 +#define PyGreenlet_Switch_NUM 6 +#define PyGreenlet_SetParent_NUM 7 + +#define PyGreenlet_MAIN_NUM 8 +#define PyGreenlet_STARTED_NUM 9 +#define PyGreenlet_ACTIVE_NUM 10 +#define PyGreenlet_GET_PARENT_NUM 11 + +#ifndef GREENLET_MODULE +/* This section is used by modules that uses the greenlet C API */ +static void** _PyGreenlet_API = NULL; + +# define PyGreenlet_Type \ + (*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM]) + +# define PyExc_GreenletError \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM]) + +# define PyExc_GreenletExit \ + ((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM]) + +/* + * PyGreenlet_New(PyObject *args) + * + * greenlet.greenlet(run, parent=None) + */ +# define PyGreenlet_New \ + (*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \ + _PyGreenlet_API[PyGreenlet_New_NUM]) + +/* + * PyGreenlet_GetCurrent(void) + * + * greenlet.getcurrent() + */ +# define PyGreenlet_GetCurrent \ + (*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM]) + +/* + * PyGreenlet_Throw( + * PyGreenlet *greenlet, + * PyObject *typ, + * PyObject *val, + * PyObject *tb) + * + * g.throw(...) + */ +# define PyGreenlet_Throw \ + (*(PyObject * (*)(PyGreenlet * self, \ + PyObject * typ, \ + PyObject * val, \ + PyObject * tb)) \ + _PyGreenlet_API[PyGreenlet_Throw_NUM]) + +/* + * PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args) + * + * g.switch(*args, **kwargs) + */ +# define PyGreenlet_Switch \ + (*(PyObject * \ + (*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \ + _PyGreenlet_API[PyGreenlet_Switch_NUM]) + +/* + * PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent) + * + * g.parent = new_parent + */ +# define PyGreenlet_SetParent \ + (*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \ + _PyGreenlet_API[PyGreenlet_SetParent_NUM]) + +/* + * PyGreenlet_GetParent(PyObject* greenlet) + * + * return greenlet.parent; + * + * This could return NULL even if there is no exception active. + * If it does not return NULL, you are responsible for decrementing the + * reference count. + */ +# define PyGreenlet_GetParent \ + (*(PyGreenlet* (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_GET_PARENT_NUM]) + +/* + * deprecated, undocumented alias. + */ +# define PyGreenlet_GET_PARENT PyGreenlet_GetParent + +# define PyGreenlet_MAIN \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_MAIN_NUM]) + +# define PyGreenlet_STARTED \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_STARTED_NUM]) + +# define PyGreenlet_ACTIVE \ + (*(int (*)(PyGreenlet*)) \ + _PyGreenlet_API[PyGreenlet_ACTIVE_NUM]) + + + + +/* Macro that imports greenlet and initializes C API */ +/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we + keep the older definition to be sure older code that might have a copy of + the header still works. */ +# define PyGreenlet_Import() \ + { \ + _PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \ + } + +#endif /* GREENLET_MODULE */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GREENLETOBJECT_H */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_allocator.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_allocator.hpp new file mode 100644 index 0000000..b452f54 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_allocator.hpp @@ -0,0 +1,63 @@ +#ifndef GREENLET_ALLOCATOR_HPP +#define GREENLET_ALLOCATOR_HPP + +#define PY_SSIZE_T_CLEAN +#include +#include +#include "greenlet_compiler_compat.hpp" + + +namespace greenlet +{ + // This allocator is stateless; all instances are identical. + // It can *ONLY* be used when we're sure we're holding the GIL + // (Python's allocators require the GIL). + template + struct PythonAllocator : public std::allocator { + + PythonAllocator(const PythonAllocator& UNUSED(other)) + : std::allocator() + { + } + + PythonAllocator(const std::allocator other) + : std::allocator(other) + {} + + template + PythonAllocator(const std::allocator& other) + : std::allocator(other) + { + } + + PythonAllocator() : std::allocator() {} + + T* allocate(size_t number_objects, const void* UNUSED(hint)=0) + { + void* p; + if (number_objects == 1) + p = PyObject_Malloc(sizeof(T)); + else + p = PyMem_Malloc(sizeof(T) * number_objects); + return static_cast(p); + } + + void deallocate(T* t, size_t n) + { + void* p = t; + if (n == 1) { + PyObject_Free(p); + } + else + PyMem_Free(p); + } + // This member is deprecated in C++17 and removed in C++20 + template< class U > + struct rebind { + typedef PythonAllocator other; + }; + + }; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_compiler_compat.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_compiler_compat.hpp new file mode 100644 index 0000000..ee5bbdd --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_compiler_compat.hpp @@ -0,0 +1,95 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_COMPILER_COMPAT_HPP +#define GREENLET_COMPILER_COMPAT_HPP + +/** + * Definitions to aid with compatibility with different compilers. + * + * .. caution:: Use extreme care with noexcept. + * Some compilers and runtimes, specifically gcc/libgcc/libstdc++ on + * Linux, implement stack unwinding by throwing an uncatchable + * exception, one that specifically does not appear to be an active + * exception to the rest of the runtime. If this happens while we're in a noexcept function, + * we have violated our dynamic exception contract, and so the runtime + * will call std::terminate(), which kills the process with the + * unhelpful message "terminate called without an active exception". + * + * This has happened in this scenario: A background thread is running + * a greenlet that has made a native call and released the GIL. + * Meanwhile, the main thread finishes and starts shutting down the + * interpreter. When the background thread is scheduled again and + * attempts to obtain the GIL, it notices that the interpreter is + * exiting and calls ``pthread_exit()``. This in turn starts to unwind + * the stack by throwing that exception. But we had the ``PyCall`` + * functions annotated as noexcept, so the runtime terminated us. + * + * #2 0x00007fab26fec2b7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6 + * #3 0x00007fab26febb3c in __gxx_personality_v0 () from /lib/x86_64-linux-gnu/libstdc++.so.6 + * #4 0x00007fab26f34de6 in ?? () from /lib/x86_64-linux-gnu/libgcc_s.so.1 + * #6 0x00007fab276a34c6 in __GI___pthread_unwind at ./nptl/unwind.c:130 + * #7 0x00007fab2769bd3a in __do_cancel () at ../sysdeps/nptl/pthreadP.h:280 + * #8 __GI___pthread_exit (value=value@entry=0x0) at ./nptl/pthread_exit.c:36 + * #9 0x000000000052e567 in PyThread_exit_thread () at ../Python/thread_pthread.h:370 + * #10 0x00000000004d60b5 in take_gil at ../Python/ceval_gil.h:224 + * #11 0x00000000004d65f9 in PyEval_RestoreThread at ../Python/ceval.c:467 + * #12 0x000000000060cce3 in setipaddr at ../Modules/socketmodule.c:1203 + * #13 0x00000000006101cd in socket_gethostbyname + */ + +#include + +# if defined(__clang__) +# define G_FP_TMPL_STATIC static +# else +// GCC has no problem allowing static function pointers, but emits +// tons of warnings about "whose type uses the anonymous namespace [-Wsubobject-linkage]" +# define G_FP_TMPL_STATIC +# endif + +# define G_NO_COPIES_OF_CLS(Cls) private: \ + Cls(const Cls& other) = delete; \ + Cls& operator=(const Cls& other) = delete + +# define G_NO_ASSIGNMENT_OF_CLS(Cls) private: \ + Cls& operator=(const Cls& other) = delete + +# define G_NO_COPY_CONSTRUCTOR_OF_CLS(Cls) private: \ + Cls(const Cls& other) = delete; + + +// CAUTION: MSVC is stupidly picky: +// +// "The compiler ignores, without warning, any __declspec keywords +// placed after * or & and in front of the variable identifier in a +// declaration." +// (https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-160) +// +// So pointer return types must be handled differently (because of the +// trailing *), or you get inscrutable compiler warnings like "error +// C2059: syntax error: ''" +// +// In C++ 11, there is a standard syntax for attributes, and +// GCC defines an attribute to use with this: [[gnu:noinline]]. +// In the future, this is expected to become standard. + +#if defined(__GNUC__) || defined(__clang__) +/* We used to check for GCC 4+ or 3.4+, but those compilers are + laughably out of date. Just assume they support it. */ +# define GREENLET_NOINLINE(name) __attribute__((noinline)) name +# define GREENLET_NOINLINE_P(rtype, name) rtype __attribute__((noinline)) name +# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +#elif defined(_MSC_VER) +/* We used to check for && (_MSC_VER >= 1300) but that's also out of date. */ +# define GREENLET_NOINLINE(name) __declspec(noinline) name +# define GREENLET_NOINLINE_P(rtype, name) __declspec(noinline) rtype name +# define UNUSED(x) UNUSED_ ## x +#endif + +#if defined(_MSC_VER) +# define G_NOEXCEPT_WIN32 noexcept +#else +# define G_NOEXCEPT_WIN32 +#endif + + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_add_pending.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_add_pending.hpp new file mode 100644 index 0000000..0d28efd --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_add_pending.hpp @@ -0,0 +1,172 @@ +#ifndef GREENLET_CPYTHON_ADD_PENDING_HPP +#define GREENLET_CPYTHON_ADD_PENDING_HPP + +#if (PY_VERSION_HEX >= 0x30800A0 && PY_VERSION_HEX < 0x3090000) && !(defined(_WIN32) || defined(WIN32)) +// XXX: From Python 3.8a3 [1] up until Python 3.9a6 [2][3], +// ``Py_AddPendingCall`` would try to produce a Python exception if +// the interpreter was in the beginning of shutting down when this +// function is called. However, ``Py_AddPendingCall`` doesn't require +// the GIL, and we are absolutely not holding it when we make that +// call. That means that trying to create the Python exception is +// using the C API in an undefined state; here the C API detects this +// and aborts the process with an error ("Fatal Python error: Python +// memory allocator called without holding the GIL": Add -> +// PyErr_SetString -> PyUnicode_New -> PyObject_Malloc). This arises +// (obviously) in multi-threaded programs and happens if one thread is +// exiting and cleaning up its thread-local data while the other +// thread is trying to shut down the interpreter. A crash on shutdown +// is still a crash and could result in data loss (e.g., daemon +// threads are still running, pending signal handlers may be present, +// buffers may not be flushed, there may be __del__ that need run, +// etc), so we have to work around it. +// +// Of course, we can (and do) check for whether the interpreter is +// shutting down before calling ``Py_AddPendingCall``, but that's a +// race condition since we don't hold the GIL, and so we may not +// actually get the right answer. Plus, ``Py_FinalizeEx`` actually +// calls ``_Py_FinishPendingCalls`` (which sets the pending->finishing +// flag, which is used to gate creating the exceptioen) *before* +// publishing any other data that would let us detect the shutdown +// (such as runtime->finalizing). So that point is moot. +// +// Our solution for those versions is to inline the same code, without +// the problematic bit that sets the exception. Unfortunately, all of +// the structure definitions are private/opaque, *and* we can't +// actually count on being able to include their definitions from +// ``internal/pycore_*``, because on some platforms those header files +// are incomplete (i.e., on macOS with macports 3.8, the includes are +// fine, but on Ubuntu jammy with 3.8 from ppa:deadsnakes or GitHub +// Actions 3.8 (I think it's Ubuntu 18.04), they con't be used; at +// least, I couldn't get them to work). So we need to define the +// structures and _PyRuntime data member ourself. Yet more +// unfortunately, _PyRuntime won't link on Windows, so we can only do +// this on other platforms. +// +// [1] https://github.com/python/cpython/commit/842a2f07f2f08a935ef470bfdaeef40f87490cfc +// [2] https://github.com/python/cpython/commit/cfc3c2f8b34d3864717ab584c5b6c260014ba55a +// [3] https://github.com/python/cpython/issues/81308 +# define GREENLET_BROKEN_PY_ADD_PENDING 1 + +// When defining these structures, the important thing is to get +// binary compatibility, i.e., structure layout. For that, we only +// need to define fields up to the ones we use; after that they're +// irrelevant UNLESS the structure is included in another structure +// *before* the structure we're interested in --- in that case, it +// must be complete. Ellipsis indicate elided trailing members. +// Pointer types are changed to void* to keep from having to define +// more structures. + +// From "internal/pycore_atomic.h" + +// There are several different definitions of this, including the +// plain ``int`` version, a ``volatile int`` and an ``_Atomic int`` +// I don't think any of those change the size/layout. +typedef struct _Py_atomic_int { + volatile int _value; +} _Py_atomic_int; + +// This needs too much infrastructure, so we just do a regular store. +#define _Py_atomic_store_relaxed(ATOMIC_VAL, NEW_VAL) \ + (ATOMIC_VAL)->_value = NEW_VAL + + + +// From "internal/pycore_pymem.h" +#define NUM_GENERATIONS 3 + + +struct gc_generation { + PyGC_Head head; // We already have this defined. + int threshold; + int count; +}; +struct gc_generation_stats { + Py_ssize_t collections; + Py_ssize_t collected; + Py_ssize_t uncollectable; +}; + +struct _gc_runtime_state { + void *trash_delete_later; + int trash_delete_nesting; + int enabled; + int debug; + struct gc_generation generations[NUM_GENERATIONS]; + void *generation0; + struct gc_generation permanent_generation; + struct gc_generation_stats generation_stats[NUM_GENERATIONS]; + int collecting; + void *garbage; + void *callbacks; + Py_ssize_t long_lived_total; + Py_ssize_t long_lived_pending; +}; + +// From "internal/pycore_pystate.h" +struct _pending_calls { + int finishing; + PyThread_type_lock lock; + _Py_atomic_int calls_to_do; + int async_exc; +#define NPENDINGCALLS 32 + struct { + int (*func)(void *); + void *arg; + } calls[NPENDINGCALLS]; + int first; + int last; +}; + +struct _ceval_runtime_state { + int recursion_limit; + int tracing_possible; + _Py_atomic_int eval_breaker; + _Py_atomic_int gil_drop_request; + struct _pending_calls pending; + // ... +}; + +typedef struct pyruntimestate { + int preinitializing; + int preinitialized; + int core_initialized; + int initialized; + void *finalizing; + + struct pyinterpreters { + PyThread_type_lock mutex; + void *head; + void *main; + int64_t next_id; + } interpreters; + // XXX Remove this field once we have a tp_* slot. + struct _xidregistry { + PyThread_type_lock mutex; + void *head; + } xidregistry; + + unsigned long main_thread; + +#define NEXITFUNCS 32 + void (*exitfuncs[NEXITFUNCS])(void); + int nexitfuncs; + + struct _gc_runtime_state gc; + struct _ceval_runtime_state ceval; + // ... +} _PyRuntimeState; + +#define SIGNAL_PENDING_CALLS(ceval) \ + do { \ + _Py_atomic_store_relaxed(&(ceval)->pending.calls_to_do, 1); \ + _Py_atomic_store_relaxed(&(ceval)->eval_breaker, 1); \ + } while (0) + +extern _PyRuntimeState _PyRuntime; + +#else +# define GREENLET_BROKEN_PY_ADD_PENDING 0 +#endif + + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_compat.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_compat.hpp new file mode 100644 index 0000000..cdc1617 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_cpython_compat.hpp @@ -0,0 +1,127 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_CPYTHON_COMPAT_H +#define GREENLET_CPYTHON_COMPAT_H + +/** + * Helpers for compatibility with multiple versions of CPython. + */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" + + +#if PY_VERSION_HEX >= 0x30A00B1 +# define GREENLET_PY310 1 +/* +Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member. +See https://github.com/python/cpython/pull/25276 +We have to save and restore this as well. +*/ +# define GREENLET_USE_CFRAME 1 +#else +# define GREENLET_USE_CFRAME 0 +# define GREENLET_PY310 0 +#endif + + + +#if PY_VERSION_HEX >= 0x30B00A4 +/* +Greenlet won't compile on anything older than Python 3.11 alpha 4 (see +https://bugs.python.org/issue46090). Summary of breaking internal changes: +- Python 3.11 alpha 1 changed how frame objects are represented internally. + - https://github.com/python/cpython/pull/30122 +- Python 3.11 alpha 3 changed how recursion limits are stored. + - https://github.com/python/cpython/pull/29524 +- Python 3.11 alpha 4 changed how exception state is stored. It also includes a + change to help greenlet save and restore the interpreter frame "data stack". + - https://github.com/python/cpython/pull/30122 + - https://github.com/python/cpython/pull/30234 +*/ +# define GREENLET_PY311 1 +#else +# define GREENLET_PY311 0 +#endif + + +#if PY_VERSION_HEX >= 0x30C0000 +# define GREENLET_PY312 1 +#else +# define GREENLET_PY312 0 +#endif + +#ifndef Py_SET_REFCNT +/* Py_REFCNT and Py_SIZE macros are converted to functions +https://bugs.python.org/issue39573 */ +# define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) +#endif + +#ifndef _Py_DEC_REFTOTAL +/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by: + https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924 + + The symbol we use to replace it was removed by at least 3.12. +*/ +# ifdef Py_REF_DEBUG +# if GREENLET_PY312 +# define _Py_DEC_REFTOTAL +# else +# define _Py_DEC_REFTOTAL _Py_RefTotal-- +# endif +# else +# define _Py_DEC_REFTOTAL +# endif +#endif +// Define these flags like Cython does if we're on an old version. +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif + +#ifndef Py_TPFLAGS_HAVE_VERSION_TAG + #define Py_TPFLAGS_HAVE_VERSION_TAG 0 +#endif + +#define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC + + +#if PY_VERSION_HEX < 0x03090000 +// The official version only became available in 3.9 +# define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o) +#endif + + +// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_EnterTracing(PyThreadState *tstate) +{ + tstate->tracing++; +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = 0; +#else + tstate->use_tracing = 0; +#endif +} +#endif + +// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2 +#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) +static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) +{ + tstate->tracing--; + int use_tracing = (tstate->c_tracefunc != NULL + || tstate->c_profilefunc != NULL); +#if PY_VERSION_HEX >= 0x030A00A1 + tstate->cframe->use_tracing = use_tracing; +#else + tstate->use_tracing = use_tracing; +#endif +} +#endif + +#endif /* GREENLET_CPYTHON_COMPAT_H */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_exceptions.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_exceptions.hpp new file mode 100644 index 0000000..3807018 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_exceptions.hpp @@ -0,0 +1,150 @@ +#ifndef GREENLET_EXCEPTIONS_HPP +#define GREENLET_EXCEPTIONS_HPP + +#define PY_SSIZE_T_CLEAN +#include +#include +#include + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +#endif + +namespace greenlet { + + class PyErrOccurred : public std::runtime_error + { + public: + + // CAUTION: In debug builds, may run arbitrary Python code. + static const PyErrOccurred + from_current() + { + assert(PyErr_Occurred()); +#ifndef NDEBUG + // This is not exception safe, and + // not necessarily safe in general (what if it switches?) + // But we only do this in debug mode, where we are in + // tight control of what exceptions are getting raised and + // can prevent those issues. + + // You can't call PyObject_Str with a pending exception. + PyObject* typ; + PyObject* val; + PyObject* tb; + + PyErr_Fetch(&typ, &val, &tb); + PyObject* typs = PyObject_Str(typ); + PyObject* vals = PyObject_Str(val ? val : typ); + const char* typ_msg = PyUnicode_AsUTF8(typs); + const char* val_msg = PyUnicode_AsUTF8(vals); + PyErr_Restore(typ, val, tb); + + std::string msg(typ_msg); + msg += ": "; + msg += val_msg; + PyErrOccurred ex(msg); + Py_XDECREF(typs); + Py_XDECREF(vals); + + return ex; +#else + return PyErrOccurred(); +#endif + } + + PyErrOccurred() : std::runtime_error("") + { + assert(PyErr_Occurred()); + } + + PyErrOccurred(const std::string& msg) : std::runtime_error(msg) + { + assert(PyErr_Occurred()); + } + + PyErrOccurred(PyObject* exc_kind, const char* const msg) + : std::runtime_error(msg) + { + PyErr_SetString(exc_kind, msg); + } + + PyErrOccurred(PyObject* exc_kind, const std::string msg) + : std::runtime_error(msg) + { + // This copies the c_str, so we don't have any lifetime + // issues to worry about. + PyErr_SetString(exc_kind, msg.c_str()); + } + }; + + class TypeError : public PyErrOccurred + { + public: + TypeError(const char* const what) + : PyErrOccurred(PyExc_TypeError, what) + { + } + TypeError(const std::string what) + : PyErrOccurred(PyExc_TypeError, what) + { + } + }; + + class ValueError : public PyErrOccurred + { + public: + ValueError(const char* const what) + : PyErrOccurred(PyExc_ValueError, what) + { + } + }; + + class AttributeError : public PyErrOccurred + { + public: + AttributeError(const char* const what) + : PyErrOccurred(PyExc_AttributeError, what) + { + } + }; + + /** + * Calls `Py_FatalError` when constructed, so you can't actually + * throw this. It just makes static analysis easier. + */ + class PyFatalError : public std::runtime_error + { + public: + PyFatalError(const char* const msg) + : std::runtime_error(msg) + { + Py_FatalError(msg); + } + }; + + static inline PyObject* + Require(PyObject* p, const std::string& msg="") + { + if (!p) { + throw PyErrOccurred(msg); + } + return p; + }; + + static inline void + Require(const int retval) + { + if (retval < 0) { + throw PyErrOccurred(); + } + }; + + +}; +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp new file mode 100644 index 0000000..d52ce1f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_greenlet.hpp @@ -0,0 +1,805 @@ +#ifndef GREENLET_GREENLET_HPP +#define GREENLET_GREENLET_HPP +/* + * Declarations of the core data structures. +*/ + +#define PY_SSIZE_T_CLEAN +#include + +#include "greenlet_compiler_compat.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_allocator.hpp" + +using greenlet::refs::OwnedObject; +using greenlet::refs::OwnedGreenlet; +using greenlet::refs::OwnedMainGreenlet; +using greenlet::refs::BorrowedGreenlet; + +#if PY_VERSION_HEX < 0x30B00A6 +# define _PyCFrame CFrame +# define _PyInterpreterFrame _interpreter_frame +#endif + +#if GREENLET_PY312 +# include "internal/pycore_frame.h" +#endif + +// XXX: TODO: Work to remove all virtual functions +// for speed of calling and size of objects (no vtable). +// One pattern is the Curiously Recurring Template +namespace greenlet +{ + class ExceptionState + { + private: + G_NO_COPIES_OF_CLS(ExceptionState); + + // Even though these are borrowed objects, we actually own + // them, when they're not null. + // XXX: Express that in the API. + private: + _PyErr_StackItem* exc_info; + _PyErr_StackItem exc_state; + public: + ExceptionState(); + void operator<<(const PyThreadState *const tstate) noexcept; + void operator>>(PyThreadState* tstate) noexcept; + void clear() noexcept; + + int tp_traverse(visitproc visit, void* arg) noexcept; + void tp_clear() noexcept; + }; + + template + void operator<<(const PyThreadState *const tstate, T& exc); + + class PythonStateContext + { + protected: + greenlet::refs::OwnedContext _context; + public: + inline const greenlet::refs::OwnedContext& context() const + { + return this->_context; + } + inline greenlet::refs::OwnedContext& context() + { + return this->_context; + } + + inline void tp_clear() + { + this->_context.CLEAR(); + } + + template + inline static PyObject* context(T* tstate) + { + return tstate->context; + } + + template + inline static void context(T* tstate, PyObject* new_context) + { + tstate->context = new_context; + tstate->context_ver++; + } + }; + class SwitchingArgs; + class PythonState : public PythonStateContext + { + public: + typedef greenlet::refs::OwnedReference OwnedFrame; + private: + G_NO_COPIES_OF_CLS(PythonState); + // We own this if we're suspended (although currently we don't + // tp_traverse into it; that's a TODO). If we're running, it's + // empty. If we get deallocated and *still* have a frame, it + // won't be reachable from the place that normally decref's + // it, so we need to do it (hence owning it). + OwnedFrame _top_frame; +#if GREENLET_USE_CFRAME + _PyCFrame* cframe; + int use_tracing; +#endif +#if GREENLET_PY312 + int py_recursion_depth; + int c_recursion_depth; +#else + int recursion_depth; +#endif + int trash_delete_nesting; +#if GREENLET_PY311 + _PyInterpreterFrame* current_frame; + _PyStackChunk* datastack_chunk; + PyObject** datastack_top; + PyObject** datastack_limit; +#endif + // The PyInterpreterFrame list on 3.12+ contains some entries that are + // on the C stack, which can't be directly accessed while a greenlet is + // suspended. In order to keep greenlet gr_frame introspection working, + // we adjust stack switching to rewrite the interpreter frame list + // to skip these C-stack frames; we call this "exposing" the greenlet's + // frames because it makes them valid to work with in Python. Then when + // the greenlet is resumed we need to remember to reverse the operation + // we did. The C-stack frames are "entry frames" which are a low-level + // interpreter detail; they're not needed for introspection, but do + // need to be present for the eval loop to work. + void unexpose_frames(); + + public: + + PythonState(); + // You can use this for testing whether we have a frame + // or not. It returns const so they can't modify it. + const OwnedFrame& top_frame() const noexcept; + + inline void operator<<(const PyThreadState *const tstate) noexcept; + inline void operator>>(PyThreadState* tstate) noexcept; + void clear() noexcept; + + int tp_traverse(visitproc visit, void* arg, bool visit_top_frame) noexcept; + void tp_clear(bool own_top_frame) noexcept; + void set_initial_state(const PyThreadState* const tstate) noexcept; +#if GREENLET_USE_CFRAME + void set_new_cframe(_PyCFrame& frame) noexcept; +#endif + + inline void may_switch_away() noexcept; + inline void will_switch_from(PyThreadState *const origin_tstate) noexcept; + void did_finish(PyThreadState* tstate) noexcept; + }; + + class StackState + { + // By having only plain C (POD) members, no virtual functions + // or bases, we get a trivial assignment operator generated + // for us. However, that's not safe since we do manage memory. + // So we declare an assignment operator that only works if we + // don't have any memory allocated. (We don't use + // std::shared_ptr for reference counting just to keep this + // object small) + private: + char* _stack_start; + char* stack_stop; + char* stack_copy; + intptr_t _stack_saved; + StackState* stack_prev; + inline int copy_stack_to_heap_up_to(const char* const stop) noexcept; + inline void free_stack_copy() noexcept; + + public: + /** + * Creates a started, but inactive, state, using *current* + * as the previous. + */ + StackState(void* mark, StackState& current); + /** + * Creates an inactive, unstarted, state. + */ + StackState(); + ~StackState(); + StackState(const StackState& other); + StackState& operator=(const StackState& other); + inline void copy_heap_to_stack(const StackState& current) noexcept; + inline int copy_stack_to_heap(char* const stackref, const StackState& current) noexcept; + inline bool started() const noexcept; + inline bool main() const noexcept; + inline bool active() const noexcept; + inline void set_active() noexcept; + inline void set_inactive() noexcept; + inline intptr_t stack_saved() const noexcept; + inline char* stack_start() const noexcept; + static inline StackState make_main() noexcept; +#ifdef GREENLET_USE_STDIO + friend std::ostream& operator<<(std::ostream& os, const StackState& s); +#endif + + // Fill in [dest, dest + n) with the values that would be at + // [src, src + n) while this greenlet is running. This is like memcpy + // except that if the greenlet is suspended it accounts for the portion + // of the greenlet's stack that was spilled to the heap. `src` may + // be on this greenlet's stack, or on the heap, but not on a different + // greenlet's stack. + void copy_from_stack(void* dest, const void* src, size_t n) const; + }; +#ifdef GREENLET_USE_STDIO + std::ostream& operator<<(std::ostream& os, const StackState& s); +#endif + + class SwitchingArgs + { + private: + G_NO_ASSIGNMENT_OF_CLS(SwitchingArgs); + // If args and kwargs are both false (NULL), this is a *throw*, not a + // switch. PyErr_... must have been called already. + OwnedObject _args; + OwnedObject _kwargs; + public: + + SwitchingArgs() + {} + + SwitchingArgs(const OwnedObject& args, const OwnedObject& kwargs) + : _args(args), + _kwargs(kwargs) + {} + + SwitchingArgs(const SwitchingArgs& other) + : _args(other._args), + _kwargs(other._kwargs) + {} + + const OwnedObject& args() + { + return this->_args; + } + + const OwnedObject& kwargs() + { + return this->_kwargs; + } + + /** + * Moves ownership from the argument to this object. + */ + SwitchingArgs& operator<<=(SwitchingArgs& other) + { + if (this != &other) { + this->_args = other._args; + this->_kwargs = other._kwargs; + other.CLEAR(); + } + return *this; + } + + /** + * Acquires ownership of the argument (consumes the reference). + */ + SwitchingArgs& operator<<=(PyObject* args) + { + this->_args = OwnedObject::consuming(args); + this->_kwargs.CLEAR(); + return *this; + } + + /** + * Acquires ownership of the argument. + * + * Sets the args to be the given value; clears the kwargs. + */ + SwitchingArgs& operator<<=(OwnedObject& args) + { + assert(&args != &this->_args); + this->_args = args; + this->_kwargs.CLEAR(); + args.CLEAR(); + + return *this; + } + + explicit operator bool() const noexcept + { + return this->_args || this->_kwargs; + } + + inline void CLEAR() + { + this->_args.CLEAR(); + this->_kwargs.CLEAR(); + } + + const std::string as_str() const noexcept + { + return PyUnicode_AsUTF8( + OwnedObject::consuming( + PyUnicode_FromFormat( + "SwitchingArgs(args=%R, kwargs=%R)", + this->_args.borrow(), + this->_kwargs.borrow() + ) + ).borrow() + ); + } + }; + + class ThreadState; + + class UserGreenlet; + class MainGreenlet; + + class Greenlet + { + private: + G_NO_COPIES_OF_CLS(Greenlet); + private: + // XXX: Work to remove these. + friend class ThreadState; + friend class UserGreenlet; + friend class MainGreenlet; + protected: + ExceptionState exception_state; + SwitchingArgs switch_args; + StackState stack_state; + PythonState python_state; + Greenlet(PyGreenlet* p, const StackState& initial_state); + public: + Greenlet(PyGreenlet* p); + virtual ~Greenlet(); + + const OwnedObject context() const; + + // You MUST call this _very_ early in the switching process to + // prepare anything that may need prepared. This might perform + // garbage collections or otherwise run arbitrary Python code. + // + // One specific use of it is for Python 3.11+, preventing + // running arbitrary code at unsafe times. See + // PythonState::may_switch_away(). + inline void may_switch_away() + { + this->python_state.may_switch_away(); + } + + inline void context(refs::BorrowedObject new_context); + + inline SwitchingArgs& args() + { + return this->switch_args; + } + + virtual const refs::BorrowedMainGreenlet main_greenlet() const = 0; + + inline intptr_t stack_saved() const noexcept + { + return this->stack_state.stack_saved(); + } + + // This is used by the macro SLP_SAVE_STATE to compute the + // difference in stack sizes. It might be nice to handle the + // computation ourself, but the type of the result + // varies by platform, so doing it in the macro is the + // simplest way. + inline const char* stack_start() const noexcept + { + return this->stack_state.stack_start(); + } + + virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); + virtual OwnedObject g_switch() = 0; + /** + * Force the greenlet to appear dead. Used when it's not + * possible to throw an exception into a greenlet anymore. + * + * This losses access to the thread state and the main greenlet. + */ + virtual void murder_in_place(); + + /** + * Called when somebody notices we were running in a dead + * thread to allow cleaning up resources (because we can't + * raise GreenletExit into it anymore). + * This is very similar to ``murder_in_place()``, except that + * it DOES NOT lose the main greenlet or thread state. + */ + inline void deactivate_and_free(); + + + // Called when some thread wants to deallocate a greenlet + // object. + // The thread may or may not be the same thread the greenlet + // was running in. + // The thread state will be null if the thread the greenlet + // was running in was known to have exited. + void deallocing_greenlet_in_thread(const ThreadState* current_state); + + // Must be called on 3.12+ before exposing a suspended greenlet's + // frames to user code. This rewrites the linked list of interpreter + // frames to skip the ones that are being stored on the C stack (which + // can't be safely accessed while the greenlet is suspended because + // that stack space might be hosting a different greenlet), and + // sets PythonState::frames_were_exposed so we remember to restore + // the original list before resuming the greenlet. The C-stack frames + // are a low-level interpreter implementation detail; while they're + // important to the bytecode eval loop, they're superfluous for + // introspection purposes. + void expose_frames(); + + + // TODO: Figure out how to make these non-public. + inline void slp_restore_state() noexcept; + inline int slp_save_state(char *const stackref) noexcept; + + inline bool is_currently_running_in_some_thread() const; + virtual bool belongs_to_thread(const ThreadState* state) const; + + inline bool started() const + { + return this->stack_state.started(); + } + inline bool active() const + { + return this->stack_state.active(); + } + inline bool main() const + { + return this->stack_state.main(); + } + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const = 0; + + virtual const OwnedGreenlet parent() const = 0; + virtual void parent(const refs::BorrowedObject new_parent) = 0; + + inline const PythonState::OwnedFrame& top_frame() + { + return this->python_state.top_frame(); + } + + virtual const OwnedObject& run() const = 0; + virtual void run(const refs::BorrowedObject nrun) = 0; + + + virtual int tp_traverse(visitproc visit, void* arg); + virtual int tp_clear(); + + + // Return the thread state that the greenlet is running in, or + // null if the greenlet is not running or the thread is known + // to have exited. + virtual ThreadState* thread_state() const noexcept = 0; + + // Return true if the greenlet is known to have been running + // (active) in a thread that has now exited. + virtual bool was_running_in_dead_thread() const noexcept = 0; + + // Return a borrowed greenlet that is the Python object + // this object represents. + virtual BorrowedGreenlet self() const noexcept = 0; + + // For testing. If this returns true, we should pretend that + // slp_switch() failed. + virtual bool force_slp_switch_error() const noexcept; + + protected: + inline void release_args(); + + // The functions that must not be inlined are declared virtual. + // We also mark them as protected, not private, so that the + // compiler is forced to call them through a function pointer. + // (A sufficiently smart compiler could directly call a private + // virtual function since it can never be overridden in a + // subclass). + + // Also TODO: Switch away from integer error codes and to enums, + // or throw exceptions when possible. + struct switchstack_result_t + { + int status; + Greenlet* the_new_current_greenlet; + OwnedGreenlet origin_greenlet; + + switchstack_result_t() + : status(0), + the_new_current_greenlet(nullptr) + {} + + switchstack_result_t(int err) + : status(err), + the_new_current_greenlet(nullptr) + {} + + switchstack_result_t(int err, Greenlet* state, OwnedGreenlet& origin) + : status(err), + the_new_current_greenlet(state), + origin_greenlet(origin) + { + } + + switchstack_result_t(int err, Greenlet* state, const BorrowedGreenlet& origin) + : status(err), + the_new_current_greenlet(state), + origin_greenlet(origin) + { + } + + switchstack_result_t(const switchstack_result_t& other) + : status(other.status), + the_new_current_greenlet(other.the_new_current_greenlet), + origin_greenlet(other.origin_greenlet) + {} + + switchstack_result_t& operator=(const switchstack_result_t& other) + { + this->status = other.status; + this->the_new_current_greenlet = other.the_new_current_greenlet; + this->origin_greenlet = other.origin_greenlet; + return *this; + } + }; + + OwnedObject on_switchstack_or_initialstub_failure( + Greenlet* target, + const switchstack_result_t& err, + const bool target_was_me=false, + const bool was_initial_stub=false); + + // Returns the previous greenlet we just switched away from. + virtual OwnedGreenlet g_switchstack_success() noexcept; + + + // Check the preconditions for switching to this greenlet; if they + // aren't met, throws PyErrOccurred. Most callers will want to + // catch this and clear the arguments + inline void check_switch_allowed() const; + class GreenletStartedWhileInPython : public std::runtime_error + { + public: + GreenletStartedWhileInPython() : std::runtime_error("") + {} + }; + + protected: + + + /** + Perform a stack switch into this greenlet. + + This temporarily sets the global variable + ``switching_thread_state`` to this greenlet; as soon as the + call to ``slp_switch`` completes, this is reset to NULL. + Consequently, this depends on the GIL. + + TODO: Adopt the stackman model and pass ``slp_switch`` a + callback function and context pointer; this eliminates the + need for global variables altogether. + + Because the stack switch happens in this function, this + function can't use its own stack (local) variables, set + before the switch, and then accessed after the switch. + + Further, you con't even access ``g_thread_state_global`` + before and after the switch from the global variable. + Because it is thread local some compilers cache it in a + register/on the stack, notably new versions of MSVC; this + breaks with strange crashes sometime later, because writing + to anything in ``g_thread_state_global`` after the switch + is actually writing to random memory. For this reason, we + call a non-inlined function to finish the operation. (XXX: + The ``/GT`` MSVC compiler argument probably fixes that.) + + It is very important that stack switch is 'atomic', i.e. no + calls into other Python code allowed (except very few that + are safe), because global variables are very fragile. (This + should no longer be the case with thread-local variables.) + + */ + // Made virtual to facilitate subclassing UserGreenlet for testing. + virtual switchstack_result_t g_switchstack(void); + +class TracingGuard +{ +private: + PyThreadState* tstate; +public: + TracingGuard() + : tstate(PyThreadState_GET()) + { + PyThreadState_EnterTracing(this->tstate); + } + + ~TracingGuard() + { + PyThreadState_LeaveTracing(this->tstate); + this->tstate = nullptr; + } + + inline void CallTraceFunction(const OwnedObject& tracefunc, + const greenlet::refs::ImmortalEventName& event, + const BorrowedGreenlet& origin, + const BorrowedGreenlet& target) + { + // TODO: This calls tracefunc(event, (origin, target)). Add a shortcut + // function for that that's specialized to avoid the Py_BuildValue + // string parsing, or start with just using "ON" format with PyTuple_Pack(2, + // origin, target). That seems like what the N format is meant + // for. + // XXX: Why does event not automatically cast back to a PyObject? + // It tries to call the "deleted constructor ImmortalEventName + // const" instead. + assert(tracefunc); + assert(event); + assert(origin); + assert(target); + greenlet::refs::NewReference retval( + PyObject_CallFunction( + tracefunc.borrow(), + "O(OO)", + event.borrow(), + origin.borrow(), + target.borrow() + )); + if (!retval) { + throw PyErrOccurred::from_current(); + } + } +}; + + static void + g_calltrace(const OwnedObject& tracefunc, + const greenlet::refs::ImmortalEventName& event, + const greenlet::refs::BorrowedGreenlet& origin, + const BorrowedGreenlet& target); + private: + OwnedObject g_switch_finish(const switchstack_result_t& err); + + }; + + class UserGreenlet : public Greenlet + { + private: + static greenlet::PythonAllocator allocator; + BorrowedGreenlet _self; + OwnedMainGreenlet _main_greenlet; + OwnedObject _run_callable; + OwnedGreenlet _parent; + public: + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + + UserGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent); + virtual ~UserGreenlet(); + + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; + virtual bool was_running_in_dead_thread() const noexcept; + virtual ThreadState* thread_state() const noexcept; + virtual OwnedObject g_switch(); + virtual const OwnedObject& run() const + { + if (this->started() || !this->_run_callable) { + throw AttributeError("run"); + } + return this->_run_callable; + } + virtual void run(const refs::BorrowedObject nrun); + + virtual const OwnedGreenlet parent() const; + virtual void parent(const refs::BorrowedObject new_parent); + + virtual const refs::BorrowedMainGreenlet main_greenlet() const; + + virtual BorrowedGreenlet self() const noexcept; + virtual void murder_in_place(); + virtual bool belongs_to_thread(const ThreadState* state) const; + virtual int tp_traverse(visitproc visit, void* arg); + virtual int tp_clear(); + class ParentIsCurrentGuard + { + private: + OwnedGreenlet oldparent; + UserGreenlet* greenlet; + G_NO_COPIES_OF_CLS(ParentIsCurrentGuard); + public: + ParentIsCurrentGuard(UserGreenlet* p, const ThreadState& thread_state); + ~ParentIsCurrentGuard(); + }; + virtual OwnedObject throw_GreenletExit_during_dealloc(const ThreadState& current_thread_state); + protected: + virtual switchstack_result_t g_initialstub(void* mark); + private: + // This function isn't meant to return. + // This accepts raw pointers and the ownership of them at the + // same time. The caller should use ``inner_bootstrap(origin.relinquish_ownership())``. + void inner_bootstrap(PyGreenlet* origin_greenlet, PyObject* run); + }; + + class BrokenGreenlet : public UserGreenlet + { + private: + static greenlet::PythonAllocator allocator; + public: + bool _force_switch_error = false; + bool _force_slp_switch_error = false; + + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + BrokenGreenlet(PyGreenlet* p, BorrowedGreenlet the_parent) + : UserGreenlet(p, the_parent) + {} + virtual ~BrokenGreenlet() + {} + + virtual switchstack_result_t g_switchstack(void); + virtual bool force_slp_switch_error() const noexcept; + + }; + + class MainGreenlet : public Greenlet + { + private: + static greenlet::PythonAllocator allocator; + refs::BorrowedMainGreenlet _self; + ThreadState* _thread_state; + G_NO_COPIES_OF_CLS(MainGreenlet); + public: + static void* operator new(size_t UNUSED(count)); + static void operator delete(void* ptr); + + MainGreenlet(refs::BorrowedMainGreenlet::PyType*, ThreadState*); + virtual ~MainGreenlet(); + + + virtual const OwnedObject& run() const; + virtual void run(const refs::BorrowedObject nrun); + + virtual const OwnedGreenlet parent() const; + virtual void parent(const refs::BorrowedObject new_parent); + + virtual const refs::BorrowedMainGreenlet main_greenlet() const; + + virtual refs::BorrowedMainGreenlet find_main_greenlet_in_lineage() const; + virtual bool was_running_in_dead_thread() const noexcept; + virtual ThreadState* thread_state() const noexcept; + void thread_state(ThreadState*) noexcept; + virtual OwnedObject g_switch(); + virtual BorrowedGreenlet self() const noexcept; + virtual int tp_traverse(visitproc visit, void* arg); + }; + + // Instantiate one on the stack to save the GC state, + // and then disable GC. When it goes out of scope, GC will be + // restored to its original state. Sadly, these APIs are only + // available on 3.10+; luckily, we only need them on 3.11+. +#if GREENLET_PY310 + class GCDisabledGuard + { + private: + int was_enabled = 0; + public: + GCDisabledGuard() + : was_enabled(PyGC_IsEnabled()) + { + PyGC_Disable(); + } + + ~GCDisabledGuard() + { + if (this->was_enabled) { + PyGC_Enable(); + } + } + }; +#endif + + OwnedObject& operator<<=(OwnedObject& lhs, greenlet::SwitchingArgs& rhs) noexcept; + + //TODO: Greenlet::g_switch() should call this automatically on its + //return value. As it is, the module code is calling it. + static inline OwnedObject + single_result(const OwnedObject& results) + { + if (results + && PyTuple_Check(results.borrow()) + && PyTuple_GET_SIZE(results.borrow()) == 1) { + PyObject* result = PyTuple_GET_ITEM(results.borrow(), 0); + assert(result); + return OwnedObject::owning(result); + } + return results; + } + + + static OwnedObject + g_handle_exit(const OwnedObject& greenlet_result); + + + template + void operator<<(const PyThreadState *const lhs, T& rhs) + { + rhs.operator<<(lhs); + } + +} // namespace greenlet ; + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_internal.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_internal.hpp new file mode 100644 index 0000000..c8e3849 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_internal.hpp @@ -0,0 +1,106 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */ +#ifndef GREENLET_INTERNAL_H +#define GREENLET_INTERNAL_H +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wmissing-field-initializers" +# pragma clang diagnostic ignored "-Wunused-variable" +#endif + +/** + * Implementation helpers. + * + * C++ templates and inline functions should go here. + */ +#define PY_SSIZE_T_CLEAN +#include "greenlet_compiler_compat.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_exceptions.hpp" +#include "greenlet_greenlet.hpp" +#include "greenlet_allocator.hpp" + +#include +#include + +#define GREENLET_MODULE +struct _greenlet; +typedef struct _greenlet PyGreenlet; +namespace greenlet { + + class ThreadState; + +}; + + +#define implementation_ptr_t greenlet::Greenlet* + + +#include "greenlet.h" + +G_FP_TMPL_STATIC inline void +greenlet::refs::MainGreenletExactChecker(void *p) +{ + if (!p) { + return; + } + // We control the class of the main greenlet exactly. + if (Py_TYPE(p) != &PyGreenlet_Type) { + std::string err("MainGreenlet: Expected exactly a greenlet, not a "); + err += Py_TYPE(p)->tp_name; + throw greenlet::TypeError(err); + } + + // Greenlets from dead threads no longer respond to main() with a + // true value; so in that case we need to perform an additional + // check. + Greenlet* g = ((PyGreenlet*)p)->pimpl; + if (g->main()) { + return; + } + if (!dynamic_cast(g)) { + std::string err("MainGreenlet: Expected exactly a main greenlet, not a "); + err += Py_TYPE(p)->tp_name; + throw greenlet::TypeError(err); + } +} + + + +template +inline greenlet::Greenlet* greenlet::refs::_OwnedGreenlet::operator->() const noexcept +{ + return reinterpret_cast(this->p)->pimpl; +} + +template +inline greenlet::Greenlet* greenlet::refs::_BorrowedGreenlet::operator->() const noexcept +{ + return reinterpret_cast(this->p)->pimpl; +} + +#include +#include + + +extern PyTypeObject PyGreenlet_Type; + + + +/** + * Forward declarations needed in multiple files. + */ +static PyGreenlet* green_create_main(greenlet::ThreadState*); +static PyObject* green_switch(PyGreenlet* self, PyObject* args, PyObject* kwargs); +static int green_is_gc(BorrowedGreenlet self); + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + + +#endif + +// Local Variables: +// flycheck-clang-include-path: ("../../include" "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/include/python3.10") +// End: diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp new file mode 100644 index 0000000..72ee68b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_refs.hpp @@ -0,0 +1,1100 @@ +#ifndef GREENLET_REFS_HPP +#define GREENLET_REFS_HPP + +#define PY_SSIZE_T_CLEAN +#include +//#include "greenlet_internal.hpp" +#include "greenlet_compiler_compat.hpp" +#include "greenlet_cpython_compat.hpp" +#include "greenlet_exceptions.hpp" + +struct _greenlet; +struct _PyMainGreenlet; + +typedef struct _greenlet PyGreenlet; +extern PyTypeObject PyGreenlet_Type; + + +#ifdef GREENLET_USE_STDIO +#include +using std::cerr; +using std::endl; +#endif + +namespace greenlet +{ + class Greenlet; + + namespace refs + { + // Type checkers throw a TypeError if the argument is not + // null, and isn't of the required Python type. + // (We can't use most of the defined type checkers + // like PyList_Check, etc, directly, because they are + // implemented as macros.) + typedef void (*TypeChecker)(void*); + + G_FP_TMPL_STATIC inline void + NoOpChecker(void*) + { + return; + } + + G_FP_TMPL_STATIC inline void + GreenletChecker(void *p) + { + if (!p) { + return; + } + + PyTypeObject* typ = Py_TYPE(p); + // fast, common path. (PyObject_TypeCheck is a macro or + // static inline function, and it also does a + // direct comparison of the type pointers, but its fast + // path only handles one type) + if (typ == &PyGreenlet_Type) { + return; + } + + if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) { + std::string err("GreenletChecker: Expected any type of greenlet, not "); + err += Py_TYPE(p)->tp_name; + throw TypeError(err); + } + } + + G_FP_TMPL_STATIC inline void + MainGreenletExactChecker(void *p); + + template + class PyObjectPointer; + + template + class OwnedReference; + + + template + class BorrowedReference; + + typedef BorrowedReference BorrowedObject; + typedef OwnedReference OwnedObject; + + class ImmortalObject; + class ImmortalString; + + template + class _OwnedGreenlet; + + typedef _OwnedGreenlet OwnedGreenlet; + typedef _OwnedGreenlet OwnedMainGreenlet; + + template + class _BorrowedGreenlet; + + typedef _BorrowedGreenlet BorrowedGreenlet; + + G_FP_TMPL_STATIC inline void + ContextExactChecker(void *p) + { + if (!p) { + return; + } + if (!PyContext_CheckExact(p)) { + throw TypeError( + "greenlet context must be a contextvars.Context or None" + ); + } + } + + typedef OwnedReference OwnedContext; + } +} + +namespace greenlet { + + + namespace refs { + // A set of classes to make reference counting rules in python + // code explicit. + // + // Rules of use: + // (1) Functions returning a new reference that the caller of the + // function is expected to dispose of should return a + // ``OwnedObject`` object. This object automatically releases its + // reference when it goes out of scope. It works like a ``std::shared_ptr`` + // and can be copied or used as a function parameter (but don't do + // that). Note that constructing a ``OwnedObject`` from a + // PyObject* steals the reference. + // (2) Parameters to functions should be either a + // ``OwnedObject&``, or, more generally, a ``PyObjectPointer&``. + // If the function needs to create its own new reference, it can + // do so by copying to a local ``OwnedObject``. + // (3) Functions returning an existing pointer that is NOT + // incref'd, and which the caller MUST NOT decref, + // should return a ``BorrowedObject``. + + // + // For a class with a single pointer member, whose constructor + // does nothing but copy a pointer parameter into the member, and + // which can then be converted back to the pointer type, compilers + // generate code that's the same as just passing the pointer. + // That is, func(BorrowedObject x) called like ``PyObject* p = + // ...; f(p)`` has 0 overhead. Similarly, they "unpack" to the + // pointer type with 0 overhead. + // + // If there are no virtual functions, no complex inheritance (maybe?) and + // no destructor, these can be directly used as parameters in + // Python callbacks like tp_init: the layout is the same as a + // single pointer. Only subclasses with trivial constructors that + // do nothing but set the single pointer member are safe to use + // that way. + + + // This is the base class for things that can be done with a + // PyObject pointer. It assumes nothing about memory management. + // NOTE: Nothing is virtual, so subclasses shouldn't add new + // storage fields or try to override these methods. + template + class PyObjectPointer + { + public: + typedef T PyType; + protected: + T* p; + public: + explicit PyObjectPointer(T* it=nullptr) : p(it) + { + TC(p); + } + + // We don't allow automatic casting to PyObject* at this + // level, because then we could be passed to Py_DECREF/INCREF, + // but we want nothing to do with memory management. If you + // know better, then you can use the get() method, like on a + // std::shared_ptr. Except we name it borrow() to clarify that + // if this is a reference-tracked object, the pointer you get + // back will go away when the object does. + // TODO: This should probably not exist here, but be moved + // down to relevant sub-types. + + inline T* borrow() const noexcept + { + return this->p; + } + + PyObject* borrow_o() const noexcept + { + return reinterpret_cast(this->p); + } + + inline T* operator->() const noexcept + { + return this->p; + } + + bool is_None() const noexcept + { + return this->p == Py_None; + } + + inline PyObject* acquire_or_None() const noexcept + { + PyObject* result = this->p ? reinterpret_cast(this->p) : Py_None; + Py_INCREF(result); + return result; + } + + explicit operator bool() const noexcept + { + return p != nullptr; + } + + inline Py_ssize_t REFCNT() const noexcept + { + return p ? Py_REFCNT(p) : -42; + } + + inline PyTypeObject* TYPE() const noexcept + { + return p ? Py_TYPE(p) : nullptr; + } + + inline OwnedObject PyStr() const noexcept; + inline const std::string as_str() const noexcept; + inline OwnedObject PyGetAttr(const ImmortalObject& name) const noexcept; + inline OwnedObject PyRequireAttr(const char* const name) const; + inline OwnedObject PyRequireAttr(const ImmortalString& name) const; + inline OwnedObject PyCall(const BorrowedObject& arg) const; + inline OwnedObject PyCall(PyGreenlet* arg) const ; + inline OwnedObject PyCall(PyObject* arg) const ; + // PyObject_Call(this, args, kwargs); + inline OwnedObject PyCall(const BorrowedObject args, + const BorrowedObject kwargs) const; + inline OwnedObject PyCall(const OwnedObject& args, + const OwnedObject& kwargs) const; + + protected: + void _set_raw_pointer(void* t) + { + TC(t); + p = reinterpret_cast(t); + } + void* _get_raw_pointer() const + { + return p; + } + }; + +#ifdef GREENLET_USE_STDIO + template + std::ostream& operator<<(std::ostream& os, const PyObjectPointer& s) + { + const std::type_info& t = typeid(s); + os << t.name() + << "(addr=" << s.borrow() + << ", refcnt=" << s.REFCNT() + << ", value=" << s.as_str() + << ")"; + + return os; + } +#endif + + template + inline bool operator==(const PyObjectPointer& lhs, const void* const rhs) noexcept + { + return lhs.borrow_o() == rhs; + } + + template + inline bool operator==(const PyObjectPointer& lhs, const PyObjectPointer& rhs) noexcept + { + return lhs.borrow_o() == rhs.borrow_o(); + } + + template + inline bool operator!=(const PyObjectPointer& lhs, + const PyObjectPointer& rhs) noexcept + { + return lhs.borrow_o() != rhs.borrow_o(); + } + + template + class OwnedReference : public PyObjectPointer + { + private: + friend class OwnedList; + + protected: + explicit OwnedReference(T* it) : PyObjectPointer(it) + { + } + + public: + + // Constructors + + static OwnedReference consuming(PyObject* p) + { + return OwnedReference(reinterpret_cast(p)); + } + + static OwnedReference owning(T* p) + { + OwnedReference result(p); + Py_XINCREF(result.p); + return result; + } + + OwnedReference() : PyObjectPointer(nullptr) + {} + + explicit OwnedReference(const PyObjectPointer<>& other) + : PyObjectPointer(nullptr) + { + T* op = other.borrow(); + TC(op); + this->p = other.borrow(); + Py_XINCREF(this->p); + } + + // It would be good to make use of the C++11 distinction + // between move and copy operations, e.g., constructing from a + // pointer should be a move operation. + // In the common case of ``OwnedObject x = Py_SomeFunction()``, + // the call to the copy constructor will be elided completely. + OwnedReference(const OwnedReference& other) + : PyObjectPointer(other.p) + { + Py_XINCREF(this->p); + } + + static OwnedReference None() + { + Py_INCREF(Py_None); + return OwnedReference(Py_None); + } + + // We can assign from exactly our type without any extra checking + OwnedReference& operator=(const OwnedReference& other) + { + Py_XINCREF(other.p); + const T* tmp = this->p; + this->p = other.p; + Py_XDECREF(tmp); + return *this; + } + + OwnedReference& operator=(const BorrowedReference other) + { + return this->operator=(other.borrow()); + } + + OwnedReference& operator=(T* const other) + { + TC(other); + Py_XINCREF(other); + T* tmp = this->p; + this->p = other; + Py_XDECREF(tmp); + return *this; + } + + // We can assign from an arbitrary reference type + // if it passes our check. + template + OwnedReference& operator=(const OwnedReference& other) + { + X* op = other.borrow(); + TC(op); + return this->operator=(reinterpret_cast(op)); + } + + inline void steal(T* other) + { + assert(this->p == nullptr); + TC(other); + this->p = other; + } + + T* relinquish_ownership() + { + T* result = this->p; + this->p = nullptr; + return result; + } + + T* acquire() const + { + // Return a new reference. + // TODO: This may go away when we have reference objects + // throughout the code. + Py_XINCREF(this->p); + return this->p; + } + + // Nothing else declares a destructor, we're the leaf, so we + // should be able to get away without virtual. + ~OwnedReference() + { + Py_CLEAR(this->p); + } + + void CLEAR() + { + Py_CLEAR(this->p); + assert(this->p == nullptr); + } + }; + + static inline + void operator<<=(PyObject*& target, OwnedObject& o) + { + target = o.relinquish_ownership(); + } + + class NewReference : public OwnedObject + { + private: + G_NO_COPIES_OF_CLS(NewReference); + public: + // Consumes the reference. Only use this + // for API return values. + NewReference(PyObject* it) : OwnedObject(it) + { + } + }; + + class NewDictReference : public NewReference + { + private: + G_NO_COPIES_OF_CLS(NewDictReference); + public: + NewDictReference() : NewReference(PyDict_New()) + { + if (!this->p) { + throw PyErrOccurred(); + } + } + + void SetItem(const char* const key, PyObject* value) + { + Require(PyDict_SetItemString(this->p, key, value)); + } + + void SetItem(const PyObjectPointer<>& key, PyObject* value) + { + Require(PyDict_SetItem(this->p, key.borrow_o(), value)); + } + }; + + template + class _OwnedGreenlet: public OwnedReference + { + private: + protected: + _OwnedGreenlet(T* it) : OwnedReference(it) + {} + + public: + _OwnedGreenlet() : OwnedReference() + {} + + _OwnedGreenlet(const _OwnedGreenlet& other) : OwnedReference(other) + { + } + _OwnedGreenlet(OwnedMainGreenlet& other) : + OwnedReference(reinterpret_cast(other.acquire())) + { + } + _OwnedGreenlet(const BorrowedGreenlet& other); + // Steals a reference. + static _OwnedGreenlet consuming(PyGreenlet* it) + { + return _OwnedGreenlet(reinterpret_cast(it)); + } + + inline _OwnedGreenlet& operator=(const OwnedGreenlet& other) + { + return this->operator=(other.borrow()); + } + + inline _OwnedGreenlet& operator=(const BorrowedGreenlet& other); + + _OwnedGreenlet& operator=(const OwnedMainGreenlet& other) + { + PyGreenlet* owned = other.acquire(); + Py_XDECREF(this->p); + this->p = reinterpret_cast(owned); + return *this; + } + + _OwnedGreenlet& operator=(T* const other) + { + OwnedReference::operator=(other); + return *this; + } + + T* relinquish_ownership() + { + T* result = this->p; + this->p = nullptr; + return result; + } + + PyObject* relinquish_ownership_o() + { + return reinterpret_cast(relinquish_ownership()); + } + + inline Greenlet* operator->() const noexcept; + inline operator Greenlet*() const noexcept; + }; + + template + class BorrowedReference : public PyObjectPointer + { + public: + // Allow implicit creation from PyObject* pointers as we + // transition to using these classes. Also allow automatic + // conversion to PyObject* for passing to C API calls and even + // for Py_INCREF/DECREF, because we ourselves do no memory management. + BorrowedReference(T* it) : PyObjectPointer(it) + {} + + BorrowedReference(const PyObjectPointer& ref) : PyObjectPointer(ref.borrow()) + {} + + BorrowedReference() : PyObjectPointer(nullptr) + {} + + operator T*() const + { + return this->p; + } + }; + + typedef BorrowedReference BorrowedObject; + //typedef BorrowedReference BorrowedGreenlet; + + template + class _BorrowedGreenlet : public BorrowedReference + { + public: + _BorrowedGreenlet() : + BorrowedReference(nullptr) + {} + + _BorrowedGreenlet(T* it) : + BorrowedReference(it) + {} + + _BorrowedGreenlet(const BorrowedObject& it); + + _BorrowedGreenlet(const OwnedGreenlet& it) : + BorrowedReference(it.borrow()) + {} + + _BorrowedGreenlet& operator=(const BorrowedObject& other); + + // We get one of these for PyGreenlet, but one for PyObject + // is handy as well + operator PyObject*() const + { + return reinterpret_cast(this->p); + } + inline Greenlet* operator->() const noexcept; + inline operator Greenlet*() const noexcept; + }; + + typedef _BorrowedGreenlet BorrowedGreenlet; + + template + _OwnedGreenlet::_OwnedGreenlet(const BorrowedGreenlet& other) + : OwnedReference(reinterpret_cast(other.borrow())) + { + Py_XINCREF(this->p); + } + + + class BorrowedMainGreenlet + : public _BorrowedGreenlet + { + public: + BorrowedMainGreenlet(const OwnedMainGreenlet& it) : + _BorrowedGreenlet(it.borrow()) + {} + BorrowedMainGreenlet(PyGreenlet* it=nullptr) + : _BorrowedGreenlet(it) + {} + }; + + template + _OwnedGreenlet& _OwnedGreenlet::operator=(const BorrowedGreenlet& other) + { + return this->operator=(other.borrow()); + } + + + class ImmortalObject : public PyObjectPointer<> + { + private: + G_NO_ASSIGNMENT_OF_CLS(ImmortalObject); + public: + explicit ImmortalObject(PyObject* it) : PyObjectPointer<>(it) + { + } + + ImmortalObject(const ImmortalObject& other) + : PyObjectPointer<>(other.p) + { + + } + + /** + * Become the new owner of the object. Does not change the + * reference count. + */ + ImmortalObject& operator=(PyObject* it) + { + assert(this->p == nullptr); + this->p = it; + return *this; + } + + static ImmortalObject consuming(PyObject* it) + { + return ImmortalObject(it); + } + + inline operator PyObject*() const + { + return this->p; + } + }; + + class ImmortalString : public ImmortalObject + { + private: + G_NO_COPIES_OF_CLS(ImmortalString); + const char* str; + public: + ImmortalString(const char* const str) : + ImmortalObject(str ? Require(PyUnicode_InternFromString(str)) : nullptr) + { + this->str = str; + } + + inline ImmortalString& operator=(const char* const str) + { + if (!this->p) { + this->p = Require(PyUnicode_InternFromString(str)); + this->str = str; + } + else { + assert(this->str == str); + } + return *this; + } + + inline operator std::string() const + { + return this->str; + } + + }; + + class ImmortalEventName : public ImmortalString + { + private: + G_NO_COPIES_OF_CLS(ImmortalEventName); + public: + ImmortalEventName(const char* const str) : ImmortalString(str) + {} + }; + + class ImmortalException : public ImmortalObject + { + private: + G_NO_COPIES_OF_CLS(ImmortalException); + public: + ImmortalException(const char* const name, PyObject* base=nullptr) : + ImmortalObject(name + // Python 2.7 isn't const correct + ? Require(PyErr_NewException((char*)name, base, nullptr)) + : nullptr) + {} + + inline bool PyExceptionMatches() const + { + return PyErr_ExceptionMatches(this->p) > 0; + } + + }; + + template + inline OwnedObject PyObjectPointer::PyStr() const noexcept + { + if (!this->p) { + return OwnedObject(); + } + return OwnedObject::consuming(PyObject_Str(reinterpret_cast(this->p))); + } + + template + inline const std::string PyObjectPointer::as_str() const noexcept + { + // NOTE: This is not Python exception safe. + if (this->p) { + // The Python APIs return a cached char* value that's only valid + // as long as the original object stays around, and we're + // about to (probably) toss it. Hence the copy to std::string. + OwnedObject py_str = this->PyStr(); + if (!py_str) { + return "(nil)"; + } + return PyUnicode_AsUTF8(py_str.borrow()); + } + return "(nil)"; + } + + template + inline OwnedObject PyObjectPointer::PyGetAttr(const ImmortalObject& name) const noexcept + { + assert(this->p); + return OwnedObject::consuming(PyObject_GetAttr(reinterpret_cast(this->p), name)); + } + + template + inline OwnedObject PyObjectPointer::PyRequireAttr(const char* const name) const + { + assert(this->p); + return OwnedObject::consuming(Require(PyObject_GetAttrString(this->p, name), name)); + } + + template + inline OwnedObject PyObjectPointer::PyRequireAttr(const ImmortalString& name) const + { + assert(this->p); + return OwnedObject::consuming(Require( + PyObject_GetAttr( + reinterpret_cast(this->p), + name + ), + name + )); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject& arg) const + { + return this->PyCall(arg.borrow()); + } + + template + inline OwnedObject PyObjectPointer::PyCall(PyGreenlet* arg) const + { + return this->PyCall(reinterpret_cast(arg)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(PyObject* arg) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_CallFunctionObjArgs(this->p, arg, NULL)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const BorrowedObject args, + const BorrowedObject kwargs) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_Call(this->p, args, kwargs)); + } + + template + inline OwnedObject PyObjectPointer::PyCall(const OwnedObject& args, + const OwnedObject& kwargs) const + { + assert(this->p); + return OwnedObject::consuming(PyObject_Call(this->p, args.borrow(), kwargs.borrow())); + } + + G_FP_TMPL_STATIC inline void + ListChecker(void * p) + { + if (!p) { + return; + } + if (!PyList_Check(p)) { + throw TypeError("Expected a list"); + } + } + + class OwnedList : public OwnedReference + { + private: + G_NO_ASSIGNMENT_OF_CLS(OwnedList); + public: + // TODO: Would like to use move. + explicit OwnedList(const OwnedObject& other) + : OwnedReference(other) + { + } + + OwnedList& operator=(const OwnedObject& other) + { + if (other && PyList_Check(other.p)) { + // Valid list. Own a new reference to it, discard the + // reference to what we did own. + PyObject* new_ptr = other.p; + Py_INCREF(new_ptr); + Py_XDECREF(this->p); + this->p = new_ptr; + } + else { + // Either the other object was NULL (an error) or it + // wasn't a list. Either way, we're now invalidated. + Py_XDECREF(this->p); + this->p = nullptr; + } + return *this; + } + + inline bool empty() const + { + return PyList_GET_SIZE(p) == 0; + } + + inline Py_ssize_t size() const + { + return PyList_GET_SIZE(p); + } + + inline BorrowedObject at(const Py_ssize_t index) const + { + return PyList_GET_ITEM(p, index); + } + + inline void clear() + { + PyList_SetSlice(p, 0, PyList_GET_SIZE(p), NULL); + } + }; + + // Use this to represent the module object used at module init + // time. + // This could either be a borrowed (Py2) or new (Py3) reference; + // either way, we don't want to do any memory management + // on it here, Python itself will handle that. + // XXX: Actually, that's not quite right. On Python 3, if an + // exception occurs before we return to the interpreter, this will + // leak; but all previous versions also had that problem. + class CreatedModule : public PyObjectPointer<> + { + private: + G_NO_COPIES_OF_CLS(CreatedModule); + public: + CreatedModule(PyModuleDef& mod_def) : PyObjectPointer<>( + Require(PyModule_Create(&mod_def))) + { + } + + // PyAddObject(): Add a reference to the object to the module. + // On return, the reference count of the object is unchanged. + // + // The docs warn that PyModule_AddObject only steals the + // reference on success, so if it fails after we've incref'd + // or allocated, we're responsible for the decref. + void PyAddObject(const char* name, const long new_bool) + { + OwnedObject p = OwnedObject::consuming(Require(PyBool_FromLong(new_bool))); + this->PyAddObject(name, p); + } + + void PyAddObject(const char* name, const OwnedObject& new_object) + { + // The caller already owns a reference they will decref + // when their variable goes out of scope, we still need to + // incref/decref. + this->PyAddObject(name, new_object.borrow()); + } + + void PyAddObject(const char* name, const ImmortalObject& new_object) + { + this->PyAddObject(name, new_object.borrow()); + } + + void PyAddObject(const char* name, PyTypeObject& type) + { + this->PyAddObject(name, reinterpret_cast(&type)); + } + + void PyAddObject(const char* name, PyObject* new_object) + { + Py_INCREF(new_object); + try { + Require(PyModule_AddObject(this->p, name, new_object)); + } + catch (const PyErrOccurred&) { + Py_DECREF(p); + throw; + } + } + }; + + class PyErrFetchParam : public PyObjectPointer<> + { + // Not an owned object, because we can't be initialized with + // one, and we only sometimes acquire ownership. + private: + G_NO_COPIES_OF_CLS(PyErrFetchParam); + public: + // To allow declaring these and passing them to + // PyErr_Fetch we implement the empty constructor, + // and the address operator. + PyErrFetchParam() : PyObjectPointer<>(nullptr) + { + } + + PyObject** operator&() + { + return &this->p; + } + + // This allows us to pass one directly without the &, + // BUT it has higher precedence than the bool operator + // if it's not explicit. + operator PyObject**() + { + return &this->p; + } + + // We don't want to be able to pass these to Py_DECREF and + // such so we don't have the implicit PyObject* conversion. + + inline PyObject* relinquish_ownership() + { + PyObject* result = this->p; + this->p = nullptr; + return result; + } + + ~PyErrFetchParam() + { + Py_XDECREF(p); + } + }; + + class OwnedErrPiece : public OwnedObject + { + private: + + public: + // Unlike OwnedObject, this increments the refcount. + OwnedErrPiece(PyObject* p=nullptr) : OwnedObject(p) + { + this->acquire(); + } + + PyObject** operator&() + { + return &this->p; + } + + inline operator PyObject*() const + { + return this->p; + } + + operator PyTypeObject*() const + { + return reinterpret_cast(this->p); + } + }; + + class PyErrPieces + { + private: + OwnedErrPiece type; + OwnedErrPiece instance; + OwnedErrPiece traceback; + bool restored; + public: + // Takes new references; if we're destroyed before + // restoring the error, we drop the references. + PyErrPieces(PyObject* t, PyObject* v, PyObject* tb) : + type(t), + instance(v), + traceback(tb), + restored(0) + { + this->normalize(); + } + + PyErrPieces() : + restored(0) + { + // PyErr_Fetch transfers ownership to us, so + // we don't actually need to INCREF; but we *do* + // need to DECREF if we're not restored. + PyErrFetchParam t, v, tb; + PyErr_Fetch(&t, &v, &tb); + type.steal(t.relinquish_ownership()); + instance.steal(v.relinquish_ownership()); + traceback.steal(tb.relinquish_ownership()); + } + + void PyErrRestore() + { + // can only do this once + assert(!this->restored); + this->restored = true; + PyErr_Restore( + this->type.relinquish_ownership(), + this->instance.relinquish_ownership(), + this->traceback.relinquish_ownership()); + assert(!this->type && !this->instance && !this->traceback); + } + + private: + void normalize() + { + // First, check the traceback argument, replacing None, + // with NULL + if (traceback.is_None()) { + traceback = nullptr; + } + + if (traceback && !PyTraceBack_Check(traceback.borrow())) { + throw PyErrOccurred(PyExc_TypeError, + "throw() third argument must be a traceback object"); + } + + if (PyExceptionClass_Check(type)) { + // If we just had a type, we'll now have a type and + // instance. + // The type's refcount will have gone up by one + // because of the instance and the instance will have + // a refcount of one. Either way, we owned, and still + // do own, exactly one reference. + PyErr_NormalizeException(&type, &instance, &traceback); + + } + else if (PyExceptionInstance_Check(type)) { + /* Raising an instance --- usually that means an + object that is a subclass of BaseException, but on + Python 2, that can also mean an arbitrary old-style + object. The value should be a dummy. */ + if (instance && !instance.is_None()) { + throw PyErrOccurred( + PyExc_TypeError, + "instance exception may not have a separate value"); + } + /* Normalize to raise , */ + this->instance = this->type; + this->type = PyExceptionInstance_Class(instance.borrow()); + + /* + It would be tempting to do this: + + Py_ssize_t type_count = Py_REFCNT(Py_TYPE(instance.borrow())); + this->type = PyExceptionInstance_Class(instance.borrow()); + assert(this->type.REFCNT() == type_count + 1); + + But that doesn't work on Python 2 in the case of + old-style instances: The result of Py_TYPE is going to + be the global shared that all + old-style classes have, while the return of Instance_Class() + will be the Python-level class object. The two are unrelated. + */ + } + else { + /* Not something you can raise. throw() fails. */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes, or instances, not %s", + Py_TYPE(type.borrow())->tp_name); + throw PyErrOccurred(); + } + } + }; + + // PyArg_Parse's O argument returns a borrowed reference. + class PyArgParseParam : public BorrowedObject + { + private: + G_NO_COPIES_OF_CLS(PyArgParseParam); + public: + explicit PyArgParseParam(PyObject* p=nullptr) : BorrowedObject(p) + { + } + + inline PyObject** operator&() + { + return &this->p; + } + }; + +};}; + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_slp_switch.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_slp_switch.hpp new file mode 100644 index 0000000..bd4b7ae --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_slp_switch.hpp @@ -0,0 +1,99 @@ +#ifndef GREENLET_SLP_SWITCH_HPP +#define GREENLET_SLP_SWITCH_HPP + +#include "greenlet_compiler_compat.hpp" +#include "greenlet_refs.hpp" + +/* + * the following macros are spliced into the OS/compiler + * specific code, in order to simplify maintenance. + */ +// We can save about 10% of the time it takes to switch greenlets if +// we thread the thread state through the slp_save_state() and the +// following slp_restore_state() calls from +// slp_switch()->g_switchstack() (which already needs to access it). +// +// However: +// +// that requires changing the prototypes and implementations of the +// switching functions. If we just change the prototype of +// slp_switch() to accept the argument and update the macros, without +// changing the implementation of slp_switch(), we get crashes on +// 64-bit Linux and 32-bit x86 (for reasons that aren't 100% clear); +// on the other hand, 64-bit macOS seems to be fine. Also, 64-bit +// windows is an issue because slp_switch is written fully in assembly +// and currently ignores its argument so some code would have to be +// adjusted there to pass the argument on to the +// ``slp_save_state_asm()`` function (but interestingly, because of +// the calling convention, the extra argument is just ignored and +// things function fine, albeit slower, if we just modify +// ``slp_save_state_asm`()` to fetch the pointer to pass to the +// macro.) +// +// Our compromise is to use a *glabal*, untracked, weak, pointer +// to the necessary thread state during the process of switching only. +// This is safe because we're protected by the GIL, and if we're +// running this code, the thread isn't exiting. This also nets us a +// 10-12% speed improvement. + +static greenlet::Greenlet* volatile switching_thread_state = nullptr; + + +extern "C" { +static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref); +static void GREENLET_NOINLINE(slp_restore_state_trampoline)(); +} + + +#define SLP_SAVE_STATE(stackref, stsizediff) \ +do { \ + assert(switching_thread_state); \ + stackref += STACK_MAGIC; \ + if (slp_save_state_trampoline((char*)stackref)) \ + return -1; \ + if (!switching_thread_state->active()) \ + return 1; \ + stsizediff = switching_thread_state->stack_start() - (char*)stackref; \ +} while (0) + +#define SLP_RESTORE_STATE() slp_restore_state_trampoline() + +#define SLP_EVAL +extern "C" { +#define slp_switch GREENLET_NOINLINE(slp_switch) +#include "slp_platformselect.h" +} +#undef slp_switch + +#ifndef STACK_MAGIC +# error \ + "greenlet needs to be ported to this platform, or taught how to detect your compiler properly." +#endif /* !STACK_MAGIC */ + + + +#ifdef EXTERNAL_ASM +/* CCP addition: Make these functions, to be called from assembler. + * The token include file for the given platform should enable the + * EXTERNAL_ASM define so that this is included. + */ +extern "C" { +intptr_t +slp_save_state_asm(intptr_t* ref) +{ + intptr_t diff; + SLP_SAVE_STATE(ref, diff); + return diff; +} + +void +slp_restore_state_asm(void) +{ + SLP_RESTORE_STATE(); +} + +extern int slp_switch(void); +}; +#endif + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state.hpp new file mode 100644 index 0000000..045371f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state.hpp @@ -0,0 +1,543 @@ +#ifndef GREENLET_THREAD_STATE_HPP +#define GREENLET_THREAD_STATE_HPP + +#include +#include + +#include "greenlet_internal.hpp" +#include "greenlet_refs.hpp" +#include "greenlet_thread_support.hpp" + +using greenlet::refs::BorrowedObject; +using greenlet::refs::BorrowedGreenlet; +using greenlet::refs::BorrowedMainGreenlet; +using greenlet::refs::OwnedMainGreenlet; +using greenlet::refs::OwnedObject; +using greenlet::refs::OwnedGreenlet; +using greenlet::refs::OwnedList; +using greenlet::refs::PyErrFetchParam; +using greenlet::refs::PyArgParseParam; +using greenlet::refs::ImmortalString; +using greenlet::refs::CreatedModule; +using greenlet::refs::PyErrPieces; +using greenlet::refs::NewReference; + +namespace greenlet { +/** + * Thread-local state of greenlets. + * + * Each native thread will get exactly one of these objects, + * automatically accessed through the best available thread-local + * mechanism the compiler supports (``thread_local`` for C++11 + * compilers or ``__thread``/``declspec(thread)`` for older GCC/clang + * or MSVC, respectively.) + * + * Previously, we kept thread-local state mostly in a bunch of + * ``static volatile`` variables in the main greenlet file.. This had + * the problem of requiring extra checks, loops, and great care + * accessing these variables if we potentially invoked any Python code + * that could release the GIL, because the state could change out from + * under us. Making the variables thread-local solves this problem. + * + * When we detected that a greenlet API accessing the current greenlet + * was invoked from a different thread than the greenlet belonged to, + * we stored a reference to the greenlet in the Python thread + * dictionary for the thread the greenlet belonged to. This could lead + * to memory leaks if the thread then exited (because of a reference + * cycle, as greenlets referred to the thread dictionary, and deleting + * non-current greenlets leaked their frame plus perhaps arguments on + * the C stack). If a thread exited while still having running + * greenlet objects (perhaps that had just switched back to the main + * greenlet), and did not invoke one of the greenlet APIs *in that + * thread, immediately before it exited, without some other thread + * then being invoked*, such a leak was guaranteed. + * + * This can be partly solved by using compiler thread-local variables + * instead of the Python thread dictionary, thus avoiding a cycle. + * + * To fully solve this problem, we need a reliable way to know that a + * thread is done and we should clean up the main greenlet. On POSIX, + * we can use the destructor function of ``pthread_key_create``, but + * there's nothing similar on Windows; a C++11 thread local object + * reliably invokes its destructor when the thread it belongs to exits + * (non-C++11 compilers offer ``__thread`` or ``declspec(thread)`` to + * create thread-local variables, but they can't hold C++ objects that + * invoke destructors; the C++11 version is the most portable solution + * I found). When the thread exits, we can drop references and + * otherwise manipulate greenlets and frames that we know can no + * longer be switched to. For compilers that don't support C++11 + * thread locals, we have a solution that uses the python thread + * dictionary, though it may not collect everything as promptly as + * other compilers do, if some other library is using the thread + * dictionary and has a cycle or extra reference. + * + * There are two small wrinkles. The first is that when the thread + * exits, it is too late to actually invoke Python APIs: the Python + * thread state is gone, and the GIL is released. To solve *this* + * problem, our destructor uses ``Py_AddPendingCall`` to transfer the + * destruction work to the main thread. (This is not an issue for the + * dictionary solution.) + * + * The second is that once the thread exits, the thread local object + * is invalid and we can't even access a pointer to it, so we can't + * pass it to ``Py_AddPendingCall``. This is handled by actually using + * a second object that's thread local (ThreadStateCreator) and having + * it dynamically allocate this object so it can live until the + * pending call runs. + */ + + + +class ThreadState { +private: + // As of commit 08ad1dd7012b101db953f492e0021fb08634afad + // this class needed 56 bytes in o Py_DEBUG build + // on 64-bit macOS 11. + // Adding the vector takes us up to 80 bytes () + + /* Strong reference to the main greenlet */ + OwnedMainGreenlet main_greenlet; + + /* Strong reference to the current greenlet. */ + OwnedGreenlet current_greenlet; + + /* Strong reference to the trace function, if any. */ + OwnedObject tracefunc; + + typedef std::vector > deleteme_t; + /* A vector of raw PyGreenlet pointers representing things that need + deleted when this thread is running. The vector owns the + references, but you need to manually INCREF/DECREF as you use + them. We don't use a vector because we + make copy of this vector, and that would become O(n) as all the + refcounts are incremented in the copy. + */ + deleteme_t deleteme; + +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + void* exception_state; +#endif + + static std::clock_t _clocks_used_doing_gc; + static ImmortalString get_referrers_name; + static PythonAllocator allocator; + + G_NO_COPIES_OF_CLS(ThreadState); + +public: + static void* operator new(size_t UNUSED(count)) + { + return ThreadState::allocator.allocate(1); + } + + static void operator delete(void* ptr) + { + return ThreadState::allocator.deallocate(static_cast(ptr), + 1); + } + + static void init() + { + ThreadState::get_referrers_name = "get_referrers"; + ThreadState::_clocks_used_doing_gc = 0; + } + + ThreadState() + : main_greenlet(OwnedMainGreenlet::consuming(green_create_main(this))), + current_greenlet(main_greenlet) + { + if (!this->main_greenlet) { + // We failed to create the main greenlet. That's bad. + throw PyFatalError("Failed to create main greenlet"); + } + // The main greenlet starts with 1 refs: The returned one. We + // then copied it to the current greenlet. + assert(this->main_greenlet.REFCNT() == 2); + +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + this->exception_state = slp_get_exception_state(); +#endif + } + + inline void restore_exception_state() + { +#ifdef GREENLET_NEEDS_EXCEPTION_STATE_SAVED + // It's probably important this be inlined and only call C + // functions to avoid adding an SEH frame. + slp_set_exception_state(this->exception_state); +#endif + } + + inline bool has_main_greenlet() + { + return !!this->main_greenlet; + } + + // Called from the ThreadStateCreator when we're in non-standard + // threading mode. In that case, there is an object in the Python + // thread state dictionary that points to us. The main greenlet + // also traverses into us, in which case it's crucial not to + // traverse back into the main greenlet. + int tp_traverse(visitproc visit, void* arg, bool traverse_main=true) + { + if (traverse_main) { + Py_VISIT(main_greenlet.borrow_o()); + } + if (traverse_main || current_greenlet != main_greenlet) { + Py_VISIT(current_greenlet.borrow_o()); + } + Py_VISIT(tracefunc.borrow()); + return 0; + } + + inline BorrowedMainGreenlet borrow_main_greenlet() const + { + assert(this->main_greenlet); + assert(this->main_greenlet.REFCNT() >= 2); + return this->main_greenlet; + }; + + inline OwnedMainGreenlet get_main_greenlet() + { + return this->main_greenlet; + } + + /** + * In addition to returning a new reference to the currunt + * greenlet, this performs any maintenance needed. + */ + inline OwnedGreenlet get_current() + { + /* green_dealloc() cannot delete greenlets from other threads, so + it stores them in the thread dict; delete them now. */ + this->clear_deleteme_list(); + //assert(this->current_greenlet->main_greenlet == this->main_greenlet); + //assert(this->main_greenlet->main_greenlet == this->main_greenlet); + return this->current_greenlet; + } + + /** + * As for non-const get_current(); + */ + inline BorrowedGreenlet borrow_current() + { + this->clear_deleteme_list(); + return this->current_greenlet; + } + + /** + * Does no maintenance. + */ + inline OwnedGreenlet get_current() const + { + return this->current_greenlet; + } + + template + inline bool is_current(const refs::PyObjectPointer& obj) const + { + return this->current_greenlet.borrow_o() == obj.borrow_o(); + } + + inline void set_current(const OwnedGreenlet& target) + { + this->current_greenlet = target; + } + +private: + /** + * Deref and remove the greenlets from the deleteme list. Must be + * holding the GIL. + * + * If *murder* is true, then we must be called from a different + * thread than the one that these greenlets were running in. + * In that case, if the greenlet was actually running, we destroy + * the frame reference and otherwise make it appear dead before + * proceeding; otherwise, we would try (and fail) to raise an + * exception in it and wind up right back in this list. + */ + inline void clear_deleteme_list(const bool murder=false) + { + if (!this->deleteme.empty()) { + // It's possible we could add items to this list while + // running Python code if there's a thread switch, so we + // need to defensively copy it before that can happen. + deleteme_t copy = this->deleteme; + this->deleteme.clear(); // in case things come back on the list + for(deleteme_t::iterator it = copy.begin(), end = copy.end(); + it != end; + ++it ) { + PyGreenlet* to_del = *it; + if (murder) { + // Force each greenlet to appear dead; we can't raise an + // exception into it anymore anyway. + to_del->pimpl->murder_in_place(); + } + + // The only reference to these greenlets should be in + // this list, decreffing them should let them be + // deleted again, triggering calls to green_dealloc() + // in the correct thread (if we're not murdering). + // This may run arbitrary Python code and switch + // threads or greenlets! + Py_DECREF(to_del); + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(nullptr); + PyErr_Clear(); + } + } + } + } + +public: + + /** + * Returns a new reference, or a false object. + */ + inline OwnedObject get_tracefunc() const + { + return tracefunc; + }; + + + inline void set_tracefunc(BorrowedObject tracefunc) + { + assert(tracefunc); + if (tracefunc == BorrowedObject(Py_None)) { + this->tracefunc.CLEAR(); + } + else { + this->tracefunc = tracefunc; + } + } + + /** + * Given a reference to a greenlet that some other thread + * attempted to delete (has a refcount of 0) store it for later + * deletion when the thread this state belongs to is current. + */ + inline void delete_when_thread_running(PyGreenlet* to_del) + { + Py_INCREF(to_del); + this->deleteme.push_back(to_del); + } + + /** + * Set to std::clock_t(-1) to disable. + */ + inline static std::clock_t& clocks_used_doing_gc() + { + return ThreadState::_clocks_used_doing_gc; + } + + ~ThreadState() + { + if (!PyInterpreterState_Head()) { + // We shouldn't get here (our callers protect us) + // but if we do, all we can do is bail early. + return; + } + + // We should not have an "origin" greenlet; that only exists + // for the temporary time during a switch, which should not + // be in progress as the thread dies. + //assert(!this->switching_state.origin); + + this->tracefunc.CLEAR(); + + // Forcibly GC as much as we can. + this->clear_deleteme_list(true); + + // The pending call did this. + assert(this->main_greenlet->thread_state() == nullptr); + + // If the main greenlet is the current greenlet, + // then we "fell off the end" and the thread died. + // It's possible that there is some other greenlet that + // switched to us, leaving a reference to the main greenlet + // on the stack, somewhere uncollectible. Try to detect that. + if (this->current_greenlet == this->main_greenlet && this->current_greenlet) { + assert(this->current_greenlet->is_currently_running_in_some_thread()); + // Drop one reference we hold. + this->current_greenlet.CLEAR(); + assert(!this->current_greenlet); + // Only our reference to the main greenlet should be left, + // But hold onto the pointer in case we need to do extra cleanup. + PyGreenlet* old_main_greenlet = this->main_greenlet.borrow(); + Py_ssize_t cnt = this->main_greenlet.REFCNT(); + this->main_greenlet.CLEAR(); + if (ThreadState::_clocks_used_doing_gc != std::clock_t(-1) + && cnt == 2 && Py_REFCNT(old_main_greenlet) == 1) { + // Highly likely that the reference is somewhere on + // the stack, not reachable by GC. Verify. + // XXX: This is O(n) in the total number of objects. + // TODO: Add a way to disable this at runtime, and + // another way to report on it. + std::clock_t begin = std::clock(); + NewReference gc(PyImport_ImportModule("gc")); + if (gc) { + OwnedObject get_referrers = gc.PyRequireAttr(ThreadState::get_referrers_name); + OwnedList refs(get_referrers.PyCall(old_main_greenlet)); + if (refs && refs.empty()) { + assert(refs.REFCNT() == 1); + // We found nothing! So we left a dangling + // reference: Probably the last thing some + // other greenlet did was call + // 'getcurrent().parent.switch()' to switch + // back to us. Clean it up. This will be the + // case on CPython 3.7 and newer, as they use + // an internal calling conversion that avoids + // creating method objects and storing them on + // the stack. + Py_DECREF(old_main_greenlet); + } + else if (refs + && refs.size() == 1 + && PyCFunction_Check(refs.at(0)) + && Py_REFCNT(refs.at(0)) == 2) { + assert(refs.REFCNT() == 1); + // Ok, we found a C method that refers to the + // main greenlet, and its only referenced + // twice, once in the list we just created, + // once from...somewhere else. If we can't + // find where else, then this is a leak. + // This happens in older versions of CPython + // that create a bound method object somewhere + // on the stack that we'll never get back to. + if (PyCFunction_GetFunction(refs.at(0).borrow()) == (PyCFunction)green_switch) { + BorrowedObject function_w = refs.at(0); + refs.clear(); // destroy the reference + // from the list. + // back to one reference. Can *it* be + // found? + assert(function_w.REFCNT() == 1); + refs = get_referrers.PyCall(function_w); + if (refs && refs.empty()) { + // Nope, it can't be found so it won't + // ever be GC'd. Drop it. + Py_CLEAR(function_w); + } + } + } + std::clock_t end = std::clock(); + ThreadState::_clocks_used_doing_gc += (end - begin); + } + } + } + + // We need to make sure this greenlet appears to be dead, + // because otherwise deallocing it would fail to raise an + // exception in it (the thread is dead) and put it back in our + // deleteme list. + if (this->current_greenlet) { + this->current_greenlet->murder_in_place(); + this->current_greenlet.CLEAR(); + } + + if (this->main_greenlet) { + // Couldn't have been the main greenlet that was running + // when the thread exited (because we already cleared this + // pointer if it was). This shouldn't be possible? + + // If the main greenlet was current when the thread died (it + // should be, right?) then we cleared its self pointer above + // when we cleared the current greenlet's main greenlet pointer. + // assert(this->main_greenlet->main_greenlet == this->main_greenlet + // || !this->main_greenlet->main_greenlet); + // // self reference, probably gone + // this->main_greenlet->main_greenlet.CLEAR(); + + // This will actually go away when the ivar is destructed. + this->main_greenlet.CLEAR(); + } + + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(NULL); + PyErr_Clear(); + } + + } + +}; + +ImmortalString ThreadState::get_referrers_name(nullptr); +PythonAllocator ThreadState::allocator; +std::clock_t ThreadState::_clocks_used_doing_gc(0); + +template +class ThreadStateCreator +{ +private: + // Initialized to 1, and, if still 1, created on access. + // Set to 0 on destruction. + ThreadState* _state; + G_NO_COPIES_OF_CLS(ThreadStateCreator); +public: + + // Only one of these, auto created per thread + ThreadStateCreator() : + _state((ThreadState*)1) + { + } + + ~ThreadStateCreator() + { + ThreadState* tmp = this->_state; + this->_state = nullptr; + if (tmp && tmp != (ThreadState*)1) { + Destructor x(tmp); + } + } + + inline ThreadState& state() + { + // The main greenlet will own this pointer when it is created, + // which will be right after this. The plan is to give every + // greenlet a pointer to the main greenlet for the thread it + // runs in; if we are doing something cross-thread, we need to + // access the pointer from the main greenlet. Deleting the + // thread, and hence the thread-local storage, will delete the + // state pointer in the main greenlet. + if (this->_state == (ThreadState*)1) { + // XXX: Assuming allocation never fails + this->_state = new ThreadState; + // For non-standard threading, we need to store an object + // in the Python thread state dictionary so that it can be + // DECREF'd when the thread ends (ideally; the dict could + // last longer) and clean this object up. + } + if (!this->_state) { + throw std::runtime_error("Accessing state after destruction."); + } + return *this->_state; + } + + operator ThreadState&() + { + return this->state(); + } + + operator ThreadState*() + { + return &this->state(); + } + + inline int tp_traverse(visitproc visit, void* arg) + { + if (this->_state) { + return this->_state->tp_traverse(visit, arg); + } + return 0; + } + +}; + + +// We can't use the PythonAllocator for this, because we push to it +// from the thread state destructor, which doesn't have the GIL, +// and Python's allocators can only be called with the GIL. +typedef std::vector cleanup_queue_t; + +}; // namespace greenlet + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp new file mode 100644 index 0000000..acf39c8 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_state_dict_cleanup.hpp @@ -0,0 +1,118 @@ +#ifndef GREENLET_THREAD_STATE_DICT_CLEANUP_HPP +#define GREENLET_THREAD_STATE_DICT_CLEANUP_HPP + +#include "greenlet_internal.hpp" +#include "greenlet_thread_state.hpp" + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmissing-field-initializers" +#endif + +#ifndef G_THREAD_STATE_DICT_CLEANUP_TYPE +// shut the compiler up if it looks at this file in isolation +#define ThreadStateCreator int +#endif + +// Define a Python object that goes in the Python thread state dict +// when the greenlet thread state is created, and which owns the +// reference to the greenlet thread local state. +// When the thread state dict is cleaned up, so too is the thread +// state. This works best if we make sure there are no circular +// references to the thread state. +typedef struct _PyGreenletCleanup { + PyObject_HEAD + ThreadStateCreator* thread_state_creator; +} PyGreenletCleanup; + +static void +cleanup_do_dealloc(PyGreenletCleanup* self) +{ + ThreadStateCreator* tmp = self->thread_state_creator; + self->thread_state_creator = nullptr; + if (tmp) { + delete tmp; + } +} + +static void +cleanup_dealloc(PyGreenletCleanup* self) +{ + PyObject_GC_UnTrack(self); + cleanup_do_dealloc(self); +} + +static int +cleanup_clear(PyGreenletCleanup* self) +{ + // This method is never called by our test cases. + cleanup_do_dealloc(self); + return 0; +} + +static int +cleanup_traverse(PyGreenletCleanup* self, visitproc visit, void* arg) +{ + if (self->thread_state_creator) { + return self->thread_state_creator->tp_traverse(visit, arg); + } + return 0; +} + +static int +cleanup_is_gc(PyGreenlet* UNUSED(self)) +{ + return 1; +} + +static PyTypeObject PyGreenletCleanup_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "greenlet._greenlet.ThreadStateCleanup", + sizeof(struct _PyGreenletCleanup), + 0, /* tp_itemsize */ + /* methods */ + (destructor)cleanup_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as _number*/ + 0, /* tp_as _sequence*/ + 0, /* tp_as _mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer*/ + G_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Internal use only", /* tp_doc */ + (traverseproc)cleanup_traverse, /* tp_traverse */ + (inquiry)cleanup_clear, /* tp_clear */ + 0, /* tp_richcompare */ + // XXX: Don't our flags promise a weakref? + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + (inquiry)cleanup_is_gc, /* tp_is_gc */ +}; + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_support.hpp b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_support.hpp new file mode 100644 index 0000000..3ded7d2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/greenlet_thread_support.hpp @@ -0,0 +1,31 @@ +#ifndef GREENLET_THREAD_SUPPORT_HPP +#define GREENLET_THREAD_SUPPORT_HPP + +/** + * Defines various utility functions to help greenlet integrate well + * with threads. This used to be needed when we supported Python + * 2.7 on Windows, which used a very old compiler. We wrote an + * alternative implementation using Python APIs and POSIX or Windows + * APIs, but that's no longer needed. So this file is a shadow of its + * former self --- but may be needed in the future. + */ + +#include +#include +#include + +#include "greenlet_compiler_compat.hpp" + +namespace greenlet { + typedef std::mutex Mutex; + typedef std::lock_guard LockGuard; + class LockInitError : public std::runtime_error + { + public: + LockInitError(const char* what) : std::runtime_error(what) + {}; + }; +}; + + +#endif /* GREENLET_THREAD_SUPPORT_HPP */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/__init__.py b/elitebot/lib/python3.11/site-packages/greenlet/platform/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/setup_switch_x64_masm.cmd b/elitebot/lib/python3.11/site-packages/greenlet/platform/setup_switch_x64_masm.cmd new file mode 100644 index 0000000..0928595 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/setup_switch_x64_masm.cmd @@ -0,0 +1,2 @@ +call "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64 +ml64 /nologo /c /Fo switch_x64_masm.obj switch_x64_masm.asm diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_aarch64_gcc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_aarch64_gcc.h new file mode 100644 index 0000000..058617c --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_aarch64_gcc.h @@ -0,0 +1,124 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-16 Add clang support using x register naming. Fredrik Fornwall + * 13-Apr-13 Add support for strange GCC caller-save decisions + * 08-Apr-13 File creation. Michael Matz + * + * NOTES + * + * Simply save all callee saved registers + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REGS_TO_SAVE "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", \ + "x27", "x28", "x30" /* aka lr */, \ + "v8", "v9", "v10", "v11", \ + "v12", "v13", "v14", "v15" + +/* + * Recall: + asm asm-qualifiers ( AssemblerTemplate + : OutputOperands + [ : InputOperands + [ : Clobbers ] ]) + + or (if asm-qualifiers contains 'goto') + + asm asm-qualifiers ( AssemblerTemplate + : OutputOperands + : InputOperands + : Clobbers + : GotoLabels) + + and OutputOperands are + + [ [asmSymbolicName] ] constraint (cvariablename) + + When a name is given, refer to it as ``%[the name]``. + When not given, ``%i`` where ``i`` is the zero-based index. + + constraints starting with ``=`` means only writing; ``+`` means + reading and writing. + + This is followed by ``r`` (must be register) or ``m`` (must be memory) + and these can be combined. + + The ``cvariablename`` is actually an lvalue expression. + + In AArch65, 31 general purpose registers. If named X0... they are + 64-bit. If named W0... they are the bottom 32 bits of the + corresponding 64 bit register. + + XZR and WZR are hardcoded to 0, and ignore writes. + + Arguments are in X0..X7. C++ uses X0 for ``this``. X0 holds simple return + values (?) + + Whenever a W register is written, the top half of the X register is zeroed. + */ + +static int +slp_switch(void) +{ + int err; + void *fp; + /* Windowz uses a 32-bit long on a 64-bit platform, unlike the rest of + the world, and in theory we can be compiled with GCC/llvm on 64-bit + windows. So we need a fixed-width type. + */ + int64_t *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("str x29, %0" : "=m"(fp) : : ); + __asm__ ("mov %0, sp" : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add sp,sp,%0\n" + "add x29,x29,%0\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + /* SLP_SAVE_STATE macro contains some return statements + (of -1 and 1). It falls through only when + the return value of slp_save_state() is zero, which + is placed in x0. + In that case we (slp_switch) also want to return zero + (also in x0 of course). + Now, some GCC versions (seen with 4.8) think it's a + good idea to save/restore x0 around the call to + slp_restore_state(), instead of simply zeroing it + at the return below. But slp_restore_state + writes random values to the stack slot used for this + save/restore (from when it once was saved above in + SLP_SAVE_STATE, when it was still uninitialized), so + "restoring" that precious zero actually makes us + return random values. There are some ways to make + GCC not use that zero value in the normal return path + (e.g. making err volatile, but that costs a little + stack space), and the simplest is to call a function + that returns an unknown value (which happens to be zero), + so the saved/restored value is unused. + + Thus, this line stores a 0 into the ``err`` variable + (which must be held in a register for this instruction, + of course). The ``w`` qualifier causes the instruction + to use W0 instead of X0, otherwise we get a warning + about a value size mismatch (because err is an int, + and aarch64 platforms are LP64: 32-bit int, 64 bit long + and pointer). + */ + __asm__ volatile ("mov %w0, #0" : "=r" (err)); + } + __asm__ volatile ("ldr x29, %0" : : "m" (fp) :); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_alpha_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_alpha_unix.h new file mode 100644 index 0000000..7e07abf --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_alpha_unix.h @@ -0,0 +1,30 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "$9", "$10", "$11", "$12", "$13", "$14", "$15", \ + "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mov $30, %0" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addq $30, %0, $30\n\t" + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mov $31, %0" : "=r" (ret) : ); + return ret; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_amd64_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_amd64_unix.h new file mode 100644 index 0000000..d470110 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_amd64_unix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 3-May-13 Ralf Schmitt + * Add support for strange GCC caller-save decisions + * (ported from switch_aarch64_gcc.h) + * 18-Aug-11 Alexey Borzenkov + * Correctly save rbp, csr and cw + * 01-Apr-04 Hye-Shik Chang + * Ported from i386 to amd64. + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for spark + * 31-Avr-02 Armin Rigo + * Added ebx, esi and edi register-saves. + * 01-Mar-02 Samual M. Rushing + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +/* #define STACK_MAGIC 3 */ +/* the above works fine with gcc 2.96, but 2.95.3 wants this */ +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "r12", "r13", "r14", "r15" + +static int +slp_switch(void) +{ + int err; + void* rbp; + void* rbx; + unsigned int csr; + unsigned short cw; + /* This used to be declared 'register', but that does nothing in + modern compilers and is explicitly forbidden in some new + standards. */ + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("stmxcsr %0" : "=m" (csr)); + __asm__ volatile ("movq %%rbp, %0" : "=m" (rbp)); + __asm__ volatile ("movq %%rbx, %0" : "=m" (rbx)); + __asm__ ("movq %%rsp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addq %0, %%rsp\n" + "addq %0, %%rbp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + __asm__ volatile ("xorq %%rax, %%rax" : "=a" (err)); + } + __asm__ volatile ("movq %0, %%rbx" : : "m" (rbx)); + __asm__ volatile ("movq %0, %%rbp" : : "m" (rbp)); + __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_gcc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_gcc.h new file mode 100644 index 0000000..655003a --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_gcc.h @@ -0,0 +1,79 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 14-Aug-06 File creation. Ported from Arm Thumb. Sylvain Baro + * 3-Sep-06 Commented out saving of r1-r3 (r4 already commented out) as I + * read that these do not need to be saved. Also added notes and + * errors related to the frame pointer. Richard Tew. + * + * NOTES + * + * It is not possible to detect if fp is used or not, so the supplied + * switch function needs to support it, so that you can remove it if + * it does not apply to you. + * + * POSSIBLE ERRORS + * + * "fp cannot be used in asm here" + * + * - Try commenting out "fp" in REGS_TO_SAVE. + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REG_SP "sp" +#define REG_SPSP "sp,sp" +#ifdef __thumb__ +#define REG_FP "r7" +#define REG_FPFP "r7,r7" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r9", "r10", "r11", "lr" +#else +#define REG_FP "fp" +#define REG_FPFP "fp,fp" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r8", "r9", "r10", "lr" +#endif +#if defined(__SOFTFP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL +#elif defined(__VFP_FP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ + "d12", "d13", "d14", "d15" +#elif defined(__MAVERICK__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "mvf4", "mvf5", "mvf6", "mvf7", \ + "mvf8", "mvf9", "mvf10", "mvf11", \ + "mvf12", "mvf13", "mvf14", "mvf15" +#else +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "f4", "f5", "f6", "f7" +#endif + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + void *fp; + int *stackref, stsizediff; + int result; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mov r0," REG_FP "\n\tstr r0,%0" : "=m" (fp) : : "r0"); + __asm__ ("mov %0," REG_SP : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add " REG_SPSP ",%0\n" + "add " REG_FPFP ",%0\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ldr r0,%1\n\tmov " REG_FP ",r0\n\tmov %0, #0" : "=r" (result) : "m" (fp) : "r0"); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return result; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_ios.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_ios.h new file mode 100644 index 0000000..9e640e1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm32_ios.h @@ -0,0 +1,67 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 31-May-15 iOS support. Ported from arm32. Proton + * + * NOTES + * + * It is not possible to detect if fp is used or not, so the supplied + * switch function needs to support it, so that you can remove it if + * it does not apply to you. + * + * POSSIBLE ERRORS + * + * "fp cannot be used in asm here" + * + * - Try commenting out "fp" in REGS_TO_SAVE. + * + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 +#define REG_SP "sp" +#define REG_SPSP "sp,sp" +#define REG_FP "r7" +#define REG_FPFP "r7,r7" +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r8", "r10", "r11", "lr" +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "d8", "d9", "d10", "d11", \ + "d12", "d13", "d14", "d15" + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + void *fp; + int *stackref, stsizediff, result; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("str " REG_FP ",%0" : "=m" (fp)); + __asm__ ("mov %0," REG_SP : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add " REG_SPSP ",%0\n" + "add " REG_FPFP ",%0\n" + : + : "r" (stsizediff) + : REGS_TO_SAVE /* Clobber registers, force compiler to + * recalculate address of void *fp from REG_SP or REG_FP */ + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ( + "ldr " REG_FP ", %1\n\t" + "mov %0, #0" + : "=r" (result) + : "m" (fp) + : REGS_TO_SAVE /* Force compiler to restore saved registers after this */ + ); + return result; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.asm b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.asm new file mode 100644 index 0000000..29f9c22 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.asm @@ -0,0 +1,53 @@ + AREA switch_arm64_masm, CODE, READONLY; + GLOBAL slp_switch [FUNC] + EXTERN slp_save_state_asm + EXTERN slp_restore_state_asm + +slp_switch + ; push callee saved registers to stack + stp x19, x20, [sp, #-16]! + stp x21, x22, [sp, #-16]! + stp x23, x24, [sp, #-16]! + stp x25, x26, [sp, #-16]! + stp x27, x28, [sp, #-16]! + stp x29, x30, [sp, #-16]! + stp d8, d9, [sp, #-16]! + stp d10, d11, [sp, #-16]! + stp d12, d13, [sp, #-16]! + stp d14, d15, [sp, #-16]! + + ; call slp_save_state_asm with stack pointer + mov x0, sp + bl slp_save_state_asm + + ; early return for return value of 1 and -1 + cmp x0, #-1 + b.eq RETURN + cmp x0, #1 + b.eq RETURN + + ; increment stack and frame pointer + add sp, sp, x0 + add x29, x29, x0 + + bl slp_restore_state_asm + + ; store return value for successful completion of routine + mov x0, #0 + +RETURN + ; pop registers from stack + ldp d14, d15, [sp], #16 + ldp d12, d13, [sp], #16 + ldp d10, d11, [sp], #16 + ldp d8, d9, [sp], #16 + ldp x29, x30, [sp], #16 + ldp x27, x28, [sp], #16 + ldp x25, x26, [sp], #16 + ldp x23, x24, [sp], #16 + ldp x21, x22, [sp], #16 + ldp x19, x20, [sp], #16 + + ret + + END diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.obj b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_masm.obj new file mode 100644 index 0000000000000000000000000000000000000000..f6f220e4310baaa9756110685ce7d6a2bdf90c37 GIT binary patch literal 746 zcma)4PiqrF6n~qoo~*PNZ{i+=wji4b#Xu2~wiJpGk)*AMF07NyB(9n1#+i+!)I;v| zBKQG3?t1eB$T(lYgGb4+lu{_QmQrebldQB_4?cMF-uu0IZ{DA2e8@rZ+e^~30488W z`B{KPh%yV{HEIpyeum^wI#7P*HfX)ux?9U&c!SFK-$o|OFtKn{Q|a-#N>2inp0-tb zCRKXAtg2SolaoLv$Ll&ds_Epj?SH+8K{t?XSjKaFsEy%yh}=V70BaHj zEY5kWk_zcJo{$SSUL~=K(zW|tnhm$rA z<%dZ$q?>RX*18r{!azhaYR1lVb;g;mR-6h!#F>|p@;aje%0a|CZrE7s+SXuT>MS=Y ziQPiMY-5DD&5+S7^H03fy7qt7ir}L34kK|h68s-MU>{lXOqlr?!Y=`~WwviNenFS_ zZalVSHh-0FU4lj#X8u5`ODn6@#{f?dHE&%XdP~_I3;$RS9-(z*>>ydkm*f@oWlUn~ Qn+^;lsEi}=H#!Q3U&UU-WdHyG literal 0 HcmV?d00001 diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_msvc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_msvc.h new file mode 100644 index 0000000..7ab7f45 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_arm64_msvc.h @@ -0,0 +1,17 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 21-Oct-21 Niyas Sait + * First version to enable win/arm64 support. + */ + +#define STACK_REFPLUS 1 +#define STACK_MAGIC 0 + +/* Use the generic support for an external assembly language slp_switch function. */ +#define EXTERNAL_ASM + +#ifdef SLP_EVAL +/* This always uses the external masm assembly file. */ +#endif \ No newline at end of file diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_csky_gcc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_csky_gcc.h new file mode 100644 index 0000000..ac469d3 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_csky_gcc.h @@ -0,0 +1,48 @@ +#ifdef SLP_EVAL +#define STACK_MAGIC 0 +#define REG_FP "r8" +#ifdef __CSKYABIV2__ +#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r9", "r10", "r11", "r15",\ + "r16", "r17", "r18", "r19", "r20", "r21", "r22",\ + "r23", "r24", "r25" + +#if defined (__CSKY_HARD_FLOAT__) || (__CSKY_VDSP__) +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "vr8", "vr9", "vr10", "vr11", "vr12",\ + "vr13", "vr14", "vr15" +#else +#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL +#endif +#else +#define REGS_TO_SAVE "r9", "r10", "r11", "r12", "r13", "r15" +#endif + + +static int +#ifdef __GNUC__ +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +slp_switch(void) +{ + int *stackref, stsizediff; + int result; + + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mov %0, sp" : "=r" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addu sp,%0\n" + "addu "REG_FP",%0\n" + : + : "r" (stsizediff) + ); + + SLP_RESTORE_STATE(); + } + __asm__ volatile ("movi %0, 0" : "=r" (result)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + + return result; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_loongarch64_linux.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_loongarch64_linux.h new file mode 100644 index 0000000..9eaf34e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_loongarch64_linux.h @@ -0,0 +1,31 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \ + "s6", "s7", "s8", "fp", \ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("move %0, $sp" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add.d $sp, $sp, %0\n\t" + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("move %0, $zero" : "=r" (ret) : ); + return ret; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_m68k_gcc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_m68k_gcc.h new file mode 100644 index 0000000..da761c2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_m68k_gcc.h @@ -0,0 +1,38 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 2014-01-06 Andreas Schwab + * File created. + */ + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", \ + "%a2", "%a3", "%a4" + +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + void *fp, *a5; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("move.l %%fp, %0" : "=m"(fp)); + __asm__ volatile ("move.l %%a5, %0" : "=m"(a5)); + __asm__ ("move.l %%sp, %0" : "=r"(stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ("add.l %0, %%sp; add.l %0, %%fp" : : "r"(stsizediff)); + SLP_RESTORE_STATE(); + __asm__ volatile ("clr.l %0" : "=g" (err)); + } + __asm__ volatile ("move.l %0, %%a5" : : "m"(a5)); + __asm__ volatile ("move.l %0, %%fp" : : "m"(fp)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + return err; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_mips_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_mips_unix.h new file mode 100644 index 0000000..b9003e9 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_mips_unix.h @@ -0,0 +1,64 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 20-Sep-14 Matt Madison + * Re-code the saving of the gp register for MIPS64. + * 05-Jan-08 Thiemo Seufer + * Ported from ppc. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "$16", "$17", "$18", "$19", "$20", "$21", "$22", \ + "$23", "$30" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; +#ifdef __mips64 + uint64_t gpsave; +#endif + __asm__ __volatile__ ("" : : : REGS_TO_SAVE); +#ifdef __mips64 + __asm__ __volatile__ ("sd $28,%0" : "=m" (gpsave) : : ); +#endif + __asm__ ("move %0, $29" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ __volatile__ ( +#ifdef __mips64 + "daddu $29, %0\n" +#else + "addu $29, %0\n" +#endif + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } +#ifdef __mips64 + __asm__ __volatile__ ("ld $28,%0" : : "m" (gpsave) : ); +#endif + __asm__ __volatile__ ("" : : : REGS_TO_SAVE); + __asm__ __volatile__ ("move %0, $0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_aix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_aix.h new file mode 100644 index 0000000..e7e0b87 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_aix.h @@ -0,0 +1,103 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 16-Oct-20 Jesse Gorzinski + * Copied from Linux PPC64 implementation + * 04-Sep-18 Alexey Borzenkov + * Workaround a gcc bug using manual save/restore of r30 + * 21-Mar-18 Tulio Magno Quites Machado Filho + * Added r30 to the list of saved registers in order to fully comply with + * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this + * register as a nonvolatile register used for local variables. + * 21-Mar-18 Laszlo Boszormenyi + * Save r2 (TOC pointer) manually. + * 10-Dec-13 Ulrich Weigand + * Support ELFv2 ABI. Save float/vector registers. + * 09-Mar-12 Michael Ellerman + * 64-bit implementation, copied from 32-bit. + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 6 + +#if defined(__ALTIVEC__) +#define ALTIVEC_REGS \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ + "v28", "v29", "v30", "v31", +#else +#define ALTIVEC_REGS +#endif + +#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r31", \ + "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ + "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ + "fr30", "fr31", \ + ALTIVEC_REGS \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + int err; + long *stackref, stsizediff; + void * toc; + void * r30; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("std 2, %0" : "=m" (toc)); + __asm__ volatile ("std 30, %0" : "=m" (r30)); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ld 30, %0" : : "m" (r30)); + __asm__ volatile ("ld 2, %0" : : "m" (toc)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_linux.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_linux.h new file mode 100644 index 0000000..3c324d0 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc64_linux.h @@ -0,0 +1,105 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 04-Sep-18 Alexey Borzenkov + * Workaround a gcc bug using manual save/restore of r30 + * 21-Mar-18 Tulio Magno Quites Machado Filho + * Added r30 to the list of saved registers in order to fully comply with + * both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this + * register as a nonvolatile register used for local variables. + * 21-Mar-18 Laszlo Boszormenyi + * Save r2 (TOC pointer) manually. + * 10-Dec-13 Ulrich Weigand + * Support ELFv2 ABI. Save float/vector registers. + * 09-Mar-12 Michael Ellerman + * 64-bit implementation, copied from 32-bit. + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#if _CALL_ELF == 2 +#define STACK_MAGIC 4 +#else +#define STACK_MAGIC 6 +#endif + +#if defined(__ALTIVEC__) +#define ALTIVEC_REGS \ + "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", \ + "v28", "v29", "v30", "v31", +#else +#define ALTIVEC_REGS +#endif + +#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "r31", \ + "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \ + "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \ + "fr30", "fr31", \ + ALTIVEC_REGS \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + int err; + long *stackref, stsizediff; + void * toc; + void * r30; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("std 2, %0" : "=m" (toc)); + __asm__ volatile ("std 30, %0" : "=m" (r30)); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("ld 30, %0" : : "m" (r30)); + __asm__ volatile ("ld 2, %0" : : "m" (toc)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_aix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_aix.h new file mode 100644 index 0000000..6d93c13 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_aix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Mar-11 Floris Bruynooghe + * Do not add stsizediff to general purpose + * register (GPR) 30 as this is a non-volatile and + * unused by the PowerOpen Environment, therefore + * this was modifying a user register instead of the + * frame pointer (which does not seem to exist). + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_linux.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_linux.h new file mode 100644 index 0000000..e83ad70 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_linux.h @@ -0,0 +1,84 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + * 31-Jul-12 Trevor Bowen + * Changed memory constraints to register only. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + "add 30, 30, 11\n" + : /* no outputs */ + : "r" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_macosx.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_macosx.h new file mode 100644 index 0000000..d6e5a03 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_macosx.h @@ -0,0 +1,82 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" + +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("; asm block 2\n\tmr %0, r1" : "=g" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "; asm block 3\n" + "\tmr r11, %0\n" + "\tadd r1, r1, r11\n" + "\tadd r30, r30, r11\n" + : /* no outputs */ + : "g" (stsizediff) + : "r11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_unix.h new file mode 100644 index 0000000..ca590a5 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_ppc_unix.h @@ -0,0 +1,82 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'r31' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 14-Jan-04 Bob Ippolito + * added cr2-cr4 to the registers to be saved. + * Open questions: Should we save FP registers? + * What about vector registers? + * Differences between darwin and unix? + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 04-Oct-02 Gustavo Niemeyer + * Ported from MacOS version. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 29-Jun-02 Christian Tismer + * Added register 13-29, 31 saves. The same way as + * Armin Rigo did for the x86_unix version. + * This seems to be now fully functional! + * 04-Mar-02 Hye-Shik Chang + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 3 + +/* !!!!WARNING!!!! need to add "r31" in the next line if this header file + * is meant to be compiled non-dynamically! + */ +#define REGS_TO_SAVE "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \ + "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", \ + "cr2", "cr3", "cr4" +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ ("mr %0, 1" : "=g" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "mr 11, %0\n" + "add 1, 1, 11\n" + "add 30, 30, 11\n" + : /* no outputs */ + : "g" (stsizediff) + : "11" + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("li %0, 0" : "=r" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_riscv_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_riscv_unix.h new file mode 100644 index 0000000..24df9db --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_riscv_unix.h @@ -0,0 +1,32 @@ +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \ + "s6", "s7", "s8", "s9", "s10", "s11", "fs0", "fs1", \ + "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", \ + "fs10", "fs11" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mv %0, sp" : "=r" (stackref) : ); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "add sp, sp, %0\n\t" + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("mv %0, zero" : "=r" (ret) : ); + return ret; +} + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_s390_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_s390_unix.h new file mode 100644 index 0000000..9199367 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_s390_unix.h @@ -0,0 +1,87 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 25-Jan-12 Alexey Borzenkov + * Fixed Linux/S390 port to work correctly with + * different optimization options both on 31-bit + * and 64-bit. Thanks to Stefan Raabe for lots + * of testing. + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 06-Oct-02 Gustavo Niemeyer + * Ported to Linux/S390. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#ifdef __s390x__ +#define STACK_MAGIC 20 /* 20 * 8 = 160 bytes of function call area */ +#else +#define STACK_MAGIC 24 /* 24 * 4 = 96 bytes of function call area */ +#endif + +/* Technically, r11-r13 also need saving, but function prolog starts + with stm(g) and since there are so many saved registers already + it won't be optimized, resulting in all r6-r15 being saved */ +#define REGS_TO_SAVE "r6", "r7", "r8", "r9", "r10", "r14", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15" + +static int +slp_switch(void) +{ + int ret; + long *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); +#ifdef __s390x__ + __asm__ volatile ("lgr %0, 15" : "=r" (stackref) : ); +#else + __asm__ volatile ("lr %0, 15" : "=r" (stackref) : ); +#endif + { + SLP_SAVE_STATE(stackref, stsizediff); +/* N.B. + r11 may be used as the frame pointer, and in that case it cannot be + clobbered and needs offsetting just like the stack pointer (but in cases + where frame pointer isn't used we might clobber it accidentally). What's + scary is that r11 is 2nd (and even 1st when GOT is used) callee saved + register that gcc would chose for surviving function calls. However, + since r6-r10 are clobbered above, their cost for reuse is reduced, so + gcc IRA will chose them over r11 (not seeing r11 is implicitly saved), + making it relatively safe to offset in all cases. :) */ + __asm__ volatile ( +#ifdef __s390x__ + "agr 15, %0\n\t" + "agr 11, %0" +#else + "ar 15, %0\n\t" + "ar 11, %0" +#endif + : /* no outputs */ + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("lhi %0, 0" : "=r" (ret) : ); + return ret; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_sparc_sun_gcc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_sparc_sun_gcc.h new file mode 100644 index 0000000..96990c3 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_sparc_sun_gcc.h @@ -0,0 +1,92 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 16-May-15 Alexey Borzenkov + * Move stack spilling code inside save/restore functions + * 30-Aug-13 Floris Bruynooghe + Clean the register windows again before returning. + This does not clobber the PIC register as it leaves + the current window intact and is required for multi- + threaded code to work correctly. + * 08-Mar-11 Floris Bruynooghe + * No need to set return value register explicitly + * before the stack and framepointer are adjusted + * as none of the other registers are influenced by + * this. Also don't needlessly clean the windows + * ('ta %0" :: "i" (ST_CLEAN_WINDOWS)') as that + * clobbers the gcc PIC register (%l7). + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * added support for SunOS sparc with gcc + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + + +#define STACK_MAGIC 0 + + +#if defined(__sparcv9) +#define SLP_FLUSHW __asm__ volatile ("flushw") +#else +#define SLP_FLUSHW __asm__ volatile ("ta 3") /* ST_FLUSH_WINDOWS */ +#endif + +/* On sparc we need to spill register windows inside save/restore functions */ +#define SLP_BEFORE_SAVE_STATE() SLP_FLUSHW +#define SLP_BEFORE_RESTORE_STATE() SLP_FLUSHW + + +static int +slp_switch(void) +{ + int err; + int *stackref, stsizediff; + + /* Put current stack pointer into stackref. + * Register spilling is done in save/restore. + */ + __asm__ volatile ("mov %%sp, %0" : "=r" (stackref)); + + { + /* Thou shalt put SLP_SAVE_STATE into a local block */ + /* Copy the current stack onto the heap */ + SLP_SAVE_STATE(stackref, stsizediff); + + /* Increment stack and frame pointer by stsizediff */ + __asm__ volatile ( + "add %0, %%sp, %%sp\n\t" + "add %0, %%fp, %%fp" + : : "r" (stsizediff)); + + /* Copy new stack from it's save store on the heap */ + SLP_RESTORE_STATE(); + + __asm__ volatile ("mov %1, %0" : "=r" (err) : "i" (0)); + return err; + } +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x32_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x32_unix.h new file mode 100644 index 0000000..893369c --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x32_unix.h @@ -0,0 +1,63 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 17-Aug-12 Fantix King + * Ported from amd64. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +#define REGS_TO_SAVE "r12", "r13", "r14", "r15" + + +static int +slp_switch(void) +{ + void* ebp; + void* ebx; + unsigned int csr; + unsigned short cw; + int err; + int *stackref, stsizediff; + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("stmxcsr %0" : "=m" (csr)); + __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); + __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); + __asm__ ("movl %%esp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addl %0, %%esp\n" + "addl %0, %%ebp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + } + __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); + __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); + __asm__ volatile ("ldmxcsr %0" : : "m" (csr)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : REGS_TO_SAVE); + __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.asm b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.asm new file mode 100644 index 0000000..f5c72a2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.asm @@ -0,0 +1,111 @@ +; +; stack switching code for MASM on x641 +; Kristjan Valur Jonsson, sept 2005 +; + + +;prototypes for our calls +slp_save_state_asm PROTO +slp_restore_state_asm PROTO + + +pushxmm MACRO reg + sub rsp, 16 + .allocstack 16 + movaps [rsp], reg ; faster than movups, but we must be aligned + ; .savexmm128 reg, offset (don't know what offset is, no documentation) +ENDM +popxmm MACRO reg + movaps reg, [rsp] ; faster than movups, but we must be aligned + add rsp, 16 +ENDM + +pushreg MACRO reg + push reg + .pushreg reg +ENDM +popreg MACRO reg + pop reg +ENDM + + +.code +slp_switch PROC FRAME + ;realign stack to 16 bytes after return address push, makes the following faster + sub rsp,8 + .allocstack 8 + + pushxmm xmm15 + pushxmm xmm14 + pushxmm xmm13 + pushxmm xmm12 + pushxmm xmm11 + pushxmm xmm10 + pushxmm xmm9 + pushxmm xmm8 + pushxmm xmm7 + pushxmm xmm6 + + pushreg r15 + pushreg r14 + pushreg r13 + pushreg r12 + + pushreg rbp + pushreg rbx + pushreg rdi + pushreg rsi + + sub rsp, 10h ;allocate the singlefunction argument (must be multiple of 16) + .allocstack 10h +.endprolog + + lea rcx, [rsp+10h] ;load stack base that we are saving + call slp_save_state_asm ;pass stackpointer, return offset in eax + cmp rax, 1 + je EXIT1 + cmp rax, -1 + je EXIT2 + ;actual stack switch: + add rsp, rax + call slp_restore_state_asm + xor rax, rax ;return 0 + +EXIT: + + add rsp, 10h + popreg rsi + popreg rdi + popreg rbx + popreg rbp + + popreg r12 + popreg r13 + popreg r14 + popreg r15 + + popxmm xmm6 + popxmm xmm7 + popxmm xmm8 + popxmm xmm9 + popxmm xmm10 + popxmm xmm11 + popxmm xmm12 + popxmm xmm13 + popxmm xmm14 + popxmm xmm15 + + add rsp, 8 + ret + +EXIT1: + mov rax, 1 + jmp EXIT + +EXIT2: + sar rax, 1 + jmp EXIT + +slp_switch ENDP + +END \ No newline at end of file diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.obj b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_masm.obj new file mode 100644 index 0000000000000000000000000000000000000000..64e3e6b898ec765d4e37075f7b1635ad24c9efa2 GIT binary patch literal 1078 zcmZ{j&ubG=5XWb`DJB@*%~BA=L%=;Gk}d_~52VO$4J4q2U~MY6&1RFl{E&?scGnt@ zn(9GNy!ihFEO@PV4?T&H9`x2*oO!!jlNJZwd!P4xlX&_;U$Bg3z>p zje>}2kp+MsxE|w5hOUr>YC~(=fz6fwPdZd5+Hlb^P3{;ZO@Yuv96GG&+Gx?QfclNd zhy2KN&~>fNnlHQRR;U1cMyQ?hlQ$~k<0KBbB<0uD2#PTjVo+na7Q;#m=@=3m;xJOa zs2V#)&Db`cY;WzTF9)11;SjkVQWE!?bPTC%x3h3^F2;aBns5!i%m4&-*h69;~AUpZR%rDpm!zuXY+kc zFCz-n*^4&c)5~}y3e?r-Evy*n*(lp9r%ti58Y#l5&)rDjx5EbRd}nC+_8znRzz&#& XZ_Fi+`GM=5Rl{n4%KxAK>jC@)Nz=zi literal 0 HcmV?d00001 diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_msvc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_msvc.h new file mode 100644 index 0000000..601ea56 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x64_msvc.h @@ -0,0 +1,60 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 26-Sep-02 Christian Tismer + * again as a result of virtualized stack access, + * the compiler used less registers. Needed to + * explicit mention registers in order to get them saved. + * Thanks to Jeff Senn for pointing this out and help. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 01-Mar-02 Christian Tismer + * Initial final version after lots of iterations for i386. + */ + +/* Avoid alloca redefined warning on mingw64 */ +#ifndef alloca +#define alloca _alloca +#endif + +#define STACK_REFPLUS 1 +#define STACK_MAGIC 0 + +/* Use the generic support for an external assembly language slp_switch function. */ +#define EXTERNAL_ASM + +#ifdef SLP_EVAL +/* This always uses the external masm assembly file. */ +#endif + +/* + * further self-processing support + */ + +/* we have IsBadReadPtr available, so we can peek at objects */ +/* +#define STACKLESS_SPY + +#ifdef IMPLEMENT_STACKLESSMODULE +#include "Windows.h" +#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) + +static int IS_ON_STACK(void*p) +{ + int stackref; + intptr_t stackbase = ((intptr_t)&stackref) & 0xfffff000; + return (intptr_t)p >= stackbase && (intptr_t)p < stackbase + 0x00100000; +} + +#endif +*/ \ No newline at end of file diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_msvc.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_msvc.h new file mode 100644 index 0000000..0f3a59f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_msvc.h @@ -0,0 +1,326 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 26-Sep-02 Christian Tismer + * again as a result of virtualized stack access, + * the compiler used less registers. Needed to + * explicit mention registers in order to get them saved. + * Thanks to Jeff Senn for pointing this out and help. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for sparc + * 01-Mar-02 Christian Tismer + * Initial final version after lots of iterations for i386. + */ + +#define alloca _alloca + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +#define STACK_MAGIC 0 + +/* Some magic to quell warnings and keep slp_switch() from crashing when built + with VC90. Disable global optimizations, and the warning: frame pointer + register 'ebp' modified by inline assembly code. + + We used to just disable global optimizations ("g") but upstream stackless + Python, as well as stackman, turn off all optimizations. + +References: +https://github.com/stackless-dev/stackman/blob/dbc72fe5207a2055e658c819fdeab9731dee78b9/stackman/platforms/switch_x86_msvc.h +https://github.com/stackless-dev/stackless/blob/main-slp/Stackless/platf/switch_x86_msvc.h +*/ +#define WIN32_LEAN_AND_MEAN +#include + +#pragma optimize("", off) /* so that autos are stored on the stack */ +#pragma warning(disable:4731) +#pragma warning(disable:4733) /* disable warning about modifying FS[0] */ + +/** + * Most modern compilers and environments handle C++ exceptions without any + * special help from us. MSVC on 32-bit windows is an exception. There, C++ + * exceptions are dealt with using Windows' Structured Exception Handling + * (SEH). + * + * SEH is implemented as a singly linked list of nodes. The + * head of this list is stored in the Thread Information Block, which itself + * is pointed to from the FS register. It's the first field in the structure, + * or offset 0, so we can access it using assembly FS:[0], or the compiler + * intrinsics and field offset information from the headers (as we do below). + * Somewhat unusually, the tail of the list doesn't have prev == NULL, it has + * prev == 0xFFFFFFFF. + * + * SEH was designed for C, and traditionally uses the MSVC compiler + * intrinsincs __try{}/__except{}. It is also utilized for C++ exceptions by + * MSVC; there, every throw of a C++ exception raises a SEH error with the + * ExceptionCode 0xE06D7363; the SEH handler list is then traversed to + * deal with the exception. + * + * If the SEH list is corrupt, then when a C++ exception is thrown the program + * will abruptly exit with exit code 1. This does not use std::terminate(), so + * std::set_terminate() is useless to debug this. + * + * The SEH list is closely tied to the call stack; entering a function that + * uses __try{} or most C++ functions will push a new handler onto the front + * of the list. Returning from the function will remove the handler. Saving + * and restoring the head node of the SEH list (FS:[0]) per-greenlet is NOT + * ENOUGH to make SEH or exceptions work. + * + * Stack switching breaks SEH because the call stack no longer necessarily + * matches the SEH list. For example, given greenlet A that switches to + * greenlet B, at the moment of entering greenlet B, we will have any SEH + * handlers from greenlet A on the SEH list; greenlet B can then add its own + * handlers to the SEH list. When greenlet B switches back to greenlet A, + * greenlet B's handlers would still be on the SEH stack, but when switch() + * returns control to greenlet A, we have replaced the contents of the stack + * in memory, so all the address that greenlet B added to the SEH list are now + * invalid: part of the call stack has been unwound, but the SEH list was out + * of sync with the call stack. The net effect is that exception handling + * stops working. + * + * Thus, when switching greenlets, we need to be sure that the SEH list + * matches the effective call stack, "cutting out" any handlers that were + * pushed by the greenlet that switched out and which are no longer valid. + * + * The easiest way to do this is to capture the SEH list at the time the main + * greenlet for a thread is created, and, when initially starting a greenlet, + * start a new SEH list for it, which contains nothing but the handler + * established for the new greenlet itself, with the tail being the handlers + * for the main greenlet. If we then save and restore the SEH per-greenlet, + * they won't interfere with each others SEH lists. (No greenlet can unwind + * the call stack past the handlers established by the main greenlet). + * + * By observation, a new thread starts with three SEH handlers on the list. By + * the time we get around to creating the main greenlet, though, there can be + * many more, established by transient calls that lead to the creation of the + * main greenlet. Therefore, 3 is a magic constant telling us when to perform + * the initial slice. + * + * All of this can be debugged using a vectored exception handler, which + * operates independently of the SEH handler list, and is called first. + * Walking the SEH list at key points can also be helpful. + * + * References: + * https://en.wikipedia.org/wiki/Win32_Thread_Information_Block + * https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 + * https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement?view=msvc-160 + * https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160 + * https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling + * https://docs.microsoft.com/en-us/windows/win32/debug/using-a-vectored-exception-handler + * https://bytepointer.com/resources/pietrek_crash_course_depths_of_win32_seh.htm + */ +#define GREENLET_NEEDS_EXCEPTION_STATE_SAVED + + +typedef struct _GExceptionRegistration { + struct _GExceptionRegistration* prev; + void* handler_f; +} GExceptionRegistration; + +static void +slp_set_exception_state(const void *const seh_state) +{ + // Because the stack from from which we do this is ALSO a handler, and + // that one we want to keep, we need to relink the current SEH handler + // frame to point to this one, cutting out the middle men, as it were. + // + // Entering a try block doesn't change the SEH frame, but entering a + // function containing a try block does. + GExceptionRegistration* current_seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + current_seh_state->prev = (GExceptionRegistration*)seh_state; +} + + +static GExceptionRegistration* +x86_slp_get_third_oldest_handler() +{ + GExceptionRegistration* a = NULL; /* Closest to the top */ + GExceptionRegistration* b = NULL; /* second */ + GExceptionRegistration* c = NULL; + GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + a = b = c = seh_state; + + while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { + if ((void*)seh_state->prev < (void*)100) { + fprintf(stderr, "\tERROR: Broken SEH chain.\n"); + return NULL; + } + a = b; + b = c; + c = seh_state; + + seh_state = seh_state->prev; + } + return a ? a : (b ? b : c); +} + + +static void* +slp_get_exception_state() +{ + // XXX: There appear to be three SEH handlers on the stack already at the + // start of the thread. Is that a guarantee? Almost certainly not. Yet in + // all observed cases it has been three. This is consistent with + // faulthandler off or on, and optimizations off or on. It may not be + // consistent with other operating system versions, though: we only have + // CI on one or two versions (don't ask what there are). + // In theory we could capture the number of handlers on the chain when + // PyInit__greenlet is called: there are probably only the default + // handlers at that point (unless we're embedded and people have used + // __try/__except or a C++ handler)? + return x86_slp_get_third_oldest_handler(); +} + +static int +slp_switch(void) +{ + /* MASM syntax is typically reversed from other assemblers. + It is usually + */ + int *stackref, stsizediff; + /* store the structured exception state for this stack */ + DWORD seh_state = __readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + __asm mov stackref, esp; + /* modify EBX, ESI and EDI in order to get them preserved */ + __asm mov ebx, ebx; + __asm xchg esi, edi; + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm { + mov eax, stsizediff + add esp, eax + add ebp, eax + } + SLP_RESTORE_STATE(); + } + __writefsdword(FIELD_OFFSET(NT_TIB, ExceptionList), seh_state); + return 0; +} + +/* re-enable ebp warning and global optimizations. */ +#pragma optimize("", on) +#pragma warning(default:4731) +#pragma warning(default:4733) /* disable warning about modifying FS[0] */ + + +#endif + +/* + * further self-processing support + */ + +/* we have IsBadReadPtr available, so we can peek at objects */ +#define STACKLESS_SPY + +#ifdef GREENLET_DEBUG + +#define CANNOT_READ_MEM(p, bytes) IsBadReadPtr(p, bytes) + +static int IS_ON_STACK(void*p) +{ + int stackref; + int stackbase = ((int)&stackref) & 0xfffff000; + return (int)p >= stackbase && (int)p < stackbase + 0x00100000; +} + +static void +x86_slp_show_seh_chain() +{ + GExceptionRegistration* seh_state = (GExceptionRegistration*)__readfsdword(FIELD_OFFSET(NT_TIB, ExceptionList)); + fprintf(stderr, "====== SEH Chain ======\n"); + while (seh_state && seh_state != (GExceptionRegistration*)0xFFFFFFFF) { + fprintf(stderr, "\tSEH_chain addr: %p handler: %p prev: %p\n", + seh_state, + seh_state->handler_f, seh_state->prev); + if ((void*)seh_state->prev < (void*)100) { + fprintf(stderr, "\tERROR: Broken chain.\n"); + break; + } + seh_state = seh_state->prev; + } + fprintf(stderr, "====== End SEH Chain ======\n"); + fflush(NULL); + return; +} + +//addVectoredExceptionHandler constants: +//CALL_FIRST means call this exception handler first; +//CALL_LAST means call this exception handler last +#define CALL_FIRST 1 +#define CALL_LAST 0 + +LONG WINAPI +GreenletVectorHandler(PEXCEPTION_POINTERS ExceptionInfo) +{ + // We get one of these for every C++ exception, with code + // E06D7363 + // This is a special value that means "C++ exception from MSVC" + // https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 + // + // Install in the module init function with: + // AddVectoredExceptionHandler(CALL_FIRST, GreenletVectorHandler); + PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; + + fprintf(stderr, + "GOT VECTORED EXCEPTION:\n" + "\tExceptionCode : %p\n" + "\tExceptionFlags : %p\n" + "\tExceptionAddr : %p\n" + "\tNumberparams : %ld\n", + ExceptionRecord->ExceptionCode, + ExceptionRecord->ExceptionFlags, + ExceptionRecord->ExceptionAddress, + ExceptionRecord->NumberParameters + ); + if (ExceptionRecord->ExceptionFlags & 1) { + fprintf(stderr, "\t\tEH_NONCONTINUABLE\n" ); + } + if (ExceptionRecord->ExceptionFlags & 2) { + fprintf(stderr, "\t\tEH_UNWINDING\n" ); + } + if (ExceptionRecord->ExceptionFlags & 4) { + fprintf(stderr, "\t\tEH_EXIT_UNWIND\n" ); + } + if (ExceptionRecord->ExceptionFlags & 8) { + fprintf(stderr, "\t\tEH_STACK_INVALID\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x10) { + fprintf(stderr, "\t\tEH_NESTED_CALL\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x20) { + fprintf(stderr, "\t\tEH_TARGET_UNWIND\n" ); + } + if (ExceptionRecord->ExceptionFlags & 0x40) { + fprintf(stderr, "\t\tEH_COLLIDED_UNWIND\n" ); + } + fprintf(stderr, "\n"); + fflush(NULL); + for(DWORD i = 0; i < ExceptionRecord->NumberParameters; i++) { + fprintf(stderr, "\t\t\tParam %ld: %lX\n", i, ExceptionRecord->ExceptionInformation[i]); + } + + if (ExceptionRecord->NumberParameters == 3) { + fprintf(stderr, "\tAbout to traverse SEH chain\n"); + // C++ Exception records have 3 params. + x86_slp_show_seh_chain(); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + + + + +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_unix.h b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_unix.h new file mode 100644 index 0000000..493fa6b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/platform/switch_x86_unix.h @@ -0,0 +1,105 @@ +/* + * this is the internal transfer function. + * + * HISTORY + * 3-May-13 Ralf Schmitt + * Add support for strange GCC caller-save decisions + * (ported from switch_aarch64_gcc.h) + * 19-Aug-11 Alexey Borzenkov + * Correctly save ebp, ebx and cw + * 07-Sep-05 (py-dev mailing list discussion) + * removed 'ebx' from the register-saved. !!!! WARNING !!!! + * It means that this file can no longer be compiled statically! + * It is now only suitable as part of a dynamic library! + * 24-Nov-02 Christian Tismer + * needed to add another magic constant to insure + * that f in slp_eval_frame(PyFrameObject *f) + * STACK_REFPLUS will probably be 1 in most cases. + * gets included into the saved stack area. + * 17-Sep-02 Christian Tismer + * after virtualizing stack save/restore, the + * stack size shrunk a bit. Needed to introduce + * an adjustment STACK_MAGIC per platform. + * 15-Sep-02 Gerd Woetzel + * slightly changed framework for spark + * 31-Avr-02 Armin Rigo + * Added ebx, esi and edi register-saves. + * 01-Mar-02 Samual M. Rushing + * Ported from i386. + */ + +#define STACK_REFPLUS 1 + +#ifdef SLP_EVAL + +/* #define STACK_MAGIC 3 */ +/* the above works fine with gcc 2.96, but 2.95.3 wants this */ +#define STACK_MAGIC 0 + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +# define ATTR_NOCLONE __attribute__((noclone)) +#else +# define ATTR_NOCLONE +#endif + +static int +slp_switch(void) +{ + int err; +#ifdef _WIN32 + void *seh; +#endif + void *ebp, *ebx; + unsigned short cw; + int *stackref, stsizediff; + __asm__ volatile ("" : : : "esi", "edi"); + __asm__ volatile ("fstcw %0" : "=m" (cw)); + __asm__ volatile ("movl %%ebp, %0" : "=m" (ebp)); + __asm__ volatile ("movl %%ebx, %0" : "=m" (ebx)); +#ifdef _WIN32 + __asm__ volatile ( + "movl %%fs:0x0, %%eax\n" + "movl %%eax, %0\n" + : "=m" (seh) + : + : "eax"); +#endif + __asm__ ("movl %%esp, %0" : "=g" (stackref)); + { + SLP_SAVE_STATE(stackref, stsizediff); + __asm__ volatile ( + "addl %0, %%esp\n" + "addl %0, %%ebp\n" + : + : "r" (stsizediff) + ); + SLP_RESTORE_STATE(); + __asm__ volatile ("xorl %%eax, %%eax" : "=a" (err)); + } +#ifdef _WIN32 + __asm__ volatile ( + "movl %0, %%eax\n" + "movl %%eax, %%fs:0x0\n" + : + : "m" (seh) + : "eax"); +#endif + __asm__ volatile ("movl %0, %%ebx" : : "m" (ebx)); + __asm__ volatile ("movl %0, %%ebp" : : "m" (ebp)); + __asm__ volatile ("fldcw %0" : : "m" (cw)); + __asm__ volatile ("" : : : "esi", "edi"); + return err; +} + +#endif + +/* + * further self-processing support + */ + +/* + * if you want to add self-inspection tools, place them + * here. See the x86_msvc for the necessary defines. + * These features are highly experimental und not + * essential yet. + */ diff --git a/elitebot/lib/python3.11/site-packages/greenlet/slp_platformselect.h b/elitebot/lib/python3.11/site-packages/greenlet/slp_platformselect.h new file mode 100644 index 0000000..c959f0f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/slp_platformselect.h @@ -0,0 +1,71 @@ +/* + * Platform Selection for Stackless Python + */ +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) && defined(_MSC_VER) +# include "platform/switch_x86_msvc.h" /* MS Visual Studio on X86 */ +#elif defined(MS_WIN64) && defined(_M_X64) && defined(_MSC_VER) || defined(__MINGW64__) +# include "platform/switch_x64_msvc.h" /* MS Visual Studio on X64 */ +#elif defined(MS_WIN64) && defined(_M_ARM64) +# include "platform/switch_arm64_msvc.h" /* MS Visual Studio on ARM64 */ +#elif defined(__GNUC__) && defined(__amd64__) && defined(__ILP32__) +# include "platform/switch_x32_unix.h" /* gcc on amd64 with x32 ABI */ +#elif defined(__GNUC__) && defined(__amd64__) +# include "platform/switch_amd64_unix.h" /* gcc on amd64 */ +#elif defined(__GNUC__) && defined(__i386__) +# include "platform/switch_x86_unix.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__powerpc64__) && (defined(__linux__) || defined(__FreeBSD__)) +# include "platform/switch_ppc64_linux.h" /* gcc on PowerPC 64-bit */ +#elif defined(__GNUC__) && defined(__PPC__) && (defined(__linux__) || defined(__FreeBSD__)) +# include "platform/switch_ppc_linux.h" /* gcc on PowerPC */ +#elif defined(__GNUC__) && defined(__ppc__) && defined(__APPLE__) +# include "platform/switch_ppc_macosx.h" /* Apple MacOS X on PowerPC */ +#elif defined(__GNUC__) && defined(__powerpc64__) && defined(_AIX) +# include "platform/switch_ppc64_aix.h" /* gcc on AIX/PowerPC 64-bit */ +#elif defined(__GNUC__) && defined(_ARCH_PPC) && defined(_AIX) +# include "platform/switch_ppc_aix.h" /* gcc on AIX/PowerPC */ +#elif defined(__GNUC__) && defined(sparc) +# include "platform/switch_sparc_sun_gcc.h" /* SunOS sparc with gcc */ +#elif defined(__SUNPRO_C) && defined(sparc) && defined(sun) +# iiclude "platform/switch_sparc_sun_gcc.h" /* SunStudio on amd64 */ +#elif defined(__SUNPRO_C) && defined(__amd64__) && defined(sun) +# include "platform/switch_amd64_unix.h" /* SunStudio on amd64 */ +#elif defined(__SUNPRO_C) && defined(__i386__) && defined(sun) +# include "platform/switch_x86_unix.h" /* SunStudio on x86 */ +#elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) +# include "platform/switch_s390_unix.h" /* Linux/S390 */ +#elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) +# include "platform/switch_s390_unix.h" /* Linux/S390 zSeries (64-bit) */ +#elif defined(__GNUC__) && defined(__arm__) +# ifdef __APPLE__ +# include +# endif +# if TARGET_OS_IPHONE +# include "platform/switch_arm32_ios.h" /* iPhone OS on arm32 */ +# else +# include "platform/switch_arm32_gcc.h" /* gcc using arm32 */ +# endif +#elif defined(__GNUC__) && defined(__mips__) && defined(__linux__) +# include "platform/switch_mips_unix.h" /* Linux/MIPS */ +#elif defined(__GNUC__) && defined(__aarch64__) +# include "platform/switch_aarch64_gcc.h" /* Aarch64 ABI */ +#elif defined(__GNUC__) && defined(__mc68000__) +# include "platform/switch_m68k_gcc.h" /* gcc on m68k */ +#elif defined(__GNUC__) && defined(__csky__) +#include "platform/switch_csky_gcc.h" /* gcc on csky */ +# elif defined(__GNUC__) && defined(__riscv) +# include "platform/switch_riscv_unix.h" /* gcc on RISC-V */ +#elif defined(__GNUC__) && defined(__alpha__) +# include "platform/switch_alpha_unix.h" /* gcc on DEC Alpha */ +#elif defined(MS_WIN32) && defined(__llvm__) && defined(__aarch64__) +# include "platform/switch_aarch64_gcc.h" /* LLVM Aarch64 ABI for Windows */ +#elif defined(__GNUC__) && defined(__loongarch64) && defined(__linux__) +# include "platform/switch_loongarch64_linux.h" /* LoongArch64 */ +#endif + +#ifdef __cplusplus +}; +#endif diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/__init__.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/__init__.py new file mode 100644 index 0000000..e249e35 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/__init__.py @@ -0,0 +1,237 @@ +# -*- coding: utf-8 -*- +""" +Tests for greenlet. + +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import sys +import unittest + +from gc import collect +from gc import get_objects +from threading import active_count as active_thread_count +from time import sleep +from time import time + +import psutil + +from greenlet import greenlet as RawGreenlet +from greenlet import getcurrent + +from greenlet._greenlet import get_pending_cleanup_count +from greenlet._greenlet import get_total_main_greenlets + +from . import leakcheck + +PY312 = sys.version_info[:2] >= (3, 12) +WIN = sys.platform.startswith("win") + +class TestCaseMetaClass(type): + # wrap each test method with + # a) leak checks + def __new__(cls, classname, bases, classDict): + # pylint and pep8 fight over what this should be called (mcs or cls). + # pylint gets it right, but we can't scope disable pep8, so we go with + # its convention. + # pylint: disable=bad-mcs-classmethod-argument + check_totalrefcount = True + + # Python 3: must copy, we mutate the classDict. Interestingly enough, + # it doesn't actually error out, but under 3.6 we wind up wrapping + # and re-wrapping the same items over and over and over. + for key, value in list(classDict.items()): + if key.startswith('test') and callable(value): + classDict.pop(key) + if check_totalrefcount: + value = leakcheck.wrap_refcount(value) + classDict[key] = value + return type.__new__(cls, classname, bases, classDict) + + +class TestCase(TestCaseMetaClass( + "NewBase", + (unittest.TestCase,), + {})): + + cleanup_attempt_sleep_duration = 0.001 + cleanup_max_sleep_seconds = 1 + + def wait_for_pending_cleanups(self, + initial_active_threads=None, + initial_main_greenlets=None): + initial_active_threads = initial_active_threads or self.threads_before_test + initial_main_greenlets = initial_main_greenlets or self.main_greenlets_before_test + sleep_time = self.cleanup_attempt_sleep_duration + # NOTE: This is racy! A Python-level thread object may be dead + # and gone, but the C thread may not yet have fired its + # destructors and added to the queue. There's no particular + # way to know that's about to happen. We try to watch the + # Python threads to make sure they, at least, have gone away. + # Counting the main greenlets, which we can easily do deterministically, + # also helps. + + # Always sleep at least once to let other threads run + sleep(sleep_time) + quit_after = time() + self.cleanup_max_sleep_seconds + # TODO: We could add an API that calls us back when a particular main greenlet is deleted? + # It would have to drop the GIL + while ( + get_pending_cleanup_count() + or active_thread_count() > initial_active_threads + or (not self.expect_greenlet_leak + and get_total_main_greenlets() > initial_main_greenlets)): + sleep(sleep_time) + if time() > quit_after: + print("Time limit exceeded.") + print("Threads: Waiting for only", initial_active_threads, + "-->", active_thread_count()) + print("MGlets : Waiting for only", initial_main_greenlets, + "-->", get_total_main_greenlets()) + break + collect() + + def count_objects(self, kind=list, exact_kind=True): + # pylint:disable=unidiomatic-typecheck + # Collect the garbage. + for _ in range(3): + collect() + if exact_kind: + return sum( + 1 + for x in get_objects() + if type(x) is kind + ) + # instances + return sum( + 1 + for x in get_objects() + if isinstance(x, kind) + ) + + greenlets_before_test = 0 + threads_before_test = 0 + main_greenlets_before_test = 0 + expect_greenlet_leak = False + + def count_greenlets(self): + """ + Find all the greenlets and subclasses tracked by the GC. + """ + return self.count_objects(RawGreenlet, False) + + def setUp(self): + # Ensure the main greenlet exists, otherwise the first test + # gets a false positive leak + super().setUp() + getcurrent() + self.threads_before_test = active_thread_count() + self.main_greenlets_before_test = get_total_main_greenlets() + self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) + self.greenlets_before_test = self.count_greenlets() + + def tearDown(self): + if getattr(self, 'skipTearDown', False): + return + + self.wait_for_pending_cleanups(self.threads_before_test, self.main_greenlets_before_test) + super().tearDown() + + def get_expected_returncodes_for_aborted_process(self): + import signal + # The child should be aborted in an unusual way. On POSIX + # platforms, this is done with abort() and signal.SIGABRT, + # which is reflected in a negative return value; however, on + # Windows, even though we observe the child print "Fatal + # Python error: Aborted" and in older versions of the C + # runtime "This application has requested the Runtime to + # terminate it in an unusual way," it always has an exit code + # of 3. This is interesting because 3 is the error code for + # ERROR_PATH_NOT_FOUND; BUT: the C runtime abort() function + # also uses this code. + # + # If we link to the static C library on Windows, the error + # code changes to '0xc0000409' (hex(3221226505)), which + # apparently is STATUS_STACK_BUFFER_OVERRUN; but "What this + # means is that nowadays when you get a + # STATUS_STACK_BUFFER_OVERRUN, it doesn’t actually mean that + # there is a stack buffer overrun. It just means that the + # application decided to terminate itself with great haste." + # + # + # On windows, we've also seen '0xc0000005' (hex(3221225477)). + # That's "Access Violation" + # + # See + # https://devblogs.microsoft.com/oldnewthing/20110519-00/?p=10623 + # and + # https://docs.microsoft.com/en-us/previous-versions/k089yyh0(v=vs.140)?redirectedfrom=MSDN + # and + # https://devblogs.microsoft.com/oldnewthing/20190108-00/?p=100655 + expected_exit = ( + -signal.SIGABRT, + # But beginning on Python 3.11, the faulthandler + # that prints the C backtraces sometimes segfaults after + # reporting the exception but before printing the stack. + # This has only been seen on linux/gcc. + -signal.SIGSEGV, + ) if not WIN else ( + 3, + 0xc0000409, + 0xc0000005, + ) + return expected_exit + + def get_process_uss(self): + """ + Return the current process's USS in bytes. + + uss is available on Linux, macOS, Windows. Also known as + "Unique Set Size", this is the memory which is unique to a + process and which would be freed if the process was terminated + right now. + + If this is not supported by ``psutil``, this raises the + :exc:`unittest.SkipTest` exception. + """ + try: + return psutil.Process().memory_full_info().uss + except AttributeError as e: + raise unittest.SkipTest("uss not supported") from e + + def run_script(self, script_name, show_output=True): + import subprocess + import os + script = os.path.join( + os.path.dirname(__file__), + script_name, + ) + + try: + return subprocess.check_output([sys.executable, script], + encoding='utf-8', + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as ex: + if show_output: + print('-----') + print('Failed to run script', script) + print('~~~~~') + print(ex.output) + print('------') + raise + + + def assertScriptRaises(self, script_name, exitcodes=None): + import subprocess + with self.assertRaises(subprocess.CalledProcessError) as exc: + output = self.run_script(script_name, show_output=False) + __traceback_info__ = output + # We're going to fail the assertion if we get here, at least + # preserve the output in the traceback. + + if exitcodes is None: + exitcodes = self.get_expected_returncodes_for_aborted_process() + self.assertIn(exc.exception.returncode, exitcodes) + return exc.exception diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension.c b/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension.c new file mode 100644 index 0000000..05e81c0 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension.c @@ -0,0 +1,231 @@ +/* This is a set of functions used by test_extension_interface.py to test the + * Greenlet C API. + */ + +#include "../greenlet.h" + +#ifndef Py_RETURN_NONE +# define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + +#define TEST_MODULE_NAME "_test_extension" + +static PyObject* +test_switch(PyObject* self, PyObject* greenlet) +{ + PyObject* result = NULL; + + if (greenlet == NULL || !PyGreenlet_Check(greenlet)) { + PyErr_BadArgument(); + return NULL; + } + + result = PyGreenlet_Switch((PyGreenlet*)greenlet, NULL, NULL); + if (result == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_AssertionError, + "greenlet.switch() failed for some reason."); + } + return NULL; + } + Py_INCREF(result); + return result; +} + +static PyObject* +test_switch_kwargs(PyObject* self, PyObject* args, PyObject* kwargs) +{ + PyGreenlet* g = NULL; + PyObject* result = NULL; + + PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g); + + if (g == NULL || !PyGreenlet_Check(g)) { + PyErr_BadArgument(); + return NULL; + } + + result = PyGreenlet_Switch(g, NULL, kwargs); + if (result == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_AssertionError, + "greenlet.switch() failed for some reason."); + } + return NULL; + } + Py_XINCREF(result); + return result; +} + +static PyObject* +test_getcurrent(PyObject* self) +{ + PyGreenlet* g = PyGreenlet_GetCurrent(); + if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) { + PyErr_SetString(PyExc_AssertionError, + "getcurrent() returned an invalid greenlet"); + Py_XDECREF(g); + return NULL; + } + Py_DECREF(g); + Py_RETURN_NONE; +} + +static PyObject* +test_setparent(PyObject* self, PyObject* arg) +{ + PyGreenlet* current; + PyGreenlet* greenlet = NULL; + + if (arg == NULL || !PyGreenlet_Check(arg)) { + PyErr_BadArgument(); + return NULL; + } + if ((current = PyGreenlet_GetCurrent()) == NULL) { + return NULL; + } + greenlet = (PyGreenlet*)arg; + if (PyGreenlet_SetParent(greenlet, current)) { + Py_DECREF(current); + return NULL; + } + Py_DECREF(current); + if (PyGreenlet_Switch(greenlet, NULL, NULL) == NULL) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject* +test_new_greenlet(PyObject* self, PyObject* callable) +{ + PyObject* result = NULL; + PyGreenlet* greenlet = PyGreenlet_New(callable, NULL); + + if (!greenlet) { + return NULL; + } + + result = PyGreenlet_Switch(greenlet, NULL, NULL); + Py_CLEAR(greenlet); + if (result == NULL) { + return NULL; + } + + Py_INCREF(result); + return result; +} + +static PyObject* +test_raise_dead_greenlet(PyObject* self) +{ + PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception."); + return NULL; +} + +static PyObject* +test_raise_greenlet_error(PyObject* self) +{ + PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception"); + return NULL; +} + +static PyObject* +test_throw(PyObject* self, PyGreenlet* g) +{ + const char msg[] = "take that sucka!"; + PyObject* msg_obj = Py_BuildValue("s", msg); + PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL); + Py_DECREF(msg_obj); + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject* +test_throw_exact(PyObject* self, PyObject* args) +{ + PyGreenlet* g = NULL; + PyObject* typ = NULL; + PyObject* val = NULL; + PyObject* tb = NULL; + + if (!PyArg_ParseTuple(args, "OOOO:throw", &g, &typ, &val, &tb)) { + return NULL; + } + + PyGreenlet_Throw(g, typ, val, tb); + if (PyErr_Occurred()) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_switch", + (PyCFunction)test_switch, + METH_O, + "Switch to the provided greenlet sending provided arguments, and \n" + "return the results."}, + {"test_switch_kwargs", + (PyCFunction)test_switch_kwargs, + METH_VARARGS | METH_KEYWORDS, + "Switch to the provided greenlet sending the provided keyword args."}, + {"test_getcurrent", + (PyCFunction)test_getcurrent, + METH_NOARGS, + "Test PyGreenlet_GetCurrent()"}, + {"test_setparent", + (PyCFunction)test_setparent, + METH_O, + "Se the parent of the provided greenlet and switch to it."}, + {"test_new_greenlet", + (PyCFunction)test_new_greenlet, + METH_O, + "Test PyGreenlet_New()"}, + {"test_raise_dead_greenlet", + (PyCFunction)test_raise_dead_greenlet, + METH_NOARGS, + "Just raise greenlet.GreenletExit"}, + {"test_raise_greenlet_error", + (PyCFunction)test_raise_greenlet_error, + METH_NOARGS, + "Just raise greenlet.error"}, + {"test_throw", + (PyCFunction)test_throw, + METH_O, + "Throw a ValueError at the provided greenlet"}, + {"test_throw_exact", + (PyCFunction)test_throw_exact, + METH_VARARGS, + "Throw exactly the arguments given at the provided greenlet"}, + {NULL, NULL, 0, NULL} +}; + + +#define INITERROR return NULL + +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, + TEST_MODULE_NAME, + NULL, + 0, + test_methods, + NULL, + NULL, + NULL, + NULL}; + +PyMODINIT_FUNC +PyInit__test_extension(void) +{ + PyObject* module = NULL; + module = PyModule_Create(&moduledef); + + if (module == NULL) { + return NULL; + } + + PyGreenlet_Import(); + return module; +} diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so b/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension.cpython-311-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..2c7fff0092af03980a310ee1dfe048e679d8f7a5 GIT binary patch literal 36624 zcmeHwdwdkt+5ef@OxPjGW^;oes0#)RD!FjcfC9@Uuv~-)L4#VCO?H#4CfRj&1HmhT zC`fIwRqNZ=s_pw~sr7BGZ7phR5$|nPw5_+=N-wtI)mp6gwy*hppXZ#jnM^j8_x-$| z&-?p>f!TA;b3e~{&SmDzOs;HPxx_RKp%0IkCk9JG1Qo)6jiw-2gRt>iB~D=4yg}5k zTynGo=~Vb-nRHl`Rb_Yj)qF{(Q;jD+))$a?;YyoXs1Q1J@{!1c(j2YraH1n4!2dV`{CF6aOAgr^ z!0A4203a9r%Ok*_9s%wfLGRWP==Y8Q|F;p~7molx1@Hh)_pt)jSEYj7LXcJAF8&j$9+E`|7CKd1LK)HEyG8SHzUfbK6L5_)6K?m@? zZ5c(sFcMvm>ger`^)RHbExaI|j-@j3L=VIzQXm69+!RTrW6ixu7$^0tZfomJrD9PO z!wY-kUD2~6UA>Hi2+nKvWj%4!Hxo-|!m++gtS1f8;5suA?d^(%7o}p6Ol&#;iz3N1 zL6&tV6RC{oink^+oxnzG(utZnDz{PYRIzmBvW1Jn(`%;J%z|%?PyJ^CD-WUzI%25z zn7B>7ZMh=QEnvttMD4W zj|LAMl`i<+i4q=g!FvM|UhRSlC8xm!_p4wIy5KvMoRAA%S0?4RxZt-a`VB7l_Z7U; z1>aCA<@CAWEy|uPF8E_g&JGuRw`!MLT<{ka{T(j&TME9%1+P=~>~+C!QTFU}!L5nX z{-<1U3<7+-?1CS!=nuN!vlYDG1wT+B<$UCV?^E`Og%YphWU-Rtb-{y5PNfTeSjl;6 zzLZ0Ajv=%Bd%ywLb0;BQcEE{89|s-q0u4mk?|>IM;D;UXVh8*q2i!S-R0bu{C?uwX zKHz}U9IKD&pv)1yTIw*M&H*Q!J{p2DM=m1&ASbb!k*P?@H(L;JY=6Drdb zcIaL%@24_Ny@&4L@`F^SsqD~hF5gFGnt~5);qu*7rs?QVlFMJCGEHTNHgNgNRHiBH zP!r0b>*vPnQIG4bR!U}nl&L_~ep4f>W)B=JK7I>m#iJ?({cNV6HJy^FpM-WE4n6Yr z{LmvGc|yh$q31uzltaMdN`QCZV0-cLiwF71e_Q6hUk8!BC$9@_oBK6TiqOtCGKCQR zIb3e_uZLOvQT#k%Jp(%9GtiyYPyB~A0jca+7uxw@{ReARliUURfu>4ol_jB_kA`+W z30rOeu>OVm4+fg*LfcL@LOUPNj0k`9kTxY7iBFa z*zVBIzw}oF^yXfP*K&J*MHn9wzxn*2!yvZ=+SZbZ+xHb;eIr#0Ewjt|8-<9oQfGk~ zrc48l8QTIN)M!w3(u@H{e3HVB|+5%l_553+9?`oH`SL^W|tsNZ)ULg4lO zK7#DBCMxbX_ffk5z5($1eQ&->{SZp#eG~jkPX_<>vksDFyBhj;OVURjHQ2p2 zwEct3LeO4Hx?ExP92j8A2|%9@v^zxD^IGp(7EU&8L6eI9HisQQK8fvUQFeHx9Y1G3 zZ+oj+`tLB7%jh!ft)0JHiL^5GWL^~s%ldNV^^2?gRPt+ZC1v`@NJHnq(C<>K?IPw~ z&7j?tA?Ke_HPBSuf8cM@HDw^HB9o*etI3btS*su2y$++!w_r(V=lk{hsP9#`7bmPG z6azc|_yj2~o|;$H-wRRoPb0)->^?D-@UK#T+-23n0;uDdtL{IKlCz8dO01x)Dei%3wX|hf-evW4DQhe zBAMLEm_^caGj(ldx~yXY9r2B^o=;~NnaD*{Gw4Y7wp|pNXpHxq9))Du8#?&bz`z!y zO>Ykj>_NH@=`WBTM*0@gz+VOi@^Gi@Fw!%S?mIj%umS0ocLoNoMk@XaKBT*mK7};! z?!dr%1jkV>6JcDkMi_m5V|?K#?{47e`f>u!7U;g0Xng)9zRKmr1)IEE#QbAUKWRqQ zBm!6CT#WOMKMxF$y<&mSe~k&!ZJx!xz$K%7m5Y7;1wQW*RD^UTasC0c%na0Ld|rm{ z0Q?^=_)Ng=z*&xZK7mxqUZ7-~S3x+mLHN>w71{iv0ucZyJvVU=`1T_eA)kMnX|5XW z^DZw4<9C6i`3F!f@Y(l>29ma!XZZqVd^F2kENKGp#e1N+EK74G1cVAg{40I57&J}r z`R9pdv9HeD0_5U?C8!$vCki~Z$yO!f8uLt9hoE_W*6vV&plf#aJ=%@xE^SJYn4`y0 z4;=NtQ4bvTz)=qz^}taN{GWS3KlkT;&JRl+KI&9PmxC%(s4eH63L&t8z{id1InZ&c zte-O+ugZE2bc`zN=M8C%N{7b3|H(jt${S4j9ekFlAy1a|Ggvzm9$OlGoUQDm^)?;6 ze}a@YnE43GM6rp(vY1^z(?&8KV`UHR8wLZxo` zx~%=B%Oj=h10!G-i~v7Ea9qjVM;ARfbi3>4PSE`TUx$){xU0nlHkLdC{z7>rpD{%GWBzq`ngLjUq5fD zpRd%8pbU~FdBT_F8s2I^{E*kyN{TM}?i$;%4x2iEJ7me1jvqV-Y7mb#q)Bh=r zwsric*sN{+slma8zo7_oF`CywsOQD8 zvmwCa9d$hh$-F!(j$3FRuN4F%lG7MHvz@p?zmU~X=QpZX7c+r1_Pdq>Um4gh7ZMzD-J)ea&rY?^6CoyLVcsCfy+(L`m2iLY?N7!Z3Y z-)S%R{tF8Bt;DvXe4dZeb1<{mD~r!ZzS^c&QtUIiP-o9X&Fxh_GN!@qCfe2hpJUz& z+J8dz?52w45D>C|3M=ii{Lcc`WWPdWYYHBNoECe4l&vlN7?=&hTn2I8qKS8sIh6O? zXLz3>iYtg`uBuH61ByMb;5xv(!mNgDuW!OD#6$VO=u^Gp;WYa}$Q*rIDOoM-$ABK) zQ1S+B^V+`zdi3m)AP|1r3!c%ZGg+lDw*lrYo^T>4yp*plDDZA1X+MIrg2ED(R)9N| zqM)eoLR8LMkfwsKa3c!-f@q>m6cjUAr5%9i0zVrX5M~86kAK2eNGqhgN%NeywDOCj zs}FVZn^EsWr0Y58GTZ&+Rbju4wl_Pu&?IAaU{Fi-h~12vbIe1)Y_LCuafNqPK7vB0 z{ZrEO^|4Q)khG^z;hVla;OVpPLsbj!Dft&zwZ%RFuN3|VOWR?8kMw-2bUny++dJT% z!f%)EM&TCw0;=47<PgHoil%DlIXqQrbepX7s-EVJ%!wa7& zeFcTX_Bz5mTlzW*ANlghf&<)I!ti~KD)fBu05!DXn@^^`P+AC}-|+1wi+)~OiBhHE zyOAh=A=}9CT|_qh(pLpwwc#5@=Dt{b9!hnF?{4CIsi+R62E(_XWWMa9{u4BOXOWaw zxRxQq_ZPyw%G#R@-zOyHS6pf_e795GUgOdR!#9`d;T4 z=`(zPrTYD@v={E)V)$?)Q561xaXSoOlr+3i?gs;I^%XZ2mD^PFg4W)4QB=X*Kolfe zFBC;%Sh%;KE7l{5#&WIw_O%dQRLO-(dp{Hu9b*TP1ni%nB1Pl5P-Sl-%!GnlkW|~> zg36*}OGbmW&R$NKjfN<`ZM?WU6m!Dhk>`Dne98uJbld`JXT*L)bQ2<{>YPgj%zVtFg^%Ql~)2}*eQF~5nfVE)wCz*O^yiu9Z_ zgh~nA4JGC?zBVR}YtpS*Qu2f%y&OREx#G_;>5ZCn&k#~!o(l%^K=JpOiiUI6O&yxW zlw1c(gn2nR?fK$Ynd+dXq8=fsSgIr~0nq$~-$I=%ZvlQwY3NgOent-arGFA5X(lP9 z(N7t?myj=3%x7dHe%V24lpfg{ppjI|-AdZ)dFJ_KS#1RAujbMWuO8DoA z_myIDoOuHX%vUQYlFZ*A>daqNe2+yuNFsg&N*cBlV}$g*R`E+F_!SY5k7@LhI@sf+ z7VSc<{c9e>FHxcjeD$anTE$>47vKktXN@!Xd z)Fn(G$@zUn2a|Sd(yOwh98_gfi0T@140Wq=D~~KR|K0T63$ltT_)UzN0u!&S_$j)# zA;vBwSMD)Ap99`}2Zh2@i=Rf`@;--O_G>>f(hkm%M4ta5ll>hs=S&veV!w`HC|t#b4ff@bS-6@Do%SKZG;twm zx09h~aiPzCj4*3h+7|mRv_#=r9y@o~4-uxBF}v+L;yIgnZn1X|**RRe!>%LSTDY*s z?jo}FT)5X>0~ZyZ%Qf9=&nF+8$C!QgLsYr*x$uiW65h!;Ov*13TbxUk zhA=0R85eq%z@f!Wgckc%A`|c`j9OOXV1>T`cbe{Q9X6 z&O$~;J`W&N1e)^2fx@l!W|ZwusCwJji^6_`OubsV)Lu`jw{yX7R}bi)+ z^jgp9C>8q)ciP_|NnfF=U041iC>C}-QS7RG8wIR(4-)FLp6wvByrkChQirp=)DV`J zs%?2mh{cx)7BAH;UjCaG!yTi`cr5nPR9@Fp9|gv)DQ=*}yZsWh z+O>Q&Q)$!94ZE(0Y8?>cD6zc6Z}PgJ-t!KtrHduYdp5BX30)CL&s_(0VSb2sD)3e` z5#Mc4RbUryMc(r6AdVnNzMADAemNB#;|H5>Z6!gDSq$I$GMx8%psl)ijQ{Uo;(8R1 zwPZbh0^!A#ysYxuccLD};#gW(+hY9vkZ;^sege~q1w;u6&q9Ln{CK*2v^`sb3>3$e0&3xA1-P%kV5St4Y5?K%%T3}%XD0m%;vqfUsaX$&aF7g@O>N`yG+-+(v1IDxD=X)Rgy#ZxGMa)&T(Dj|xK z@t(ghZsxW>8Bfg!<4ZE1X%)sToJGwjex}}yC^4>)!k1))Uo(aTo&tf_RI|YDH1a$A zL^17A#FDX7N|_LcEoTGDA>tP`Z6xnXmM2POJtoOS7`N^LVJ%yK??JK2L0|CW{5S49%<0`b>yR&LQK%b_2jEez}ndreJJ-346P-M4sM6TDEH$; zD+=)lESmfhN=A=GLe_wH70&un+?aVB^`HZACYT-o@Uy_uouBG{g{4k{5HZt4HDek` zex@*n&aeQIk+$B0!s(}j=rPFHk5kONQ<3{nNeJ@1Yc$I!oAt25Nbw9j(Kw6Z@6_9= z;w#u)8Pnb&aEf5pL*$2>O|PX88w9vE$~C+A$J%m~BvqJf&q58u&Y z-hm%uy`3N>)Lhlzn1ZupG^4iM}4*4>(QHP}`Vt2YPhj2~i8=w;2S zGvqfqj1AU*LCopTg6Iqi2~FV98BJ+kXj-RJJRlJ6RpQ2?`La!J!qAyNSD0B&j8P|p zVb1#sOC!2C^=5d{m@B)cGJHRY$6?$W!cLKljJe|}3U=b$j&m;JVm`O`&rsTrliPcp z5&%~G500(Eu*mH_7gNURIJv!Bk=cNg+gr1kv=>M1J%)Iwz3DE(cH*J-z6Y7RadLZW zo;>DJ?fpEk&*2nePFR^S*xnfhF*cB4ORO*{q4xd=9Pi<*-m55dd#53&fg0@+g)ng^ zL>No0FN2jEY92L|#^&uK^9LKJ;We<{rM1!+Vl1*hCawPo#7xYBH8|%{ENZGeT7{eE znl>9oE5|EvRv*Y=n3$PV&>}RD8cn8XK{NoL!f*`2EfdKlII7=PEZOlnixM?-9c)x_ z5a`Xq?@2ZU!Mt%g2&#^wAowB7+KaQ6=dG$5g8d!k_X&0uOPWWp)yOWzIUm6?g@eVs zp;HdGC-QK6Kak(T$+5Ex9e|GwaD#F3*bUg+R$Ie`2X46Syg=R5#ljjgS zYlw$pXCp{5#6z+3ugLrhPL3VTlgB(NcJ=}LFiynI*~$!#of#jZvC;}+=nOgxA4Y@q zC@Hj{;|*~C9w+zSEMYdIILs!rF7@8gqp>Q+iNU5`iT?#!?Jp2FIHcR2(*u(6L}LwH zCua62S}$5e5AQUQ%-OCG)TQU#qzbgas=ikhvaP;D2ZX4(8l#Hg<5t%@fR{;yXmyHx z+4X&6sWt0i?lhdWJlOkABv=aN3vtRu^>d@Xg7Wh?xlvzI+6CQ&FiMY`1)(#gPQQ_S~g}eEx7fz>*t}B4&&BO zCcyO%0yPd7gcUfa(-u0tdb$Q@;|nO5H#9ZA#%W7qKc^cS-{Z7%1_}MXa(OnxAwbf< zXxyj8-vw#^uEjr#%+GKxA@NH{_7W1jgrqK|ZlFb)I+GRoHEVFr*2p}a(NvCUK}@+$ znMd9IFwAjw_jv*G0>REgExFUToM^O|H*7f3SWg4MoO>O?B|`aF@9C}Wt&$Z!oIV!d zk5HfYsDdY;FdG-R^*9@+p2>4ob%%hGN4u=vKd`%T#-~_f0oTT0hcKgak4opkXeRv37NBmY+)~JL8i`R1%2M( zWsS_!8BI0B%YRpXqASn2Faln-J=X-Nid1NZ6U0ni>GLH4R!-#jG=A4$%{*tasu*=- zIHkmx>?i23A?jZB{X$gwCHL zC>cd%4E|+?$5&7wxedVWB8RXBP>eo}=?eh&Y9$0OECb;gm;j1cgf%F_H$((FZgH96 zRN=2MP8_$ajI@@#dBZ};s@4cxpVy$RWiyev0rurdmZQCKwGY|ZX2zHbtfM&1sToVh zp#p~(S?iQ*N+atEjCEtFlJ&>J(ly53g$3)zwiK){I0s&yZi)IbMK~jiCz+Ch_-4w= zP-a}Kv}JVd7+a=QY=!=RTPVBV50QCs(9l}awZfkp$rDL ztTBTQ#n$^EA3_U*A#=&L67+b1f_X4$GSl zME*6FFWAAJ3W8M-?|kDzvlqMJ!Ad~qd-t%Su4DO{Pjee@7d^u z=HcKb2A7qC$Y*&kw8qi><=qhNql{=dOgQ z5^yXfo*rFh1_MtA5)=cpRn=lmq}r5wp1FcNlCjF+GCXc$<)2rEY8khoKo#^n;vvs? zJwIm8O$V&p^MLdk$Sm*jcA(+7$543&cuPqL=*D?=5ULyuSCM7PiT4oo`@+aKfHgcH zTxzrg$dSp+ddm-qhNrlOH0MLj?)<+}O@DluY^@(U^@5@U68!m|y_ao;`#fDQl7lNq zMB1vD2sLxLCC5^&AB0Hh(#Hjb0s}n{UAY`^<-2;y_gO~LvQ}9o7enI> z<@sClH(CW094+i;vjsxP`KIU9tn*FJU0LUw`JP`X=bJK^u_La682}1qQwOt2t%Zv( z4rWsY^BFRleV%V{G(SikAEsiObg5@CKrtJJVCbolObU*jP-l^(5X+&_e9Z^ z)ga|ZWK5%W zyo5}%rD?AmfoXSMhS3VL;kN5M)WZzVqnCR#Fj3AzzDY2^J5SFb`7c_P7+bjlWy?)` zrrD^?bSG7&xwrHkkew@pbIf=Jwv6Hcam+ zyycx1J*`;pB)cMQv2Zf6DMnwlX6A4Pg5^w|7I<;IJCYIUt^|Dw8}HBKTiT0b?E=f4 zNG6j?u*B|gYa|^5tgD?Yz-#gR@ok5KK72HrK3kpW>4LqjwF-xNp4i4D;7zS zInb1f_l3Lh9(g=Tg!FyvT(8>W``hWwJ#A<5assdYC&N7v)V^u`(#BQcHI2>d)~ph( z?cr1mlG8D{h=BQP@jCk&eodWx){V6oG;D$rWs)Lblp#I%DmulRdRJedR*_8+*(TX9 zyAS^^yTkDIu0$dgj>hSW27=MOWEVvNwF@M5rxIclJckfScg5RSy6&aUPu`P(y{&Cs5qz>f4HKKOCST2~dlVXn zeuy5lP(aa!sw`V8YbclPXfSy#L@3oUDEich(U$0G!??gb6e9EoH{jo%SVx5Y%f6;@ z#nCFMbZ5LhgG&$?r5p=vq&1!BLSN)&<~StJE^d^b<#pw_TK=^pkie|$e* zjwyOvKv$qY2rwA36sh_v`xwQ-YiU^97)L;G`^#?Z{Q5unJ=WcdA%JQz*cqBOE0?kZ zhI}<7$5of>D<-(&l0L?z68!-J9p(JR6Yi++DE9_xSA2D34d}YV^dLR#;h~oM0FyYJ zOT!5<4E{NT?xdrG6Th?a3u(;mRwJjXPne=*QD>~}B9Jaxg6V?4;6iPLF$LOb^kJu> z_3$4X+w3`n5QV9VPlTS1Q5wN@ly=KumBzVLter7fJf%@XQwPT1jBxw~3rLdq)B?% z-;dyEm0wEHpUjc{DT6_tbmjcJ6d<7%rKT6*aGE@VH9{(uRI?g&P&9bfqfFrl4%u=T zE!cOoy2wte42j12xOd610U%l}&}=Qcyzb4kz_|pm4OCc-4OCg`owBm4dMU5Tv(r;s zr(9j=p{q;kL36~@;SQ{aFkQ+R8C-7Yy9??AKH6R#0SH(0U~1uL9J8;SuvN+VO&_kF zTw-zmp_@x;6$WZ70^kdpUHb&yeG4qAKkW!!e+x|O&h+-g=61w-Vwhb}jHKE+=i)xo zv{PpWrga3St)3yz_D!isa${gxd(*N-0?i}sOzS0yT)V*zx&GprsynHB3uc-g_9xX+ z&3NQ_-TYKrT2l~?)>`OSgUcrjh}5FW)3SSH+k*yS$4r7a!e2Xq=!JZ*rwOZ_G<6S} zB1j0WURYTdC4=*GSh?NdW9Lxf01vJw(F65giGhh+)o7xZ{<@4~U?iojxTEK2NcBY~ zNB5x`D9b@UI1*6jz@W&Yd$Wxl@42`)p5m1+bsK5{8l9L5H_G@ppmt8_$x%8?QFpt} zf2d%FXwq4FEQbz5tkqflb|0uDZs>1P6|YgLA=c^a7ZfN@ylbqxeJGnO-JyW@s}#&S zyI+AuW>y4r6Oj)v>ugkk{y8&tezNS%I;*$EAyH?Y5}SwBg}tp^&hlm{spM~+KP{`N zNoN;iL1(W}*>kd>CY?Pu3p!inoJn3DG^-soablLVNoTcsw5iT&wPc;vtCbMUDW38s zG`M*o&dmyto0H;6bLvVT8K)u6P{OpehR9WYaX^v%S*2(-oxK_Npy~MZIM4zPOJW3n zv(C0C0Weu-=?O$SNM`fxx}-JbaDgPpBe9C{n5@huou$9@MF%wN?D{O|?BP0w`N1Rq zOdfc2W&Dbtnp5X>6&$rWSCPru=u*tVJY4&*M#f&bv|oIzQdC6c9Em2vZF4?y_{z-J zL^{nODHqW&oAPo<8b)M_OO!2x?KjM~L{Y8Cre{shwu+W8LUi7tIPT7JuG868HDY{v zbPDlJ#rkkoM3c^bkOi&%P-Tx(QsLcz$}S!R>Fnw(sL9bnD*Lz+^=wvpj@HyfuV#sc zyEk7G=`?3+YNSqc#6?~XNyF5UA%9TT{O6!m+6(lG1RXiV6R{!2C<2EEXDN_&8+b2J zAl-Vo#!H%qj!YUEyp-#+y5pSK+v1}bo@r8ltDth4lP0Ud~E zopnkaKDZd>WTmn0Q#I$N8!nHO2bH9dN@0x7?*CLJ#7u`4@R_WDW}Uq^3p!h8zvGbE ze7i1bO(QG`@GOL4qZi`oz+k1b-_C;84i}fB*@d`HaqRx@ahkU)`ny${yV;FlbUA8; z=Rf$Eu2T1kUq|8wg?A^16hN=r_2TanH=!zzM6dbWZ1gq}9aB`gMWtU*sl*Qcx|e%N z7vCVI%<1LWenqEOGCvzkO0W6c^zJUY zS9Li(P`K$oy-baoC*B!wQ{jPPVd87g`a4n@k4Ih^POlj{kBJH%biwI59bW?w!G)4q z2k|0?mk9mcJc-3S2FQ@!EiO45ncgq-clb2@O~~Z3|LaPQexfR>7#=`M_UKn<@dzFt zPve*Ly5EBQy@I>nW&DSNyI--R3v-gAzmv9~rQ@|*1$V!5Q={PSw=(7^xckBR6$0j`eM;EnaPIy zD)ir1*6`0UyiB;i$M+?`@nUfH@4;(&y1u1)>G;v``x#y#L{LLy${z%wumAXm!e0P= zuD|bn2=KsAQZ8BMFcAzd838_V1o-q3;EMpyrI%hab(zk3qa(mmBf#lZ*IaVGFarFm zBf#$)0siC&@RtG4Rj%cQ7u@q!c z`!@44540z|SUr;C-c20#M8L2u!*IBx8#}P+OeBTBSP%WQ9qHU6hxDO;>mK;kZS3Y~ zc3UO;C+%Gu)Oe6*=r*P_XaSyGNYTzSl<{65ZA*ujrPpG|m9~Yry16SGZtII=cX@(K zS1wz)C`_M}#6q_wy}3IRX+@ez$+T1FdJ>sfO-D~}4L@NuEgltI;%BL9qMLibDLBQJ z9b?qa^pHXrI6PDmAwrc);)$6WZn&BZJa=L38zSMzUB8J%i=y=c_y6fK|u8LU>a`su?1bm;V6%xiRzUdn2Iys*GW z5Wgf_>(}2S)+wzgoQJC@LO{~DfHgmT7m*H~y6x9=I$Z}^`nIqx>+cKeG(f^|xb2rv zA)*SW`RThTbm&xn&)DrhUH=}?lI(@VgkuYq49-+v{SiM_8N>Y72N?N8Z}Vj*TQ%uY zd^iu%>)^1&<{amWQ<`14AF*=QELY2Dp-vPLje~;qVDSZ#odFc4pu)C3= zYZ)CM`nuxaG)dv6*JYjF4>EdNQ1k2SnEoT=-w$3gQS<9{^5K8N4;DV2!!O02=GW`# zj}-p_Re$X_ZMTktm%;1Q|I~aIE1s&AX@g9%znWjCzXrz1FM^7+PNtozs1wbn(?0^? zNHqrej1;hhc-v2 ze*==ne|AJ$gi*U^ND8-IZd%&fb;F2rpW?p=Z@M}UH|@zI z@SnU!a>ZQ+yZL92z<;CK@_f$aa5sOW;&<1xEiCoFLX(^0(EK`WQv41Q&Yp3Rg!EA7 zb{v{dgU%a)|L)C_Lf^92^lpACn;Pj%FPDW|l>a877{ICBq30i(ZglJ-n>}v1N@j~( XNVk5vJ>nu^#yhW;{Bak9t0?{-OR33R literal 0 HcmV?d00001 diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp b/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp new file mode 100644 index 0000000..5cbe6a7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpp @@ -0,0 +1,226 @@ +/* This is a set of functions used to test C++ exceptions are not + * broken during greenlet switches + */ + +#include "../greenlet.h" +#include "../greenlet_compiler_compat.hpp" +#include +#include + +struct exception_t { + int depth; + exception_t(int depth) : depth(depth) {} +}; + +/* Functions are called via pointers to prevent inlining */ +static void (*p_test_exception_throw_nonstd)(int depth); +static void (*p_test_exception_throw_std)(); +static PyObject* (*p_test_exception_switch_recurse)(int depth, int left); + +static void +test_exception_throw_nonstd(int depth) +{ + throw exception_t(depth); +} + +static void +test_exception_throw_std() +{ + throw std::runtime_error("Thrown from an extension."); +} + +static PyObject* +test_exception_switch_recurse(int depth, int left) +{ + if (left > 0) { + return p_test_exception_switch_recurse(depth, left - 1); + } + + PyObject* result = NULL; + PyGreenlet* self = PyGreenlet_GetCurrent(); + if (self == NULL) + return NULL; + + try { + if (PyGreenlet_Switch(PyGreenlet_GET_PARENT(self), NULL, NULL) == NULL) { + Py_DECREF(self); + return NULL; + } + p_test_exception_throw_nonstd(depth); + PyErr_SetString(PyExc_RuntimeError, + "throwing C++ exception didn't work"); + } + catch (const exception_t& e) { + if (e.depth != depth) + PyErr_SetString(PyExc_AssertionError, "depth mismatch"); + else + result = PyLong_FromLong(depth); + } + catch (...) { + PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception"); + } + + Py_DECREF(self); + return result; +} + +/* test_exception_switch(int depth) + * - recurses depth times + * - switches to parent inside try/catch block + * - throws an exception that (expected to be caught in the same function) + * - verifies depth matches (exceptions shouldn't be caught in other greenlets) + */ +static PyObject* +test_exception_switch(PyObject* UNUSED(self), PyObject* args) +{ + int depth; + if (!PyArg_ParseTuple(args, "i", &depth)) + return NULL; + return p_test_exception_switch_recurse(depth, depth); +} + + +static PyObject* +py_test_exception_throw_nonstd(PyObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + p_test_exception_throw_nonstd(0); + PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); + return NULL; +} + +static PyObject* +py_test_exception_throw_std(PyObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + p_test_exception_throw_std(); + PyErr_SetString(PyExc_AssertionError, "unreachable code running after throw"); + return NULL; +} + +static PyObject* +py_test_call(PyObject* self, PyObject* arg) +{ + PyObject* noargs = PyTuple_New(0); + PyObject* ret = PyObject_Call(arg, noargs, nullptr); + Py_DECREF(noargs); + return ret; +} + + + +/* test_exception_switch_and_do_in_g2(g2func) + * - creates new greenlet g2 to run g2func + * - switches to g2 inside try/catch block + * - verifies that no exception has been caught + * + * it is used together with test_exception_throw to verify that unhandled + * exceptions thrown in one greenlet do not propagate to other greenlet nor + * segfault the process. + */ +static PyObject* +test_exception_switch_and_do_in_g2(PyObject* self, PyObject* args) +{ + PyObject* g2func = NULL; + PyObject* result = NULL; + + if (!PyArg_ParseTuple(args, "O", &g2func)) + return NULL; + PyGreenlet* g2 = PyGreenlet_New(g2func, NULL); + if (!g2) { + return NULL; + } + + try { + result = PyGreenlet_Switch(g2, NULL, NULL); + if (!result) { + return NULL; + } + } + catch (const exception_t& e) { + /* if we are here the memory can be already corrupted and the program + * might crash before below py-level exception might become printed. + * -> print something to stderr to make it clear that we had entered + * this catch block. + * See comments in inner_bootstrap() + */ +#if defined(WIN32) || defined(_WIN32) + fprintf(stderr, "C++ exception unexpectedly caught in g1\n"); + PyErr_SetString(PyExc_AssertionError, "C++ exception unexpectedly caught in g1"); + Py_XDECREF(result); + return NULL; +#else + throw; +#endif + } + + Py_XDECREF(result); + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_exception_switch", + (PyCFunction)&test_exception_switch, + METH_VARARGS, + "Switches to parent twice, to test exception handling and greenlet " + "switching."}, + {"test_exception_switch_and_do_in_g2", + (PyCFunction)&test_exception_switch_and_do_in_g2, + METH_VARARGS, + "Creates new greenlet g2 to run g2func and switches to it inside try/catch " + "block. Used together with test_exception_throw to verify that unhandled " + "C++ exceptions thrown in a greenlet doe not corrupt memory."}, + {"test_exception_throw_nonstd", + (PyCFunction)&py_test_exception_throw_nonstd, + METH_VARARGS, + "Throws non-standard C++ exception. Calling this function directly should abort the process." + }, + {"test_exception_throw_std", + (PyCFunction)&py_test_exception_throw_std, + METH_VARARGS, + "Throws standard C++ exception. Calling this function directly should abort the process." + }, + {"test_call", + (PyCFunction)&py_test_call, + METH_O, + "Call the given callable. Unlike calling it directly, this creates a " + "new C-level stack frame, which may be helpful in testing." + }, + {NULL, NULL, 0, NULL} +}; + + +static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, + "greenlet.tests._test_extension_cpp", + NULL, + 0, + test_methods, + NULL, + NULL, + NULL, + NULL}; + +PyMODINIT_FUNC +PyInit__test_extension_cpp(void) +{ + PyObject* module = NULL; + + module = PyModule_Create(&moduledef); + + if (module == NULL) { + return NULL; + } + + PyGreenlet_Import(); + if (_PyGreenlet_API == NULL) { + return NULL; + } + + p_test_exception_throw_nonstd = test_exception_throw_nonstd; + p_test_exception_throw_std = test_exception_throw_std; + p_test_exception_switch_recurse = test_exception_switch_recurse; + + return module; +} diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so b/elitebot/lib/python3.11/site-packages/greenlet/tests/_test_extension_cpp.cpython-311-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..714dfa89743185a26036846f6615d63061f5cf82 GIT binary patch literal 57288 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 literal 0 HcmV?d00001 diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py new file mode 100644 index 0000000..6dd1492 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_clearing_run_switches.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +""" +If we have a run callable passed to the constructor or set as an +attribute, but we don't actually use that (because ``__getattribute__`` +or the like interferes), then when we clear callable before beginning +to run, there's an opportunity for Python code to run. + +""" +import greenlet + +g = None +main = greenlet.getcurrent() + +results = [] + +class RunCallable: + + def __del__(self): + results.append(('RunCallable', '__del__')) + main.switch('from RunCallable') + + +class G(greenlet.greenlet): + + def __getattribute__(self, name): + if name == 'run': + results.append(('G.__getattribute__', 'run')) + return run_func + return object.__getattribute__(self, name) + + +def run_func(): + results.append(('run_func', 'enter')) + + +g = G(RunCallable()) +# Try to start G. It will get to the point where it deletes +# its run callable C++ variable in inner_bootstrap. That triggers +# the __del__ method, which switches back to main before g +# actually even starts running. +x = g.switch() +results.append(('main: g.switch()', x)) +# In the C++ code, this results in g->g_switch() appearing to return, even though +# it has yet to run. +print('In main with', x, flush=True) +g.switch() +print('RESULTS', results) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py new file mode 100644 index 0000000..fa4dc2e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_cpp_exception.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +""" +Helper for testing a C++ exception throw aborts the process. + +Takes one argument, the name of the function in :mod:`_test_extension_cpp` to call. +""" +import sys +import greenlet +from greenlet.tests import _test_extension_cpp +print('fail_cpp_exception is running') + +def run_unhandled_exception_in_greenlet_aborts(): + def _(): + _test_extension_cpp.test_exception_switch_and_do_in_g2( + _test_extension_cpp.test_exception_throw_nonstd + ) + g1 = greenlet.greenlet(_) + g1.switch() + + +func_name = sys.argv[1] +try: + func = getattr(_test_extension_cpp, func_name) +except AttributeError: + if func_name == run_unhandled_exception_in_greenlet_aborts.__name__: + func = run_unhandled_exception_in_greenlet_aborts + elif func_name == 'run_as_greenlet_target': + g = greenlet.greenlet(_test_extension_cpp.test_exception_throw_std) + func = g.switch + else: + raise +print('raising', func, flush=True) +func() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py new file mode 100644 index 0000000..c1a44ef --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_initialstub_already_started.py @@ -0,0 +1,78 @@ +""" +Testing initialstub throwing an already started exception. +""" + +import greenlet + +a = None +b = None +c = None +main = greenlet.getcurrent() + +# If we switch into a dead greenlet, +# we go looking for its parents. +# if a parent is not yet started, we start it. + +results = [] + +def a_run(*args): + #results.append('A') + results.append(('Begin A', args)) + + +def c_run(): + results.append('Begin C') + b.switch('From C') + results.append('C done') + +class A(greenlet.greenlet): pass + +class B(greenlet.greenlet): + doing_it = False + def __getattribute__(self, name): + if name == 'run' and not self.doing_it: + assert greenlet.getcurrent() is c + self.doing_it = True + results.append('Switch to b from B.__getattribute__ in ' + + type(greenlet.getcurrent()).__name__) + b.switch() + results.append('B.__getattribute__ back from main in ' + + type(greenlet.getcurrent()).__name__) + if name == 'run': + name = '_B_run' + return object.__getattribute__(self, name) + + def _B_run(self, *arg): + results.append(('Begin B', arg)) + results.append('_B_run switching to main') + main.switch('From B') + +class C(greenlet.greenlet): + pass +a = A(a_run) +b = B(parent=a) +c = C(c_run, b) + +# Start a child; while running, it will start B, +# but starting B will ALSO start B. +result = c.switch() +results.append(('main from c', result)) + +# Switch back to C, which was in the middle of switching +# already. This will throw the ``GreenletStartedWhileInPython`` +# exception, which results in parent A getting started (B is finished) +c.switch() + +results.append(('A dead?', a.dead, 'B dead?', b.dead, 'C dead?', c.dead)) + +# A and B should both be dead now. +assert a.dead +assert b.dead +assert not c.dead + +result = c.switch() +results.append(('main from c.2', result)) +# Now C is dead +assert c.dead + +print("RESULTS:", results) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py new file mode 100644 index 0000000..0990526 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_slp_switch.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" +A test helper for seeing what happens when slp_switch() +fails. +""" +# pragma: no cover + +import greenlet + + +print('fail_slp_switch is running', flush=True) + +runs = [] +def func(): + runs.append(1) + greenlet.getcurrent().parent.switch() + runs.append(2) + greenlet.getcurrent().parent.switch() + runs.append(3) + +g = greenlet._greenlet.UnswitchableGreenlet(func) +g.switch() +assert runs == [1] +g.switch() +assert runs == [1, 2] +g.force_slp_switch_error = True + +# This should crash. +g.switch() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py new file mode 100644 index 0000000..e151b19 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets.py @@ -0,0 +1,44 @@ +""" +Uses a trace function to switch greenlets at unexpected times. + +In the trace function, we switch from the current greenlet to another +greenlet, which switches +""" +import greenlet + +g1 = None +g2 = None + +switch_to_g2 = False + +def tracefunc(*args): + print('TRACE', *args) + global switch_to_g2 + if switch_to_g2: + switch_to_g2 = False + g2.switch() + print('\tLEAVE TRACE', *args) + +def g1_run(): + print('In g1_run') + global switch_to_g2 + switch_to_g2 = True + from_parent = greenlet.getcurrent().parent.switch() + print('Return to g1_run') + print('From parent', from_parent) + +def g2_run(): + #g1.switch() + greenlet.getcurrent().parent.switch() + +greenlet.settrace(tracefunc) + +g1 = greenlet.greenlet(g1_run) +g2 = greenlet.greenlet(g2_run) + +# This switch didn't actually finish! +# And if it did, it would raise TypeError +# because g1_run() doesn't take any arguments. +g1.switch(1) +print('Back in main') +g1.switch(2) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py new file mode 100644 index 0000000..1f6b66b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_three_greenlets2.py @@ -0,0 +1,55 @@ +""" +Like fail_switch_three_greenlets, but the call into g1_run would actually be +valid. +""" +import greenlet + +g1 = None +g2 = None + +switch_to_g2 = True + +results = [] + +def tracefunc(*args): + results.append(('trace', args[0])) + print('TRACE', *args) + global switch_to_g2 + if switch_to_g2: + switch_to_g2 = False + g2.switch('g2 from tracefunc') + print('\tLEAVE TRACE', *args) + +def g1_run(arg): + results.append(('g1 arg', arg)) + print('In g1_run') + from_parent = greenlet.getcurrent().parent.switch('from g1_run') + results.append(('g1 from parent', from_parent)) + return 'g1 done' + +def g2_run(arg): + #g1.switch() + results.append(('g2 arg', arg)) + parent = greenlet.getcurrent().parent.switch('from g2_run') + global switch_to_g2 + switch_to_g2 = False + results.append(('g2 from parent', parent)) + return 'g2 done' + + +greenlet.settrace(tracefunc) + +g1 = greenlet.greenlet(g1_run) +g2 = greenlet.greenlet(g2_run) + +x = g1.switch('g1 from main') +results.append(('main g1', x)) +print('Back in main', x) +x = g1.switch('g2 from main') +results.append(('main g2', x)) +print('back in amain again', x) +x = g1.switch('g1 from main 2') +results.append(('main g1.2', x)) +x = g2.switch() +results.append(('main g2.2', x)) +print("RESULTS:", results) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py new file mode 100644 index 0000000..3e52345 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/fail_switch_two_greenlets.py @@ -0,0 +1,41 @@ +""" +Uses a trace function to switch greenlets at unexpected times. + +In the trace function, we switch from the current greenlet to another +greenlet, which switches +""" +import greenlet + +g1 = None +g2 = None + +switch_to_g2 = False + +def tracefunc(*args): + print('TRACE', *args) + global switch_to_g2 + if switch_to_g2: + switch_to_g2 = False + g2.switch() + print('\tLEAVE TRACE', *args) + +def g1_run(): + print('In g1_run') + global switch_to_g2 + switch_to_g2 = True + greenlet.getcurrent().parent.switch() + print('Return to g1_run') + print('Falling off end of g1_run') + +def g2_run(): + g1.switch() + print('Falling off end of g2') + +greenlet.settrace(tracefunc) + +g1 = greenlet.greenlet(g1_run) +g2 = greenlet.greenlet(g2_run) + +g1.switch() +print('Falling off end of main') +g2.switch() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/leakcheck.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/leakcheck.py new file mode 100644 index 0000000..a5152fb --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/leakcheck.py @@ -0,0 +1,319 @@ +# Copyright (c) 2018 gevent community +# Copyright (c) 2021 greenlet community +# +# This was originally part of gevent's test suite. The main author +# (Jason Madden) vendored a copy of it into greenlet. +# +# 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. +from __future__ import print_function + +import os +import sys +import gc + +from functools import wraps +import unittest + + +import objgraph + +# graphviz 0.18 (Nov 7 2021), available only on Python 3.6 and newer, +# has added type hints (sigh). It wants to use ``typing.Literal`` for +# some stuff, but that's only available on Python 3.9+. If that's not +# found, it creates a ``unittest.mock.MagicMock`` object and annotates +# with that. These are GC'able objects, and doing almost *anything* +# with them results in an explosion of objects. For example, trying to +# compare them for equality creates new objects. This causes our +# leakchecks to fail, with reports like: +# +# greenlet.tests.leakcheck.LeakCheckError: refcount increased by [337, 1333, 343, 430, 530, 643, 769] +# _Call 1820 +546 +# dict 4094 +76 +# MagicProxy 585 +73 +# tuple 2693 +66 +# _CallList 24 +3 +# weakref 1441 +1 +# function 5996 +1 +# type 736 +1 +# cell 592 +1 +# MagicMock 8 +1 +# +# To avoid this, we *could* filter this type of object out early. In +# principle it could leak, but we don't use mocks in greenlet, so it +# doesn't leak from us. However, a further issue is that ``MagicMock`` +# objects have subobjects that are also GC'able, like ``_Call``, and +# those create new mocks of their own too. So we'd have to filter them +# as well, and they're not public. That's OK, we can workaround the +# problem by being very careful to never compare by equality or other +# user-defined operators, only using object identity or other builtin +# functions. + +RUNNING_ON_GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS') +RUNNING_ON_TRAVIS = os.environ.get('TRAVIS') or RUNNING_ON_GITHUB_ACTIONS +RUNNING_ON_APPVEYOR = os.environ.get('APPVEYOR') +RUNNING_ON_CI = RUNNING_ON_TRAVIS or RUNNING_ON_APPVEYOR +RUNNING_ON_MANYLINUX = os.environ.get('GREENLET_MANYLINUX') +SKIP_LEAKCHECKS = RUNNING_ON_MANYLINUX or os.environ.get('GREENLET_SKIP_LEAKCHECKS') +SKIP_FAILING_LEAKCHECKS = os.environ.get('GREENLET_SKIP_FAILING_LEAKCHECKS') +ONLY_FAILING_LEAKCHECKS = os.environ.get('GREENLET_ONLY_FAILING_LEAKCHECKS') + +def ignores_leakcheck(func): + """ + Ignore the given object during leakchecks. + + Can be applied to a method, in which case the method will run, but + will not be subject to leak checks. + + If applied to a class, the entire class will be skipped during leakchecks. This + is intended to be used for classes that are very slow and cause problems such as + test timeouts; typically it will be used for classes that are subclasses of a base + class and specify variants of behaviour (such as pool sizes). + """ + func.ignore_leakcheck = True + return func + +def fails_leakcheck(func): + """ + Mark that the function is known to leak. + """ + func.fails_leakcheck = True + if SKIP_FAILING_LEAKCHECKS: + func = unittest.skip("Skipping known failures")(func) + return func + +class LeakCheckError(AssertionError): + pass + +if hasattr(sys, 'getobjects'): + # In a Python build with ``--with-trace-refs``, make objgraph + # trace *all* the objects, not just those that are tracked by the + # GC + class _MockGC(object): + def get_objects(self): + return sys.getobjects(0) # pylint:disable=no-member + def __getattr__(self, name): + return getattr(gc, name) + objgraph.gc = _MockGC() + fails_strict_leakcheck = fails_leakcheck +else: + def fails_strict_leakcheck(func): + """ + Decorator for a function that is known to fail when running + strict (``sys.getobjects()``) leakchecks. + + This type of leakcheck finds all objects, even those, such as + strings, which are not tracked by the garbage collector. + """ + return func + +class ignores_types_in_strict_leakcheck(object): + def __init__(self, types): + self.types = types + def __call__(self, func): + func.leakcheck_ignore_types = self.types + return func + +class _RefCountChecker(object): + + # Some builtin things that we ignore + # XXX: Those things were ignored by gevent, but they're important here, + # presumably. + IGNORED_TYPES = () #(tuple, dict, types.FrameType, types.TracebackType) + + def __init__(self, testcase, function): + self.testcase = testcase + self.function = function + self.deltas = [] + self.peak_stats = {} + self.ignored_types = () + + # The very first time we are called, we have already been + # self.setUp() by the test runner, so we don't need to do it again. + self.needs_setUp = False + + def _include_object_p(self, obj): + # pylint:disable=too-many-return-statements + # + # See the comment block at the top. We must be careful to + # avoid invoking user-defined operations. + if obj is self: + return False + kind = type(obj) + # ``self._include_object_p == obj`` returns NotImplemented + # for non-function objects, which causes the interpreter + # to try to reverse the order of arguments...which leads + # to the explosion of mock objects. We don't want that, so we implement + # the check manually. + if kind == type(self._include_object_p): + try: + # pylint:disable=not-callable + exact_method_equals = self._include_object_p.__eq__(obj) + except AttributeError: + # Python 2.7 methods may only have __cmp__, and that raises a + # TypeError for non-method arguments + # pylint:disable=no-member + exact_method_equals = self._include_object_p.__cmp__(obj) == 0 + + if exact_method_equals is not NotImplemented and exact_method_equals: + return False + + # Similarly, we need to check identity in our __dict__ to avoid mock explosions. + for x in self.__dict__.values(): + if obj is x: + return False + + + if kind in self.ignored_types or kind in self.IGNORED_TYPES: + return False + + return True + + def _growth(self): + return objgraph.growth(limit=None, peak_stats=self.peak_stats, + filter=self._include_object_p) + + def _report_diff(self, growth): + if not growth: + return "" + + lines = [] + width = max(len(name) for name, _, _ in growth) + for name, count, delta in growth: + lines.append('%-*s%9d %+9d' % (width, name, count, delta)) + + diff = '\n'.join(lines) + return diff + + + def _run_test(self, args, kwargs): + gc_enabled = gc.isenabled() + gc.disable() + + if self.needs_setUp: + self.testcase.setUp() + self.testcase.skipTearDown = False + try: + self.function(self.testcase, *args, **kwargs) + finally: + self.testcase.tearDown() + self.testcase.doCleanups() + self.testcase.skipTearDown = True + self.needs_setUp = True + if gc_enabled: + gc.enable() + + def _growth_after(self): + # Grab post snapshot + # pylint:disable=no-member + if 'urlparse' in sys.modules: + sys.modules['urlparse'].clear_cache() + if 'urllib.parse' in sys.modules: + sys.modules['urllib.parse'].clear_cache() + + return self._growth() + + def _check_deltas(self, growth): + # Return false when we have decided there is no leak, + # true if we should keep looping, raises an assertion + # if we have decided there is a leak. + + deltas = self.deltas + if not deltas: + # We haven't run yet, no data, keep looping + return True + + if gc.garbage: + raise LeakCheckError("Generated uncollectable garbage %r" % (gc.garbage,)) + + + # the following configurations are classified as "no leak" + # [0, 0] + # [x, 0, 0] + # [... a, b, c, d] where a+b+c+d = 0 + # + # the following configurations are classified as "leak" + # [... z, z, z] where z > 0 + + if deltas[-2:] == [0, 0] and len(deltas) in (2, 3): + return False + + if deltas[-3:] == [0, 0, 0]: + return False + + if len(deltas) >= 4 and sum(deltas[-4:]) == 0: + return False + + if len(deltas) >= 3 and deltas[-1] > 0 and deltas[-1] == deltas[-2] and deltas[-2] == deltas[-3]: + diff = self._report_diff(growth) + raise LeakCheckError('refcount increased by %r\n%s' % (deltas, diff)) + + # OK, we don't know for sure yet. Let's search for more + if sum(deltas[-3:]) <= 0 or sum(deltas[-4:]) <= 0 or deltas[-4:].count(0) >= 2: + # this is suspicious, so give a few more runs + limit = 11 + else: + limit = 7 + if len(deltas) >= limit: + raise LeakCheckError('refcount increased by %r\n%s' + % (deltas, + self._report_diff(growth))) + + # We couldn't decide yet, keep going + return True + + def __call__(self, args, kwargs): + for _ in range(3): + gc.collect() + + expect_failure = getattr(self.function, 'fails_leakcheck', False) + if expect_failure: + self.testcase.expect_greenlet_leak = True + self.ignored_types = getattr(self.function, "leakcheck_ignore_types", ()) + + # Capture state before; the incremental will be + # updated by each call to _growth_after + growth = self._growth() + + try: + while self._check_deltas(growth): + self._run_test(args, kwargs) + + growth = self._growth_after() + + self.deltas.append(sum((stat[2] for stat in growth))) + except LeakCheckError: + if not expect_failure: + raise + else: + if expect_failure: + raise LeakCheckError("Expected %s to leak but it did not." % (self.function,)) + +def wrap_refcount(method): + if getattr(method, 'ignore_leakcheck', False) or SKIP_LEAKCHECKS: + return method + + @wraps(method) + def wrapper(self, *args, **kwargs): # pylint:disable=too-many-branches + if getattr(self, 'ignore_leakcheck', False): + raise unittest.SkipTest("This class ignored during leakchecks") + if ONLY_FAILING_LEAKCHECKS and not getattr(method, 'fails_leakcheck', False): + raise unittest.SkipTest("Only running tests that fail leakchecks.") + return _RefCountChecker(self, method)(args, kwargs) + + return wrapper diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py new file mode 100644 index 0000000..9a16f67 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_contextvars.py @@ -0,0 +1,310 @@ +from __future__ import print_function + +import gc +import sys +import unittest + +from functools import partial +from unittest import skipUnless +from unittest import skipIf + +from greenlet import greenlet +from greenlet import getcurrent +from . import TestCase + + +try: + from contextvars import Context + from contextvars import ContextVar + from contextvars import copy_context + # From the documentation: + # + # Important: Context Variables should be created at the top module + # level and never in closures. Context objects hold strong + # references to context variables which prevents context variables + # from being properly garbage collected. + ID_VAR = ContextVar("id", default=None) + VAR_VAR = ContextVar("var", default=None) + ContextVar = None +except ImportError: + Context = ContextVar = copy_context = None + +# We don't support testing if greenlet's built-in context var support is disabled. +@skipUnless(Context is not None, "ContextVar not supported") +class ContextVarsTests(TestCase): + def _new_ctx_run(self, *args, **kwargs): + return copy_context().run(*args, **kwargs) + + def _increment(self, greenlet_id, callback, counts, expect): + ctx_var = ID_VAR + if expect is None: + self.assertIsNone(ctx_var.get()) + else: + self.assertEqual(ctx_var.get(), expect) + ctx_var.set(greenlet_id) + for _ in range(2): + counts[ctx_var.get()] += 1 + callback() + + def _test_context(self, propagate_by): + # pylint:disable=too-many-branches + ID_VAR.set(0) + + callback = getcurrent().switch + counts = dict((i, 0) for i in range(5)) + + lets = [ + greenlet(partial( + partial( + copy_context().run, + self._increment + ) if propagate_by == "run" else self._increment, + greenlet_id=i, + callback=callback, + counts=counts, + expect=( + i - 1 if propagate_by == "share" else + 0 if propagate_by in ("set", "run") else None + ) + )) + for i in range(1, 5) + ] + + for let in lets: + if propagate_by == "set": + let.gr_context = copy_context() + elif propagate_by == "share": + let.gr_context = getcurrent().gr_context + + for i in range(2): + counts[ID_VAR.get()] += 1 + for let in lets: + let.switch() + + if propagate_by == "run": + # Must leave each context.run() in reverse order of entry + for let in reversed(lets): + let.switch() + else: + # No context.run(), so fine to exit in any order. + for let in lets: + let.switch() + + for let in lets: + self.assertTrue(let.dead) + # When using run(), we leave the run() as the greenlet dies, + # and there's no context "underneath". When not using run(), + # gr_context still reflects the context the greenlet was + # running in. + if propagate_by == 'run': + self.assertIsNone(let.gr_context) + else: + self.assertIsNotNone(let.gr_context) + + + if propagate_by == "share": + self.assertEqual(counts, {0: 1, 1: 1, 2: 1, 3: 1, 4: 6}) + else: + self.assertEqual(set(counts.values()), set([2])) + + def test_context_propagated_by_context_run(self): + self._new_ctx_run(self._test_context, "run") + + def test_context_propagated_by_setting_attribute(self): + self._new_ctx_run(self._test_context, "set") + + def test_context_not_propagated(self): + self._new_ctx_run(self._test_context, None) + + def test_context_shared(self): + self._new_ctx_run(self._test_context, "share") + + def test_break_ctxvars(self): + let1 = greenlet(copy_context().run) + let2 = greenlet(copy_context().run) + let1.switch(getcurrent().switch) + let2.switch(getcurrent().switch) + # Since let2 entered the current context and let1 exits its own, the + # interpreter emits: + # RuntimeError: cannot exit context: thread state references a different context object + let1.switch() + + def test_not_broken_if_using_attribute_instead_of_context_run(self): + let1 = greenlet(getcurrent().switch) + let2 = greenlet(getcurrent().switch) + let1.gr_context = copy_context() + let2.gr_context = copy_context() + let1.switch() + let2.switch() + let1.switch() + let2.switch() + + def test_context_assignment_while_running(self): + # pylint:disable=too-many-statements + ID_VAR.set(None) + + def target(): + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + + # Context is created on first use + ID_VAR.set(1) + self.assertIsInstance(gr.gr_context, Context) + self.assertEqual(ID_VAR.get(), 1) + self.assertEqual(gr.gr_context[ID_VAR], 1) + + # Clearing the context makes it get re-created as another + # empty context when next used + old_context = gr.gr_context + gr.gr_context = None # assign None while running + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + ID_VAR.set(2) + self.assertIsInstance(gr.gr_context, Context) + self.assertEqual(ID_VAR.get(), 2) + self.assertEqual(gr.gr_context[ID_VAR], 2) + + new_context = gr.gr_context + getcurrent().parent.switch((old_context, new_context)) + # parent switches us back to old_context + + self.assertEqual(ID_VAR.get(), 1) + gr.gr_context = new_context # assign non-None while running + self.assertEqual(ID_VAR.get(), 2) + + getcurrent().parent.switch() + # parent switches us back to no context + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + gr.gr_context = old_context + self.assertEqual(ID_VAR.get(), 1) + + getcurrent().parent.switch() + # parent switches us back to no context + self.assertIsNone(ID_VAR.get()) + self.assertIsNone(gr.gr_context) + + gr = greenlet(target) + + with self.assertRaisesRegex(AttributeError, "can't delete context attribute"): + del gr.gr_context + + self.assertIsNone(gr.gr_context) + old_context, new_context = gr.switch() + self.assertIs(new_context, gr.gr_context) + self.assertEqual(old_context[ID_VAR], 1) + self.assertEqual(new_context[ID_VAR], 2) + self.assertEqual(new_context.run(ID_VAR.get), 2) + gr.gr_context = old_context # assign non-None while suspended + gr.switch() + self.assertIs(gr.gr_context, new_context) + gr.gr_context = None # assign None while suspended + gr.switch() + self.assertIs(gr.gr_context, old_context) + gr.gr_context = None + gr.switch() + self.assertIsNone(gr.gr_context) + + # Make sure there are no reference leaks + gr = None + gc.collect() + self.assertEqual(sys.getrefcount(old_context), 2) + self.assertEqual(sys.getrefcount(new_context), 2) + + def test_context_assignment_different_thread(self): + import threading + VAR_VAR.set(None) + ctx = Context() + + is_running = threading.Event() + should_suspend = threading.Event() + did_suspend = threading.Event() + should_exit = threading.Event() + holder = [] + + def greenlet_in_thread_fn(): + VAR_VAR.set(1) + is_running.set() + should_suspend.wait(10) + VAR_VAR.set(2) + getcurrent().parent.switch() + holder.append(VAR_VAR.get()) + + def thread_fn(): + gr = greenlet(greenlet_in_thread_fn) + gr.gr_context = ctx + holder.append(gr) + gr.switch() + did_suspend.set() + should_exit.wait(10) + gr.switch() + del gr + greenlet() # trigger cleanup + + thread = threading.Thread(target=thread_fn, daemon=True) + thread.start() + is_running.wait(10) + gr = holder[0] + + # Can't access or modify context if the greenlet is running + # in a different thread + with self.assertRaisesRegex(ValueError, "running in a different"): + getattr(gr, 'gr_context') + with self.assertRaisesRegex(ValueError, "running in a different"): + gr.gr_context = None + + should_suspend.set() + did_suspend.wait(10) + + # OK to access and modify context if greenlet is suspended + self.assertIs(gr.gr_context, ctx) + self.assertEqual(gr.gr_context[VAR_VAR], 2) + gr.gr_context = None + + should_exit.set() + thread.join(10) + + self.assertEqual(holder, [gr, None]) + + # Context can still be accessed/modified when greenlet is dead: + self.assertIsNone(gr.gr_context) + gr.gr_context = ctx + self.assertIs(gr.gr_context, ctx) + + # Otherwise we leak greenlets on some platforms. + # XXX: Should be able to do this automatically + del holder[:] + gr = None + thread = None + + def test_context_assignment_wrong_type(self): + g = greenlet() + with self.assertRaisesRegex(TypeError, + "greenlet context must be a contextvars.Context or None"): + g.gr_context = self + + +@skipIf(Context is not None, "ContextVar supported") +class NoContextVarsTests(TestCase): + def test_contextvars_errors(self): + let1 = greenlet(getcurrent().switch) + self.assertFalse(hasattr(let1, 'gr_context')) + with self.assertRaises(AttributeError): + getattr(let1, 'gr_context') + + with self.assertRaises(AttributeError): + let1.gr_context = None + + let1.switch() + + with self.assertRaises(AttributeError): + getattr(let1, 'gr_context') + + with self.assertRaises(AttributeError): + let1.gr_context = None + + del let1 + + +if __name__ == '__main__': + unittest.main() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_cpp.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_cpp.py new file mode 100644 index 0000000..2d0cc9c --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_cpp.py @@ -0,0 +1,73 @@ +from __future__ import print_function +from __future__ import absolute_import + +import subprocess +import unittest + +import greenlet +from . import _test_extension_cpp +from . import TestCase +from . import WIN + +class CPPTests(TestCase): + def test_exception_switch(self): + greenlets = [] + for i in range(4): + g = greenlet.greenlet(_test_extension_cpp.test_exception_switch) + g.switch(i) + greenlets.append(g) + for i, g in enumerate(greenlets): + self.assertEqual(g.switch(), i) + + def _do_test_unhandled_exception(self, target): + import os + import sys + script = os.path.join( + os.path.dirname(__file__), + 'fail_cpp_exception.py', + ) + args = [sys.executable, script, target.__name__ if not isinstance(target, str) else target] + __traceback_info__ = args + with self.assertRaises(subprocess.CalledProcessError) as exc: + subprocess.check_output( + args, + encoding='utf-8', + stderr=subprocess.STDOUT + ) + + ex = exc.exception + expected_exit = self.get_expected_returncodes_for_aborted_process() + self.assertIn(ex.returncode, expected_exit) + self.assertIn('fail_cpp_exception is running', ex.output) + return ex.output + + + def test_unhandled_nonstd_exception_aborts(self): + # verify that plain unhandled throw aborts + self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_nonstd) + + def test_unhandled_std_exception_aborts(self): + # verify that plain unhandled throw aborts + self._do_test_unhandled_exception(_test_extension_cpp.test_exception_throw_std) + + @unittest.skipIf(WIN, "XXX: This does not crash on Windows") + # Meaning the exception is getting lost somewhere... + def test_unhandled_std_exception_as_greenlet_function_aborts(self): + # verify that plain unhandled throw aborts + output = self._do_test_unhandled_exception('run_as_greenlet_target') + self.assertIn( + # We really expect this to be prefixed with "greenlet: Unhandled C++ exception:" + # as added by our handler for std::exception (see TUserGreenlet.cpp), but + # that's not correct everywhere --- our handler never runs before std::terminate + # gets called (for example, on arm32). + 'Thrown from an extension.', + output + ) + + def test_unhandled_exception_in_greenlet_aborts(self): + # verify that unhandled throw called in greenlet aborts too + self._do_test_unhandled_exception('run_unhandled_exception_in_greenlet_aborts') + + +if __name__ == '__main__': + unittest.main() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py new file mode 100644 index 0000000..34b6656 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_extension_interface.py @@ -0,0 +1,115 @@ +from __future__ import print_function +from __future__ import absolute_import + +import sys + +import greenlet +from . import _test_extension +from . import TestCase + +# pylint:disable=c-extension-no-member + +class CAPITests(TestCase): + def test_switch(self): + self.assertEqual( + 50, _test_extension.test_switch(greenlet.greenlet(lambda: 50))) + + def test_switch_kwargs(self): + def adder(x, y): + return x * y + g = greenlet.greenlet(adder) + self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2)) + + def test_setparent(self): + # pylint:disable=disallowed-name + def foo(): + def bar(): + greenlet.getcurrent().parent.switch() + + # This final switch should go back to the main greenlet, since + # the test_setparent() function in the C extension should have + # reparented this greenlet. + greenlet.getcurrent().parent.switch() + raise AssertionError("Should never have reached this code") + child = greenlet.greenlet(bar) + child.switch() + greenlet.getcurrent().parent.switch(child) + greenlet.getcurrent().parent.throw( + AssertionError("Should never reach this code")) + foo_child = greenlet.greenlet(foo).switch() + self.assertEqual(None, _test_extension.test_setparent(foo_child)) + + def test_getcurrent(self): + _test_extension.test_getcurrent() + + def test_new_greenlet(self): + self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15)) + + def test_raise_greenlet_dead(self): + self.assertRaises( + greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet) + + def test_raise_greenlet_error(self): + self.assertRaises( + greenlet.error, _test_extension.test_raise_greenlet_error) + + def test_throw(self): + seen = [] + + def foo(): # pylint:disable=disallowed-name + try: + greenlet.getcurrent().parent.switch() + except ValueError: + seen.append(sys.exc_info()[1]) + except greenlet.GreenletExit: + raise AssertionError + g = greenlet.greenlet(foo) + g.switch() + _test_extension.test_throw(g) + self.assertEqual(len(seen), 1) + self.assertTrue( + isinstance(seen[0], ValueError), + "ValueError was not raised in foo()") + self.assertEqual( + str(seen[0]), + 'take that sucka!', + "message doesn't match") + + def test_non_traceback_param(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + Exception, + Exception(), + self + ) + self.assertEqual(str(exc.exception), + "throw() third argument must be a traceback object") + + def test_instance_of_wrong_type(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + Exception(), + BaseException(), + None, + ) + + self.assertEqual(str(exc.exception), + "instance exception may not have a separate value") + + def test_not_throwable(self): + with self.assertRaises(TypeError) as exc: + _test_extension.test_throw_exact( + greenlet.getcurrent(), + "abc", + None, + None, + ) + self.assertEqual(str(exc.exception), + "exceptions must be classes, or instances, not str") + + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_gc.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_gc.py new file mode 100644 index 0000000..994addb --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_gc.py @@ -0,0 +1,86 @@ +import gc + +import weakref + +import greenlet + + +from . import TestCase +from .leakcheck import fails_leakcheck +# These only work with greenlet gc support +# which is no longer optional. +assert greenlet.GREENLET_USE_GC + +class GCTests(TestCase): + def test_dead_circular_ref(self): + o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch()) + gc.collect() + if o() is not None: + import sys + print("O IS NOT NONE.", sys.getrefcount(o())) + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + def test_circular_greenlet(self): + class circular_greenlet(greenlet.greenlet): + self = None + o = circular_greenlet() + o.self = o + o = weakref.ref(o) + gc.collect() + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + def test_inactive_ref(self): + class inactive_greenlet(greenlet.greenlet): + def __init__(self): + greenlet.greenlet.__init__(self, run=self.run) + + def run(self): + pass + o = inactive_greenlet() + o = weakref.ref(o) + gc.collect() + self.assertIsNone(o()) + self.assertFalse(gc.garbage, gc.garbage) + + @fails_leakcheck + def test_finalizer_crash(self): + # This test is designed to crash when active greenlets + # are made garbage collectable, until the underlying + # problem is resolved. How does it work: + # - order of object creation is important + # - array is created first, so it is moved to unreachable first + # - we create a cycle between a greenlet and this array + # - we create an object that participates in gc, is only + # referenced by a greenlet, and would corrupt gc lists + # on destruction, the easiest is to use an object with + # a finalizer + # - because array is the first object in unreachable it is + # cleared first, which causes all references to greenlet + # to disappear and causes greenlet to be destroyed, but since + # it is still live it causes a switch during gc, which causes + # an object with finalizer to be destroyed, which causes stack + # corruption and then a crash + + class object_with_finalizer(object): + def __del__(self): + pass + array = [] + parent = greenlet.getcurrent() + def greenlet_body(): + greenlet.getcurrent().object = object_with_finalizer() + try: + parent.switch() + except greenlet.GreenletExit: + print("Got greenlet exit!") + finally: + del greenlet.getcurrent().object + g = greenlet.greenlet(greenlet_body) + g.array = array + array.append(g) + g.switch() + del array + del g + greenlet.getcurrent() + gc.collect() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator.py new file mode 100644 index 0000000..ca4a644 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator.py @@ -0,0 +1,59 @@ + +from greenlet import greenlet + +from . import TestCase + +class genlet(greenlet): + parent = None + def __init__(self, *args, **kwds): + self.args = args + self.kwds = kwds + + def run(self): + fn, = self.fn + fn(*self.args, **self.kwds) + + def __iter__(self): + return self + + def __next__(self): + self.parent = greenlet.getcurrent() + result = self.switch() + if self: + return result + + raise StopIteration + + next = __next__ + + +def Yield(value): + g = greenlet.getcurrent() + while not isinstance(g, genlet): + if g is None: + raise RuntimeError('yield outside a genlet') + g = g.parent + g.parent.switch(value) + + +def generator(func): + class Generator(genlet): + fn = (func,) + return Generator + +# ____________________________________________________________ + + +class GeneratorTests(TestCase): + def test_generator(self): + seen = [] + + def g(n): + for i in range(n): + seen.append(i) + Yield(i) + g = generator(g) + for _ in range(3): + for j in g(5): + seen.append(j) + self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py new file mode 100644 index 0000000..8d752a6 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_generator_nested.py @@ -0,0 +1,168 @@ + +from greenlet import greenlet +from . import TestCase +from .leakcheck import fails_leakcheck + +class genlet(greenlet): + parent = None + def __init__(self, *args, **kwds): + self.args = args + self.kwds = kwds + self.child = None + + def run(self): + # Note the function is packed in a tuple + # to avoid creating a bound method for it. + fn, = self.fn + fn(*self.args, **self.kwds) + + def __iter__(self): + return self + + def set_child(self, child): + self.child = child + + def __next__(self): + if self.child: + child = self.child + while child.child: + tmp = child + child = child.child + tmp.child = None + + result = child.switch() + else: + self.parent = greenlet.getcurrent() + result = self.switch() + + if self: + return result + + raise StopIteration + + next = __next__ + +def Yield(value, level=1): + g = greenlet.getcurrent() + + while level != 0: + if not isinstance(g, genlet): + raise RuntimeError('yield outside a genlet') + if level > 1: + g.parent.set_child(g) + g = g.parent + level -= 1 + + g.switch(value) + + +def Genlet(func): + class TheGenlet(genlet): + fn = (func,) + return TheGenlet + +# ____________________________________________________________ + + +def g1(n, seen): + for i in range(n): + seen.append(i + 1) + yield i + + +def g2(n, seen): + for i in range(n): + seen.append(i + 1) + Yield(i) + +g2 = Genlet(g2) + + +def nested(i): + Yield(i) + + +def g3(n, seen): + for i in range(n): + seen.append(i + 1) + nested(i) +g3 = Genlet(g3) + + +def a(n): + if n == 0: + return + for ii in ax(n - 1): + Yield(ii) + Yield(n) +ax = Genlet(a) + + +def perms(l): + if len(l) > 1: + for e in l: + # No syntactical sugar for generator expressions + x = [Yield([e] + p) for p in perms([x for x in l if x != e])] + assert x + else: + Yield(l) +perms = Genlet(perms) + + +def gr1(n): + for ii in range(1, n): + Yield(ii) + Yield(ii * ii, 2) + +gr1 = Genlet(gr1) + + +def gr2(n, seen): + for ii in gr1(n): + seen.append(ii) + +gr2 = Genlet(gr2) + + +class NestedGeneratorTests(TestCase): + def test_layered_genlets(self): + seen = [] + for ii in gr2(5, seen): + seen.append(ii) + self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16]) + + @fails_leakcheck + def test_permutations(self): + gen_perms = perms(list(range(4))) + permutations = list(gen_perms) + self.assertEqual(len(permutations), 4 * 3 * 2 * 1) + self.assertIn([0, 1, 2, 3], permutations) + self.assertIn([3, 2, 1, 0], permutations) + res = [] + for ii in zip(perms(list(range(4))), perms(list(range(3)))): + res.append(ii) + self.assertEqual( + res, + [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]), + ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]), + ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])]) + # XXX Test to make sure we are working as a generator expression + + def test_genlet_simple(self): + for g in g1, g2, g3: + seen = [] + for _ in range(3): + for j in g(5, seen): + seen.append(j) + self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4]) + + def test_genlet_bad(self): + try: + Yield(10) + except RuntimeError: + pass + + def test_nested_genlets(self): + seen = [] + for ii in ax(5): + seen.append(ii) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py new file mode 100644 index 0000000..51849cd --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet.py @@ -0,0 +1,1311 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import gc +import sys +import time +import threading + +from abc import ABCMeta, abstractmethod + +import greenlet +from greenlet import greenlet as RawGreenlet +from . import TestCase +from .leakcheck import fails_leakcheck + + +# We manually manage locks in many tests +# pylint:disable=consider-using-with +# pylint:disable=too-many-public-methods +# This module is quite large. +# TODO: Refactor into separate test files. For example, +# put all the regression tests that used to produce +# crashes in test_greenlet_no_crash; put tests that DO deliberately crash +# the interpreter into test_greenlet_crash. +# pylint:disable=too-many-lines + +class SomeError(Exception): + pass + + +def fmain(seen): + try: + greenlet.getcurrent().parent.switch() + except: + seen.append(sys.exc_info()[0]) + raise + raise SomeError + + +def send_exception(g, exc): + # note: send_exception(g, exc) can be now done with g.throw(exc). + # the purpose of this test is to explicitly check the propagation rules. + def crasher(exc): + raise exc + g1 = RawGreenlet(crasher, parent=g) + g1.switch(exc) + + +class TestGreenlet(TestCase): + + def _do_simple_test(self): + lst = [] + + def f(): + lst.append(1) + greenlet.getcurrent().parent.switch() + lst.append(3) + g = RawGreenlet(f) + lst.append(0) + g.switch() + lst.append(2) + g.switch() + lst.append(4) + self.assertEqual(lst, list(range(5))) + + def test_simple(self): + self._do_simple_test() + + def test_switch_no_run_raises_AttributeError(self): + g = RawGreenlet() + with self.assertRaises(AttributeError) as exc: + g.switch() + + self.assertIn("run", str(exc.exception)) + + def test_throw_no_run_raises_AttributeError(self): + g = RawGreenlet() + with self.assertRaises(AttributeError) as exc: + g.throw(SomeError) + + self.assertIn("run", str(exc.exception)) + + def test_parent_equals_None(self): + g = RawGreenlet(parent=None) + self.assertIsNotNone(g) + self.assertIs(g.parent, greenlet.getcurrent()) + + def test_run_equals_None(self): + g = RawGreenlet(run=None) + self.assertIsNotNone(g) + self.assertIsNone(g.run) + + def test_two_children(self): + lst = [] + + def f(): + lst.append(1) + greenlet.getcurrent().parent.switch() + lst.extend([1, 1]) + g = RawGreenlet(f) + h = RawGreenlet(f) + g.switch() + self.assertEqual(len(lst), 1) + h.switch() + self.assertEqual(len(lst), 2) + h.switch() + self.assertEqual(len(lst), 4) + self.assertEqual(h.dead, True) + g.switch() + self.assertEqual(len(lst), 6) + self.assertEqual(g.dead, True) + + def test_two_recursive_children(self): + lst = [] + + def f(): + lst.append('b') + greenlet.getcurrent().parent.switch() + + def g(): + lst.append('a') + g = RawGreenlet(f) + g.switch() + lst.append('c') + + g = RawGreenlet(g) + self.assertEqual(sys.getrefcount(g), 2) + g.switch() + self.assertEqual(lst, ['a', 'b', 'c']) + # Just the one in this frame, plus the one on the stack we pass to the function + self.assertEqual(sys.getrefcount(g), 2) + + def test_threads(self): + success = [] + + def f(): + self._do_simple_test() + success.append(True) + ths = [threading.Thread(target=f) for i in range(10)] + for th in ths: + th.start() + for th in ths: + th.join(10) + self.assertEqual(len(success), len(ths)) + + def test_exception(self): + seen = [] + g1 = RawGreenlet(fmain) + g2 = RawGreenlet(fmain) + g1.switch(seen) + g2.switch(seen) + g2.parent = g1 + + self.assertEqual(seen, []) + #with self.assertRaises(SomeError): + # p("***Switching back") + # g2.switch() + # Creating this as a bound method can reveal bugs that + # are hidden on newer versions of Python that avoid creating + # bound methods for direct expressions; IOW, don't use the `with` + # form! + self.assertRaises(SomeError, g2.switch) + self.assertEqual(seen, [SomeError]) + + value = g2.switch() + self.assertEqual(value, ()) + self.assertEqual(seen, [SomeError]) + + value = g2.switch(25) + self.assertEqual(value, 25) + self.assertEqual(seen, [SomeError]) + + + def test_send_exception(self): + seen = [] + g1 = RawGreenlet(fmain) + g1.switch(seen) + self.assertRaises(KeyError, send_exception, g1, KeyError) + self.assertEqual(seen, [KeyError]) + + def test_dealloc(self): + seen = [] + g1 = RawGreenlet(fmain) + g2 = RawGreenlet(fmain) + g1.switch(seen) + g2.switch(seen) + self.assertEqual(seen, []) + del g1 + gc.collect() + self.assertEqual(seen, [greenlet.GreenletExit]) + del g2 + gc.collect() + self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit]) + + def test_dealloc_catches_GreenletExit_throws_other(self): + def run(): + try: + greenlet.getcurrent().parent.switch() + except greenlet.GreenletExit: + raise SomeError from None + + g = RawGreenlet(run) + g.switch() + # Destroying the only reference to the greenlet causes it + # to get GreenletExit; when it in turn raises, even though we're the parent + # we don't get the exception, it just gets printed. + # When we run on 3.8 only, we can use sys.unraisablehook + oldstderr = sys.stderr + try: + from cStringIO import StringIO + except ImportError: + from io import StringIO + stderr = sys.stderr = StringIO() + try: + del g + finally: + sys.stderr = oldstderr + + v = stderr.getvalue() + self.assertIn("Exception", v) + self.assertIn('ignored', v) + self.assertIn("SomeError", v) + + + def test_dealloc_other_thread(self): + seen = [] + someref = [] + + bg_glet_created_running_and_no_longer_ref_in_bg = threading.Event() + fg_ref_released = threading.Event() + bg_should_be_clear = threading.Event() + ok_to_exit_bg_thread = threading.Event() + + def f(): + g1 = RawGreenlet(fmain) + g1.switch(seen) + someref.append(g1) + del g1 + gc.collect() + + bg_glet_created_running_and_no_longer_ref_in_bg.set() + fg_ref_released.wait(3) + + RawGreenlet() # trigger release + bg_should_be_clear.set() + ok_to_exit_bg_thread.wait(3) + RawGreenlet() # One more time + + t = threading.Thread(target=f) + t.start() + bg_glet_created_running_and_no_longer_ref_in_bg.wait(10) + + self.assertEqual(seen, []) + self.assertEqual(len(someref), 1) + del someref[:] + gc.collect() + # g1 is not released immediately because it's from another thread + self.assertEqual(seen, []) + fg_ref_released.set() + bg_should_be_clear.wait(3) + try: + self.assertEqual(seen, [greenlet.GreenletExit]) + finally: + ok_to_exit_bg_thread.set() + t.join(10) + del seen[:] + del someref[:] + + def test_frame(self): + def f1(): + f = sys._getframe(0) # pylint:disable=protected-access + self.assertEqual(f.f_back, None) + greenlet.getcurrent().parent.switch(f) + return "meaning of life" + g = RawGreenlet(f1) + frame = g.switch() + self.assertTrue(frame is g.gr_frame) + self.assertTrue(g) + + from_g = g.switch() + self.assertFalse(g) + self.assertEqual(from_g, 'meaning of life') + self.assertEqual(g.gr_frame, None) + + def test_thread_bug(self): + def runner(x): + g = RawGreenlet(lambda: time.sleep(x)) + g.switch() + t1 = threading.Thread(target=runner, args=(0.2,)) + t2 = threading.Thread(target=runner, args=(0.3,)) + t1.start() + t2.start() + t1.join(10) + t2.join(10) + + def test_switch_kwargs(self): + def run(a, b): + self.assertEqual(a, 4) + self.assertEqual(b, 2) + return 42 + x = RawGreenlet(run).switch(a=4, b=2) + self.assertEqual(x, 42) + + def test_switch_kwargs_to_parent(self): + def run(x): + greenlet.getcurrent().parent.switch(x=x) + greenlet.getcurrent().parent.switch(2, x=3) + return x, x ** 2 + g = RawGreenlet(run) + self.assertEqual({'x': 3}, g.switch(3)) + self.assertEqual(((2,), {'x': 3}), g.switch()) + self.assertEqual((3, 9), g.switch()) + + def test_switch_to_another_thread(self): + data = {} + created_event = threading.Event() + done_event = threading.Event() + + def run(): + data['g'] = RawGreenlet(lambda: None) + created_event.set() + done_event.wait(10) + thread = threading.Thread(target=run) + thread.start() + created_event.wait(10) + with self.assertRaises(greenlet.error): + data['g'].switch() + done_event.set() + thread.join(10) + # XXX: Should handle this automatically + data.clear() + + def test_exc_state(self): + def f(): + try: + raise ValueError('fun') + except: # pylint:disable=bare-except + exc_info = sys.exc_info() + RawGreenlet(h).switch() + self.assertEqual(exc_info, sys.exc_info()) + + def h(): + self.assertEqual(sys.exc_info(), (None, None, None)) + + RawGreenlet(f).switch() + + def test_instance_dict(self): + def f(): + greenlet.getcurrent().test = 42 + def deldict(g): + del g.__dict__ + def setdict(g, value): + g.__dict__ = value + g = RawGreenlet(f) + self.assertEqual(g.__dict__, {}) + g.switch() + self.assertEqual(g.test, 42) + self.assertEqual(g.__dict__, {'test': 42}) + g.__dict__ = g.__dict__ + self.assertEqual(g.__dict__, {'test': 42}) + self.assertRaises(TypeError, deldict, g) + self.assertRaises(TypeError, setdict, g, 42) + + def test_running_greenlet_has_no_run(self): + has_run = [] + def func(): + has_run.append( + hasattr(greenlet.getcurrent(), 'run') + ) + + g = RawGreenlet(func) + g.switch() + self.assertEqual(has_run, [False]) + + def test_deepcopy(self): + import copy + self.assertRaises(TypeError, copy.copy, RawGreenlet()) + self.assertRaises(TypeError, copy.deepcopy, RawGreenlet()) + + def test_parent_restored_on_kill(self): + hub = RawGreenlet(lambda: None) + main = greenlet.getcurrent() + result = [] + def worker(): + try: + # Wait to be killed by going back to the test. + main.switch() + except greenlet.GreenletExit: + # Resurrect and switch to parent + result.append(greenlet.getcurrent().parent) + result.append(greenlet.getcurrent()) + hub.switch() + g = RawGreenlet(worker, parent=hub) + g.switch() + # delete the only reference, thereby raising GreenletExit + del g + self.assertTrue(result) + self.assertIs(result[0], main) + self.assertIs(result[1].parent, hub) + # Delete them, thereby breaking the cycle between the greenlet + # and the frame, which otherwise would never be collectable + # XXX: We should be able to automatically fix this. + del result[:] + hub = None + main = None + + def test_parent_return_failure(self): + # No run causes AttributeError on switch + g1 = RawGreenlet() + # Greenlet that implicitly switches to parent + g2 = RawGreenlet(lambda: None, parent=g1) + # AttributeError should propagate to us, no fatal errors + with self.assertRaises(AttributeError): + g2.switch() + + def test_throw_exception_not_lost(self): + class mygreenlet(RawGreenlet): + def __getattribute__(self, name): + try: + raise Exception # pylint:disable=broad-exception-raised + except: # pylint:disable=bare-except + pass + return RawGreenlet.__getattribute__(self, name) + g = mygreenlet(lambda: None) + self.assertRaises(SomeError, g.throw, SomeError()) + + @fails_leakcheck + def _do_test_throw_to_dead_thread_doesnt_crash(self, wait_for_cleanup=False): + result = [] + def worker(): + greenlet.getcurrent().parent.switch() + + def creator(): + g = RawGreenlet(worker) + g.switch() + result.append(g) + if wait_for_cleanup: + # Let this greenlet eventually be cleaned up. + g.switch() + greenlet.getcurrent() + t = threading.Thread(target=creator) + t.start() + t.join(10) + del t + # But, depending on the operating system, the thread + # deallocator may not actually have run yet! So we can't be + # sure about the error message unless we wait. + if wait_for_cleanup: + self.wait_for_pending_cleanups() + with self.assertRaises(greenlet.error) as exc: + result[0].throw(SomeError) + + if not wait_for_cleanup: + self.assertIn( + str(exc.exception), [ + "cannot switch to a different thread (which happens to have exited)", + "cannot switch to a different thread" + ] + ) + else: + self.assertEqual( + str(exc.exception), + "cannot switch to a different thread (which happens to have exited)", + ) + + if hasattr(result[0].gr_frame, 'clear'): + # The frame is actually executing (it thinks), we can't clear it. + with self.assertRaises(RuntimeError): + result[0].gr_frame.clear() + # Unfortunately, this doesn't actually clear the references, they're in the + # fast local array. + if not wait_for_cleanup: + result[0].gr_frame.f_locals.clear() + else: + self.assertIsNone(result[0].gr_frame) + + del creator + worker = None + del result[:] + # XXX: we ought to be able to automatically fix this. + # See issue 252 + self.expect_greenlet_leak = True # direct us not to wait for it to go away + + @fails_leakcheck + def test_throw_to_dead_thread_doesnt_crash(self): + self._do_test_throw_to_dead_thread_doesnt_crash() + + def test_throw_to_dead_thread_doesnt_crash_wait(self): + self._do_test_throw_to_dead_thread_doesnt_crash(True) + + @fails_leakcheck + def test_recursive_startup(self): + class convoluted(RawGreenlet): + def __init__(self): + RawGreenlet.__init__(self) + self.count = 0 + def __getattribute__(self, name): + if name == 'run' and self.count == 0: + self.count = 1 + self.switch(43) + return RawGreenlet.__getattribute__(self, name) + def run(self, value): + while True: + self.parent.switch(value) + g = convoluted() + self.assertEqual(g.switch(42), 43) + # Exits the running greenlet, otherwise it leaks + # XXX: We should be able to automatically fix this + #g.throw(greenlet.GreenletExit) + #del g + self.expect_greenlet_leak = True + + def test_threaded_updatecurrent(self): + # released when main thread should execute + lock1 = threading.Lock() + lock1.acquire() + # released when another thread should execute + lock2 = threading.Lock() + lock2.acquire() + class finalized(object): + def __del__(self): + # happens while in green_updatecurrent() in main greenlet + # should be very careful not to accidentally call it again + # at the same time we must make sure another thread executes + lock2.release() + lock1.acquire() + # now ts_current belongs to another thread + def deallocator(): + greenlet.getcurrent().parent.switch() + def fthread(): + lock2.acquire() + greenlet.getcurrent() + del g[0] + lock1.release() + lock2.acquire() + greenlet.getcurrent() + lock1.release() + main = greenlet.getcurrent() + g = [RawGreenlet(deallocator)] + g[0].bomb = finalized() + g[0].switch() + t = threading.Thread(target=fthread) + t.start() + # let another thread grab ts_current and deallocate g[0] + lock2.release() + lock1.acquire() + # this is the corner stone + # getcurrent() will notice that ts_current belongs to another thread + # and start the update process, which would notice that g[0] should + # be deallocated, and that will execute an object's finalizer. Now, + # that object will let another thread run so it can grab ts_current + # again, which would likely crash the interpreter if there's no + # check for this case at the end of green_updatecurrent(). This test + # passes if getcurrent() returns correct result, but it's likely + # to randomly crash if it's not anyway. + self.assertEqual(greenlet.getcurrent(), main) + # wait for another thread to complete, just in case + t.join(10) + + def test_dealloc_switch_args_not_lost(self): + seen = [] + def worker(): + # wait for the value + value = greenlet.getcurrent().parent.switch() + # delete all references to ourself + del worker[0] + initiator.parent = greenlet.getcurrent().parent + # switch to main with the value, but because + # ts_current is the last reference to us we + # return here immediately, where we resurrect ourself. + try: + greenlet.getcurrent().parent.switch(value) + finally: + seen.append(greenlet.getcurrent()) + def initiator(): + return 42 # implicitly falls thru to parent + + worker = [RawGreenlet(worker)] + + worker[0].switch() # prime worker + initiator = RawGreenlet(initiator, worker[0]) + value = initiator.switch() + self.assertTrue(seen) + self.assertEqual(value, 42) + + def test_tuple_subclass(self): + # The point of this test is to see what happens when a custom + # tuple subclass is used as an object passed directly to the C + # function ``green_switch``; part of ``green_switch`` checks + # the ``len()`` of the ``args`` tuple, and that can call back + # into Python. Here, when it calls back into Python, we + # recursively enter ``green_switch`` again. + + # This test is really only relevant on Python 2. The builtin + # `apply` function directly passes the given args tuple object + # to the underlying function, whereas the Python 3 version + # unpacks and repacks into an actual tuple. This could still + # happen using the C API on Python 3 though. We should write a + # builtin version of apply() ourself. + def _apply(func, a, k): + func(*a, **k) + + class mytuple(tuple): + def __len__(self): + greenlet.getcurrent().switch() + return tuple.__len__(self) + args = mytuple() + kwargs = dict(a=42) + def switchapply(): + _apply(greenlet.getcurrent().parent.switch, args, kwargs) + g = RawGreenlet(switchapply) + self.assertEqual(g.switch(), kwargs) + + def test_abstract_subclasses(self): + AbstractSubclass = ABCMeta( + 'AbstractSubclass', + (RawGreenlet,), + {'run': abstractmethod(lambda self: None)}) + + class BadSubclass(AbstractSubclass): + pass + + class GoodSubclass(AbstractSubclass): + def run(self): + pass + + GoodSubclass() # should not raise + self.assertRaises(TypeError, BadSubclass) + + def test_implicit_parent_with_threads(self): + if not gc.isenabled(): + return # cannot test with disabled gc + N = gc.get_threshold()[0] + if N < 50: + return # cannot test with such a small N + def attempt(): + lock1 = threading.Lock() + lock1.acquire() + lock2 = threading.Lock() + lock2.acquire() + recycled = [False] + def another_thread(): + lock1.acquire() # wait for gc + greenlet.getcurrent() # update ts_current + lock2.release() # release gc + t = threading.Thread(target=another_thread) + t.start() + class gc_callback(object): + def __del__(self): + lock1.release() + lock2.acquire() + recycled[0] = True + class garbage(object): + def __init__(self): + self.cycle = self + self.callback = gc_callback() + l = [] + x = range(N*2) + current = greenlet.getcurrent() + g = garbage() + for _ in x: + g = None # lose reference to garbage + if recycled[0]: + # gc callback called prematurely + t.join(10) + return False + last = RawGreenlet() + if recycled[0]: + break # yes! gc called in green_new + l.append(last) # increase allocation counter + else: + # gc callback not called when expected + gc.collect() + if recycled[0]: + t.join(10) + return False + self.assertEqual(last.parent, current) + for g in l: + self.assertEqual(g.parent, current) + return True + for _ in range(5): + if attempt(): + break + + def test_issue_245_reference_counting_subclass_no_threads(self): + # https://github.com/python-greenlet/greenlet/issues/245 + # Before the fix, this crashed pretty reliably on + # Python 3.10, at least on macOS; but much less reliably on other + # interpreters (memory layout must have changed). + # The threaded test crashed more reliably on more interpreters. + from greenlet import getcurrent + from greenlet import GreenletExit + + class Greenlet(RawGreenlet): + pass + + initial_refs = sys.getrefcount(Greenlet) + # This has to be an instance variable because + # Python 2 raises a SyntaxError if we delete a local + # variable referenced in an inner scope. + self.glets = [] # pylint:disable=attribute-defined-outside-init + + def greenlet_main(): + try: + getcurrent().parent.switch() + except GreenletExit: + self.glets.append(getcurrent()) + + # Before the + for _ in range(10): + Greenlet(greenlet_main).switch() + + del self.glets + self.assertEqual(sys.getrefcount(Greenlet), initial_refs) + + def test_issue_245_reference_counting_subclass_threads(self): + # https://github.com/python-greenlet/greenlet/issues/245 + from threading import Thread + from threading import Event + + from greenlet import getcurrent + + class MyGreenlet(RawGreenlet): + pass + + glets = [] + ref_cleared = Event() + + def greenlet_main(): + getcurrent().parent.switch() + + def thread_main(greenlet_running_event): + mine = MyGreenlet(greenlet_main) + glets.append(mine) + # The greenlets being deleted must be active + mine.switch() + # Don't keep any reference to it in this thread + del mine + # Let main know we published our greenlet. + greenlet_running_event.set() + # Wait for main to let us know the references are + # gone and the greenlet objects no longer reachable + ref_cleared.wait(10) + # The creating thread must call getcurrent() (or a few other + # greenlet APIs) because that's when the thread-local list of dead + # greenlets gets cleared. + getcurrent() + + # We start with 3 references to the subclass: + # - This module + # - Its __mro__ + # - The __subclassess__ attribute of greenlet + # - (If we call gc.get_referents(), we find four entries, including + # some other tuple ``(greenlet)`` that I'm not sure about but must be part + # of the machinery.) + # + # On Python 3.10 it's often enough to just run 3 threads; on Python 2.7, + # more threads are needed, and the results are still + # non-deterministic. Presumably the memory layouts are different + initial_refs = sys.getrefcount(MyGreenlet) + thread_ready_events = [] + for _ in range( + initial_refs + 45 + ): + event = Event() + thread = Thread(target=thread_main, args=(event,)) + thread_ready_events.append(event) + thread.start() + + + for done_event in thread_ready_events: + done_event.wait(10) + + + del glets[:] + ref_cleared.set() + # Let any other thread run; it will crash the interpreter + # if not fixed (or silently corrupt memory and we possibly crash + # later). + self.wait_for_pending_cleanups() + self.assertEqual(sys.getrefcount(MyGreenlet), initial_refs) + + def test_falling_off_end_switches_to_unstarted_parent_raises_error(self): + def no_args(): + return 13 + + parent_never_started = RawGreenlet(no_args) + + def leaf(): + return 42 + + child = RawGreenlet(leaf, parent_never_started) + + # Because the run function takes to arguments + with self.assertRaises(TypeError): + child.switch() + + def test_falling_off_end_switches_to_unstarted_parent_works(self): + def one_arg(x): + return (x, 24) + + parent_never_started = RawGreenlet(one_arg) + + def leaf(): + return 42 + + child = RawGreenlet(leaf, parent_never_started) + + result = child.switch() + self.assertEqual(result, (42, 24)) + + def test_switch_to_dead_greenlet_with_unstarted_perverse_parent(self): + class Parent(RawGreenlet): + def __getattribute__(self, name): + if name == 'run': + raise SomeError + + + parent_never_started = Parent() + seen = [] + child = RawGreenlet(lambda: seen.append(42), parent_never_started) + # Because we automatically start the parent when the child is + # finished + with self.assertRaises(SomeError): + child.switch() + + self.assertEqual(seen, [42]) + + with self.assertRaises(SomeError): + child.switch() + self.assertEqual(seen, [42]) + + def test_switch_to_dead_greenlet_reparent(self): + seen = [] + parent_never_started = RawGreenlet(lambda: seen.append(24)) + child = RawGreenlet(lambda: seen.append(42)) + + child.switch() + self.assertEqual(seen, [42]) + + child.parent = parent_never_started + # This actually is the same as switching to the parent. + result = child.switch() + self.assertIsNone(result) + self.assertEqual(seen, [42, 24]) + + def test_can_access_f_back_of_suspended_greenlet(self): + # This tests our frame rewriting to work around Python 3.12+ having + # some interpreter frames on the C stack. It will crash in the absence + # of that logic. + main = greenlet.getcurrent() + + def outer(): + inner() + + def inner(): + main.switch(sys._getframe(0)) + + hub = RawGreenlet(outer) + # start it + hub.switch() + + # start another greenlet to make sure we aren't relying on + # anything in `hub` still being on the C stack + unrelated = RawGreenlet(lambda: None) + unrelated.switch() + + # now it is suspended + self.assertIsNotNone(hub.gr_frame) + self.assertEqual(hub.gr_frame.f_code.co_name, "inner") + self.assertIsNotNone(hub.gr_frame.f_back) + self.assertEqual(hub.gr_frame.f_back.f_code.co_name, "outer") + # The next line is what would crash + self.assertIsNone(hub.gr_frame.f_back.f_back) + + def test_get_stack_with_nested_c_calls(self): + from functools import partial + from . import _test_extension_cpp + + def recurse(v): + if v > 0: + return v * _test_extension_cpp.test_call(partial(recurse, v - 1)) + return greenlet.getcurrent().parent.switch() + + gr = RawGreenlet(recurse) + gr.switch(5) + frame = gr.gr_frame + for i in range(5): + self.assertEqual(frame.f_locals["v"], i) + frame = frame.f_back + self.assertEqual(frame.f_locals["v"], 5) + self.assertIsNone(frame.f_back) + self.assertEqual(gr.switch(10), 1200) # 1200 = 5! * 10 + + def test_frames_always_exposed(self): + # On Python 3.12 this will crash if we don't set the + # gr_frames_always_exposed attribute. More background: + # https://github.com/python-greenlet/greenlet/issues/388 + main = greenlet.getcurrent() + + def outer(): + inner(sys._getframe(0)) + + def inner(frame): + main.switch(frame) + + gr = RawGreenlet(outer) + frame = gr.switch() + + # Do something else to clobber the part of the C stack used by `gr`, + # so we can't skate by on "it just happened to still be there" + unrelated = RawGreenlet(lambda: None) + unrelated.switch() + + self.assertEqual(frame.f_code.co_name, "outer") + # The next line crashes on 3.12 if we haven't exposed the frames. + self.assertIsNone(frame.f_back) + + +class TestGreenletSetParentErrors(TestCase): + def test_threaded_reparent(self): + data = {} + created_event = threading.Event() + done_event = threading.Event() + + def run(): + data['g'] = RawGreenlet(lambda: None) + created_event.set() + done_event.wait(10) + + def blank(): + greenlet.getcurrent().parent.switch() + + thread = threading.Thread(target=run) + thread.start() + created_event.wait(10) + g = RawGreenlet(blank) + g.switch() + with self.assertRaises(ValueError) as exc: + g.parent = data['g'] + done_event.set() + thread.join(10) + + self.assertEqual(str(exc.exception), "parent cannot be on a different thread") + + def test_unexpected_reparenting(self): + another = [] + def worker(): + g = RawGreenlet(lambda: None) + another.append(g) + g.switch() + t = threading.Thread(target=worker) + t.start() + t.join(10) + # The first time we switch (running g_initialstub(), which is + # when we look up the run attribute) we attempt to change the + # parent to one from another thread (which also happens to be + # dead). ``g_initialstub()`` should detect this and raise a + # greenlet error. + # + # EXCEPT: With the fix for #252, this is actually detected + # sooner, when setting the parent itself. Prior to that fix, + # the main greenlet from the background thread kept a valid + # value for ``run_info``, and appeared to be a valid parent + # until we actually started the greenlet. But now that it's + # cleared, this test is catching whether ``green_setparent`` + # can detect the dead thread. + # + # Further refactoring once again changes this back to a greenlet.error + # + # We need to wait for the cleanup to happen, but we're + # deliberately leaking a main greenlet here. + self.wait_for_pending_cleanups(initial_main_greenlets=self.main_greenlets_before_test + 1) + + class convoluted(RawGreenlet): + def __getattribute__(self, name): + if name == 'run': + self.parent = another[0] # pylint:disable=attribute-defined-outside-init + return RawGreenlet.__getattribute__(self, name) + g = convoluted(lambda: None) + with self.assertRaises(greenlet.error) as exc: + g.switch() + self.assertEqual(str(exc.exception), + "cannot switch to a different thread (which happens to have exited)") + del another[:] + + def test_unexpected_reparenting_thread_running(self): + # Like ``test_unexpected_reparenting``, except the background thread is + # actually still alive. + another = [] + switched_to_greenlet = threading.Event() + keep_main_alive = threading.Event() + def worker(): + g = RawGreenlet(lambda: None) + another.append(g) + g.switch() + switched_to_greenlet.set() + keep_main_alive.wait(10) + class convoluted(RawGreenlet): + def __getattribute__(self, name): + if name == 'run': + self.parent = another[0] # pylint:disable=attribute-defined-outside-init + return RawGreenlet.__getattribute__(self, name) + + t = threading.Thread(target=worker) + t.start() + + switched_to_greenlet.wait(10) + try: + g = convoluted(lambda: None) + + with self.assertRaises(greenlet.error) as exc: + g.switch() + self.assertEqual(str(exc.exception), "cannot switch to a different thread") + finally: + keep_main_alive.set() + t.join(10) + # XXX: Should handle this automatically. + del another[:] + + def test_cannot_delete_parent(self): + worker = RawGreenlet(lambda: None) + self.assertIs(worker.parent, greenlet.getcurrent()) + + with self.assertRaises(AttributeError) as exc: + del worker.parent + self.assertEqual(str(exc.exception), "can't delete attribute") + + def test_cannot_delete_parent_of_main(self): + with self.assertRaises(AttributeError) as exc: + del greenlet.getcurrent().parent + self.assertEqual(str(exc.exception), "can't delete attribute") + + + def test_main_greenlet_parent_is_none(self): + # assuming we're in a main greenlet here. + self.assertIsNone(greenlet.getcurrent().parent) + + def test_set_parent_wrong_types(self): + def bg(): + # Go back to main. + greenlet.getcurrent().parent.switch() + + def check(glet): + for p in None, 1, self, "42": + with self.assertRaises(TypeError) as exc: + glet.parent = p + + self.assertEqual( + str(exc.exception), + "GreenletChecker: Expected any type of greenlet, not " + type(p).__name__) + + # First, not running + g = RawGreenlet(bg) + self.assertFalse(g) + check(g) + + # Then when running. + g.switch() + self.assertTrue(g) + check(g) + + # Let it finish + g.switch() + + + def test_trivial_cycle(self): + glet = RawGreenlet(lambda: None) + with self.assertRaises(ValueError) as exc: + glet.parent = glet + self.assertEqual(str(exc.exception), "cyclic parent chain") + + def test_trivial_cycle_main(self): + # This used to produce a ValueError, but we catch it earlier than that now. + with self.assertRaises(AttributeError) as exc: + greenlet.getcurrent().parent = greenlet.getcurrent() + self.assertEqual(str(exc.exception), "cannot set the parent of a main greenlet") + + def test_deeper_cycle(self): + g1 = RawGreenlet(lambda: None) + g2 = RawGreenlet(lambda: None) + g3 = RawGreenlet(lambda: None) + + g1.parent = g2 + g2.parent = g3 + with self.assertRaises(ValueError) as exc: + g3.parent = g1 + self.assertEqual(str(exc.exception), "cyclic parent chain") + + +class TestRepr(TestCase): + + def assertEndsWith(self, got, suffix): + self.assertTrue(got.endswith(suffix), (got, suffix)) + + def test_main_while_running(self): + r = repr(greenlet.getcurrent()) + self.assertEndsWith(r, " current active started main>") + + def test_main_in_background(self): + main = greenlet.getcurrent() + def run(): + return repr(main) + + g = RawGreenlet(run) + r = g.switch() + self.assertEndsWith(r, ' suspended active started main>') + + def test_initial(self): + r = repr(RawGreenlet()) + self.assertEndsWith(r, ' pending>') + + def test_main_from_other_thread(self): + main = greenlet.getcurrent() + + class T(threading.Thread): + original_main = thread_main = None + main_glet = None + def run(self): + self.original_main = repr(main) + self.main_glet = greenlet.getcurrent() + self.thread_main = repr(self.main_glet) + + t = T() + t.start() + t.join(10) + + self.assertEndsWith(t.original_main, ' suspended active started main>') + self.assertEndsWith(t.thread_main, ' current active started main>') + # give the machinery time to notice the death of the thread, + # and clean it up. Note that we don't use + # ``expect_greenlet_leak`` or wait_for_pending_cleanups, + # because at this point we know we have an extra greenlet + # still reachable. + for _ in range(3): + time.sleep(0.001) + + # In the past, main greenlets, even from dead threads, never + # really appear dead. We have fixed that, and we also report + # that the thread is dead in the repr. (Do this multiple times + # to make sure that we don't self-modify and forget our state + # in the C++ code). + for _ in range(3): + self.assertTrue(t.main_glet.dead) + r = repr(t.main_glet) + self.assertEndsWith(r, ' (thread exited) dead>') + + def test_dead(self): + g = RawGreenlet(lambda: None) + g.switch() + self.assertEndsWith(repr(g), ' dead>') + self.assertNotIn('suspended', repr(g)) + self.assertNotIn('started', repr(g)) + self.assertNotIn('active', repr(g)) + + def test_formatting_produces_native_str(self): + # https://github.com/python-greenlet/greenlet/issues/218 + # %s formatting on Python 2 was producing unicode, not str. + + g_dead = RawGreenlet(lambda: None) + g_not_started = RawGreenlet(lambda: None) + g_cur = greenlet.getcurrent() + + for g in g_dead, g_not_started, g_cur: + + self.assertIsInstance( + '%s' % (g,), + str + ) + self.assertIsInstance( + '%r' % (g,), + str, + ) + + +class TestMainGreenlet(TestCase): + # Tests some implementation details, and relies on some + # implementation details. + + def _check_current_is_main(self): + # implementation detail + assert 'main' in repr(greenlet.getcurrent()) + + t = type(greenlet.getcurrent()) + assert 'main' not in repr(t) + return t + + def test_main_greenlet_type_can_be_subclassed(self): + main_type = self._check_current_is_main() + subclass = type('subclass', (main_type,), {}) + self.assertIsNotNone(subclass) + + def test_main_greenlet_is_greenlet(self): + self._check_current_is_main() + self.assertIsInstance(greenlet.getcurrent(), RawGreenlet) + + + +class TestBrokenGreenlets(TestCase): + # Tests for things that used to, or still do, terminate the interpreter. + # This often means doing unsavory things. + + def test_failed_to_initialstub(self): + def func(): + raise AssertionError("Never get here") + + + g = greenlet._greenlet.UnswitchableGreenlet(func) + g.force_switch_error = True + + with self.assertRaisesRegex(SystemError, + "Failed to switch stacks into a greenlet for the first time."): + g.switch() + + def test_failed_to_switch_into_running(self): + runs = [] + def func(): + runs.append(1) + greenlet.getcurrent().parent.switch() + runs.append(2) + greenlet.getcurrent().parent.switch() + runs.append(3) # pragma: no cover + + g = greenlet._greenlet.UnswitchableGreenlet(func) + g.switch() + self.assertEqual(runs, [1]) + g.switch() + self.assertEqual(runs, [1, 2]) + g.force_switch_error = True + + with self.assertRaisesRegex(SystemError, + "Failed to switch stacks into a running greenlet."): + g.switch() + + # If we stopped here, we would fail the leakcheck, because we've left + # the ``inner_bootstrap()`` C frame and its descendents hanging around, + # which have a bunch of Python references. They'll never get cleaned up + # if we don't let the greenlet finish. + g.force_switch_error = False + g.switch() + self.assertEqual(runs, [1, 2, 3]) + + def test_failed_to_slp_switch_into_running(self): + ex = self.assertScriptRaises('fail_slp_switch.py') + + self.assertIn('fail_slp_switch is running', ex.output) + self.assertIn(ex.returncode, self.get_expected_returncodes_for_aborted_process()) + + def test_reentrant_switch_two_greenlets(self): + # Before we started capturing the arguments in g_switch_finish, this could crash. + output = self.run_script('fail_switch_two_greenlets.py') + self.assertIn('In g1_run', output) + self.assertIn('TRACE', output) + self.assertIn('LEAVE TRACE', output) + self.assertIn('Falling off end of main', output) + self.assertIn('Falling off end of g1_run', output) + self.assertIn('Falling off end of g2', output) + + def test_reentrant_switch_three_greenlets(self): + # On debug builds of greenlet, this used to crash with an assertion error; + # on non-debug versions, it ran fine (which it should not do!). + # Now it always crashes correctly with a TypeError + ex = self.assertScriptRaises('fail_switch_three_greenlets.py', exitcodes=(1,)) + + self.assertIn('TypeError', ex.output) + self.assertIn('positional arguments', ex.output) + + def test_reentrant_switch_three_greenlets2(self): + # This actually passed on debug and non-debug builds. It + # should probably have been triggering some debug assertions + # but it didn't. + # + # I think the fixes for the above test also kicked in here. + output = self.run_script('fail_switch_three_greenlets2.py') + self.assertIn( + "RESULTS: [('trace', 'switch'), " + "('trace', 'switch'), ('g2 arg', 'g2 from tracefunc'), " + "('trace', 'switch'), ('main g1', 'from g2_run'), ('trace', 'switch'), " + "('g1 arg', 'g1 from main'), ('trace', 'switch'), ('main g2', 'from g1_run'), " + "('trace', 'switch'), ('g1 from parent', 'g1 from main 2'), ('trace', 'switch'), " + "('main g1.2', 'g1 done'), ('trace', 'switch'), ('g2 from parent', ()), " + "('trace', 'switch'), ('main g2.2', 'g2 done')]", + output + ) + + def test_reentrant_switch_GreenletAlreadyStartedInPython(self): + output = self.run_script('fail_initialstub_already_started.py') + + self.assertIn( + "RESULTS: ['Begin C', 'Switch to b from B.__getattribute__ in C', " + "('Begin B', ()), '_B_run switching to main', ('main from c', 'From B'), " + "'B.__getattribute__ back from main in C', ('Begin A', (None,)), " + "('A dead?', True, 'B dead?', True, 'C dead?', False), " + "'C done', ('main from c.2', None)]", + output + ) + + def test_reentrant_switch_run_callable_has_del(self): + output = self.run_script('fail_clearing_run_switches.py') + self.assertIn( + "RESULTS [" + "('G.__getattribute__', 'run'), ('RunCallable', '__del__'), " + "('main: g.switch()', 'from RunCallable'), ('run_func', 'enter')" + "]", + output + ) + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py new file mode 100644 index 0000000..8d9716e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_greenlet_trash.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- +""" +Tests for greenlets interacting with the CPython trash can API. + +The CPython trash can API is not designed to be re-entered from a +single thread. But this can happen using greenlets, if something +during the object deallocation process switches greenlets, and this second +greenlet then causes the trash can to get entered again. Here, we do this +very explicitly, but in other cases (like gevent) it could be arbitrarily more +complicated: for example, a weakref callback might try to acquire a lock that's +already held by another greenlet; that would allow a greenlet switch to occur. + +See https://github.com/gevent/gevent/issues/1909 + +This test is fragile and relies on details of the CPython +implementation (like most of the rest of this package): + + - We enter the trashcan and deferred deallocation after + ``_PyTrash_UNWIND_LEVEL`` calls. This constant, defined in + CPython's object.c, is generally 50. That's basically how many objects are required to + get us into the deferred deallocation situation. + + - The test fails by hitting an ``assert()`` in object.c; if the + build didn't enable assert, then we don't catch this. + + - If the test fails in that way, the interpreter crashes. +""" +from __future__ import print_function, absolute_import, division + +import unittest + +class TestTrashCanReEnter(unittest.TestCase): + + def test_it(self): + # Try several times to trigger it, because it isn't 100% + # reliable. + for _ in range(10): + self.check_it() + + def check_it(self): # pylint:disable=too-many-statements + import greenlet + from greenlet._greenlet import get_tstate_trash_delete_nesting # pylint:disable=no-name-in-module + + main = greenlet.getcurrent() + + assert get_tstate_trash_delete_nesting() == 0 + + # We expect to be in deferred deallocation after this many + # deallocations have occurred. TODO: I wish we had a better way to do + # this --- that was before get_tstate_trash_delete_nesting; perhaps + # we can use that API to do better? + TRASH_UNWIND_LEVEL = 50 + # How many objects to put in a container; it's the container that + # queues objects for deferred deallocation. + OBJECTS_PER_CONTAINER = 500 + + class Dealloc: # define the class here because we alter class variables each time we run. + """ + An object with a ``__del__`` method. When it starts getting deallocated + from a deferred trash can run, it switches greenlets, allocates more objects + which then also go in the trash can. If we don't save state appropriately, + nesting gets out of order and we can crash the interpreter. + """ + + #: Has our deallocation actually run and switched greenlets? + #: When it does, this will be set to the current greenlet. This should + #: be happening in the main greenlet, so we check that down below. + SPAWNED = False + + #: Has the background greenlet run? + BG_RAN = False + + BG_GLET = None + + #: How many of these things have ever been allocated. + CREATED = 0 + + #: How many of these things have ever been deallocated. + DESTROYED = 0 + + #: How many were destroyed not in the main greenlet. There should always + #: be some. + #: If the test is broken or things change in the trashcan implementation, + #: this may not be correct. + DESTROYED_BG = 0 + + def __init__(self, sequence_number): + """ + :param sequence_number: The ordinal of this object during + one particular creation run. This is used to detect (guess, really) + when we have entered the trash can's deferred deallocation. + """ + self.i = sequence_number + Dealloc.CREATED += 1 + + def __del__(self): + if self.i == TRASH_UNWIND_LEVEL and not self.SPAWNED: + Dealloc.SPAWNED = greenlet.getcurrent() + other = Dealloc.BG_GLET = greenlet.greenlet(background_greenlet) + x = other.switch() + assert x == 42 + # It's important that we don't switch back to the greenlet, + # we leave it hanging there in an incomplete state. But we don't let it + # get collected, either. If we complete it now, while we're still + # in the scope of the initial trash can, things work out and we + # don't see the problem. We need this greenlet to complete + # at some point in the future, after we've exited this trash can invocation. + del other + elif self.i == 40 and greenlet.getcurrent() is not main: + Dealloc.BG_RAN = True + try: + main.switch(42) + except greenlet.GreenletExit as ex: + # We expect this; all references to us go away + # while we're still running, and we need to finish deleting + # ourself. + Dealloc.BG_RAN = type(ex) + del ex + + # Record the fact that we're dead last of all. This ensures that + # we actually get returned too. + Dealloc.DESTROYED += 1 + if greenlet.getcurrent() is not main: + Dealloc.DESTROYED_BG += 1 + + + def background_greenlet(): + # We direct through a second function, instead of + # directly calling ``make_some()``, so that we have complete + # control over when these objects are destroyed: we need them + # to be destroyed in the context of the background greenlet + t = make_some() + del t # Triggere deletion. + + def make_some(): + t = () + i = OBJECTS_PER_CONTAINER + while i: + # Nest the tuples; it's the recursion that gets us + # into trash. + t = (Dealloc(i), t) + i -= 1 + return t + + + some = make_some() + self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER) + self.assertEqual(Dealloc.DESTROYED, 0) + + # If we're going to crash, it should be on the following line. + # We only crash if ``assert()`` is enabled, of course. + del some + + # For non-debug builds of CPython, we won't crash. The best we can do is check + # the nesting level explicitly. + self.assertEqual(0, get_tstate_trash_delete_nesting()) + + # Discard this, raising GreenletExit into where it is waiting. + Dealloc.BG_GLET = None + # The same nesting level maintains. + self.assertEqual(0, get_tstate_trash_delete_nesting()) + + # We definitely cleaned some up in the background + self.assertGreater(Dealloc.DESTROYED_BG, 0) + + # Make sure all the cleanups happened. + self.assertIs(Dealloc.SPAWNED, main) + self.assertTrue(Dealloc.BG_RAN) + self.assertEqual(Dealloc.BG_RAN, greenlet.GreenletExit) + self.assertEqual(Dealloc.CREATED, Dealloc.DESTROYED ) + self.assertEqual(Dealloc.CREATED, OBJECTS_PER_CONTAINER * 2) + + import gc + gc.collect() + + +if __name__ == '__main__': + unittest.main() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_leaks.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_leaks.py new file mode 100644 index 0000000..ed1fa71 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_leaks.py @@ -0,0 +1,443 @@ +# -*- coding: utf-8 -*- +""" +Testing scenarios that may have leaked. +""" +from __future__ import print_function, absolute_import, division + +import sys +import gc + +import time +import weakref +import threading + + +import greenlet +from . import TestCase +from .leakcheck import fails_leakcheck +from .leakcheck import ignores_leakcheck +from .leakcheck import RUNNING_ON_MANYLINUX + +# pylint:disable=protected-access + +assert greenlet.GREENLET_USE_GC # Option to disable this was removed in 1.0 + +class HasFinalizerTracksInstances(object): + EXTANT_INSTANCES = set() + def __init__(self, msg): + self.msg = sys.intern(msg) + self.EXTANT_INSTANCES.add(id(self)) + def __del__(self): + self.EXTANT_INSTANCES.remove(id(self)) + def __repr__(self): + return "" % ( + id(self), self.msg + ) + @classmethod + def reset(cls): + cls.EXTANT_INSTANCES.clear() + + +class TestLeaks(TestCase): + + def test_arg_refs(self): + args = ('a', 'b', 'c') + refcount_before = sys.getrefcount(args) + # pylint:disable=unnecessary-lambda + g = greenlet.greenlet( + lambda *args: greenlet.getcurrent().parent.switch(*args)) + for _ in range(100): + g.switch(*args) + self.assertEqual(sys.getrefcount(args), refcount_before) + + def test_kwarg_refs(self): + kwargs = {} + # pylint:disable=unnecessary-lambda + g = greenlet.greenlet( + lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs)) + for _ in range(100): + g.switch(**kwargs) + self.assertEqual(sys.getrefcount(kwargs), 2) + + + @staticmethod + def __recycle_threads(): + # By introducing a thread that does sleep we allow other threads, + # that have triggered their __block condition, but did not have a + # chance to deallocate their thread state yet, to finally do so. + # The way it works is by requiring a GIL switch (different thread), + # which does a GIL release (sleep), which might do a GIL switch + # to finished threads and allow them to clean up. + def worker(): + time.sleep(0.001) + t = threading.Thread(target=worker) + t.start() + time.sleep(0.001) + t.join(10) + + def test_threaded_leak(self): + gg = [] + def worker(): + # only main greenlet present + gg.append(weakref.ref(greenlet.getcurrent())) + for _ in range(2): + t = threading.Thread(target=worker) + t.start() + t.join(10) + del t + greenlet.getcurrent() # update ts_current + self.__recycle_threads() + greenlet.getcurrent() # update ts_current + gc.collect() + greenlet.getcurrent() # update ts_current + for g in gg: + self.assertIsNone(g()) + + def test_threaded_adv_leak(self): + gg = [] + def worker(): + # main and additional *finished* greenlets + ll = greenlet.getcurrent().ll = [] + def additional(): + ll.append(greenlet.getcurrent()) + for _ in range(2): + greenlet.greenlet(additional).switch() + gg.append(weakref.ref(greenlet.getcurrent())) + for _ in range(2): + t = threading.Thread(target=worker) + t.start() + t.join(10) + del t + greenlet.getcurrent() # update ts_current + self.__recycle_threads() + greenlet.getcurrent() # update ts_current + gc.collect() + greenlet.getcurrent() # update ts_current + for g in gg: + self.assertIsNone(g()) + + def assertClocksUsed(self): + used = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() + self.assertGreaterEqual(used, 0) + # we don't lose the value + greenlet._greenlet.enable_optional_cleanup(True) + used2 = greenlet._greenlet.get_clocks_used_doing_optional_cleanup() + self.assertEqual(used, used2) + self.assertGreater(greenlet._greenlet.CLOCKS_PER_SEC, 1) + + def _check_issue251(self, + manually_collect_background=True, + explicit_reference_to_switch=False): + # See https://github.com/python-greenlet/greenlet/issues/251 + # Killing a greenlet (probably not the main one) + # in one thread from another thread would + # result in leaking a list (the ts_delkey list). + # We no longer use lists to hold that stuff, though. + + # For the test to be valid, even empty lists have to be tracked by the + # GC + + assert gc.is_tracked([]) + HasFinalizerTracksInstances.reset() + greenlet.getcurrent() + greenlets_before = self.count_objects(greenlet.greenlet, exact_kind=False) + + background_glet_running = threading.Event() + background_glet_killed = threading.Event() + background_greenlets = [] + + # XXX: Switching this to a greenlet subclass that overrides + # run results in all callers failing the leaktest; that + # greenlet instance is leaked. There's a bound method for + # run() living on the stack of the greenlet in g_initialstub, + # and since we don't manually switch back to the background + # greenlet to let it "fall off the end" and exit the + # g_initialstub function, it never gets cleaned up. Making the + # garbage collector aware of this bound method (making it an + # attribute of the greenlet structure and traversing into it) + # doesn't help, for some reason. + def background_greenlet(): + # Throw control back to the main greenlet. + jd = HasFinalizerTracksInstances("DELETING STACK OBJECT") + greenlet._greenlet.set_thread_local( + 'test_leaks_key', + HasFinalizerTracksInstances("DELETING THREAD STATE")) + # Explicitly keeping 'switch' in a local variable + # breaks this test in all versions + if explicit_reference_to_switch: + s = greenlet.getcurrent().parent.switch + s([jd]) + else: + greenlet.getcurrent().parent.switch([jd]) + + bg_main_wrefs = [] + + def background_thread(): + glet = greenlet.greenlet(background_greenlet) + bg_main_wrefs.append(weakref.ref(glet.parent)) + + background_greenlets.append(glet) + glet.switch() # Be sure it's active. + # Control is ours again. + del glet # Delete one reference from the thread it runs in. + background_glet_running.set() + background_glet_killed.wait(10) + + # To trigger the background collection of the dead + # greenlet, thus clearing out the contents of the list, we + # need to run some APIs. See issue 252. + if manually_collect_background: + greenlet.getcurrent() + + + t = threading.Thread(target=background_thread) + t.start() + background_glet_running.wait(10) + greenlet.getcurrent() + lists_before = self.count_objects(list, exact_kind=True) + + assert len(background_greenlets) == 1 + self.assertFalse(background_greenlets[0].dead) + # Delete the last reference to the background greenlet + # from a different thread. This puts it in the background thread's + # ts_delkey list. + del background_greenlets[:] + background_glet_killed.set() + + # Now wait for the background thread to die. + t.join(10) + del t + # As part of the fix for 252, we need to cycle the ceval.c + # interpreter loop to be sure it has had a chance to process + # the pending call. + self.wait_for_pending_cleanups() + + lists_after = self.count_objects(list, exact_kind=True) + greenlets_after = self.count_objects(greenlet.greenlet, exact_kind=False) + + # On 2.7, we observe that lists_after is smaller than + # lists_before. No idea what lists got cleaned up. All the + # Python 3 versions match exactly. + self.assertLessEqual(lists_after, lists_before) + # On versions after 3.6, we've successfully cleaned up the + # greenlet references thanks to the internal "vectorcall" + # protocol; prior to that, there is a reference path through + # the ``greenlet.switch`` method still on the stack that we + # can't reach to clean up. The C code goes through terrific + # lengths to clean that up. + if not explicit_reference_to_switch \ + and greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: + # If cleanup was disabled, though, we may not find it. + self.assertEqual(greenlets_after, greenlets_before) + if manually_collect_background: + # TODO: Figure out how to make this work! + # The one on the stack is still leaking somehow + # in the non-manually-collect state. + self.assertEqual(HasFinalizerTracksInstances.EXTANT_INSTANCES, set()) + else: + # The explicit reference prevents us from collecting it + # and it isn't always found by the GC either for some + # reason. The entire frame is leaked somehow, on some + # platforms (e.g., MacPorts builds of Python (all + # versions!)), but not on other platforms (the linux and + # windows builds on GitHub actions and Appveyor). So we'd + # like to write a test that proves that the main greenlet + # sticks around, and we can on my machine (macOS 11.6, + # MacPorts builds of everything) but we can't write that + # same test on other platforms. However, hopefully iteration + # done by leakcheck will find it. + pass + + if greenlet._greenlet.get_clocks_used_doing_optional_cleanup() is not None: + self.assertClocksUsed() + + def test_issue251_killing_cross_thread_leaks_list(self): + self._check_issue251() + + def test_issue251_with_cleanup_disabled(self): + greenlet._greenlet.enable_optional_cleanup(False) + try: + self._check_issue251() + finally: + greenlet._greenlet.enable_optional_cleanup(True) + + @fails_leakcheck + def test_issue251_issue252_need_to_collect_in_background(self): + # Between greenlet 1.1.2 and the next version, this was still + # failing because the leak of the list still exists when we + # don't call a greenlet API before exiting the thread. The + # proximate cause is that neither of the two greenlets from + # the background thread are actually being destroyed, even + # though the GC is in fact visiting both objects. It's not + # clear where that leak is? For some reason the thread-local + # dict holding it isn't being cleaned up. + # + # The leak, I think, is in the CPYthon internal function that + # calls into green_switch(). The argument tuple is still on + # the C stack somewhere and can't be reached? That doesn't + # make sense, because the tuple should be collectable when + # this object goes away. + # + # Note that this test sometimes spuriously passes on Linux, + # for some reason, but I've never seen it pass on macOS. + self._check_issue251(manually_collect_background=False) + + @fails_leakcheck + def test_issue251_issue252_need_to_collect_in_background_cleanup_disabled(self): + self.expect_greenlet_leak = True + greenlet._greenlet.enable_optional_cleanup(False) + try: + self._check_issue251(manually_collect_background=False) + finally: + greenlet._greenlet.enable_optional_cleanup(True) + + @fails_leakcheck + def test_issue251_issue252_explicit_reference_not_collectable(self): + self._check_issue251( + manually_collect_background=False, + explicit_reference_to_switch=True) + + UNTRACK_ATTEMPTS = 100 + + def _only_test_some_versions(self): + # We're only looking for this problem specifically on 3.11, + # and this set of tests is relatively fragile, depending on + # OS and memory management details. So we want to run it on 3.11+ + # (obviously) but not every older 3.x version in order to reduce + # false negatives. At the moment, those false results seem to have + # resolved, so we are actually running this on 3.8+ + assert sys.version_info[0] >= 3 + if sys.version_info[:2] < (3, 8): + self.skipTest('Only observed on 3.11') + if RUNNING_ON_MANYLINUX: + self.skipTest("Slow and not worth repeating here") + + @ignores_leakcheck + # Because we're just trying to track raw memory, not objects, and running + # the leakcheck makes an already slow test slower. + def test_untracked_memory_doesnt_increase(self): + # See https://github.com/gevent/gevent/issues/1924 + # and https://github.com/python-greenlet/greenlet/issues/328 + self._only_test_some_versions() + def f(): + return 1 + + ITER = 10000 + def run_it(): + for _ in range(ITER): + greenlet.greenlet(f).switch() + + # Establish baseline + for _ in range(3): + run_it() + + # uss: (Linux, macOS, Windows): aka "Unique Set Size", this is + # the memory which is unique to a process and which would be + # freed if the process was terminated right now. + uss_before = self.get_process_uss() + + for count in range(self.UNTRACK_ATTEMPTS): + uss_before = max(uss_before, self.get_process_uss()) + run_it() + + uss_after = self.get_process_uss() + if uss_after <= uss_before and count > 1: + break + + self.assertLessEqual(uss_after, uss_before) + + def _check_untracked_memory_thread(self, deallocate_in_thread=True): + self._only_test_some_versions() + # Like the above test, but what if there are a bunch of + # unfinished greenlets in a thread that dies? + # Does it matter if we deallocate in the thread or not? + EXIT_COUNT = [0] + + def f(): + try: + greenlet.getcurrent().parent.switch() + except greenlet.GreenletExit: + EXIT_COUNT[0] += 1 + raise + return 1 + + ITER = 10000 + def run_it(): + glets = [] + for _ in range(ITER): + # Greenlet starts, switches back to us. + # We keep a strong reference to the greenlet though so it doesn't + # get a GreenletExit exception. + g = greenlet.greenlet(f) + glets.append(g) + g.switch() + + return glets + + test = self + + class ThreadFunc: + uss_before = uss_after = 0 + glets = () + ITER = 2 + def __call__(self): + self.uss_before = test.get_process_uss() + + for _ in range(self.ITER): + self.glets += tuple(run_it()) + + for g in self.glets: + test.assertIn('suspended active', str(g)) + # Drop them. + if deallocate_in_thread: + self.glets = () + self.uss_after = test.get_process_uss() + + # Establish baseline + uss_before = uss_after = None + for count in range(self.UNTRACK_ATTEMPTS): + EXIT_COUNT[0] = 0 + thread_func = ThreadFunc() + t = threading.Thread(target=thread_func) + t.start() + t.join(30) + self.assertFalse(t.is_alive()) + + if uss_before is None: + uss_before = thread_func.uss_before + + uss_before = max(uss_before, thread_func.uss_before) + if deallocate_in_thread: + self.assertEqual(thread_func.glets, ()) + self.assertEqual(EXIT_COUNT[0], ITER * thread_func.ITER) + + del thread_func # Deallocate the greenlets; but this won't raise into them + del t + if not deallocate_in_thread: + self.assertEqual(EXIT_COUNT[0], 0) + if deallocate_in_thread: + self.wait_for_pending_cleanups() + + uss_after = self.get_process_uss() + # See if we achieve a non-growth state at some point. Break when we do. + if uss_after <= uss_before and count > 1: + break + + self.wait_for_pending_cleanups() + uss_after = self.get_process_uss() + self.assertLessEqual(uss_after, uss_before, "after attempts %d" % (count,)) + + @ignores_leakcheck + # Because we're just trying to track raw memory, not objects, and running + # the leakcheck makes an already slow test slower. + def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_thread(self): + self._check_untracked_memory_thread(deallocate_in_thread=True) + + @ignores_leakcheck + # Because the main greenlets from the background threads do not exit in a timely fashion, + # we fail the object-based leakchecks. + def test_untracked_memory_doesnt_increase_unfinished_thread_dealloc_in_main(self): + self._check_untracked_memory_thread(deallocate_in_thread=False) + +if __name__ == '__main__': + __import__('unittest').main() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py new file mode 100644 index 0000000..b362bf9 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_stack_saved.py @@ -0,0 +1,19 @@ +import greenlet +from . import TestCase + + +class Test(TestCase): + + def test_stack_saved(self): + main = greenlet.getcurrent() + self.assertEqual(main._stack_saved, 0) + + def func(): + main.switch(main._stack_saved) + + g = greenlet.greenlet(func) + x = g.switch() + self.assertGreater(x, 0) + self.assertGreater(g._stack_saved, 0) + g.switch() + self.assertEqual(g._stack_saved, 0) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_throw.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_throw.py new file mode 100644 index 0000000..f4f9a14 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_throw.py @@ -0,0 +1,128 @@ +import sys + + +from greenlet import greenlet +from . import TestCase + +def switch(*args): + return greenlet.getcurrent().parent.switch(*args) + + +class ThrowTests(TestCase): + def test_class(self): + def f(): + try: + switch("ok") + except RuntimeError: + switch("ok") + return + switch("fail") + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError) + self.assertEqual(res, "ok") + + def test_val(self): + def f(): + try: + switch("ok") + except RuntimeError: + val = sys.exc_info()[1] + if str(val) == "ciao": + switch("ok") + return + switch("fail") + + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError("ciao")) + self.assertEqual(res, "ok") + + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw(RuntimeError, "ciao") + self.assertEqual(res, "ok") + + def test_kill(self): + def f(): + switch("ok") + switch("fail") + g = greenlet(f) + res = g.switch() + self.assertEqual(res, "ok") + res = g.throw() + self.assertTrue(isinstance(res, greenlet.GreenletExit)) + self.assertTrue(g.dead) + res = g.throw() # immediately eaten by the already-dead greenlet + self.assertTrue(isinstance(res, greenlet.GreenletExit)) + + def test_throw_goes_to_original_parent(self): + main = greenlet.getcurrent() + + def f1(): + try: + main.switch("f1 ready to catch") + except IndexError: + return "caught" + return "normal exit" + + def f2(): + main.switch("from f2") + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + with self.assertRaises(IndexError): + g2.throw(IndexError) + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + res = g1.switch() + self.assertEqual(res, "f1 ready to catch") + res = g2.throw(IndexError) + self.assertEqual(res, "caught") + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + g1 = greenlet(f1) + g2 = greenlet(f2, parent=g1) + res = g1.switch() + self.assertEqual(res, "f1 ready to catch") + res = g2.switch() + self.assertEqual(res, "from f2") + res = g2.throw(IndexError) + self.assertEqual(res, "caught") + self.assertTrue(g2.dead) + self.assertTrue(g1.dead) + + def test_non_traceback_param(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + Exception, + Exception(), + self + ) + self.assertEqual(str(exc.exception), + "throw() third argument must be a traceback object") + + def test_instance_of_wrong_type(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + Exception(), + BaseException() + ) + + self.assertEqual(str(exc.exception), + "instance exception may not have a separate value") + + def test_not_throwable(self): + with self.assertRaises(TypeError) as exc: + greenlet.getcurrent().throw( + "abc" + ) + self.assertEqual(str(exc.exception), + "exceptions must be classes, or instances, not str") diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_tracing.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_tracing.py new file mode 100644 index 0000000..c044d4b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_tracing.py @@ -0,0 +1,291 @@ +from __future__ import print_function +import sys +import greenlet +import unittest + +from . import TestCase +from . import PY312 + +# https://discuss.python.org/t/cpython-3-12-greenlet-and-tracing-profiling-how-to-not-crash-and-get-correct-results/33144/2 +DEBUG_BUILD_PY312 = ( + PY312 and hasattr(sys, 'gettotalrefcount'), + "Broken on debug builds of Python 3.12" +) + +class SomeError(Exception): + pass + +class GreenletTracer(object): + oldtrace = None + + def __init__(self, error_on_trace=False): + self.actions = [] + self.error_on_trace = error_on_trace + + def __call__(self, *args): + self.actions.append(args) + if self.error_on_trace: + raise SomeError + + def __enter__(self): + self.oldtrace = greenlet.settrace(self) + return self.actions + + def __exit__(self, *args): + greenlet.settrace(self.oldtrace) + + +class TestGreenletTracing(TestCase): + """ + Tests of ``greenlet.settrace()`` + """ + + def test_a_greenlet_tracing(self): + main = greenlet.getcurrent() + def dummy(): + pass + def dummyexc(): + raise SomeError() + + with GreenletTracer() as actions: + g1 = greenlet.greenlet(dummy) + g1.switch() + g2 = greenlet.greenlet(dummyexc) + self.assertRaises(SomeError, g2.switch) + + self.assertEqual(actions, [ + ('switch', (main, g1)), + ('switch', (g1, main)), + ('switch', (main, g2)), + ('throw', (g2, main)), + ]) + + def test_b_exception_disables_tracing(self): + main = greenlet.getcurrent() + def dummy(): + main.switch() + g = greenlet.greenlet(dummy) + g.switch() + with GreenletTracer(error_on_trace=True) as actions: + self.assertRaises(SomeError, g.switch) + self.assertEqual(greenlet.gettrace(), None) + + self.assertEqual(actions, [ + ('switch', (main, g)), + ]) + + def test_set_same_tracer_twice(self): + # https://github.com/python-greenlet/greenlet/issues/332 + # Our logic in asserting that the tracefunction should + # gain a reference was incorrect if the same tracefunction was set + # twice. + tracer = GreenletTracer() + with tracer: + greenlet.settrace(tracer) + + +class PythonTracer(object): + oldtrace = None + + def __init__(self): + self.actions = [] + + def __call__(self, frame, event, arg): + # Record the co_name so we have an idea what function we're in. + self.actions.append((event, frame.f_code.co_name)) + + def __enter__(self): + self.oldtrace = sys.setprofile(self) + return self.actions + + def __exit__(self, *args): + sys.setprofile(self.oldtrace) + +def tpt_callback(): + return 42 + +class TestPythonTracing(TestCase): + """ + Tests of the interaction of ``sys.settrace()`` + with greenlet facilities. + + NOTE: Most of this is probably CPython specific. + """ + + maxDiff = None + + def test_trace_events_trivial(self): + with PythonTracer() as actions: + tpt_callback() + # If we use the sys.settrace instead of setprofile, we get + # this: + + # self.assertEqual(actions, [ + # ('call', 'tpt_callback'), + # ('call', '__exit__'), + # ]) + + self.assertEqual(actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + def _trace_switch(self, glet): + with PythonTracer() as actions: + glet.switch() + return actions + + def _check_trace_events_func_already_set(self, glet): + actions = self._trace_switch(glet) + self.assertEqual(actions, [ + ('return', '__enter__'), + ('c_call', '_trace_switch'), + ('call', 'run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('return', 'run'), + ('c_return', '_trace_switch'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + def test_trace_events_into_greenlet_func_already_set(self): + def run(): + return tpt_callback() + + self._check_trace_events_func_already_set(greenlet.greenlet(run)) + + def test_trace_events_into_greenlet_subclass_already_set(self): + class X(greenlet.greenlet): + def run(self): + return tpt_callback() + self._check_trace_events_func_already_set(X()) + + def _check_trace_events_from_greenlet_sets_profiler(self, g, tracer): + g.switch() + tpt_callback() + tracer.__exit__() + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('return', 'run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + + def test_trace_events_from_greenlet_func_sets_profiler(self): + tracer = PythonTracer() + def run(): + tracer.__enter__() + return tpt_callback() + + self._check_trace_events_from_greenlet_sets_profiler(greenlet.greenlet(run), + tracer) + + def test_trace_events_from_greenlet_subclass_sets_profiler(self): + tracer = PythonTracer() + class X(greenlet.greenlet): + def run(self): + tracer.__enter__() + return tpt_callback() + + self._check_trace_events_from_greenlet_sets_profiler(X(), tracer) + + @unittest.skipIf(*DEBUG_BUILD_PY312) + def test_trace_events_multiple_greenlets_switching(self): + tracer = PythonTracer() + + g1 = None + g2 = None + + def g1_run(): + tracer.__enter__() + tpt_callback() + g2.switch() + tpt_callback() + return 42 + + def g2_run(): + tpt_callback() + tracer.__exit__() + tpt_callback() + g1.switch() + + g1 = greenlet.greenlet(g1_run) + g2 = greenlet.greenlet(g2_run) + + x = g1.switch() + self.assertEqual(x, 42) + tpt_callback() # ensure not in the trace + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('c_call', 'g1_run'), + ('call', 'g2_run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + @unittest.skipIf(*DEBUG_BUILD_PY312) + def test_trace_events_multiple_greenlets_switching_siblings(self): + # Like the first version, but get both greenlets running first + # as "siblings" and then establish the tracing. + tracer = PythonTracer() + + g1 = None + g2 = None + + def g1_run(): + greenlet.getcurrent().parent.switch() + tracer.__enter__() + tpt_callback() + g2.switch() + tpt_callback() + return 42 + + def g2_run(): + greenlet.getcurrent().parent.switch() + + tpt_callback() + tracer.__exit__() + tpt_callback() + g1.switch() + + g1 = greenlet.greenlet(g1_run) + g2 = greenlet.greenlet(g2_run) + + # Start g1 + g1.switch() + # And it immediately returns control to us. + # Start g2 + g2.switch() + # Which also returns. Now kick of the real part of the + # test. + x = g1.switch() + self.assertEqual(x, 42) + + tpt_callback() # ensure not in the trace + self.assertEqual(tracer.actions, [ + ('return', '__enter__'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('c_call', 'g1_run'), + ('call', 'tpt_callback'), + ('return', 'tpt_callback'), + ('call', '__exit__'), + ('c_call', '__exit__'), + ]) + + +if __name__ == '__main__': + unittest.main() diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_version.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_version.py new file mode 100644 index 0000000..96c17cf --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_version.py @@ -0,0 +1,41 @@ +#! /usr/bin/env python +from __future__ import absolute_import +from __future__ import print_function + +import sys +import os +from unittest import TestCase as NonLeakingTestCase + +import greenlet + +# No reason to run this multiple times under leakchecks, +# it doesn't do anything. +class VersionTests(NonLeakingTestCase): + def test_version(self): + def find_dominating_file(name): + if os.path.exists(name): + return name + + tried = [] + here = os.path.abspath(os.path.dirname(__file__)) + for i in range(10): + up = ['..'] * i + path = [here] + up + [name] + fname = os.path.join(*path) + fname = os.path.abspath(fname) + tried.append(fname) + if os.path.exists(fname): + return fname + raise AssertionError("Could not find file " + name + "; checked " + str(tried)) + + try: + setup_py = find_dominating_file('setup.py') + except AssertionError as e: + self.skipTest("Unable to find setup.py; must be out of tree. " + str(e)) + + + invoke_setup = "%s %s --version" % (sys.executable, setup_py) + with os.popen(invoke_setup) as f: + sversion = f.read().strip() + + self.assertEqual(sversion, greenlet.__version__) diff --git a/elitebot/lib/python3.11/site-packages/greenlet/tests/test_weakref.py b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_weakref.py new file mode 100644 index 0000000..05a38a7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/greenlet/tests/test_weakref.py @@ -0,0 +1,35 @@ +import gc +import weakref + + +import greenlet +from . import TestCase + +class WeakRefTests(TestCase): + def test_dead_weakref(self): + def _dead_greenlet(): + g = greenlet.greenlet(lambda: None) + g.switch() + return g + o = weakref.ref(_dead_greenlet()) + gc.collect() + self.assertEqual(o(), None) + + def test_inactive_weakref(self): + o = weakref.ref(greenlet.greenlet()) + gc.collect() + self.assertEqual(o(), None) + + def test_dealloc_weakref(self): + seen = [] + def worker(): + try: + greenlet.getcurrent().parent.switch() + finally: + seen.append(g()) + g = greenlet.greenlet(worker) + g.switch() + g2 = greenlet.greenlet(lambda: None, g) + g = weakref.ref(g2) + g2 = None + self.assertEqual(seen, [None]) diff --git a/elitebot/lib/python3.11/site-packages/mysql/__init__.py b/elitebot/lib/python3.11/site-packages/mysql/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/__init__.py b/elitebot/lib/python3.11/site-packages/mysql/connector/__init__.py new file mode 100644 index 0000000..8a2428e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/__init__.py @@ -0,0 +1,207 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +""" +MySQL Connector/Python - MySQL driver written in Python +""" + +try: + import _mysql_connector # pylint: disable=F0401 + from .connection_cext import CMySQLConnection +except ImportError: + HAVE_CEXT = False +else: + HAVE_CEXT = True + +from . import version +from .connection import MySQLConnection +from .errors import ( # pylint: disable=W0622 + Error, Warning, InterfaceError, DatabaseError, + NotSupportedError, DataError, IntegrityError, ProgrammingError, + OperationalError, InternalError, custom_error_exception, PoolError) +from .constants import FieldFlag, FieldType, CharacterSet, \ + RefreshOption, ClientFlag +from .dbapi import ( + Date, Time, Timestamp, Binary, DateFromTicks, + TimestampFromTicks, TimeFromTicks, + STRING, BINARY, NUMBER, DATETIME, ROWID, + apilevel, threadsafety, paramstyle) +from .optionfiles import read_option_files + +_CONNECTION_POOLS = {} + +def _get_pooled_connection(**kwargs): + """Return a pooled MySQL connection""" + # If no pool name specified, generate one + from .pooling import ( + MySQLConnectionPool, generate_pool_name, + CONNECTION_POOL_LOCK) + + try: + pool_name = kwargs['pool_name'] + except KeyError: + pool_name = generate_pool_name(**kwargs) + + # Setup the pool, ensuring only 1 thread can update at a time + with CONNECTION_POOL_LOCK: + if pool_name not in _CONNECTION_POOLS: + _CONNECTION_POOLS[pool_name] = MySQLConnectionPool(**kwargs) + elif isinstance(_CONNECTION_POOLS[pool_name], MySQLConnectionPool): + # pool_size must be the same + check_size = _CONNECTION_POOLS[pool_name].pool_size + if ('pool_size' in kwargs + and kwargs['pool_size'] != check_size): + raise PoolError("Size can not be changed " + "for active pools.") + + # Return pooled connection + try: + return _CONNECTION_POOLS[pool_name].get_connection() + except AttributeError: + raise InterfaceError( + "Failed getting connection from pool '{0}'".format(pool_name)) + + +def _get_failover_connection(**kwargs): + """Return a MySQL connection and try to failover if needed + + An InterfaceError is raise when no MySQL is available. ValueError is + raised when the failover server configuration contains an illegal + connection argument. Supported arguments are user, password, host, port, + unix_socket and database. ValueError is also raised when the failover + argument was not provided. + + Returns MySQLConnection instance. + """ + config = kwargs.copy() + try: + failover = config['failover'] + except KeyError: + raise ValueError('failover argument not provided') + del config['failover'] + + support_cnx_args = set( + ['user', 'password', 'host', 'port', 'unix_socket', + 'database', 'pool_name', 'pool_size']) + + # First check if we can add all use the configuration + for server in failover: + diff = set(server.keys()) - support_cnx_args + if diff: + raise ValueError( + "Unsupported connection argument {0} in failover: {1}".format( + 's' if len(diff) > 1 else '', + ', '.join(diff))) + + for server in failover: + new_config = config.copy() + new_config.update(server) + try: + return connect(**new_config) + except Error: + # If we failed to connect, we try the next server + pass + + raise InterfaceError("Could not failover: no MySQL server available") + + +def connect(*args, **kwargs): + """Create or get a MySQL connection object + + In its simpliest form, Connect() will open a connection to a + MySQL server and return a MySQLConnection object. + + When any connection pooling arguments are given, for example pool_name + or pool_size, a pool is created or a previously one is used to return + a PooledMySQLConnection. + + Returns MySQLConnection or PooledMySQLConnection. + """ + # Option files + if 'option_files' in kwargs: + new_config = read_option_files(**kwargs) + return connect(**new_config) + + if all(['fabric' in kwargs, 'failover' in kwargs]): + raise InterfaceError("fabric and failover arguments can not be used") + + if 'fabric' in kwargs: + if 'pool_name' in kwargs: + raise AttributeError("'pool_name' argument is not supported with " + " MySQL Fabric. Use 'pool_size' instead.") + from .fabric import connect as fabric_connect + return fabric_connect(*args, **kwargs) + + # Failover + if 'failover' in kwargs: + return _get_failover_connection(**kwargs) + + # Pooled connections + try: + from .constants import CNX_POOL_ARGS + if any([key in kwargs for key in CNX_POOL_ARGS]): + return _get_pooled_connection(**kwargs) + except NameError: + # No pooling + pass + + use_pure = kwargs.setdefault('use_pure', True) + + try: + del kwargs['use_pure'] + except KeyError: + # Just making sure 'use_pure' is not kwargs + pass + + if HAVE_CEXT and not use_pure: + return CMySQLConnection(*args, **kwargs) + else: + return MySQLConnection(*args, **kwargs) +Connect = connect # pylint: disable=C0103 + +__version_info__ = version.VERSION +__version__ = version.VERSION_TEXT + +__all__ = [ + 'MySQLConnection', 'Connect', 'custom_error_exception', + + # Some useful constants + 'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption', + 'HAVE_CEXT', + + # Error handling + 'Error', 'Warning', + 'InterfaceError', 'DatabaseError', + 'NotSupportedError', 'DataError', 'IntegrityError', 'ProgrammingError', + 'OperationalError', 'InternalError', + + # DBAPI PEP 249 required exports + 'connect', 'apilevel', 'threadsafety', 'paramstyle', + 'Date', 'Time', 'Timestamp', 'Binary', + 'DateFromTicks', 'DateFromTicks', 'TimestampFromTicks', 'TimeFromTicks', + 'STRING', 'BINARY', 'NUMBER', + 'DATETIME', 'ROWID', + + # C Extension + 'CMySQLConnection', + ] diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/abstracts.py b/elitebot/lib/python3.11/site-packages/mysql/connector/abstracts.py new file mode 100644 index 0000000..6bbd2c1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/abstracts.py @@ -0,0 +1,1158 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Module gathering all abstract base classes""" + +from abc import ABCMeta, abstractmethod, abstractproperty +import re +import time + +from .catch23 import make_abc, BYTE_TYPES +from .conversion import MySQLConverterBase +from .constants import ClientFlag, CharacterSet, DEFAULT_CONFIGURATION +from .optionfiles import MySQLOptionsParser +from . import errors + +@make_abc(ABCMeta) +class MySQLConnectionAbstract(object): + + """Abstract class for classes connecting to a MySQL server""" + + def __init__(self, **kwargs): + """Initialize""" + self._client_flags = ClientFlag.get_default() + self._charset_id = 33 + self._sql_mode = None + self._time_zone = None + self._autocommit = False + self._server_version = None + self._handshake = None + + self._user = '' + self._password = '' + self._database = '' + self._host = '127.0.0.1' + self._port = 3306 + self._unix_socket = None + self._client_host = '' + self._client_port = 0 + self._ssl = {} + self._force_ipv6 = False + + self._use_unicode = True + self._get_warnings = False + self._raise_on_warnings = False + self._connection_timeout = None + self._buffered = False + self._unread_result = False + self._have_next_result = False + self._raw = False + self._in_transaction = False + + self._prepared_statements = None + + self._ssl_active = False + self._auth_plugin = None + self._pool_config_version = None + self.converter = None + self._converter_class = None + self._compress = False + + self._consume_results = False + + def _get_self(self): + """Return self for weakref.proxy + + This method is used when the original object is needed when using + weakref.proxy. + """ + return self + + def _read_option_files(self, config): + """ + Read option files for connection parameters. + + Checks if connection arguments contain option file arguments, and then + reads option files accordingly. + """ + if 'option_files' in config: + try: + if isinstance(config['option_groups'], str): + config['option_groups'] = [config['option_groups']] + groups = config['option_groups'] + del config['option_groups'] + except KeyError: + groups = ['client', 'connector_python'] + + if isinstance(config['option_files'], str): + config['option_files'] = [config['option_files']] + option_parser = MySQLOptionsParser(list(config['option_files']), + keep_dashes=False) + del config['option_files'] + + config_from_file = option_parser.get_groups_as_dict_with_priority( + *groups) + config_options = {} + for group in groups: + try: + for option, value in config_from_file[group].items(): + try: + if option == 'socket': + option = 'unix_socket' + # pylint: disable=W0104 + DEFAULT_CONFIGURATION[option] + # pylint: enable=W0104 + + if (option not in config_options or + config_options[option][1] <= value[1]): + config_options[option] = value + except KeyError: + if group is 'connector_python': + raise AttributeError("Unsupported argument " + "'{0}'".format(option)) + except KeyError: + continue + + for option, value in config_options.items(): + if option not in config: + try: + config[option] = eval(value[0]) # pylint: disable=W0123 + except (NameError, SyntaxError): + config[option] = value[0] + return config + + @property + def user(self): + """User used while connecting to MySQL""" + return self._user + + @property + def server_host(self): + """MySQL server IP address or name""" + return self._host + + @property + def server_port(self): + "MySQL server TCP/IP port" + return self._port + + @property + def unix_socket(self): + "MySQL Unix socket file location" + return self._unix_socket + + @abstractproperty + def database(self): + """Get the current database""" + pass + + @database.setter + def database(self, value): + """Set the current database""" + self.cmd_query("USE %s" % value) + + @property + def can_consume_results(self): + """Returns whether to consume results""" + return self._consume_results + + def config(self, **kwargs): + """Configure the MySQL Connection + + This method allows you to configure the MySQLConnection instance. + + Raises on errors. + """ + config = kwargs.copy() + if 'dsn' in config: + raise errors.NotSupportedError("Data source name is not supported") + + # Read option files + self._read_option_files(config) + + # Configure how we handle MySQL warnings + try: + self.get_warnings = config['get_warnings'] + del config['get_warnings'] + except KeyError: + pass # Leave what was set or default + try: + self.raise_on_warnings = config['raise_on_warnings'] + del config['raise_on_warnings'] + except KeyError: + pass # Leave what was set or default + + # Configure client flags + try: + default = ClientFlag.get_default() + self.set_client_flags(config['client_flags'] or default) + del config['client_flags'] + except KeyError: + pass # Missing client_flags-argument is OK + + try: + if config['compress']: + self._compress = True + self.set_client_flags([ClientFlag.COMPRESS]) + except KeyError: + pass # Missing compress argument is OK + + try: + if not config['allow_local_infile']: + self.set_client_flags([-ClientFlag.LOCAL_FILES]) + except KeyError: + pass # Missing allow_local_infile argument is OK + + try: + if not config['consume_results']: + self._consume_results = False + else: + self._consume_results = True + except KeyError: + self._consume_results = False + + # Configure character set and collation + if 'charset' in config or 'collation' in config: + try: + charset = config['charset'] + del config['charset'] + except KeyError: + charset = None + try: + collation = config['collation'] + del config['collation'] + except KeyError: + collation = None + self._charset_id = CharacterSet.get_charset_info(charset, + collation)[0] + + # Set converter class + try: + self.set_converter_class(config['converter_class']) + except KeyError: + pass # Using default converter class + except TypeError: + raise AttributeError("Converter class should be a subclass " + "of conversion.MySQLConverterBase.") + + # Compatible configuration with other drivers + compat_map = [ + # (,) + ('db', 'database'), + ('passwd', 'password'), + ('connect_timeout', 'connection_timeout'), + ] + for compat, translate in compat_map: + try: + if translate not in config: + config[translate] = config[compat] + del config[compat] + except KeyError: + pass # Missing compat argument is OK + + # Configure login information + if 'user' in config or 'password' in config: + try: + user = config['user'] + del config['user'] + except KeyError: + user = self._user + try: + password = config['password'] + del config['password'] + except KeyError: + password = self._password + self.set_login(user, password) + + # Check network locations + try: + self._port = int(config['port']) + del config['port'] + except KeyError: + pass # Missing port argument is OK + except ValueError: + raise errors.InterfaceError( + "TCP/IP port number should be an integer") + + # Other configuration + set_ssl_flag = False + for key, value in config.items(): + try: + DEFAULT_CONFIGURATION[key] + except KeyError: + raise AttributeError("Unsupported argument '{0}'".format(key)) + # SSL Configuration + if key.startswith('ssl_'): + set_ssl_flag = True + self._ssl.update({key.replace('ssl_', ''): value}) + else: + attribute = '_' + key + try: + setattr(self, attribute, value.strip()) + except AttributeError: + setattr(self, attribute, value) + + if set_ssl_flag: + if 'verify_cert' not in self._ssl: + self._ssl['verify_cert'] = \ + DEFAULT_CONFIGURATION['ssl_verify_cert'] + # Make sure both ssl_key/ssl_cert are set, or neither (XOR) + if 'ca' not in self._ssl or self._ssl['ca'] is None: + raise AttributeError( + "Missing ssl_ca argument.") + if bool('key' in self._ssl) != bool('cert' in self._ssl): + raise AttributeError( + "ssl_key and ssl_cert need to be both " + "specified, or neither." + ) + # Make sure key/cert are set to None + elif not set(('key', 'cert')) <= set(self._ssl): + self._ssl['key'] = None + self._ssl['cert'] = None + elif (self._ssl['key'] is None) != (self._ssl['cert'] is None): + raise AttributeError( + "ssl_key and ssl_cert need to be both " + "set, or neither." + ) + self.set_client_flags([ClientFlag.SSL]) + + def _check_server_version(self, server_version): + """Check the MySQL version + + This method will check the MySQL version and raise an InterfaceError + when it is not supported or invalid. It will return the version + as a tuple with major, minor and patch. + + Raises InterfaceError if invalid server version. + + Returns tuple + """ + if isinstance(server_version, BYTE_TYPES): + server_version = server_version.decode() + + # pylint: disable=W1401 + regex_ver = re.compile(r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)") + # pylint: enable=W1401 + match = regex_ver.match(server_version) + if not match: + raise errors.InterfaceError("Failed parsing MySQL version") + + version = tuple([int(v) for v in match.groups()[0:3]]) + if 'fabric' in match.group(4).lower(): + if version < (1, 5): + raise errors.InterfaceError( + "MySQL Fabric '{0}' is not supported".format( + server_version)) + elif version < (4, 1): + raise errors.InterfaceError( + "MySQL Version '{0}' is not supported.".format(server_version)) + + return version + + def get_server_version(self): + """Get the MySQL version + + This method returns the MySQL server version as a tuple. If not + previously connected, it will return None. + + Returns a tuple or None. + """ + return self._server_version + + def get_server_info(self): + """Get the original MySQL version information + + This method returns the original MySQL server as text. If not + previously connected, it will return None. + + Returns a string or None. + """ + try: + return self._handshake['server_version_original'] + except (TypeError, KeyError): + return None + + @abstractproperty + def in_transaction(self): + """MySQL session has started a transaction""" + pass + + def set_client_flags(self, flags): + """Set the client flags + + The flags-argument can be either an int or a list (or tuple) of + ClientFlag-values. If it is an integer, it will set client_flags + to flags as is. + If flags is a list (or tuple), each flag will be set or unset + when it's negative. + + set_client_flags([ClientFlag.FOUND_ROWS,-ClientFlag.LONG_FLAG]) + + Raises ProgrammingError when the flags argument is not a set or + an integer bigger than 0. + + Returns self.client_flags + """ + if isinstance(flags, int) and flags > 0: + self._client_flags = flags + elif isinstance(flags, (tuple, list)): + for flag in flags: + if flag < 0: + self._client_flags &= ~abs(flag) + else: + self._client_flags |= flag + else: + raise errors.ProgrammingError( + "set_client_flags expect integer (>0) or set") + return self._client_flags + + def isset_client_flag(self, flag): + """Check if a client flag is set""" + if (self._client_flags & flag) > 0: + return True + return False + + @property + def time_zone(self): + """Get the current time zone""" + return self.info_query("SELECT @@session.time_zone")[0] + + @time_zone.setter + def time_zone(self, value): + """Set the time zone""" + self.cmd_query("SET @@session.time_zone = '{0}'".format(value)) + self._time_zone = value + + @property + def sql_mode(self): + """Get the SQL mode""" + return self.info_query("SELECT @@session.sql_mode")[0] + + @sql_mode.setter + def sql_mode(self, value): + """Set the SQL mode + + This method sets the SQL Mode for the current connection. The value + argument can be either a string with comma separate mode names, or + a sequence of mode names. + + It is good practice to use the constants class SQLMode: + from mysql.connector.constants import SQLMode + cnx.sql_mode = [SQLMode.NO_ZERO_DATE, SQLMode.REAL_AS_FLOAT] + """ + if isinstance(value, (list, tuple)): + value = ','.join(value) + self.cmd_query("SET @@session.sql_mode = '{0}'".format(value)) + self._sql_mode = value + + @abstractmethod + def info_query(self, query): + """Send a query which only returns 1 row""" + pass + + def set_login(self, username=None, password=None): + """Set login information for MySQL + + Set the username and/or password for the user connecting to + the MySQL Server. + """ + if username is not None: + self._user = username.strip() + else: + self._user = '' + if password is not None: + self._password = password + else: + self._password = '' + + def set_unicode(self, value=True): + """Toggle unicode mode + + Set whether we return string fields as unicode or not. + Default is True. + """ + self._use_unicode = value + if self.converter: + self.converter.set_unicode(value) + + @property + def autocommit(self): + """Get whether autocommit is on or off""" + value = self.info_query("SELECT @@session.autocommit")[0] + return True if value == 1 else False + + @autocommit.setter + def autocommit(self, value): + """Toggle autocommit""" + switch = 'ON' if value else 'OFF' + self.cmd_query("SET @@session.autocommit = {0}".format(switch)) + self._autocommit = value + + @property + def get_warnings(self): + """Get whether this connection retrieves warnings automatically + + This method returns whether this connection retrieves warnings + automatically. + + Returns True, or False when warnings are not retrieved. + """ + return self._get_warnings + + @get_warnings.setter + def get_warnings(self, value): + """Set whether warnings should be automatically retrieved + + The toggle-argument must be a boolean. When True, cursors for this + connection will retrieve information about warnings (if any). + + Raises ValueError on error. + """ + if not isinstance(value, bool): + raise ValueError("Expected a boolean type") + self._get_warnings = value + + @property + def raise_on_warnings(self): + """Get whether this connection raises an error on warnings + + This method returns whether this connection will raise errors when + MySQL reports warnings. + + Returns True or False. + """ + return self._raise_on_warnings + + @raise_on_warnings.setter + def raise_on_warnings(self, value): + """Set whether warnings raise an error + + The toggle-argument must be a boolean. When True, cursors for this + connection will raise an error when MySQL reports warnings. + + Raising on warnings implies retrieving warnings automatically. In + other words: warnings will be set to True. If set to False, warnings + will be also set to False. + + Raises ValueError on error. + """ + if not isinstance(value, bool): + raise ValueError("Expected a boolean type") + self._raise_on_warnings = value + self._get_warnings = value + + + @property + def unread_result(self): + """Get whether there is an unread result + + This method is used by cursors to check whether another cursor still + needs to retrieve its result set. + + Returns True, or False when there is no unread result. + """ + return self._unread_result + + @unread_result.setter + def unread_result(self, value): + """Set whether there is an unread result + + This method is used by cursors to let other cursors know there is + still a result set that needs to be retrieved. + + Raises ValueError on errors. + """ + if not isinstance(value, bool): + raise ValueError("Expected a boolean type") + self._unread_result = value + + @property + def charset(self): + """Returns the character set for current connection + + This property returns the character set name of the current connection. + The server is queried when the connection is active. If not connected, + the configured character set name is returned. + + Returns a string. + """ + return CharacterSet.get_info(self._charset_id)[0] + + @property + def python_charset(self): + """Returns the Python character set for current connection + + This property returns the character set name of the current connection. + Note that, unlike property charset, this checks if the previously set + character set is supported by Python and if not, it returns the + equivalent character set that Python supports. + + Returns a string. + """ + encoding = CharacterSet.get_info(self._charset_id)[0] + if encoding in ('utf8mb4', 'binary'): + return 'utf8' + else: + return encoding + + def set_charset_collation(self, charset=None, collation=None): + """Sets the character set and collation for the current connection + + This method sets the character set and collation to be used for + the current connection. The charset argument can be either the + name of a character set as a string, or the numerical equivalent + as defined in constants.CharacterSet. + + When the collation is not given, the default will be looked up and + used. + + For example, the following will set the collation for the latin1 + character set to latin1_general_ci: + + set_charset('latin1','latin1_general_ci') + + """ + if charset: + if isinstance(charset, int): + self._charset_id = charset + (self._charset_id, charset_name, collation_name) = \ + CharacterSet.get_charset_info(charset) + elif isinstance(charset, str): + (self._charset_id, charset_name, collation_name) = \ + CharacterSet.get_charset_info(charset, collation) + else: + raise ValueError( + "charset should be either integer, string or None") + elif collation: + (self._charset_id, charset_name, collation_name) = \ + CharacterSet.get_charset_info(collation=collation) + + self._execute_query("SET NAMES '{0}' COLLATE '{1}'".format( + charset_name, collation_name)) + + try: + # Required for C Extension + self.set_character_set_name(charset_name) # pylint: disable=E1101 + except AttributeError: + # Not required for pure Python connection + pass + + if self.converter: + self.converter.set_charset(charset_name) + + @property + def collation(self): + """Returns the collation for current connection + + This property returns the collation name of the current connection. + The server is queried when the connection is active. If not connected, + the configured collation name is returned. + + Returns a string. + """ + return CharacterSet.get_charset_info(self._charset_id)[2] + + @abstractmethod + def _do_handshake(self): + """Gather information of the MySQL server before authentication""" + pass + + @abstractmethod + def _open_connection(self): + """Open the connection to the MySQL server""" + pass + + def _post_connection(self): + """Executes commands after connection has been established + + This method executes commands after the connection has been + established. Some setting like autocommit, character set, and SQL mode + are set using this method. + """ + self.set_charset_collation(self._charset_id) + self.autocommit = self._autocommit + if self._time_zone: + self.time_zone = self._time_zone + if self._sql_mode: + self.sql_mode = self._sql_mode + + @abstractmethod + def disconnect(self): + """Disconnect from the MySQL server""" + pass + close = disconnect + + def connect(self, **kwargs): + """Connect to the MySQL server + + This method sets up the connection to the MySQL server. If no + arguments are given, it will use the already configured or default + values. + """ + if len(kwargs) > 0: + self.config(**kwargs) + + self.disconnect() + self._open_connection() + self._post_connection() + + def reconnect(self, attempts=1, delay=0): + """Attempt to reconnect to the MySQL server + + The argument attempts should be the number of times a reconnect + is tried. The delay argument is the number of seconds to wait between + each retry. + + You may want to set the number of attempts higher and use delay when + you expect the MySQL server to be down for maintenance or when you + expect the network to be temporary unavailable. + + Raises InterfaceError on errors. + """ + counter = 0 + while counter != attempts: + counter = counter + 1 + try: + self.disconnect() + self.connect() + if self.is_connected(): + break + except Exception as err: # pylint: disable=W0703 + if counter == attempts: + msg = "Can not reconnect to MySQL after {0} "\ + "attempt(s): {1}".format(attempts, str(err)) + raise errors.InterfaceError(msg) + if delay > 0: + time.sleep(delay) + + @abstractmethod + def is_connected(self): + """Reports whether the connection to MySQL Server is available""" + pass + + @abstractmethod + def ping(self, reconnect=False, attempts=1, delay=0): + """Check availability of the MySQL server""" + pass + + @abstractmethod + def commit(self): + """Commit current transaction""" + pass + + @abstractmethod + def cursor(self, buffered=None, raw=None, prepared=None, cursor_class=None, + dictionary=None, named_tuple=None): + """Instantiates and returns a cursor""" + pass + + @abstractmethod + def _execute_query(self, query): + """Execute a query""" + pass + + @abstractmethod + def rollback(self): + """Rollback current transaction""" + pass + + def start_transaction(self, consistent_snapshot=False, + isolation_level=None, readonly=None): + """Start a transaction + + This method explicitly starts a transaction sending the + START TRANSACTION statement to the MySQL server. You can optionally + set whether there should be a consistent snapshot, which + isolation level you need or which access mode i.e. READ ONLY or + READ WRITE. + + For example, to start a transaction with isolation level SERIALIZABLE, + you would do the following: + >>> cnx = mysql.connector.connect(..) + >>> cnx.start_transaction(isolation_level='SERIALIZABLE') + + Raises ProgrammingError when a transaction is already in progress + and when ValueError when isolation_level specifies an Unknown + level. + """ + if self.in_transaction: + raise errors.ProgrammingError("Transaction already in progress") + + if isolation_level: + level = isolation_level.strip().replace('-', ' ').upper() + levels = ['READ UNCOMMITTED', 'READ COMMITTED', 'REPEATABLE READ', + 'SERIALIZABLE'] + + if level not in levels: + raise ValueError( + 'Unknown isolation level "{0}"'.format(isolation_level)) + + self._execute_query( + "SET TRANSACTION ISOLATION LEVEL {0}".format(level)) + + if readonly is not None: + if self._server_version < (5, 6, 5): + raise ValueError( + "MySQL server version {0} does not support " + "this feature".format(self._server_version)) + + if readonly: + access_mode = 'READ ONLY' + else: + access_mode = 'READ WRITE' + self._execute_query( + "SET TRANSACTION {0}".format(access_mode)) + + query = "START TRANSACTION" + if consistent_snapshot: + query += " WITH CONSISTENT SNAPSHOT" + self.cmd_query(query) + + def reset_session(self, user_variables=None, session_variables=None): + """Clears the current active session + + This method resets the session state, if the MySQL server is 5.7.3 + or later active session will be reset without re-authenticating. + For other server versions session will be reset by re-authenticating. + + It is possible to provide a sequence of variables and their values to + be set after clearing the session. This is possible for both user + defined variables and session variables. + This method takes two arguments user_variables and session_variables + which are dictionaries. + + Raises OperationalError if not connected, InternalError if there are + unread results and InterfaceError on errors. + """ + if not self.is_connected(): + raise errors.OperationalError("MySQL Connection not available.") + + try: + self.cmd_reset_connection() + except (errors.NotSupportedError, NotImplementedError): + if self._compress: + raise errors.NotSupportedError( + "Reset session is not supported with compression for " + "MySQL server version 5.7.2 or earlier.") + else: + self.cmd_change_user(self._user, self._password, + self._database, self._charset_id) + + if user_variables or session_variables: + cur = self.cursor() + if user_variables: + for key, value in user_variables.items(): + cur.execute("SET @`{0}` = %s".format(key), (value,)) + if session_variables: + for key, value in session_variables.items(): + cur.execute("SET SESSION `{0}` = %s".format(key), (value,)) + cur.close() + + def set_converter_class(self, convclass): + """ + Set the converter class to be used. This should be a class overloading + methods and members of conversion.MySQLConverter. + """ + if convclass and issubclass(convclass, MySQLConverterBase): + charset_name = CharacterSet.get_info(self._charset_id)[0] + self._converter_class = convclass + self.converter = convclass(charset_name, self._use_unicode) + else: + raise TypeError("Converter class should be a subclass " + "of conversion.MySQLConverterBase.") + + @abstractmethod + def get_rows(self, count=None, binary=False, columns=None): + """Get all rows returned by the MySQL server""" + pass + + def cmd_init_db(self, database): + """Change the current database""" + raise NotImplementedError + + def cmd_query(self, query, raw=False, buffered=False, raw_as_string=False): + """Send a query to the MySQL server""" + raise NotImplementedError + + def cmd_query_iter(self, statements): + """Send one or more statements to the MySQL server""" + raise NotImplementedError + + def cmd_refresh(self, options): + """Send the Refresh command to the MySQL server""" + raise NotImplementedError + + def cmd_quit(self): + """Close the current connection with the server""" + raise NotImplementedError + + def cmd_shutdown(self, shutdown_type=None): + """Shut down the MySQL Server""" + raise NotImplementedError + + def cmd_statistics(self): + """Send the statistics command to the MySQL Server""" + raise NotImplementedError + + def cmd_process_info(self): + """Get the process list of the MySQL Server + + This method is a placeholder to notify that the PROCESS_INFO command + is not supported by raising the NotSupportedError. The command + "SHOW PROCESSLIST" should be send using the cmd_query()-method or + using the INFORMATION_SCHEMA database. + + Raises NotSupportedError exception + """ + raise errors.NotSupportedError( + "Not implemented. Use SHOW PROCESSLIST or INFORMATION_SCHEMA") + + def cmd_process_kill(self, mysql_pid): + """Kill a MySQL process""" + raise NotImplementedError + + def cmd_debug(self): + """Send the DEBUG command""" + raise NotImplementedError + + def cmd_ping(self): + """Send the PING command""" + raise NotImplementedError + + def cmd_change_user(self, username='', password='', database='', + charset=33): + """Change the current logged in user""" + raise NotImplementedError + + def cmd_stmt_prepare(self, statement): + """Prepare a MySQL statement""" + raise NotImplementedError + + def cmd_stmt_execute(self, statement_id, data=(), parameters=(), flags=0): + """Execute a prepared MySQL statement""" + raise NotImplementedError + + def cmd_stmt_close(self, statement_id): + """Deallocate a prepared MySQL statement""" + raise NotImplementedError + + def cmd_stmt_send_long_data(self, statement_id, param_id, data): + """Send data for a column""" + raise NotImplementedError + + def cmd_stmt_reset(self, statement_id): + """Reset data for prepared statement sent as long data""" + raise NotImplementedError + + def cmd_reset_connection(self): + """Resets the session state without re-authenticating""" + raise NotImplementedError + + +@make_abc(ABCMeta) +class MySQLCursorAbstract(object): + """Abstract cursor class + + Abstract class defining cursor class with method and members + required by the Python Database API Specification v2.0. + """ + def __init__(self): + """Initialization""" + self._description = None + self._rowcount = -1 + self._last_insert_id = None + self._warnings = None + self.arraysize = 1 + + @abstractmethod + def callproc(self, procname, args=()): + """Calls a stored procedure with the given arguments + + The arguments will be set during this session, meaning + they will be called like ___arg where + is an enumeration (+1) of the arguments. + + Coding Example: + 1) Defining the Stored Routine in MySQL: + CREATE PROCEDURE multiply(IN pFac1 INT, IN pFac2 INT, OUT pProd INT) + BEGIN + SET pProd := pFac1 * pFac2; + END + + 2) Executing in Python: + args = (5,5,0) # 0 is to hold pprod + cursor.callproc('multiply', args) + print(cursor.fetchone()) + + Does not return a value, but a result set will be + available when the CALL-statement execute successfully. + Raises exceptions when something is wrong. + """ + pass + + @abstractmethod + def close(self): + """Close the cursor.""" + pass + + @abstractmethod + def execute(self, operation, params=(), multi=False): + """Executes the given operation + + Executes the given operation substituting any markers with + the given parameters. + + For example, getting all rows where id is 5: + cursor.execute("SELECT * FROM t1 WHERE id = %s", (5,)) + + The multi argument should be set to True when executing multiple + statements in one operation. If not set and multiple results are + found, an InterfaceError will be raised. + + If warnings where generated, and connection.get_warnings is True, then + self._warnings will be a list containing these warnings. + + Returns an iterator when multi is True, otherwise None. + """ + pass + + @abstractmethod + def executemany(self, operation, seqparams): + """Execute the given operation multiple times + + The executemany() method will execute the operation iterating + over the list of parameters in seq_params. + + Example: Inserting 3 new employees and their phone number + + data = [ + ('Jane','555-001'), + ('Joe', '555-001'), + ('John', '555-003') + ] + stmt = "INSERT INTO employees (name, phone) VALUES ('%s','%s')" + cursor.executemany(stmt, data) + + INSERT statements are optimized by batching the data, that is + using the MySQL multiple rows syntax. + + Results are discarded. If they are needed, consider looping over + data using the execute() method. + """ + pass + + @abstractmethod + def fetchone(self): + """Returns next row of a query result set + + Returns a tuple or None. + """ + pass + + @abstractmethod + def fetchmany(self, size=1): + """Returns the next set of rows of a query result, returning a + list of tuples. When no more rows are available, it returns an + empty list. + + The number of rows returned can be specified using the size argument, + which defaults to one + """ + pass + + @abstractmethod + def fetchall(self): + """Returns all rows of a query result set + + Returns a list of tuples. + """ + pass + + def nextset(self): + """Not Implemented.""" + pass + + def setinputsizes(self, sizes): + """Not Implemented.""" + pass + + def setoutputsize(self, size, column=None): + """Not Implemented.""" + pass + + def reset(self, free=True): + """Reset the cursor to default""" + pass + + @abstractproperty + def description(self): + """Returns description of columns in a result + + This property returns a list of tuples describing the columns in + in a result set. A tuple is described as follows:: + + (column_name, + type, + None, + None, + None, + None, + null_ok, + column_flags) # Addition to PEP-249 specs + + Returns a list of tuples. + """ + return self._description + + @abstractproperty + def rowcount(self): + """Returns the number of rows produced or affected + + This property returns the number of rows produced by queries + such as a SELECT, or affected rows when executing DML statements + like INSERT or UPDATE. + + Note that for non-buffered cursors it is impossible to know the + number of rows produced before having fetched them all. For those, + the number of rows will be -1 right after execution, and + incremented when fetching rows. + + Returns an integer. + """ + return self._rowcount + + @abstractproperty + def lastrowid(self): + """Returns the value generated for an AUTO_INCREMENT column + + Returns the value generated for an AUTO_INCREMENT column by + the previous INSERT or UPDATE statement or None when there is + no such value available. + + Returns a long value or None. + """ + return self._last_insert_id + + def fetchwarnings(self): + """Returns Warnings.""" + return self._warnings diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/authentication.py b/elitebot/lib/python3.11/site-packages/mysql/connector/authentication.py new file mode 100644 index 0000000..4d8cdb8 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/authentication.py @@ -0,0 +1,191 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Implementing support for MySQL Authentication Plugins""" + +from hashlib import sha1 +import struct + +from . import errors +from .catch23 import PY2, isstr + + +class BaseAuthPlugin(object): + """Base class for authentication plugins + + + Classes inheriting from BaseAuthPlugin should implement the method + prepare_password(). When instantiating, auth_data argument is + required. The username, password and database are optional. The + ssl_enabled argument can be used to tell the plugin whether SSL is + active or not. + + The method auth_response() method is used to retrieve the password + which was prepared by prepare_password(). + """ + + requires_ssl = False + plugin_name = '' + + def __init__(self, auth_data, username=None, password=None, database=None, + ssl_enabled=False): + """Initialization""" + self._auth_data = auth_data + self._username = username + self._password = password + self._database = database + self._ssl_enabled = ssl_enabled + + def prepare_password(self): + """Prepares and returns password to be send to MySQL + + This method needs to be implemented by classes inheriting from + this class. It is used by the auth_response() method. + + Raises NotImplementedError. + """ + raise NotImplementedError + + def auth_response(self): + """Returns the prepared password to send to MySQL + + Raises InterfaceError on errors. For example, when SSL is required + by not enabled. + + Returns str + """ + if self.requires_ssl and not self._ssl_enabled: + raise errors.InterfaceError("{name} requires SSL".format( + name=self.plugin_name)) + return self.prepare_password() + + +class MySQLNativePasswordAuthPlugin(BaseAuthPlugin): + """Class implementing the MySQL Native Password authentication plugin""" + + requires_ssl = False + plugin_name = 'mysql_native_password' + + def prepare_password(self): + """Prepares and returns password as native MySQL 4.1+ password""" + if not self._auth_data: + raise errors.InterfaceError("Missing authentication data (seed)") + + if not self._password: + return b'' + password = self._password + + if isstr(self._password): + password = self._password.encode('utf-8') + else: + password = self._password + + if PY2: + password = buffer(password) # pylint: disable=E0602 + try: + auth_data = buffer(self._auth_data) # pylint: disable=E0602 + except TypeError: + raise errors.InterfaceError("Authentication data incorrect") + else: + password = password + auth_data = self._auth_data + + hash4 = None + try: + hash1 = sha1(password).digest() + hash2 = sha1(hash1).digest() + hash3 = sha1(auth_data + hash2).digest() + if PY2: + xored = [ord(h1) ^ ord(h3) for (h1, h3) in zip(hash1, hash3)] + else: + xored = [h1 ^ h3 for (h1, h3) in zip(hash1, hash3)] + hash4 = struct.pack('20B', *xored) + except Exception as exc: + raise errors.InterfaceError( + "Failed scrambling password; {0}".format(exc)) + + return hash4 + + +class MySQLClearPasswordAuthPlugin(BaseAuthPlugin): + """Class implementing the MySQL Clear Password authentication plugin""" + + requires_ssl = True + plugin_name = 'mysql_clear_password' + + def prepare_password(self): + """Returns password as as clear text""" + if not self._password: + return b'\x00' + password = self._password + + if PY2: + if isinstance(password, unicode): # pylint: disable=E0602 + password = password.encode('utf8') + elif isinstance(password, str): + password = password.encode('utf8') + + return password + b'\x00' + + +class MySQLSHA256PasswordAuthPlugin(BaseAuthPlugin): + """Class implementing the MySQL SHA256 authentication plugin + + Note that encrypting using RSA is not supported since the Python + Standard Library does not provide this OpenSSL functionality. + """ + + requires_ssl = True + plugin_name = 'sha256_password' + + def prepare_password(self): + """Returns password as as clear text""" + if not self._password: + return b'\x00' + password = self._password + + if PY2: + if isinstance(password, unicode): # pylint: disable=E0602 + password = password.encode('utf8') + elif isinstance(password, str): + password = password.encode('utf8') + + return password + b'\x00' + + +def get_auth_plugin(plugin_name): + """Return authentication class based on plugin name + + This function returns the class for the authentication plugin plugin_name. + The returned class is a subclass of BaseAuthPlugin. + + Raises errors.NotSupportedError when plugin_name is not supported. + + Returns subclass of BaseAuthPlugin. + """ + for authclass in BaseAuthPlugin.__subclasses__(): # pylint: disable=E1101 + if authclass.plugin_name == plugin_name: + return authclass + + raise errors.NotSupportedError( + "Authentication plugin '{0}' is not supported".format(plugin_name)) diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/catch23.py b/elitebot/lib/python3.11/site-packages/mysql/connector/catch23.py new file mode 100644 index 0000000..3efd41c --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/catch23.py @@ -0,0 +1,114 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Python v2 to v3 migration module""" + +from decimal import Decimal +import struct +import sys + +from .custom_types import HexLiteral + +# pylint: disable=E0602,E1103 + +PY2 = sys.version_info[0] == 2 + +if PY2: + NUMERIC_TYPES = (int, float, Decimal, HexLiteral, long) + INT_TYPES = (int, long) + UNICODE_TYPES = (unicode,) + STRING_TYPES = (str, unicode) + BYTE_TYPES = (bytearray,) +else: + NUMERIC_TYPES = (int, float, Decimal, HexLiteral) + INT_TYPES = (int,) + UNICODE_TYPES = (str,) + STRING_TYPES = (str,) + BYTE_TYPES = (bytearray, bytes) + + +def init_bytearray(payload=b'', encoding='utf-8'): + """Initializes a bytearray from the payload""" + if isinstance(payload, bytearray): + return payload + + if PY2: + return bytearray(payload) + + if isinstance(payload, int): + return bytearray(payload) + elif not isinstance(payload, bytes): + try: + return bytearray(payload.encode(encoding=encoding)) + except AttributeError: + raise ValueError("payload must be a str or bytes") + + + return bytearray(payload) + + +def isstr(obj): + """Returns whether a variable is a string""" + if PY2: + return isinstance(obj, basestring) + else: + return isinstance(obj, str) + +def isunicode(obj): + """Returns whether a variable is a of unicode type""" + if PY2: + return isinstance(obj, unicode) + else: + return isinstance(obj, str) + + +if PY2: + def struct_unpack(fmt, buf): + """Wrapper around struct.unpack handling buffer as bytes and strings""" + if isinstance(buf, (bytearray, bytes)): + return struct.unpack_from(fmt, buffer(buf)) + return struct.unpack_from(fmt, buf) +else: + struct_unpack = struct.unpack # pylint: disable=C0103 + + +def make_abc(base_class): + """Decorator used to create a abstract base class + + We use this decorator to create abstract base classes instead of + using the abc-module. The decorator makes it possible to do the + same in both Python v2 and v3 code. + """ + def wrapper(class_): + """Wrapper""" + attrs = class_.__dict__.copy() + for attr in '__dict__', '__weakref__': + attrs.pop(attr, None) # ignore missing attributes + + bases = class_.__bases__ + if PY2: + attrs['__metaclass__'] = class_ + else: + bases = (class_,) + bases + return base_class(class_.__name__, bases, attrs) + return wrapper diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/charsets.py b/elitebot/lib/python3.11/site-packages/mysql/connector/charsets.py new file mode 100644 index 0000000..48b066e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/charsets.py @@ -0,0 +1,286 @@ +# -*- coding: utf-8 -*- + +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# This file was auto-generated. +_GENERATED_ON = '2015-08-24' +_MYSQL_VERSION = (5, 7, 8) + +"""This module contains the MySQL Server Character Sets""" + +MYSQL_CHARACTER_SETS = [ + # (character set name, collation, default) + None, + ("big5", "big5_chinese_ci", True), # 1 + ("latin2", "latin2_czech_cs", False), # 2 + ("dec8", "dec8_swedish_ci", True), # 3 + ("cp850", "cp850_general_ci", True), # 4 + ("latin1", "latin1_german1_ci", False), # 5 + ("hp8", "hp8_english_ci", True), # 6 + ("koi8r", "koi8r_general_ci", True), # 7 + ("latin1", "latin1_swedish_ci", True), # 8 + ("latin2", "latin2_general_ci", True), # 9 + ("swe7", "swe7_swedish_ci", True), # 10 + ("ascii", "ascii_general_ci", True), # 11 + ("ujis", "ujis_japanese_ci", True), # 12 + ("sjis", "sjis_japanese_ci", True), # 13 + ("cp1251", "cp1251_bulgarian_ci", False), # 14 + ("latin1", "latin1_danish_ci", False), # 15 + ("hebrew", "hebrew_general_ci", True), # 16 + None, + ("tis620", "tis620_thai_ci", True), # 18 + ("euckr", "euckr_korean_ci", True), # 19 + ("latin7", "latin7_estonian_cs", False), # 20 + ("latin2", "latin2_hungarian_ci", False), # 21 + ("koi8u", "koi8u_general_ci", True), # 22 + ("cp1251", "cp1251_ukrainian_ci", False), # 23 + ("gb2312", "gb2312_chinese_ci", True), # 24 + ("greek", "greek_general_ci", True), # 25 + ("cp1250", "cp1250_general_ci", True), # 26 + ("latin2", "latin2_croatian_ci", False), # 27 + ("gbk", "gbk_chinese_ci", True), # 28 + ("cp1257", "cp1257_lithuanian_ci", False), # 29 + ("latin5", "latin5_turkish_ci", True), # 30 + ("latin1", "latin1_german2_ci", False), # 31 + ("armscii8", "armscii8_general_ci", True), # 32 + ("utf8", "utf8_general_ci", True), # 33 + ("cp1250", "cp1250_czech_cs", False), # 34 + ("ucs2", "ucs2_general_ci", True), # 35 + ("cp866", "cp866_general_ci", True), # 36 + ("keybcs2", "keybcs2_general_ci", True), # 37 + ("macce", "macce_general_ci", True), # 38 + ("macroman", "macroman_general_ci", True), # 39 + ("cp852", "cp852_general_ci", True), # 40 + ("latin7", "latin7_general_ci", True), # 41 + ("latin7", "latin7_general_cs", False), # 42 + ("macce", "macce_bin", False), # 43 + ("cp1250", "cp1250_croatian_ci", False), # 44 + ("utf8mb4", "utf8mb4_general_ci", True), # 45 + ("utf8mb4", "utf8mb4_bin", False), # 46 + ("latin1", "latin1_bin", False), # 47 + ("latin1", "latin1_general_ci", False), # 48 + ("latin1", "latin1_general_cs", False), # 49 + ("cp1251", "cp1251_bin", False), # 50 + ("cp1251", "cp1251_general_ci", True), # 51 + ("cp1251", "cp1251_general_cs", False), # 52 + ("macroman", "macroman_bin", False), # 53 + ("utf16", "utf16_general_ci", True), # 54 + ("utf16", "utf16_bin", False), # 55 + ("utf16le", "utf16le_general_ci", True), # 56 + ("cp1256", "cp1256_general_ci", True), # 57 + ("cp1257", "cp1257_bin", False), # 58 + ("cp1257", "cp1257_general_ci", True), # 59 + ("utf32", "utf32_general_ci", True), # 60 + ("utf32", "utf32_bin", False), # 61 + ("utf16le", "utf16le_bin", False), # 62 + ("binary", "binary", True), # 63 + ("armscii8", "armscii8_bin", False), # 64 + ("ascii", "ascii_bin", False), # 65 + ("cp1250", "cp1250_bin", False), # 66 + ("cp1256", "cp1256_bin", False), # 67 + ("cp866", "cp866_bin", False), # 68 + ("dec8", "dec8_bin", False), # 69 + ("greek", "greek_bin", False), # 70 + ("hebrew", "hebrew_bin", False), # 71 + ("hp8", "hp8_bin", False), # 72 + ("keybcs2", "keybcs2_bin", False), # 73 + ("koi8r", "koi8r_bin", False), # 74 + ("koi8u", "koi8u_bin", False), # 75 + None, + ("latin2", "latin2_bin", False), # 77 + ("latin5", "latin5_bin", False), # 78 + ("latin7", "latin7_bin", False), # 79 + ("cp850", "cp850_bin", False), # 80 + ("cp852", "cp852_bin", False), # 81 + ("swe7", "swe7_bin", False), # 82 + ("utf8", "utf8_bin", False), # 83 + ("big5", "big5_bin", False), # 84 + ("euckr", "euckr_bin", False), # 85 + ("gb2312", "gb2312_bin", False), # 86 + ("gbk", "gbk_bin", False), # 87 + ("sjis", "sjis_bin", False), # 88 + ("tis620", "tis620_bin", False), # 89 + ("ucs2", "ucs2_bin", False), # 90 + ("ujis", "ujis_bin", False), # 91 + ("geostd8", "geostd8_general_ci", True), # 92 + ("geostd8", "geostd8_bin", False), # 93 + ("latin1", "latin1_spanish_ci", False), # 94 + ("cp932", "cp932_japanese_ci", True), # 95 + ("cp932", "cp932_bin", False), # 96 + ("eucjpms", "eucjpms_japanese_ci", True), # 97 + ("eucjpms", "eucjpms_bin", False), # 98 + ("cp1250", "cp1250_polish_ci", False), # 99 + None, + ("utf16", "utf16_unicode_ci", False), # 101 + ("utf16", "utf16_icelandic_ci", False), # 102 + ("utf16", "utf16_latvian_ci", False), # 103 + ("utf16", "utf16_romanian_ci", False), # 104 + ("utf16", "utf16_slovenian_ci", False), # 105 + ("utf16", "utf16_polish_ci", False), # 106 + ("utf16", "utf16_estonian_ci", False), # 107 + ("utf16", "utf16_spanish_ci", False), # 108 + ("utf16", "utf16_swedish_ci", False), # 109 + ("utf16", "utf16_turkish_ci", False), # 110 + ("utf16", "utf16_czech_ci", False), # 111 + ("utf16", "utf16_danish_ci", False), # 112 + ("utf16", "utf16_lithuanian_ci", False), # 113 + ("utf16", "utf16_slovak_ci", False), # 114 + ("utf16", "utf16_spanish2_ci", False), # 115 + ("utf16", "utf16_roman_ci", False), # 116 + ("utf16", "utf16_persian_ci", False), # 117 + ("utf16", "utf16_esperanto_ci", False), # 118 + ("utf16", "utf16_hungarian_ci", False), # 119 + ("utf16", "utf16_sinhala_ci", False), # 120 + ("utf16", "utf16_german2_ci", False), # 121 + ("utf16", "utf16_croatian_ci", False), # 122 + ("utf16", "utf16_unicode_520_ci", False), # 123 + ("utf16", "utf16_vietnamese_ci", False), # 124 + None, + None, + None, + ("ucs2", "ucs2_unicode_ci", False), # 128 + ("ucs2", "ucs2_icelandic_ci", False), # 129 + ("ucs2", "ucs2_latvian_ci", False), # 130 + ("ucs2", "ucs2_romanian_ci", False), # 131 + ("ucs2", "ucs2_slovenian_ci", False), # 132 + ("ucs2", "ucs2_polish_ci", False), # 133 + ("ucs2", "ucs2_estonian_ci", False), # 134 + ("ucs2", "ucs2_spanish_ci", False), # 135 + ("ucs2", "ucs2_swedish_ci", False), # 136 + ("ucs2", "ucs2_turkish_ci", False), # 137 + ("ucs2", "ucs2_czech_ci", False), # 138 + ("ucs2", "ucs2_danish_ci", False), # 139 + ("ucs2", "ucs2_lithuanian_ci", False), # 140 + ("ucs2", "ucs2_slovak_ci", False), # 141 + ("ucs2", "ucs2_spanish2_ci", False), # 142 + ("ucs2", "ucs2_roman_ci", False), # 143 + ("ucs2", "ucs2_persian_ci", False), # 144 + ("ucs2", "ucs2_esperanto_ci", False), # 145 + ("ucs2", "ucs2_hungarian_ci", False), # 146 + ("ucs2", "ucs2_sinhala_ci", False), # 147 + ("ucs2", "ucs2_german2_ci", False), # 148 + ("ucs2", "ucs2_croatian_ci", False), # 149 + ("ucs2", "ucs2_unicode_520_ci", False), # 150 + ("ucs2", "ucs2_vietnamese_ci", False), # 151 + None, + None, + None, + None, + None, + None, + None, + ("ucs2", "ucs2_general_mysql500_ci", False), # 159 + ("utf32", "utf32_unicode_ci", False), # 160 + ("utf32", "utf32_icelandic_ci", False), # 161 + ("utf32", "utf32_latvian_ci", False), # 162 + ("utf32", "utf32_romanian_ci", False), # 163 + ("utf32", "utf32_slovenian_ci", False), # 164 + ("utf32", "utf32_polish_ci", False), # 165 + ("utf32", "utf32_estonian_ci", False), # 166 + ("utf32", "utf32_spanish_ci", False), # 167 + ("utf32", "utf32_swedish_ci", False), # 168 + ("utf32", "utf32_turkish_ci", False), # 169 + ("utf32", "utf32_czech_ci", False), # 170 + ("utf32", "utf32_danish_ci", False), # 171 + ("utf32", "utf32_lithuanian_ci", False), # 172 + ("utf32", "utf32_slovak_ci", False), # 173 + ("utf32", "utf32_spanish2_ci", False), # 174 + ("utf32", "utf32_roman_ci", False), # 175 + ("utf32", "utf32_persian_ci", False), # 176 + ("utf32", "utf32_esperanto_ci", False), # 177 + ("utf32", "utf32_hungarian_ci", False), # 178 + ("utf32", "utf32_sinhala_ci", False), # 179 + ("utf32", "utf32_german2_ci", False), # 180 + ("utf32", "utf32_croatian_ci", False), # 181 + ("utf32", "utf32_unicode_520_ci", False), # 182 + ("utf32", "utf32_vietnamese_ci", False), # 183 + None, + None, + None, + None, + None, + None, + None, + None, + ("utf8", "utf8_unicode_ci", False), # 192 + ("utf8", "utf8_icelandic_ci", False), # 193 + ("utf8", "utf8_latvian_ci", False), # 194 + ("utf8", "utf8_romanian_ci", False), # 195 + ("utf8", "utf8_slovenian_ci", False), # 196 + ("utf8", "utf8_polish_ci", False), # 197 + ("utf8", "utf8_estonian_ci", False), # 198 + ("utf8", "utf8_spanish_ci", False), # 199 + ("utf8", "utf8_swedish_ci", False), # 200 + ("utf8", "utf8_turkish_ci", False), # 201 + ("utf8", "utf8_czech_ci", False), # 202 + ("utf8", "utf8_danish_ci", False), # 203 + ("utf8", "utf8_lithuanian_ci", False), # 204 + ("utf8", "utf8_slovak_ci", False), # 205 + ("utf8", "utf8_spanish2_ci", False), # 206 + ("utf8", "utf8_roman_ci", False), # 207 + ("utf8", "utf8_persian_ci", False), # 208 + ("utf8", "utf8_esperanto_ci", False), # 209 + ("utf8", "utf8_hungarian_ci", False), # 210 + ("utf8", "utf8_sinhala_ci", False), # 211 + ("utf8", "utf8_german2_ci", False), # 212 + ("utf8", "utf8_croatian_ci", False), # 213 + ("utf8", "utf8_unicode_520_ci", False), # 214 + ("utf8", "utf8_vietnamese_ci", False), # 215 + None, + None, + None, + None, + None, + None, + None, + ("utf8", "utf8_general_mysql500_ci", False), # 223 + ("utf8mb4", "utf8mb4_unicode_ci", False), # 224 + ("utf8mb4", "utf8mb4_icelandic_ci", False), # 225 + ("utf8mb4", "utf8mb4_latvian_ci", False), # 226 + ("utf8mb4", "utf8mb4_romanian_ci", False), # 227 + ("utf8mb4", "utf8mb4_slovenian_ci", False), # 228 + ("utf8mb4", "utf8mb4_polish_ci", False), # 229 + ("utf8mb4", "utf8mb4_estonian_ci", False), # 230 + ("utf8mb4", "utf8mb4_spanish_ci", False), # 231 + ("utf8mb4", "utf8mb4_swedish_ci", False), # 232 + ("utf8mb4", "utf8mb4_turkish_ci", False), # 233 + ("utf8mb4", "utf8mb4_czech_ci", False), # 234 + ("utf8mb4", "utf8mb4_danish_ci", False), # 235 + ("utf8mb4", "utf8mb4_lithuanian_ci", False), # 236 + ("utf8mb4", "utf8mb4_slovak_ci", False), # 237 + ("utf8mb4", "utf8mb4_spanish2_ci", False), # 238 + ("utf8mb4", "utf8mb4_roman_ci", False), # 239 + ("utf8mb4", "utf8mb4_persian_ci", False), # 240 + ("utf8mb4", "utf8mb4_esperanto_ci", False), # 241 + ("utf8mb4", "utf8mb4_hungarian_ci", False), # 242 + ("utf8mb4", "utf8mb4_sinhala_ci", False), # 243 + ("utf8mb4", "utf8mb4_german2_ci", False), # 244 + ("utf8mb4", "utf8mb4_croatian_ci", False), # 245 + ("utf8mb4", "utf8mb4_unicode_520_ci", False), # 246 + ("utf8mb4", "utf8mb4_vietnamese_ci", False), # 247 + ("gb18030", "gb18030_chinese_ci", True), # 248 + ("gb18030", "gb18030_bin", False), # 249 + ("gb18030", "gb18030_unicode_520_ci", False), # 250 +] + diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/connection.py b/elitebot/lib/python3.11/site-packages/mysql/connector/connection.py new file mode 100644 index 0000000..453c73e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/connection.py @@ -0,0 +1,1059 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Implementing communication with MySQL servers. +""" + +from io import IOBase +import os +import time + +from .authentication import get_auth_plugin +from .catch23 import PY2, isstr +from .constants import ( + ClientFlag, ServerCmd, ServerFlag, + flag_is_set, ShutdownType, NET_BUFFER_LENGTH +) + +from . import errors +from .conversion import MySQLConverter +from .cursor import ( + CursorBase, MySQLCursor, MySQLCursorRaw, + MySQLCursorBuffered, MySQLCursorBufferedRaw, MySQLCursorPrepared, + MySQLCursorDict, MySQLCursorBufferedDict, MySQLCursorNamedTuple, + MySQLCursorBufferedNamedTuple) +from .network import MySQLUnixSocket, MySQLTCPSocket +from .protocol import MySQLProtocol +from .utils import int4store +from .abstracts import MySQLConnectionAbstract + + +class MySQLConnection(MySQLConnectionAbstract): + """Connection to a MySQL Server""" + def __init__(self, *args, **kwargs): + self._protocol = None + self._socket = None + self._handshake = None + super(MySQLConnection, self).__init__(*args, **kwargs) + + self._converter_class = MySQLConverter + + self._client_flags = ClientFlag.get_default() + self._charset_id = 33 + self._sql_mode = None + self._time_zone = None + self._autocommit = False + + self._user = '' + self._password = '' + self._database = '' + self._host = '127.0.0.1' + self._port = 3306 + self._unix_socket = None + self._client_host = '' + self._client_port = 0 + self._ssl = {} + self._force_ipv6 = False + + self._use_unicode = True + self._get_warnings = False + self._raise_on_warnings = False + self._connection_timeout = None + self._buffered = False + self._unread_result = False + self._have_next_result = False + self._raw = False + self._in_transaction = False + + self._prepared_statements = None + + self._ssl_active = False + self._auth_plugin = None + self._pool_config_version = None + + if len(kwargs) > 0: + self.connect(**kwargs) + + def _do_handshake(self): + """Get the handshake from the MySQL server""" + packet = self._socket.recv() + if packet[4] == 255: + raise errors.get_exception(packet) + + self._handshake = None + try: + handshake = self._protocol.parse_handshake(packet) + except Exception as err: + raise errors.InterfaceError( + 'Failed parsing handshake; {0}'.format(err)) + + self._server_version = self._check_server_version( + handshake['server_version_original']) + + if handshake['capabilities'] & ClientFlag.PLUGIN_AUTH: + self.set_client_flags([ClientFlag.PLUGIN_AUTH]) + + self._handshake = handshake + + def _do_auth(self, username=None, password=None, database=None, + client_flags=0, charset=33, ssl_options=None): + """Authenticate with the MySQL server + + Authentication happens in two parts. We first send a response to the + handshake. The MySQL server will then send either an AuthSwitchRequest + or an error packet. + + Raises NotSupportedError when we get the old, insecure password + reply back. Raises any error coming from MySQL. + """ + self._ssl_active = False + if client_flags & ClientFlag.SSL and ssl_options: + packet = self._protocol.make_auth_ssl(charset=charset, + client_flags=client_flags) + self._socket.send(packet) + self._socket.switch_to_ssl(**ssl_options) + self._ssl_active = True + + packet = self._protocol.make_auth( + handshake=self._handshake, + username=username, password=password, database=database, + charset=charset, client_flags=client_flags, + ssl_enabled=self._ssl_active, + auth_plugin=self._auth_plugin) + self._socket.send(packet) + self._auth_switch_request(username, password) + + if not (client_flags & ClientFlag.CONNECT_WITH_DB) and database: + self.cmd_init_db(database) + + return True + + def _auth_switch_request(self, username=None, password=None): + """Handle second part of authentication + + Raises NotSupportedError when we get the old, insecure password + reply back. Raises any error coming from MySQL. + """ + packet = self._socket.recv() + if packet[4] == 254 and len(packet) == 5: + raise errors.NotSupportedError( + "Authentication with old (insecure) passwords " + "is not supported. For more information, lookup " + "Password Hashing in the latest MySQL manual") + elif packet[4] == 254: + # AuthSwitchRequest + (new_auth_plugin, + auth_data) = self._protocol.parse_auth_switch_request(packet) + auth = get_auth_plugin(new_auth_plugin)( + auth_data, password=password, ssl_enabled=self._ssl_active) + response = auth.auth_response() + self._socket.send(response) + packet = self._socket.recv() + if packet[4] != 1: + return self._handle_ok(packet) + else: + auth_data = self._protocol.parse_auth_more_data(packet) + elif packet[4] == 255: + raise errors.get_exception(packet) + + def _get_connection(self, prtcls=None): + """Get connection based on configuration + + This method will return the appropriated connection object using + the connection parameters. + + Returns subclass of MySQLBaseSocket. + """ + conn = None + if self.unix_socket and os.name != 'nt': + conn = MySQLUnixSocket(unix_socket=self.unix_socket) + else: + conn = MySQLTCPSocket(host=self.server_host, + port=self.server_port, + force_ipv6=self._force_ipv6) + conn.set_connection_timeout(self._connection_timeout) + return conn + + def _open_connection(self): + """Open the connection to the MySQL server + + This method sets up and opens the connection to the MySQL server. + + Raises on errors. + """ + self._protocol = MySQLProtocol() + self._socket = self._get_connection() + self._socket.open_connection() + self._do_handshake() + self._do_auth(self._user, self._password, + self._database, self._client_flags, self._charset_id, + self._ssl) + self.set_converter_class(self._converter_class) + if self._client_flags & ClientFlag.COMPRESS: + self._socket.recv = self._socket.recv_compressed + self._socket.send = self._socket.send_compressed + + def shutdown(self): + """Shut down connection to MySQL Server. + """ + if not self._socket: + return + + try: + self._socket.shutdown() + except (AttributeError, errors.Error): + pass # Getting an exception would mean we are disconnected. + + def close(self): + """Disconnect from the MySQL server""" + if not self._socket: + return + + try: + self.cmd_quit() + self._socket.close_connection() + except (AttributeError, errors.Error): + pass # Getting an exception would mean we are disconnected. + disconnect = close + + def _send_cmd(self, command, argument=None, packet_number=0, packet=None, + expect_response=True, compressed_packet_number=0): + """Send a command to the MySQL server + + This method sends a command with an optional argument. + If packet is not None, it will be sent and the argument will be + ignored. + + The packet_number is optional and should usually not be used. + + Some commands might not result in the MySQL server returning + a response. If a command does not return anything, you should + set expect_response to False. The _send_cmd method will then + return None instead of a MySQL packet. + + Returns a MySQL packet or None. + """ + self.handle_unread_result() + + try: + self._socket.send( + self._protocol.make_command(command, packet or argument), + packet_number, compressed_packet_number) + except AttributeError: + raise errors.OperationalError("MySQL Connection not available.") + + if not expect_response: + return None + return self._socket.recv() + + def _send_data(self, data_file, send_empty_packet=False): + """Send data to the MySQL server + + This method accepts a file-like object and sends its data + as is to the MySQL server. If the send_empty_packet is + True, it will send an extra empty package (for example + when using LOAD LOCAL DATA INFILE). + + Returns a MySQL packet. + """ + self.handle_unread_result() + + if not hasattr(data_file, 'read'): + raise ValueError("expecting a file-like object") + + try: + buf = data_file.read(NET_BUFFER_LENGTH - 16) + while buf: + self._socket.send(buf) + buf = data_file.read(NET_BUFFER_LENGTH - 16) + except AttributeError: + raise errors.OperationalError("MySQL Connection not available.") + + if send_empty_packet: + try: + self._socket.send(b'') + except AttributeError: + raise errors.OperationalError( + "MySQL Connection not available.") + + return self._socket.recv() + + def _handle_server_status(self, flags): + """Handle the server flags found in MySQL packets + + This method handles the server flags send by MySQL OK and EOF + packets. It, for example, checks whether there exists more result + sets or whether there is an ongoing transaction. + """ + self._have_next_result = flag_is_set(ServerFlag.MORE_RESULTS_EXISTS, + flags) + self._in_transaction = flag_is_set(ServerFlag.STATUS_IN_TRANS, flags) + + @property + def in_transaction(self): + """MySQL session has started a transaction""" + return self._in_transaction + + def _handle_ok(self, packet): + """Handle a MySQL OK packet + + This method handles a MySQL OK packet. When the packet is found to + be an Error packet, an error will be raised. If the packet is neither + an OK or an Error packet, errors.InterfaceError will be raised. + + Returns a dict() + """ + if packet[4] == 0: + ok_pkt = self._protocol.parse_ok(packet) + self._handle_server_status(ok_pkt['status_flag']) + return ok_pkt + elif packet[4] == 255: + raise errors.get_exception(packet) + raise errors.InterfaceError('Expected OK packet') + + def _handle_eof(self, packet): + """Handle a MySQL EOF packet + + This method handles a MySQL EOF packet. When the packet is found to + be an Error packet, an error will be raised. If the packet is neither + and OK or an Error packet, errors.InterfaceError will be raised. + + Returns a dict() + """ + if packet[4] == 254: + eof = self._protocol.parse_eof(packet) + self._handle_server_status(eof['status_flag']) + return eof + elif packet[4] == 255: + raise errors.get_exception(packet) + raise errors.InterfaceError('Expected EOF packet') + + def _handle_load_data_infile(self, filename): + """Handle a LOAD DATA INFILE LOCAL request""" + try: + data_file = open(filename, 'rb') + except IOError: + # Send a empty packet to cancel the operation + try: + self._socket.send(b'') + except AttributeError: + raise errors.OperationalError( + "MySQL Connection not available.") + raise errors.InterfaceError( + "File '{0}' could not be read".format(filename)) + + return self._handle_ok(self._send_data(data_file, + send_empty_packet=True)) + + def _handle_result(self, packet): + """Handle a MySQL Result + + This method handles a MySQL result, for example, after sending the + query command. OK and EOF packets will be handled and returned. If + the packet is an Error packet, an errors.Error-exception will be + raised. + + The dictionary returned of: + - columns: column information + - eof: the EOF-packet information + + Returns a dict() + """ + if not packet or len(packet) < 4: + raise errors.InterfaceError('Empty response') + elif packet[4] == 0: + return self._handle_ok(packet) + elif packet[4] == 251: + if PY2: + filename = str(packet[5:]) + else: + filename = packet[5:].decode() + return self._handle_load_data_infile(filename) + elif packet[4] == 254: + return self._handle_eof(packet) + elif packet[4] == 255: + raise errors.get_exception(packet) + + # We have a text result set + column_count = self._protocol.parse_column_count(packet) + if not column_count or not isinstance(column_count, int): + raise errors.InterfaceError('Illegal result set.') + + columns = [None,] * column_count + for i in range(0, column_count): + columns[i] = self._protocol.parse_column( + self._socket.recv(), self.python_charset) + + eof = self._handle_eof(self._socket.recv()) + self.unread_result = True + return {'columns': columns, 'eof': eof} + + def get_row(self, binary=False, columns=None): + """Get the next rows returned by the MySQL server + + This method gets one row from the result set after sending, for + example, the query command. The result is a tuple consisting of the + row and the EOF packet. + If no row was available in the result set, the row data will be None. + + Returns a tuple. + """ + (rows, eof) = self.get_rows(count=1, binary=binary, columns=columns) + if len(rows): + return (rows[0], eof) + return (None, eof) + + def get_rows(self, count=None, binary=False, columns=None): + """Get all rows returned by the MySQL server + + This method gets all rows returned by the MySQL server after sending, + for example, the query command. The result is a tuple consisting of + a list of rows and the EOF packet. + + Returns a tuple() + """ + if not self.unread_result: + raise errors.InternalError("No result set available.") + + try: + if binary: + rows = self._protocol.read_binary_result( + self._socket, columns, count) + else: + rows = self._protocol.read_text_result(self._socket, self._server_version, count=count) + except errors.Error as err: + self.unread_result = False + raise err + + if rows[-1] is not None: + ek = rows[-1] # OK or EOF + self._handle_server_status(ek['status_flag'] if 'status_flag' in ek else ek['server_status']) + self.unread_result = False + + return rows + + def consume_results(self): + """Consume results + """ + if self.unread_result: + self.get_rows() + + def cmd_init_db(self, database): + """Change the current database + + This method changes the current (default) database by sending the + INIT_DB command. The result is a dictionary containing the OK packet + information. + + Returns a dict() + """ + return self._handle_ok( + self._send_cmd(ServerCmd.INIT_DB, database.encode('utf-8'))) + + def cmd_query(self, query, raw=False, buffered=False, raw_as_string=False): + """Send a query to the MySQL server + + This method send the query to the MySQL server and returns the result. + + If there was a text result, a tuple will be returned consisting of + the number of columns and a list containing information about these + columns. + + When the query doesn't return a text result, the OK or EOF packet + information as dictionary will be returned. In case the result was + an error, exception errors.Error will be raised. + + Returns a tuple() + """ + if not isinstance(query, bytes): + query = query.encode('utf-8') + result = self._handle_result(self._send_cmd(ServerCmd.QUERY, query)) + + if self._have_next_result: + raise errors.InterfaceError( + 'Use cmd_query_iter for statements with multiple queries.') + + return result + + def cmd_query_iter(self, statements): + """Send one or more statements to the MySQL server + + Similar to the cmd_query method, but instead returns a generator + object to iterate through results. It sends the statements to the + MySQL server and through the iterator you can get the results. + + statement = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2' + for result in cnx.cmd_query(statement, iterate=True): + if 'columns' in result: + columns = result['columns'] + rows = cnx.get_rows() + else: + # do something useful with INSERT result + + Returns a generator. + """ + if not isinstance(statements, bytearray): + if isstr(statements): + statements = bytearray(statements.encode('utf-8')) + else: + statements = bytearray(statements) + + # Handle the first query result + yield self._handle_result(self._send_cmd(ServerCmd.QUERY, statements)) + + # Handle next results, if any + while self._have_next_result: + self.handle_unread_result() + yield self._handle_result(self._socket.recv()) + + def cmd_refresh(self, options): + """Send the Refresh command to the MySQL server + + This method sends the Refresh command to the MySQL server. The options + argument should be a bitwise value using constants.RefreshOption. + Usage example: + RefreshOption = mysql.connector.RefreshOption + refresh = RefreshOption.LOG | RefreshOption.THREADS + cnx.cmd_refresh(refresh) + + The result is a dictionary with the OK packet information. + + Returns a dict() + """ + return self._handle_ok( + self._send_cmd(ServerCmd.REFRESH, int4store(options))) + + def cmd_quit(self): + """Close the current connection with the server + + This method sends the QUIT command to the MySQL server, closing the + current connection. Since the no response can be returned to the + client, cmd_quit() will return the packet it send. + + Returns a str() + """ + self.handle_unread_result() + + packet = self._protocol.make_command(ServerCmd.QUIT) + self._socket.send(packet, 0, 0) + return packet + + def cmd_shutdown(self, shutdown_type=None): + """Shut down the MySQL Server + + This method sends the SHUTDOWN command to the MySQL server and is only + possible if the current user has SUPER privileges. The result is a + dictionary containing the OK packet information. + + Note: Most applications and scripts do not the SUPER privilege. + + Returns a dict() + """ + if shutdown_type: + if not ShutdownType.get_info(shutdown_type): + raise errors.InterfaceError("Invalid shutdown type") + atype = shutdown_type + else: + atype = ShutdownType.SHUTDOWN_DEFAULT + return self._handle_eof(self._send_cmd(ServerCmd.SHUTDOWN, + int4store(atype))) + + def cmd_statistics(self): + """Send the statistics command to the MySQL Server + + This method sends the STATISTICS command to the MySQL server. The + result is a dictionary with various statistical information. + + Returns a dict() + """ + self.handle_unread_result() + + packet = self._protocol.make_command(ServerCmd.STATISTICS) + self._socket.send(packet, 0, 0) + return self._protocol.parse_statistics(self._socket.recv()) + + def cmd_process_kill(self, mysql_pid): + """Kill a MySQL process + + This method send the PROCESS_KILL command to the server along with + the process ID. The result is a dictionary with the OK packet + information. + + Returns a dict() + """ + return self._handle_ok( + self._send_cmd(ServerCmd.PROCESS_KILL, int4store(mysql_pid))) + + def cmd_debug(self): + """Send the DEBUG command + + This method sends the DEBUG command to the MySQL server, which + requires the MySQL user to have SUPER privilege. The output will go + to the MySQL server error log and the result of this method is a + dictionary with EOF packet information. + + Returns a dict() + """ + return self._handle_eof(self._send_cmd(ServerCmd.DEBUG)) + + def cmd_ping(self): + """Send the PING command + + This method sends the PING command to the MySQL server. It is used to + check if the the connection is still valid. The result of this + method is dictionary with OK packet information. + + Returns a dict() + """ + return self._handle_ok(self._send_cmd(ServerCmd.PING)) + + def cmd_change_user(self, username='', password='', database='', + charset=33): + """Change the current logged in user + + This method allows to change the current logged in user information. + The result is a dictionary with OK packet information. + + Returns a dict() + """ + self.handle_unread_result() + + if self._compress: + raise errors.NotSupportedError("Change user is not supported with " + "compression.") + + packet = self._protocol.make_change_user( + handshake=self._handshake, + username=username, password=password, database=database, + charset=charset, client_flags=self._client_flags, + ssl_enabled=self._ssl_active, + auth_plugin=self._auth_plugin) + self._socket.send(packet, 0, 0) + + ok_packet = self._auth_switch_request(username, password) + + try: + if not (self._client_flags & ClientFlag.CONNECT_WITH_DB) \ + and database: + self.cmd_init_db(database) + except: + raise + + self._charset_id = charset + self._post_connection() + + return ok_packet + + @property + def database(self): + """Get the current database""" + return self.info_query("SELECT DATABASE()")[0] + + @database.setter + def database(self, value): # pylint: disable=W0221 + """Set the current database""" + self.cmd_query("USE %s" % value) + + def is_connected(self): + """Reports whether the connection to MySQL Server is available + + This method checks whether the connection to MySQL is available. + It is similar to ping(), but unlike the ping()-method, either True + or False is returned and no exception is raised. + + Returns True or False. + """ + try: + self.cmd_ping() + except: + return False # This method does not raise + return True + + def reset_session(self, user_variables=None, session_variables=None): + """Clears the current active session + + This method resets the session state, if the MySQL server is 5.7.3 + or later active session will be reset without re-authenticating. + For other server versions session will be reset by re-authenticating. + + It is possible to provide a sequence of variables and their values to + be set after clearing the session. This is possible for both user + defined variables and session variables. + This method takes two arguments user_variables and session_variables + which are dictionaries. + + Raises OperationalError if not connected, InternalError if there are + unread results and InterfaceError on errors. + """ + if not self.is_connected(): + raise errors.OperationalError("MySQL Connection not available.") + + try: + self.cmd_reset_connection() + except errors.NotSupportedError: + self.cmd_change_user(self._user, self._password, + self._database, self._charset_id) + + cur = self.cursor() + if user_variables: + for key, value in user_variables.items(): + cur.execute("SET @`{0}` = %s".format(key), (value,)) + if session_variables: + for key, value in session_variables.items(): + cur.execute("SET SESSION `{0}` = %s".format(key), (value,)) + + def reconnect(self, attempts=1, delay=0): + """Attempt to reconnect to the MySQL server + + The argument attempts should be the number of times a reconnect + is tried. The delay argument is the number of seconds to wait between + each retry. + + You may want to set the number of attempts higher and use delay when + you expect the MySQL server to be down for maintenance or when you + expect the network to be temporary unavailable. + + Raises InterfaceError on errors. + """ + counter = 0 + while counter != attempts: + counter = counter + 1 + try: + self.disconnect() + self.connect() + if self.is_connected(): + break + except Exception as err: # pylint: disable=W0703 + if counter == attempts: + msg = "Can not reconnect to MySQL after {0} "\ + "attempt(s): {1}".format(attempts, str(err)) + raise errors.InterfaceError(msg) + if delay > 0: + time.sleep(delay) + + def ping(self, reconnect=False, attempts=1, delay=0): + """Check availability of the MySQL server + + When reconnect is set to True, one or more attempts are made to try + to reconnect to the MySQL server using the reconnect()-method. + + delay is the number of seconds to wait between each retry. + + When the connection is not available, an InterfaceError is raised. Use + the is_connected()-method if you just want to check the connection + without raising an error. + + Raises InterfaceError on errors. + """ + try: + self.cmd_ping() + except: + if reconnect: + self.reconnect(attempts=attempts, delay=delay) + else: + raise errors.InterfaceError("Connection to MySQL is" + " not available.") + + @property + def connection_id(self): + """MySQL connection ID""" + try: + return self._handshake['server_threadid'] + except KeyError: + return None + + def cursor(self, buffered=None, raw=None, prepared=None, cursor_class=None, + dictionary=None, named_tuple=None): + """Instantiates and returns a cursor + + By default, MySQLCursor is returned. Depending on the options + while connecting, a buffered and/or raw cursor is instantiated + instead. Also depending upon the cursor options, rows can be + returned as dictionary or named tuple. + + Dictionary and namedtuple based cursors are available with buffered + output but not raw. + + It is possible to also give a custom cursor through the + cursor_class parameter, but it needs to be a subclass of + mysql.connector.cursor.CursorBase. + + Raises ProgrammingError when cursor_class is not a subclass of + CursorBase. Raises ValueError when cursor is not available. + + Returns a cursor-object + """ + self.handle_unread_result() + + if not self.is_connected(): + raise errors.OperationalError("MySQL Connection not available.") + if cursor_class is not None: + if not issubclass(cursor_class, CursorBase): + raise errors.ProgrammingError( + "Cursor class needs be to subclass of cursor.CursorBase") + return (cursor_class)(self) + + buffered = buffered if buffered is not None else self._buffered + raw = raw if raw is not None else self._raw + + cursor_type = 0 + if buffered is True: + cursor_type |= 1 + if raw is True: + cursor_type |= 2 + if dictionary is True: + cursor_type |= 4 + if named_tuple is True: + cursor_type |= 8 + if prepared is True: + cursor_type |= 16 + + types = { + 0: MySQLCursor, # 0 + 1: MySQLCursorBuffered, + 2: MySQLCursorRaw, + 3: MySQLCursorBufferedRaw, + 4: MySQLCursorDict, + 5: MySQLCursorBufferedDict, + 8: MySQLCursorNamedTuple, + 9: MySQLCursorBufferedNamedTuple, + 16: MySQLCursorPrepared + } + try: + return (types[cursor_type])(self) + except KeyError: + args = ('buffered', 'raw', 'dictionary', 'named_tuple', 'prepared') + raise ValueError('Cursor not available with given criteria: ' + + ', '.join([args[i] for i in range(5) + if cursor_type & (1 << i) != 0])) + + def commit(self): + """Commit current transaction""" + self._execute_query("COMMIT") + + def rollback(self): + """Rollback current transaction""" + if self.unread_result: + self.get_rows() + + self._execute_query("ROLLBACK") + + def _execute_query(self, query): + """Execute a query + + This method simply calls cmd_query() after checking for unread + result. If there are still unread result, an errors.InterfaceError + is raised. Otherwise whatever cmd_query() returns is returned. + + Returns a dict() + """ + self.handle_unread_result() + self.cmd_query(query) + + def info_query(self, query): + """Send a query which only returns 1 row""" + cursor = self.cursor(buffered=True) + cursor.execute(query) + return cursor.fetchone() + + def _handle_binary_ok(self, packet): + """Handle a MySQL Binary Protocol OK packet + + This method handles a MySQL Binary Protocol OK packet. When the + packet is found to be an Error packet, an error will be raised. If + the packet is neither an OK or an Error packet, errors.InterfaceError + will be raised. + + Returns a dict() + """ + if packet[4] == 0: + return self._protocol.parse_binary_prepare_ok(packet) + elif packet[4] == 255: + raise errors.get_exception(packet) + raise errors.InterfaceError('Expected Binary OK packet') + + def _handle_binary_result(self, packet): + """Handle a MySQL Result + + This method handles a MySQL result, for example, after sending the + query command. OK and EOF packets will be handled and returned. If + the packet is an Error packet, an errors.Error-exception will be + raised. + + The tuple returned by this method consist of: + - the number of columns in the result, + - a list of tuples with information about the columns, + - the EOF packet information as a dictionary. + + Returns tuple() or dict() + """ + if not packet or len(packet) < 4: + raise errors.InterfaceError('Empty response') + elif packet[4] == 0: + return self._handle_ok(packet) + elif packet[4] == 254: + return self._handle_eof(packet) + elif packet[4] == 255: + raise errors.get_exception(packet) + + # We have a binary result set + column_count = self._protocol.parse_column_count(packet) + if not column_count or not isinstance(column_count, int): + raise errors.InterfaceError('Illegal result set.') + + columns = [None] * column_count + for i in range(0, column_count): + columns[i] = self._protocol.parse_column( + self._socket.recv(), self.python_charset) + + eof = self._handle_eof(self._socket.recv()) + return (column_count, columns, eof) + + def cmd_stmt_prepare(self, statement): + """Prepare a MySQL statement + + This method will send the PREPARE command to MySQL together with the + given statement. + + Returns a dict() + """ + packet = self._send_cmd(ServerCmd.STMT_PREPARE, statement) + result = self._handle_binary_ok(packet) + + result['columns'] = [] + result['parameters'] = [] + if result['num_params'] > 0: + for _ in range(0, result['num_params']): + result['parameters'].append( + self._protocol.parse_column(self._socket.recv(), + self.python_charset)) + self._handle_eof(self._socket.recv()) + if result['num_columns'] > 0: + for _ in range(0, result['num_columns']): + result['columns'].append( + self._protocol.parse_column(self._socket.recv(), + self.python_charset)) + self._handle_eof(self._socket.recv()) + + return result + + def cmd_stmt_execute(self, statement_id, data=(), parameters=(), flags=0): + """Execute a prepared MySQL statement""" + parameters = list(parameters) + long_data_used = {} + + if data: + for param_id, _ in enumerate(parameters): + if isinstance(data[param_id], IOBase): + binary = True + try: + binary = 'b' not in data[param_id].mode + except AttributeError: + pass + self.cmd_stmt_send_long_data(statement_id, param_id, + data[param_id]) + long_data_used[param_id] = (binary,) + + execute_packet = self._protocol.make_stmt_execute( + statement_id, data, tuple(parameters), flags, + long_data_used, self.charset) + packet = self._send_cmd(ServerCmd.STMT_EXECUTE, packet=execute_packet) + result = self._handle_binary_result(packet) + return result + + def cmd_stmt_close(self, statement_id): + """Deallocate a prepared MySQL statement + + This method deallocates the prepared statement using the + statement_id. Note that the MySQL server does not return + anything. + """ + self._send_cmd(ServerCmd.STMT_CLOSE, int4store(statement_id), + expect_response=False) + + def cmd_stmt_send_long_data(self, statement_id, param_id, data): + """Send data for a column + + This methods send data for a column (for example BLOB) for statement + identified by statement_id. The param_id indicate which parameter + the data belongs too. + The data argument should be a file-like object. + + Since MySQL does not send anything back, no error is raised. When + the MySQL server is not reachable, an OperationalError is raised. + + cmd_stmt_send_long_data should be called before cmd_stmt_execute. + + The total bytes send is returned. + + Returns int. + """ + chunk_size = 8192 + total_sent = 0 + # pylint: disable=W0212 + prepare_packet = self._protocol._prepare_stmt_send_long_data + # pylint: enable=W0212 + try: + buf = data.read(chunk_size) + while buf: + packet = prepare_packet(statement_id, param_id, buf) + self._send_cmd(ServerCmd.STMT_SEND_LONG_DATA, packet=packet, + expect_response=False) + total_sent += len(buf) + buf = data.read(chunk_size) + except AttributeError: + raise errors.OperationalError("MySQL Connection not available.") + + return total_sent + + def cmd_stmt_reset(self, statement_id): + """Reset data for prepared statement sent as long data + + The result is a dictionary with OK packet information. + + Returns a dict() + """ + self._handle_ok(self._send_cmd(ServerCmd.STMT_RESET, + int4store(statement_id))) + + def cmd_reset_connection(self): + """Resets the session state without re-authenticating + + Works only for MySQL server 5.7.3 or later. + The result is a dictionary with OK packet information. + + Returns a dict() + """ + if self._server_version < (5, 7, 3): + raise errors.NotSupportedError("MySQL version 5.7.2 and " + "earlier does not support " + "COM_RESET_CONNECTION.") + self._handle_ok(self._send_cmd(ServerCmd.RESET_CONNECTION)) + self._post_connection() + + def handle_unread_result(self): + """Check whether there is an unread result""" + if self.can_consume_results: + self.consume_results() + elif self.unread_result: + raise errors.InternalError("Unread result found") diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/connection_cext.py b/elitebot/lib/python3.11/site-packages/mysql/connector/connection_cext.py new file mode 100644 index 0000000..9c00a9a --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/connection_cext.py @@ -0,0 +1,594 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Connection class using the C Extension +""" + +# Detection of abstract methods in pylint is not working correctly +#pylint: disable=W0223 + +from . import errors +from .catch23 import INT_TYPES +from .constants import ( + CharacterSet, FieldFlag, ServerFlag, ShutdownType, ClientFlag +) +from .abstracts import MySQLConnectionAbstract, MySQLCursorAbstract +from .protocol import MySQLProtocol + +HAVE_CMYSQL = False +# pylint: disable=F0401,C0413 +try: + import _mysql_connector + from .cursor_cext import ( + CMySQLCursor, CMySQLCursorRaw, + CMySQLCursorBuffered, CMySQLCursorBufferedRaw, CMySQLCursorPrepared, + CMySQLCursorDict, CMySQLCursorBufferedDict, CMySQLCursorNamedTuple, + CMySQLCursorBufferedNamedTuple) + from _mysql_connector import MySQLInterfaceError # pylint: disable=F0401 +except ImportError as exc: + raise ImportError( + "MySQL Connector/Python C Extension not available ({0})".format( + str(exc) + )) +else: + HAVE_CMYSQL = True +# pylint: enable=F0401,C0413 + +class CMySQLConnection(MySQLConnectionAbstract): + + """Class initiating a MySQL Connection using Connector/C""" + + def __init__(self, **kwargs): + """Initialization""" + if not HAVE_CMYSQL: + raise RuntimeError( + "MySQL Connector/Python C Extension not available") + self._cmysql = None + self._connection_timeout = 2 + self._columns = [] + self.converter = None + super(CMySQLConnection, self).__init__(**kwargs) + + if len(kwargs) > 0: + self.connect(**kwargs) + + def _do_handshake(self): + """Gather information of the MySQL server before authentication""" + self._handshake = { + 'protocol': self._cmysql.get_proto_info(), + 'server_version_original': self._cmysql.get_server_info(), + 'server_threadid': self._cmysql.thread_id(), + 'charset': None, + 'server_status': None, + 'auth_plugin': None, + 'auth_data': None, + 'capabilities': self._cmysql.st_server_capabilities(), + } + + self._server_version = self._check_server_version( + self._handshake['server_version_original'] + ) + + @property + def _server_status(self): + """Returns the server status attribute of MYSQL structure""" + return self._cmysql.st_server_status() + + def set_unicode(self, value=True): + """Toggle unicode mode + + Set whether we return string fields as unicode or not. + Default is True. + """ + self._use_unicode = value + if self._cmysql: + self._cmysql.use_unicode(value) + if self.converter: + self.converter.set_unicode(value) + + @property + def autocommit(self): + """Get whether autocommit is on or off""" + value = self.info_query("SELECT @@session.autocommit")[0] + return True if value == 1 else False + + @autocommit.setter + def autocommit(self, value): # pylint: disable=W0221 + """Toggle autocommit""" + try: + self._cmysql.autocommit(value) + self._autocommit = value + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + @property + def database(self): + """Get the current database""" + return self.info_query("SELECT DATABASE()")[0] + + @database.setter + def database(self, value): # pylint: disable=W0221 + """Set the current database""" + self._cmysql.select_db(value) + + @property + def in_transaction(self): + """MySQL session has started a transaction""" + return self._server_status & ServerFlag.STATUS_IN_TRANS + + def _open_connection(self): + charset_name = CharacterSet.get_info(self._charset_id)[0] + + self._cmysql = _mysql_connector.MySQL( + buffered=self._buffered, + raw=self._raw, + charset_name=charset_name, + connection_timeout=int(self._connection_timeout or 10), + use_unicode=self._use_unicode, + auth_plugin=self._auth_plugin) + + cnx_kwargs = { + 'host': self._host, + 'user': self._user, + 'password': self._password, + 'database': self._database, + 'port': self._port, + 'client_flags': self._client_flags, + 'unix_socket': self._unix_socket, + 'compress': self.isset_client_flag(ClientFlag.COMPRESS) + } + + if self.isset_client_flag(ClientFlag.SSL): + cnx_kwargs.update({ + 'ssl_ca': self._ssl['ca'], + 'ssl_cert': self._ssl['cert'], + 'ssl_key': self._ssl['key'], + 'ssl_verify_cert': self._ssl['verify_cert'] + }) + + try: + self._cmysql.connect(**cnx_kwargs) + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + self._do_handshake() + + def close(self): + """Disconnect from the MySQL server""" + if self._cmysql: + try: + self._cmysql.close() + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + self._cmysql = None + disconnect = close + + def is_connected(self): + """Reports whether the connection to MySQL Server is available""" + if self._cmysql: + return self._cmysql.ping() + + return False + + def ping(self, reconnect=False, attempts=1, delay=0): + """Check availability of the MySQL server + + When reconnect is set to True, one or more attempts are made to try + to reconnect to the MySQL server using the reconnect()-method. + + delay is the number of seconds to wait between each retry. + + When the connection is not available, an InterfaceError is raised. Use + the is_connected()-method if you just want to check the connection + without raising an error. + + Raises InterfaceError on errors. + """ + errmsg = "Connection to MySQL is not available" + + try: + connected = self._cmysql.ping() + except AttributeError: + pass # Raise or reconnect later + else: + if connected: + return + + if reconnect: + self.reconnect(attempts=attempts, delay=delay) + else: + raise errors.InterfaceError(errmsg) + + def set_character_set_name(self, charset): + """Sets the default character set name for current connection. + """ + self._cmysql.set_character_set(charset) + + def info_query(self, query): + """Send a query which only returns 1 row""" + self._cmysql.query(query) + first_row = () + if self._cmysql.have_result_set: + first_row = self._cmysql.fetch_row() + if self._cmysql.fetch_row(): + self._cmysql.free_result() + raise errors.InterfaceError( + "Query should not return more than 1 row") + self._cmysql.free_result() + + return first_row + + @property + def connection_id(self): + """MySQL connection ID""" + try: + return self._cmysql.thread_id() + except MySQLInterfaceError: + pass # Just return None + + return None + + def get_rows(self, count=None, binary=False, columns=None): + """Get all or a subset of rows returned by the MySQL server""" + if not (self._cmysql and self.unread_result): + raise errors.InternalError("No result set available") + + rows = [] + if count is not None and count <= 0: + raise AttributeError("count should be 1 or higher, or None") + + counter = 0 + try: + row = self._cmysql.fetch_row() + while row: + if self.converter: + row = list(row) + for i, _ in enumerate(row): + row[i] = self.converter.to_python(self._columns[i], + row[i]) + row = tuple(row) + rows.append(row) + counter += 1 + if count and counter == count: + break + row = self._cmysql.fetch_row() + except MySQLInterfaceError as exc: + self.free_result() + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + return rows + + def get_row(self, binary=False, columns=None): + """Get the next rows returned by the MySQL server""" + try: + return self.get_rows(count=1, binary=binary, columns=columns)[0] + except IndexError: + # No row available + return None + + def next_result(self): + """Reads the next result""" + if self._cmysql: + self._cmysql.consume_result() + return self._cmysql.next_result() + return None + + def free_result(self): + """Frees the result""" + if self._cmysql: + self._cmysql.free_result() + + def commit(self): + """Commit current transaction""" + if self._cmysql: + self._cmysql.commit() + + def rollback(self): + """Rollback current transaction""" + if self._cmysql: + self._cmysql.consume_result() + self._cmysql.rollback() + + def cmd_init_db(self, database): + """Change the current database""" + try: + self._cmysql.select_db(database) + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + def fetch_eof_columns(self): + """Fetch EOF and column information""" + if not self._cmysql.have_result_set: + raise errors.InterfaceError("No result set") + + fields = self._cmysql.fetch_fields() + self._columns = [] + for col in fields: + self._columns.append(( + col[4], + int(col[8]), + None, + None, + None, + None, + ~int(col[9]) & FieldFlag.NOT_NULL, + int(col[9]) + )) + + return { + 'eof': { + 'status_flag': self._server_status, + 'warning_count': self._cmysql.st_warning_count(), + }, + 'columns': self._columns, + } + + def fetch_eof_status(self): + """Fetch EOF and status information""" + if self._cmysql: + return { + 'warning_count': self._cmysql.st_warning_count(), + 'field_count': self._cmysql.st_field_count(), + 'insert_id': self._cmysql.insert_id(), + 'affected_rows': self._cmysql.affected_rows(), + 'server_status': self._server_status, + } + + return None + + def cmd_query(self, query, raw=False, buffered=False, raw_as_string=False): + """Send a query to the MySQL server""" + self.handle_unread_result() + + try: + if not isinstance(query, bytes): + query = query.encode('utf-8') + self._cmysql.query(query, + raw=raw, buffered=buffered, + raw_as_string=raw_as_string) + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(exc.errno, msg=exc.msg, + sqlstate=exc.sqlstate) + except AttributeError: + if self._unix_socket: + addr = self._unix_socket + else: + addr = self._host + ':' + str(self._port) + raise errors.OperationalError( + errno=2055, values=(addr, 'Connection not available.')) + + self._columns = [] + if not self._cmysql.have_result_set: + # No result + return self.fetch_eof_status() + + return self.fetch_eof_columns() + _execute_query = cmd_query + + def cursor(self, buffered=None, raw=None, prepared=None, cursor_class=None, + dictionary=None, named_tuple=None): + """Instantiates and returns a cursor using C Extension + + By default, CMySQLCursor is returned. Depending on the options + while connecting, a buffered and/or raw cursor is instantiated + instead. Also depending upon the cursor options, rows can be + returned as dictionary or named tuple. + + Dictionary and namedtuple based cursors are available with buffered + output but not raw. + + It is possible to also give a custom cursor through the + cursor_class parameter, but it needs to be a subclass of + mysql.connector.cursor_cext.CMySQLCursor. + + Raises ProgrammingError when cursor_class is not a subclass of + CursorBase. Raises ValueError when cursor is not available. + + Returns instance of CMySQLCursor or subclass. + + :param buffered: Return a buffering cursor + :param raw: Return a raw cursor + :param prepared: Return a cursor which uses prepared statements + :param cursor_class: Use a custom cursor class + :param dictionary: Rows are returned as dictionary + :param named_tuple: Rows are returned as named tuple + :return: Subclass of CMySQLCursor + :rtype: CMySQLCursor or subclass + """ + self.handle_unread_result() + if not self.is_connected(): + raise errors.OperationalError("MySQL Connection not available.") + if cursor_class is not None: + if not issubclass(cursor_class, MySQLCursorAbstract): + raise errors.ProgrammingError( + "Cursor class needs be to subclass" + " of cursor_cext.CMySQLCursor") + return (cursor_class)(self) + + buffered = buffered or self._buffered + raw = raw or self._raw + + cursor_type = 0 + if buffered is True: + cursor_type |= 1 + if raw is True: + cursor_type |= 2 + if dictionary is True: + cursor_type |= 4 + if named_tuple is True: + cursor_type |= 8 + if prepared is True: + cursor_type |= 16 + + types = { + 0: CMySQLCursor, # 0 + 1: CMySQLCursorBuffered, + 2: CMySQLCursorRaw, + 3: CMySQLCursorBufferedRaw, + 4: CMySQLCursorDict, + 5: CMySQLCursorBufferedDict, + 8: CMySQLCursorNamedTuple, + 9: CMySQLCursorBufferedNamedTuple, + 16: CMySQLCursorPrepared + } + try: + return (types[cursor_type])(self) + except KeyError: + args = ('buffered', 'raw', 'dictionary', 'named_tuple', 'prepared') + raise ValueError('Cursor not available with given criteria: ' + + ', '.join([args[i] for i in range(5) + if cursor_type & (1 << i) != 0])) + + @property + def num_rows(self): + """Returns number of rows of current result set""" + if not self._cmysql.have_result_set: + raise errors.InterfaceError("No result set") + + return self._cmysql.num_rows() + + @property + def warning_count(self): + """Returns number of warnings""" + if not self._cmysql: + return 0 + + return self._cmysql.warning_count() + + @property + def result_set_available(self): + """Check if a result set is available""" + if not self._cmysql: + return False + + return self._cmysql.have_result_set + + @property + def unread_result(self): + """Check if there are unread results or rows""" + return self.result_set_available + + @property + def more_results(self): + """Check if there are more results""" + return self._cmysql.more_results() + + def prepare_for_mysql(self, params): + """Prepare parameters for statements + + This method is use by cursors to prepared parameters found in the + list (or tuple) params. + + Returns dict. + """ + if isinstance(params, (list, tuple)): + result = self._cmysql.convert_to_mysql(*params) + elif isinstance(params, dict): + result = {} + for key, value in params.items(): + result[key] = self._cmysql.convert_to_mysql(value)[0] + else: + raise ValueError("Could not process parameters") + + return result + + def consume_results(self): + """Consume the current result + + This method consume the result by reading (consuming) all rows. + """ + self._cmysql.consume_result() + + def cmd_change_user(self, username='', password='', database='', + charset=33): + """Change the current logged in user""" + try: + self._cmysql.change_user(username, password, database) + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + self._charset_id = charset + self._post_connection() + + def cmd_refresh(self, options): + """Send the Refresh command to the MySQL server""" + try: + self._cmysql.refresh(options) + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + return self.fetch_eof_status() + + def cmd_quit(self): + """Close the current connection with the server""" + self.close() + + def cmd_shutdown(self, shutdown_type=None): + """Shut down the MySQL Server""" + if not self._cmysql: + raise errors.OperationalError("MySQL Connection not available") + + if shutdown_type: + if not ShutdownType.get_info(shutdown_type): + raise errors.InterfaceError("Invalid shutdown type") + level = shutdown_type + else: + level = ShutdownType.SHUTDOWN_DEFAULT + + try: + self._cmysql.shutdown(level) + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + self.close() + + def cmd_statistics(self): + """Return statistics from the MySQL server""" + self.handle_unread_result() + + try: + stat = self._cmysql.stat() + return MySQLProtocol().parse_statistics(stat, with_header=False) + except (MySQLInterfaceError, errors.InterfaceError) as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + def cmd_process_kill(self, mysql_pid): + """Kill a MySQL process""" + if not isinstance(mysql_pid, INT_TYPES): + raise ValueError("MySQL PID must be int") + self.info_query("KILL {0}".format(mysql_pid)) + + def handle_unread_result(self): + """Check whether there is an unread result""" + if self.can_consume_results: + self.consume_results() + elif self.unread_result: + raise errors.InternalError("Unread result found") diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/constants.py b/elitebot/lib/python3.11/site-packages/mysql/connector/constants.py new file mode 100644 index 0000000..8d27cb0 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/constants.py @@ -0,0 +1,754 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Various MySQL constants and character sets +""" + +from .errors import ProgrammingError +from .charsets import MYSQL_CHARACTER_SETS + +MAX_PACKET_LENGTH = 16777215 +NET_BUFFER_LENGTH = 8192 +MAX_MYSQL_TABLE_COLUMNS = 4096 + +DEFAULT_CONFIGURATION = { + 'database': None, + 'user': '', + 'password': '', + 'host': '127.0.0.1', + 'port': 3306, + 'unix_socket': None, + 'use_unicode': True, + 'charset': 'utf8', + 'collation': None, + 'converter_class': None, + 'autocommit': False, + 'time_zone': None, + 'sql_mode': None, + 'get_warnings': False, + 'raise_on_warnings': False, + 'connection_timeout': None, + 'client_flags': 0, + 'compress': False, + 'buffered': False, + 'raw': False, + 'ssl_ca': None, + 'ssl_cert': None, + 'ssl_key': None, + 'ssl_verify_cert': False, + 'ssl_cipher': None, + 'passwd': None, + 'db': None, + 'connect_timeout': None, + 'dsn': None, + 'force_ipv6': False, + 'auth_plugin': None, + 'allow_local_infile': True, + 'consume_results': False, +} + +CNX_POOL_ARGS = ('pool_name', 'pool_size', 'pool_reset_session') +CNX_FABRIC_ARGS = ['fabric_host', 'fabric_username', 'fabric_password', + 'fabric_port', 'fabric_connect_attempts', + 'fabric_connect_delay', 'fabric_report_errors', + 'fabric_ssl_ca', 'fabric_ssl_key', 'fabric_ssl_cert', + 'fabric_user'] + +def flag_is_set(flag, flags): + """Checks if the flag is set + + Returns boolean""" + if (flags & flag) > 0: + return True + return False + + +class _Constants(object): + """ + Base class for constants + """ + prefix = '' + desc = {} + + def __new__(cls): + raise TypeError("Can not instanciate from %s" % cls.__name__) + + @classmethod + def get_desc(cls, name): + """Get description of given constant""" + try: + return cls.desc[name][1] + except: + return None + + @classmethod + def get_info(cls, num): + """Get information about given constant""" + for name, info in cls.desc.items(): + if info[0] == num: + return name + return None + + @classmethod + def get_full_info(cls): + """get full information about given constant""" + res = () + try: + res = ["%s : %s" % (k, v[1]) for k, v in cls.desc.items()] + except Exception as err: # pylint: disable=W0703 + res = ('No information found in constant class.%s' % err) + + return res + + +class _Flags(_Constants): + """Base class for classes describing flags + """ + + @classmethod + def get_bit_info(cls, value): + """Get the name of all bits set + + Returns a list of strings.""" + res = [] + for name, info in cls.desc.items(): + if value & info[0]: + res.append(name) + return res + + +class FieldType(_Constants): + """MySQL Field Types + """ + prefix = 'FIELD_TYPE_' + DECIMAL = 0x00 + TINY = 0x01 + SHORT = 0x02 + LONG = 0x03 + FLOAT = 0x04 + DOUBLE = 0x05 + NULL = 0x06 + TIMESTAMP = 0x07 + LONGLONG = 0x08 + INT24 = 0x09 + DATE = 0x0a + TIME = 0x0b + DATETIME = 0x0c + YEAR = 0x0d + NEWDATE = 0x0e + VARCHAR = 0x0f + BIT = 0x10 + NEWDECIMAL = 0xf6 + ENUM = 0xf7 + SET = 0xf8 + TINY_BLOB = 0xf9 + MEDIUM_BLOB = 0xfa + LONG_BLOB = 0xfb + BLOB = 0xfc + VAR_STRING = 0xfd + STRING = 0xfe + GEOMETRY = 0xff + + desc = { + 'DECIMAL': (0x00, 'DECIMAL'), + 'TINY': (0x01, 'TINY'), + 'SHORT': (0x02, 'SHORT'), + 'LONG': (0x03, 'LONG'), + 'FLOAT': (0x04, 'FLOAT'), + 'DOUBLE': (0x05, 'DOUBLE'), + 'NULL': (0x06, 'NULL'), + 'TIMESTAMP': (0x07, 'TIMESTAMP'), + 'LONGLONG': (0x08, 'LONGLONG'), + 'INT24': (0x09, 'INT24'), + 'DATE': (0x0a, 'DATE'), + 'TIME': (0x0b, 'TIME'), + 'DATETIME': (0x0c, 'DATETIME'), + 'YEAR': (0x0d, 'YEAR'), + 'NEWDATE': (0x0e, 'NEWDATE'), + 'VARCHAR': (0x0f, 'VARCHAR'), + 'BIT': (0x10, 'BIT'), + 'NEWDECIMAL': (0xf6, 'NEWDECIMAL'), + 'ENUM': (0xf7, 'ENUM'), + 'SET': (0xf8, 'SET'), + 'TINY_BLOB': (0xf9, 'TINY_BLOB'), + 'MEDIUM_BLOB': (0xfa, 'MEDIUM_BLOB'), + 'LONG_BLOB': (0xfb, 'LONG_BLOB'), + 'BLOB': (0xfc, 'BLOB'), + 'VAR_STRING': (0xfd, 'VAR_STRING'), + 'STRING': (0xfe, 'STRING'), + 'GEOMETRY': (0xff, 'GEOMETRY'), + } + + @classmethod + def get_string_types(cls): + """Get the list of all string types""" + return [ + cls.VARCHAR, + cls.ENUM, + cls.VAR_STRING, cls.STRING, + ] + + @classmethod + def get_binary_types(cls): + """Get the list of all binary types""" + return [ + cls.TINY_BLOB, cls.MEDIUM_BLOB, + cls.LONG_BLOB, cls.BLOB, + ] + + @classmethod + def get_number_types(cls): + """Get the list of all number types""" + return [ + cls.DECIMAL, cls.NEWDECIMAL, + cls.TINY, cls.SHORT, cls.LONG, + cls.FLOAT, cls.DOUBLE, + cls.LONGLONG, cls.INT24, + cls.BIT, + cls.YEAR, + ] + + @classmethod + def get_timestamp_types(cls): + """Get the list of all timestamp types""" + return [ + cls.DATETIME, cls.TIMESTAMP, + ] + + +class FieldFlag(_Flags): + """MySQL Field Flags + + Field flags as found in MySQL sources mysql-src/include/mysql_com.h + """ + _prefix = '' + NOT_NULL = 1 << 0 + PRI_KEY = 1 << 1 + UNIQUE_KEY = 1 << 2 + MULTIPLE_KEY = 1 << 3 + BLOB = 1 << 4 + UNSIGNED = 1 << 5 + ZEROFILL = 1 << 6 + BINARY = 1 << 7 + + ENUM = 1 << 8 + AUTO_INCREMENT = 1 << 9 + TIMESTAMP = 1 << 10 + SET = 1 << 11 + + NO_DEFAULT_VALUE = 1 << 12 + ON_UPDATE_NOW = 1 << 13 + NUM = 1 << 14 + PART_KEY = 1 << 15 + GROUP = 1 << 14 # SAME AS NUM !!!!!!!???? + UNIQUE = 1 << 16 + BINCMP = 1 << 17 + + GET_FIXED_FIELDS = 1 << 18 + FIELD_IN_PART_FUNC = 1 << 19 + FIELD_IN_ADD_INDEX = 1 << 20 + FIELD_IS_RENAMED = 1 << 21 + + desc = { + 'NOT_NULL': (1 << 0, "Field can't be NULL"), + 'PRI_KEY': (1 << 1, "Field is part of a primary key"), + 'UNIQUE_KEY': (1 << 2, "Field is part of a unique key"), + 'MULTIPLE_KEY': (1 << 3, "Field is part of a key"), + 'BLOB': (1 << 4, "Field is a blob"), + 'UNSIGNED': (1 << 5, "Field is unsigned"), + 'ZEROFILL': (1 << 6, "Field is zerofill"), + 'BINARY': (1 << 7, "Field is binary "), + 'ENUM': (1 << 8, "field is an enum"), + 'AUTO_INCREMENT': (1 << 9, "field is a autoincrement field"), + 'TIMESTAMP': (1 << 10, "Field is a timestamp"), + 'SET': (1 << 11, "field is a set"), + 'NO_DEFAULT_VALUE': (1 << 12, "Field doesn't have default value"), + 'ON_UPDATE_NOW': (1 << 13, "Field is set to NOW on UPDATE"), + 'NUM': (1 << 14, "Field is num (for clients)"), + + 'PART_KEY': (1 << 15, "Intern; Part of some key"), + 'GROUP': (1 << 14, "Intern: Group field"), # Same as NUM + 'UNIQUE': (1 << 16, "Intern: Used by sql_yacc"), + 'BINCMP': (1 << 17, "Intern: Used by sql_yacc"), + 'GET_FIXED_FIELDS': (1 << 18, "Used to get fields in item tree"), + 'FIELD_IN_PART_FUNC': (1 << 19, "Field part of partition func"), + 'FIELD_IN_ADD_INDEX': (1 << 20, "Intern: Field used in ADD INDEX"), + 'FIELD_IS_RENAMED': (1 << 21, "Intern: Field is being renamed"), + } + + +class ServerCmd(_Constants): + """MySQL Server Commands + """ + _prefix = 'COM_' + SLEEP = 0 + QUIT = 1 + INIT_DB = 2 + QUERY = 3 + FIELD_LIST = 4 + CREATE_DB = 5 + DROP_DB = 6 + REFRESH = 7 + SHUTDOWN = 8 + STATISTICS = 9 + PROCESS_INFO = 10 + CONNECT = 11 + PROCESS_KILL = 12 + DEBUG = 13 + PING = 14 + TIME = 15 + DELAYED_INSERT = 16 + CHANGE_USER = 17 + BINLOG_DUMP = 18 + TABLE_DUMP = 19 + CONNECT_OUT = 20 + REGISTER_SLAVE = 21 + STMT_PREPARE = 22 + STMT_EXECUTE = 23 + STMT_SEND_LONG_DATA = 24 + STMT_CLOSE = 25 + STMT_RESET = 26 + SET_OPTION = 27 + STMT_FETCH = 28 + DAEMON = 29 + BINLOG_DUMP_GTID = 30 + RESET_CONNECTION = 31 + + desc = { + 'SLEEP': (0, 'SLEEP'), + 'QUIT': (1, 'QUIT'), + 'INIT_DB': (2, 'INIT_DB'), + 'QUERY': (3, 'QUERY'), + 'FIELD_LIST': (4, 'FIELD_LIST'), + 'CREATE_DB': (5, 'CREATE_DB'), + 'DROP_DB': (6, 'DROP_DB'), + 'REFRESH': (7, 'REFRESH'), + 'SHUTDOWN': (8, 'SHUTDOWN'), + 'STATISTICS': (9, 'STATISTICS'), + 'PROCESS_INFO': (10, 'PROCESS_INFO'), + 'CONNECT': (11, 'CONNECT'), + 'PROCESS_KILL': (12, 'PROCESS_KILL'), + 'DEBUG': (13, 'DEBUG'), + 'PING': (14, 'PING'), + 'TIME': (15, 'TIME'), + 'DELAYED_INSERT': (16, 'DELAYED_INSERT'), + 'CHANGE_USER': (17, 'CHANGE_USER'), + 'BINLOG_DUMP': (18, 'BINLOG_DUMP'), + 'TABLE_DUMP': (19, 'TABLE_DUMP'), + 'CONNECT_OUT': (20, 'CONNECT_OUT'), + 'REGISTER_SLAVE': (21, 'REGISTER_SLAVE'), + 'STMT_PREPARE': (22, 'STMT_PREPARE'), + 'STMT_EXECUTE': (23, 'STMT_EXECUTE'), + 'STMT_SEND_LONG_DATA': (24, 'STMT_SEND_LONG_DATA'), + 'STMT_CLOSE': (25, 'STMT_CLOSE'), + 'STMT_RESET': (26, 'STMT_RESET'), + 'SET_OPTION': (27, 'SET_OPTION'), + 'STMT_FETCH': (28, 'STMT_FETCH'), + 'DAEMON': (29, 'DAEMON'), + 'BINLOG_DUMP_GTID': (30, 'BINLOG_DUMP_GTID'), + 'RESET_CONNECTION': (31, 'RESET_CONNECTION'), + } + + +class ClientFlag(_Flags): + """MySQL Client Flags + + Client options as found in the MySQL sources mysql-src/include/mysql_com.h + """ + LONG_PASSWD = 1 << 0 + FOUND_ROWS = 1 << 1 + LONG_FLAG = 1 << 2 + CONNECT_WITH_DB = 1 << 3 + NO_SCHEMA = 1 << 4 + COMPRESS = 1 << 5 + ODBC = 1 << 6 + LOCAL_FILES = 1 << 7 + IGNORE_SPACE = 1 << 8 + PROTOCOL_41 = 1 << 9 + INTERACTIVE = 1 << 10 + SSL = 1 << 11 + IGNORE_SIGPIPE = 1 << 12 + TRANSACTIONS = 1 << 13 + RESERVED = 1 << 14 + SECURE_CONNECTION = 1 << 15 + MULTI_STATEMENTS = 1 << 16 + MULTI_RESULTS = 1 << 17 + PS_MULTI_RESULTS = 1 << 18 + PLUGIN_AUTH = 1 << 19 + CONNECT_ARGS = 1 << 20 + PLUGIN_AUTH_LENENC_CLIENT_DATA = 1 << 21 + CAN_HANDLE_EXPIRED_PASSWORDS = 1 << 22 + SESION_TRACK = 1 << 23 + DEPRECATE_EOF = 1 << 24 + SSL_VERIFY_SERVER_CERT = 1 << 30 + REMEMBER_OPTIONS = 1 << 31 + + desc = { + 'LONG_PASSWD': (1 << 0, 'New more secure passwords'), + 'FOUND_ROWS': (1 << 1, 'Found instead of affected rows'), + 'LONG_FLAG': (1 << 2, 'Get all column flags'), + 'CONNECT_WITH_DB': (1 << 3, 'One can specify db on connect'), + 'NO_SCHEMA': (1 << 4, "Don't allow database.table.column"), + 'COMPRESS': (1 << 5, 'Can use compression protocol'), + 'ODBC': (1 << 6, 'ODBC client'), + 'LOCAL_FILES': (1 << 7, 'Can use LOAD DATA LOCAL'), + 'IGNORE_SPACE': (1 << 8, "Ignore spaces before ''"), + 'PROTOCOL_41': (1 << 9, 'New 4.1 protocol'), + 'INTERACTIVE': (1 << 10, 'This is an interactive client'), + 'SSL': (1 << 11, 'Switch to SSL after handshake'), + 'IGNORE_SIGPIPE': (1 << 12, 'IGNORE sigpipes'), + 'TRANSACTIONS': (1 << 13, 'Client knows about transactions'), + 'RESERVED': (1 << 14, 'Old flag for 4.1 protocol'), + 'SECURE_CONNECTION': (1 << 15, 'New 4.1 authentication'), + 'MULTI_STATEMENTS': (1 << 16, 'Enable/disable multi-stmt support'), + 'MULTI_RESULTS': (1 << 17, 'Enable/disable multi-results'), + 'PS_MULTI_RESULTS': (1 << 18, 'Multi-results in PS-protocol'), + 'PLUGIN_AUTH': (1 << 19, 'Client supports plugin authentication'), + 'CONNECT_ARGS': (1 << 20, 'Client supports connection attributes'), + 'PLUGIN_AUTH_LENENC_CLIENT_DATA': (1 << 21, + 'Enable authentication response packet to be larger than 255 bytes'), + 'CAN_HANDLE_EXPIRED_PASSWORDS': (1 << 22, "Don't close the connection for a connection with expired password"), + 'SESION_TRACK': (1 << 23, 'Capable of handling server state change information'), + 'DEPRECATE_EOF': (1 << 24, 'Client no longer needs EOF packet'), + 'SSL_VERIFY_SERVER_CERT': (1 << 30, ''), + 'REMEMBER_OPTIONS': (1 << 31, ''), + } + + default = [ + LONG_PASSWD, + LONG_FLAG, + CONNECT_WITH_DB, + PROTOCOL_41, + TRANSACTIONS, + SECURE_CONNECTION, + MULTI_STATEMENTS, + MULTI_RESULTS, + LOCAL_FILES, + ] + + @classmethod + def get_default(cls): + """Get the default client options set + + Returns a flag with all the default client options set""" + flags = 0 + for option in cls.default: + flags |= option + return flags + + +class ServerFlag(_Flags): + """MySQL Server Flags + + Server flags as found in the MySQL sources mysql-src/include/mysql_com.h + """ + _prefix = 'SERVER_' + STATUS_IN_TRANS = 1 << 0 + STATUS_AUTOCOMMIT = 1 << 1 + MORE_RESULTS_EXISTS = 1 << 3 + QUERY_NO_GOOD_INDEX_USED = 1 << 4 + QUERY_NO_INDEX_USED = 1 << 5 + STATUS_CURSOR_EXISTS = 1 << 6 + STATUS_LAST_ROW_SENT = 1 << 7 + STATUS_DB_DROPPED = 1 << 8 + STATUS_NO_BACKSLASH_ESCAPES = 1 << 9 + + desc = { + 'SERVER_STATUS_IN_TRANS': (1 << 0, + 'Transaction has started'), + 'SERVER_STATUS_AUTOCOMMIT': (1 << 1, + 'Server in auto_commit mode'), + 'SERVER_MORE_RESULTS_EXISTS': (1 << 3, + 'Multi query - ' + 'next query exists'), + 'SERVER_QUERY_NO_GOOD_INDEX_USED': (1 << 4, ''), + 'SERVER_QUERY_NO_INDEX_USED': (1 << 5, ''), + 'SERVER_STATUS_CURSOR_EXISTS': (1 << 6, ''), + 'SERVER_STATUS_LAST_ROW_SENT': (1 << 7, ''), + 'SERVER_STATUS_DB_DROPPED': (1 << 8, 'A database was dropped'), + 'SERVER_STATUS_NO_BACKSLASH_ESCAPES': (1 << 9, ''), + } + + +class RefreshOption(_Constants): + """MySQL Refresh command options + + Options used when sending the COM_REFRESH server command. + """ + _prefix = 'REFRESH_' + GRANT = 1 << 0 + LOG = 1 << 1 + TABLES = 1 << 2 + HOST = 1 << 3 + STATUS = 1 << 4 + THREADS = 1 << 5 + SLAVE = 1 << 6 + + desc = { + 'GRANT': (1 << 0, 'Refresh grant tables'), + 'LOG': (1 << 1, 'Start on new log file'), + 'TABLES': (1 << 2, 'close all tables'), + 'HOSTS': (1 << 3, 'Flush host cache'), + 'STATUS': (1 << 4, 'Flush status variables'), + 'THREADS': (1 << 5, 'Flush thread cache'), + 'SLAVE': (1 << 6, 'Reset master info and restart slave thread'), + } + + +class ShutdownType(_Constants): + """MySQL Shutdown types + + Shutdown types used by the COM_SHUTDOWN server command. + """ + _prefix = '' + SHUTDOWN_DEFAULT = 0 + SHUTDOWN_WAIT_CONNECTIONS = 1 + SHUTDOWN_WAIT_TRANSACTIONS = 2 + SHUTDOWN_WAIT_UPDATES = 8 + SHUTDOWN_WAIT_ALL_BUFFERS = 16 + SHUTDOWN_WAIT_CRITICAL_BUFFERS = 17 + KILL_QUERY = 254 + KILL_CONNECTION = 255 + + desc = { + 'SHUTDOWN_DEFAULT': ( + SHUTDOWN_DEFAULT, + "defaults to SHUTDOWN_WAIT_ALL_BUFFERS"), + 'SHUTDOWN_WAIT_CONNECTIONS': ( + SHUTDOWN_WAIT_CONNECTIONS, + "wait for existing connections to finish"), + 'SHUTDOWN_WAIT_TRANSACTIONS': ( + SHUTDOWN_WAIT_TRANSACTIONS, + "wait for existing trans to finish"), + 'SHUTDOWN_WAIT_UPDATES': ( + SHUTDOWN_WAIT_UPDATES, + "wait for existing updates to finish"), + 'SHUTDOWN_WAIT_ALL_BUFFERS': ( + SHUTDOWN_WAIT_ALL_BUFFERS, + "flush InnoDB and other storage engine buffers"), + 'SHUTDOWN_WAIT_CRITICAL_BUFFERS': ( + SHUTDOWN_WAIT_CRITICAL_BUFFERS, + "don't flush InnoDB buffers, " + "flush other storage engines' buffers"), + 'KILL_QUERY': ( + KILL_QUERY, + "(no description)"), + 'KILL_CONNECTION': ( + KILL_CONNECTION, + "(no description)"), + } + + +class CharacterSet(_Constants): + """MySQL supported character sets and collations + + List of character sets with their collations supported by MySQL. This + maps to the character set we get from the server within the handshake + packet. + + The list is hardcode so we avoid a database query when getting the + name of the used character set or collation. + """ + desc = MYSQL_CHARACTER_SETS + + # Multi-byte character sets which use 5c (backslash) in characters + slash_charsets = (1, 13, 28, 84, 87, 88) + + @classmethod + def get_info(cls, setid): + """Retrieves character set information as tuple using an ID + + Retrieves character set and collation information based on the + given MySQL ID. + + Raises ProgrammingError when character set is not supported. + + Returns a tuple. + """ + try: + return cls.desc[setid][0:2] + except IndexError: + raise ProgrammingError( + "Character set '{0}' unsupported".format(setid)) + + @classmethod + def get_desc(cls, setid): + """Retrieves character set information as string using an ID + + Retrieves character set and collation information based on the + given MySQL ID. + + Returns a tuple. + """ + try: + return "%s/%s" % cls.get_info(setid) + except: + raise + + @classmethod + def get_default_collation(cls, charset): + """Retrieves the default collation for given character set + + Raises ProgrammingError when character set is not supported. + + Returns list (collation, charset, index) + """ + if isinstance(charset, int): + try: + info = cls.desc[charset] + return info[1], info[0], charset + except: + ProgrammingError("Character set ID '%s' unsupported." % ( + charset)) + + for cid, info in enumerate(cls.desc): + if info is None: + continue + if info[0] == charset and info[2] is True: + return info[1], info[0], cid + + raise ProgrammingError("Character set '%s' unsupported." % (charset)) + + @classmethod + def get_charset_info(cls, charset=None, collation=None): + """Get character set information using charset name and/or collation + + Retrieves character set and collation information given character + set name and/or a collation name. + If charset is an integer, it will look up the character set based + on the MySQL's ID. + For example: + get_charset_info('utf8',None) + get_charset_info(collation='utf8_general_ci') + get_charset_info(47) + + Raises ProgrammingError when character set is not supported. + + Returns a tuple with (id, characterset name, collation) + """ + if isinstance(charset, int): + try: + info = cls.desc[charset] + return (charset, info[0], info[1]) + except IndexError: + ProgrammingError("Character set ID {0} unknown.".format( + charset)) + + if charset is not None and collation is None: + info = cls.get_default_collation(charset) + return (info[2], info[1], info[0]) + elif charset is None and collation is not None: + for cid, info in enumerate(cls.desc): + if info is None: + continue + if collation == info[1]: + return (cid, info[0], info[1]) + raise ProgrammingError("Collation '{0}' unknown.".format(collation)) + else: + for cid, info in enumerate(cls.desc): + if info is None: + continue + if info[0] == charset and info[1] == collation: + return (cid, info[0], info[1]) + raise ProgrammingError("Character set '{0}' unknown.".format( + charset)) + + @classmethod + def get_supported(cls): + """Retrieves a list with names of all supproted character sets + + Returns a tuple. + """ + res = [] + for info in cls.desc: + if info and info[0] not in res: + res.append(info[0]) + return tuple(res) + + +class SQLMode(_Constants): # pylint: disable=R0921 + """MySQL SQL Modes + + The numeric values of SQL Modes are not interesting, only the names + are used when setting the SQL_MODE system variable using the MySQL + SET command. + + See http://dev.mysql.com/doc/refman/5.6/en/server-sql-mode.html + """ + _prefix = 'MODE_' + REAL_AS_FLOAT = 'REAL_AS_FLOAT' + PIPES_AS_CONCAT = 'PIPES_AS_CONCAT' + ANSI_QUOTES = 'ANSI_QUOTES' + IGNORE_SPACE = 'IGNORE_SPACE' + NOT_USED = 'NOT_USED' + ONLY_FULL_GROUP_BY = 'ONLY_FULL_GROUP_BY' + NO_UNSIGNED_SUBTRACTION = 'NO_UNSIGNED_SUBTRACTION' + NO_DIR_IN_CREATE = 'NO_DIR_IN_CREATE' + POSTGRESQL = 'POSTGRESQL' + ORACLE = 'ORACLE' + MSSQL = 'MSSQL' + DB2 = 'DB2' + MAXDB = 'MAXDB' + NO_KEY_OPTIONS = 'NO_KEY_OPTIONS' + NO_TABLE_OPTIONS = 'NO_TABLE_OPTIONS' + NO_FIELD_OPTIONS = 'NO_FIELD_OPTIONS' + MYSQL323 = 'MYSQL323' + MYSQL40 = 'MYSQL40' + ANSI = 'ANSI' + NO_AUTO_VALUE_ON_ZERO = 'NO_AUTO_VALUE_ON_ZERO' + NO_BACKSLASH_ESCAPES = 'NO_BACKSLASH_ESCAPES' + STRICT_TRANS_TABLES = 'STRICT_TRANS_TABLES' + STRICT_ALL_TABLES = 'STRICT_ALL_TABLES' + NO_ZERO_IN_DATE = 'NO_ZERO_IN_DATE' + NO_ZERO_DATE = 'NO_ZERO_DATE' + INVALID_DATES = 'INVALID_DATES' + ERROR_FOR_DIVISION_BY_ZERO = 'ERROR_FOR_DIVISION_BY_ZERO' + TRADITIONAL = 'TRADITIONAL' + NO_AUTO_CREATE_USER = 'NO_AUTO_CREATE_USER' + HIGH_NOT_PRECEDENCE = 'HIGH_NOT_PRECEDENCE' + NO_ENGINE_SUBSTITUTION = 'NO_ENGINE_SUBSTITUTION' + PAD_CHAR_TO_FULL_LENGTH = 'PAD_CHAR_TO_FULL_LENGTH' + + @classmethod + def get_desc(cls, name): + raise NotImplementedError + + @classmethod + def get_info(cls, number): + raise NotImplementedError + + @classmethod + def get_full_info(cls): + """Returns a sequence of all available SQL Modes + + This class method returns a tuple containing all SQL Mode names. The + names will be alphabetically sorted. + + Returns a tuple. + """ + res = [] + for key in vars(cls).keys(): + if not key.startswith('_') \ + and not hasattr(getattr(cls, key), '__call__'): + res.append(key) + return tuple(sorted(res)) diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/conversion.py b/elitebot/lib/python3.11/site-packages/mysql/connector/conversion.py new file mode 100644 index 0000000..d94e9e9 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/conversion.py @@ -0,0 +1,586 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Converting MySQL and Python types +""" + +import datetime +import time +from decimal import Decimal + +from .constants import FieldType, FieldFlag, CharacterSet +from .catch23 import PY2, NUMERIC_TYPES, struct_unpack +from .custom_types import HexLiteral + + +class MySQLConverterBase(object): + """Base class for conversion classes + + All class dealing with converting to and from MySQL data types must + be a subclass of this class. + """ + + def __init__(self, charset='utf8', use_unicode=True): + self.python_types = None + self.mysql_types = None + self.charset = None + self.charset_id = 0 + self.use_unicode = None + self.set_charset(charset) + self.set_unicode(use_unicode) + self._cache_field_types = {} + + def set_charset(self, charset): + """Set character set""" + if charset == 'utf8mb4': + charset = 'utf8' + if charset is not None: + self.charset = charset + else: + # default to utf8 + self.charset = 'utf8' + self.charset_id = CharacterSet.get_charset_info(self.charset)[0] + + def set_unicode(self, value=True): + """Set whether to use Unicode""" + self.use_unicode = value + + def to_mysql(self, value): + """Convert Python data type to MySQL""" + type_name = value.__class__.__name__.lower() + try: + return getattr(self, "_{0}_to_mysql".format(type_name))(value) + except AttributeError: + return value + + def to_python(self, vtype, value): + """Convert MySQL data type to Python""" + + if (value == b'\x00' or value is None) and vtype[1] != FieldType.BIT: + # Don't go further when we hit a NULL value + return None + + if not self._cache_field_types: + self._cache_field_types = {} + for name, info in FieldType.desc.items(): + try: + self._cache_field_types[info[0]] = getattr( + self, '_{0}_to_python'.format(name)) + except AttributeError: + # We ignore field types which has no method + pass + + try: + return self._cache_field_types[vtype[1]](value, vtype) + except KeyError: + return value + + def escape(self, buf): + """Escape buffer for sending to MySQL""" + return buf + + def quote(self, buf): + """Quote buffer for sending to MySQL""" + return str(buf) + + +class MySQLConverter(MySQLConverterBase): + """Default conversion class for MySQL Connector/Python. + + o escape method: for escaping values send to MySQL + o quoting method: for quoting values send to MySQL in statements + o conversion mapping: maps Python and MySQL data types to + function for converting them. + + Whenever one needs to convert values differently, a converter_class + argument can be given while instantiating a new connection like + cnx.connect(converter_class=CustomMySQLConverterClass). + + """ + + def __init__(self, charset=None, use_unicode=True): + MySQLConverterBase.__init__(self, charset, use_unicode) + self._cache_field_types = {} + + def escape(self, value): + """ + Escapes special characters as they are expected to by when MySQL + receives them. + As found in MySQL source mysys/charset.c + + Returns the value if not a string, or the escaped string. + """ + if value is None: + return value + elif isinstance(value, NUMERIC_TYPES): + return value + if isinstance(value, (bytes, bytearray)): + value = value.replace(b'\\', b'\\\\') + value = value.replace(b'\n', b'\\n') + value = value.replace(b'\r', b'\\r') + value = value.replace(b'\047', b'\134\047') # single quotes + value = value.replace(b'\042', b'\134\042') # double quotes + value = value.replace(b'\032', b'\134\032') # for Win32 + else: + value = value.replace('\\', '\\\\') + value = value.replace('\n', '\\n') + value = value.replace('\r', '\\r') + value = value.replace('\047', '\134\047') # single quotes + value = value.replace('\042', '\134\042') # double quotes + value = value.replace('\032', '\134\032') # for Win32 + return value + + def quote(self, buf): + """ + Quote the parameters for commands. General rules: + o numbers are returns as bytes using ascii codec + o None is returned as bytearray(b'NULL') + o Everything else is single quoted '' + + Returns a bytearray object. + """ + if isinstance(buf, NUMERIC_TYPES): + if PY2: + if isinstance(buf, float): + return repr(buf) + else: + return str(buf) + else: + return str(buf).encode('ascii') + elif isinstance(buf, type(None)): + return bytearray(b"NULL") + else: + return bytearray(b"'" + buf + b"'") + + def to_mysql(self, value): + """Convert Python data type to MySQL""" + type_name = value.__class__.__name__.lower() + try: + return getattr(self, "_{0}_to_mysql".format(type_name))(value) + except AttributeError: + raise TypeError("Python '{0}' cannot be converted to a " + "MySQL type".format(type_name)) + + def to_python(self, vtype, value): + """Convert MySQL data type to Python""" + if value == 0 and vtype[1] != FieldType.BIT: # \x00 + # Don't go further when we hit a NULL value + return None + if value is None: + return None + + if not self._cache_field_types: + self._cache_field_types = {} + for name, info in FieldType.desc.items(): + try: + self._cache_field_types[info[0]] = getattr( + self, '_{0}_to_python'.format(name)) + except AttributeError: + # We ignore field types which has no method + pass + + try: + return self._cache_field_types[vtype[1]](value, vtype) + except KeyError: + # If one type is not defined, we just return the value as str + try: + return value.decode('utf-8') + except UnicodeDecodeError: + return value + except ValueError as err: + raise ValueError("%s (field %s)" % (err, vtype[0])) + except TypeError as err: + raise TypeError("%s (field %s)" % (err, vtype[0])) + except: + raise + + def _int_to_mysql(self, value): + """Convert value to int""" + return int(value) + + def _long_to_mysql(self, value): + """Convert value to int""" + return int(value) + + def _float_to_mysql(self, value): + """Convert value to float""" + return float(value) + + def _str_to_mysql(self, value): + """Convert value to string""" + if PY2: + return str(value) + return self._unicode_to_mysql(value) + + def _unicode_to_mysql(self, value): + """Convert unicode""" + charset = self.charset + charset_id = self.charset_id + if charset == 'binary': + charset = 'utf8' + charset_id = CharacterSet.get_charset_info(charset)[0] + encoded = value.encode(charset) + if charset_id in CharacterSet.slash_charsets: + if b'\x5c' in encoded: + return HexLiteral(value, charset) + return encoded + + def _bytes_to_mysql(self, value): + """Convert value to bytes""" + return value + + def _bytearray_to_mysql(self, value): + """Convert value to bytes""" + return bytes(value) + + def _bool_to_mysql(self, value): + """Convert value to boolean""" + if value: + return 1 + else: + return 0 + + def _nonetype_to_mysql(self, value): + """ + This would return what None would be in MySQL, but instead we + leave it None and return it right away. The actual conversion + from None to NULL happens in the quoting functionality. + + Return None. + """ + return None + + def _datetime_to_mysql(self, value): + """ + Converts a datetime instance to a string suitable for MySQL. + The returned string has format: %Y-%m-%d %H:%M:%S[.%f] + + If the instance isn't a datetime.datetime type, it return None. + + Returns a bytes. + """ + if value.microsecond: + fmt = '{0:d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}' + return fmt.format( + value.year, value.month, value.day, + value.hour, value.minute, value.second, + value.microsecond).encode('ascii') + + fmt = '{0:d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}' + return fmt.format( + value.year, value.month, value.day, + value.hour, value.minute, value.second).encode('ascii') + + def _date_to_mysql(self, value): + """ + Converts a date instance to a string suitable for MySQL. + The returned string has format: %Y-%m-%d + + If the instance isn't a datetime.date type, it return None. + + Returns a bytes. + """ + return '{0:d}-{1:02d}-{2:02d}'.format(value.year, value.month, + value.day).encode('ascii') + + def _time_to_mysql(self, value): + """ + Converts a time instance to a string suitable for MySQL. + The returned string has format: %H:%M:%S[.%f] + + If the instance isn't a datetime.time type, it return None. + + Returns a bytes. + """ + if value.microsecond: + return value.strftime('%H:%M:%S.%f').encode('ascii') + return value.strftime('%H:%M:%S').encode('ascii') + + def _struct_time_to_mysql(self, value): + """ + Converts a time.struct_time sequence to a string suitable + for MySQL. + The returned string has format: %Y-%m-%d %H:%M:%S + + Returns a bytes or None when not valid. + """ + return time.strftime('%Y-%m-%d %H:%M:%S', value).encode('ascii') + + def _timedelta_to_mysql(self, value): + """ + Converts a timedelta instance to a string suitable for MySQL. + The returned string has format: %H:%M:%S + + Returns a bytes. + """ + seconds = abs(value.days * 86400 + value.seconds) + + if value.microseconds: + fmt = '{0:02d}:{1:02d}:{2:02d}.{3:06d}' + if value.days < 0: + mcs = 1000000 - value.microseconds + seconds -= 1 + else: + mcs = value.microseconds + else: + fmt = '{0:02d}:{1:02d}:{2:02d}' + + if value.days < 0: + fmt = '-' + fmt + + (hours, remainder) = divmod(seconds, 3600) + (mins, secs) = divmod(remainder, 60) + + if value.microseconds: + result = fmt.format(hours, mins, secs, mcs) + else: + result = fmt.format(hours, mins, secs) + + if PY2: + return result + else: + return result.encode('ascii') + + def _decimal_to_mysql(self, value): + """ + Converts a decimal.Decimal instance to a string suitable for + MySQL. + + Returns a bytes or None when not valid. + """ + if isinstance(value, Decimal): + return str(value).encode('ascii') + + return None + + def row_to_python(self, row, fields): + """Convert a MySQL text result row to Python types + + The row argument is a sequence containing text result returned + by a MySQL server. Each value of the row is converted to the + using the field type information in the fields argument. + + Returns a tuple. + """ + i = 0 + result = [None]*len(fields) + + if not self._cache_field_types: + self._cache_field_types = {} + for name, info in FieldType.desc.items(): + try: + self._cache_field_types[info[0]] = getattr( + self, '_{0}_to_python'.format(name)) + except AttributeError: + # We ignore field types which has no method + pass + + for field in fields: + field_type = field[1] + + if (row[i] == 0 and field_type != FieldType.BIT) or row[i] is None: + # Don't convert NULL value + i += 1 + continue + + try: + result[i] = self._cache_field_types[field_type](row[i], field) + except KeyError: + # If one type is not defined, we just return the value as str + try: + result[i] = row[i].decode('utf-8') + except UnicodeDecodeError: + result[i] = row[i] + except (ValueError, TypeError) as err: + err.message = "{0} (field {1})".format(str(err), field[0]) + raise + + i += 1 + + return tuple(result) + + def _FLOAT_to_python(self, value, desc=None): # pylint: disable=C0103 + """ + Returns value as float type. + """ + return float(value) + + _DOUBLE_to_python = _FLOAT_to_python + + def _INT_to_python(self, value, desc=None): # pylint: disable=C0103 + """ + Returns value as int type. + """ + return int(value) + + _TINY_to_python = _INT_to_python + _SHORT_to_python = _INT_to_python + _INT24_to_python = _INT_to_python + _LONG_to_python = _INT_to_python + _LONGLONG_to_python = _INT_to_python + + def _DECIMAL_to_python(self, value, desc=None): # pylint: disable=C0103 + """ + Returns value as a decimal.Decimal. + """ + val = value.decode(self.charset) + return Decimal(val) + + _NEWDECIMAL_to_python = _DECIMAL_to_python + + def _str(self, value, desc=None): + """ + Returns value as str type. + """ + return str(value) + + def _BIT_to_python(self, value, dsc=None): # pylint: disable=C0103 + """Returns BIT columntype as integer""" + int_val = value + if len(int_val) < 8: + int_val = b'\x00' * (8 - len(int_val)) + int_val + return struct_unpack('>Q', int_val)[0] + + def _DATE_to_python(self, value, dsc=None): # pylint: disable=C0103 + """ + Returns DATE column type as datetime.date type. + """ + try: + parts = value.split(b'-') + return datetime.date(int(parts[0]), int(parts[1]), int(parts[2])) + except ValueError: + return None + + _NEWDATE_to_python = _DATE_to_python + + def _TIME_to_python(self, value, dsc=None): # pylint: disable=C0103 + """ + Returns TIME column type as datetime.time type. + """ + time_val = None + try: + (hms, mcs) = value.split(b'.') + mcs = int(mcs.ljust(6, b'0')) + except ValueError: + hms = value + mcs = 0 + try: + (hours, mins, secs) = [int(d) for d in hms.split(b':')] + if value[0] == 45 or value[0] == '-': # if PY3 or PY2 + mins, secs, mcs = -mins, -secs, -mcs + time_val = datetime.timedelta(hours=hours, minutes=mins, + seconds=secs, microseconds=mcs) + except ValueError: + raise ValueError( + "Could not convert {0} to python datetime.timedelta".format( + value)) + else: + return time_val + + def _DATETIME_to_python(self, value, dsc=None): # pylint: disable=C0103 + """ + Returns DATETIME column type as datetime.datetime type. + """ + datetime_val = None + try: + (date_, time_) = value.split(b' ') + if len(time_) > 8: + (hms, mcs) = time_.split(b'.') + mcs = int(mcs.ljust(6, b'0')) + else: + hms = time_ + mcs = 0 + dtval = [int(i) for i in date_.split(b'-')] + \ + [int(i) for i in hms.split(b':')] + [mcs, ] + datetime_val = datetime.datetime(*dtval) + except ValueError: + datetime_val = None + + return datetime_val + + _TIMESTAMP_to_python = _DATETIME_to_python + + def _YEAR_to_python(self, value, desc=None): # pylint: disable=C0103 + """Returns YEAR column type as integer""" + try: + year = int(value) + except ValueError: + raise ValueError("Failed converting YEAR to int (%s)" % value) + + return year + + def _SET_to_python(self, value, dsc=None): # pylint: disable=C0103 + """Returns SET column type as set + + Actually, MySQL protocol sees a SET as a string type field. So this + code isn't called directly, but used by STRING_to_python() method. + + Returns SET column type as a set. + """ + set_type = None + val = value.decode(self.charset) + if not val: + return set() + try: + set_type = set(val.split(',')) + except ValueError: + raise ValueError("Could not convert set %s to a sequence." % value) + return set_type + + def _STRING_to_python(self, value, dsc=None): # pylint: disable=C0103 + """ + Note that a SET is a string too, but using the FieldFlag we can see + whether we have to split it. + + Returns string typed columns as string type. + """ + if dsc is not None: + # Check if we deal with a SET + if dsc[7] & FieldFlag.SET: + return self._SET_to_python(value, dsc) + if dsc[7] & FieldFlag.BINARY: + return value + + if self.charset == 'binary': + return value + if isinstance(value, (bytes, bytearray)) and self.use_unicode: + return value.decode(self.charset) + + return value + + _VAR_STRING_to_python = _STRING_to_python + + def _BLOB_to_python(self, value, dsc=None): # pylint: disable=C0103 + """Convert BLOB data type to Python""" + if dsc is not None: + if dsc[7] & FieldFlag.BINARY: + if PY2: + return value + else: + return bytes(value) + + return self._STRING_to_python(value, dsc) + + _LONG_BLOB_to_python = _BLOB_to_python + _MEDIUM_BLOB_to_python = _BLOB_to_python + _TINY_BLOB_to_python = _BLOB_to_python diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/cursor.py b/elitebot/lib/python3.11/site-packages/mysql/connector/cursor.py new file mode 100644 index 0000000..02fa976 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/cursor.py @@ -0,0 +1,1368 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Cursor classes +""" + +from collections import namedtuple +import re +import weakref + +from . import errors +from .abstracts import MySQLCursorAbstract +from .catch23 import PY2 + +SQL_COMMENT = r"\/\*.*?\*\/" +RE_SQL_COMMENT = re.compile( + r'''({0})|(["'`][^"'`]*?({0})[^"'`]*?["'`])'''.format(SQL_COMMENT), + re.I | re.M | re.S) +RE_SQL_ON_DUPLICATE = re.compile( + r'''\s*ON\s+DUPLICATE\s+KEY(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$''', + re.I | re.M | re.S) +RE_SQL_INSERT_STMT = re.compile( + r"({0}|\s)*INSERT({0}|\s)*INTO.+VALUES.*".format(SQL_COMMENT), + re.I | re.M | re.S) +RE_SQL_INSERT_VALUES = re.compile(r'.*VALUES\s*(\(.*\)).*', re.I | re.M | re.S) +RE_PY_PARAM = re.compile(b'(%s)') +RE_PY_MAPPING_PARAM = re.compile( + br''' + % + \((?P[^)]+)\) + (?P[diouxXeEfFgGcrs%]) + ''', + re.X +) +RE_SQL_SPLIT_STMTS = re.compile( + b''';(?=(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$)''') +RE_SQL_FIND_PARAM = re.compile( + b'''%s(?=(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$)''') + +ERR_NO_RESULT_TO_FETCH = "No result set to fetch from" + + +class _ParamSubstitutor(object): + """ + Substitutes parameters into SQL statement. + """ + def __init__(self, params): + self.params = params + self.index = 0 + + def __call__(self, matchobj): + index = self.index + self.index += 1 + try: + return bytes(self.params[index]) + except IndexError: + raise errors.ProgrammingError( + "Not enough parameters for the SQL statement") + + @property + def remaining(self): + """Returns number of parameters remaining to be substituted""" + return len(self.params) - self.index + + +def _bytestr_format_dict(bytestr, value_dict): + """ + >>> _bytestr_format_dict(b'%(a)s', {b'a': b'foobar'}) + b'foobar + >>> _bytestr_format_dict(b'%%(a)s', {b'a': b'foobar'}) + b'%%(a)s' + >>> _bytestr_format_dict(b'%%%(a)s', {b'a': b'foobar'}) + b'%%foobar' + >>> _bytestr_format_dict(b'%(x)s %(y)s', + ... {b'x': b'x=%(y)s', b'y': b'y=%(x)s'}) + b'x=%(y)s y=%(x)s' + """ + def replace(matchobj): + value = None + groups = matchobj.groupdict() + if groups["conversion_type"] == b"%": + value = b"%" + if groups["conversion_type"] == b"s": + key = groups["mapping_key"].encode("utf-8") \ + if PY2 else groups["mapping_key"] + value = value_dict[key] + if value is None: + raise ValueError("Unsupported conversion_type: {0}" + "".format(groups["conversion_type"])) + return value.decode("utf-8") if PY2 else value + return RE_PY_MAPPING_PARAM.sub(replace, bytestr.decode("utf-8") + if PY2 else bytestr) + +class CursorBase(MySQLCursorAbstract): + """ + Base for defining MySQLCursor. This class is a skeleton and defines + methods and members as required for the Python Database API + Specification v2.0. + + It's better to inherite from MySQLCursor. + """ + + _raw = False + + def __init__(self): + self._description = None + self._rowcount = -1 + self._last_insert_id = None + self.arraysize = 1 + super(CursorBase, self).__init__() + + def callproc(self, procname, args=()): + """Calls a stored procedue with the given arguments + + The arguments will be set during this session, meaning + they will be called like ___arg where + is an enumeration (+1) of the arguments. + + Coding Example: + 1) Definining the Stored Routine in MySQL: + CREATE PROCEDURE multiply(IN pFac1 INT, IN pFac2 INT, OUT pProd INT) + BEGIN + SET pProd := pFac1 * pFac2; + END + + 2) Executing in Python: + args = (5,5,0) # 0 is to hold pprod + cursor.callproc('multiply', args) + print(cursor.fetchone()) + + Does not return a value, but a result set will be + available when the CALL-statement execute successfully. + Raises exceptions when something is wrong. + """ + pass + + def close(self): + """Close the cursor.""" + pass + + def execute(self, operation, params=(), multi=False): + """Executes the given operation + + Executes the given operation substituting any markers with + the given parameters. + + For example, getting all rows where id is 5: + cursor.execute("SELECT * FROM t1 WHERE id = %s", (5,)) + + The multi argument should be set to True when executing multiple + statements in one operation. If not set and multiple results are + found, an InterfaceError will be raised. + + If warnings where generated, and connection.get_warnings is True, then + self._warnings will be a list containing these warnings. + + Returns an iterator when multi is True, otherwise None. + """ + pass + + def executemany(self, operation, seqparams): + """Execute the given operation multiple times + + The executemany() method will execute the operation iterating + over the list of parameters in seq_params. + + Example: Inserting 3 new employees and their phone number + + data = [ + ('Jane','555-001'), + ('Joe', '555-001'), + ('John', '555-003') + ] + stmt = "INSERT INTO employees (name, phone) VALUES ('%s','%s')" + cursor.executemany(stmt, data) + + INSERT statements are optimized by batching the data, that is + using the MySQL multiple rows syntax. + + Results are discarded. If they are needed, consider looping over + data using the execute() method. + """ + pass + + def fetchone(self): + """Returns next row of a query result set + + Returns a tuple or None. + """ + pass + + def fetchmany(self, size=1): + """Returns the next set of rows of a query result, returning a + list of tuples. When no more rows are available, it returns an + empty list. + + The number of rows returned can be specified using the size argument, + which defaults to one + """ + pass + + def fetchall(self): + """Returns all rows of a query result set + + Returns a list of tuples. + """ + pass + + def nextset(self): + """Not Implemented.""" + pass + + def setinputsizes(self, sizes): + """Not Implemented.""" + pass + + def setoutputsize(self, size, column=None): + """Not Implemented.""" + pass + + def reset(self, free=True): + """Reset the cursor to default""" + pass + + @property + def description(self): + """Returns description of columns in a result + + This property returns a list of tuples describing the columns in + in a result set. A tuple is described as follows:: + + (column_name, + type, + None, + None, + None, + None, + null_ok, + column_flags) # Addition to PEP-249 specs + + Returns a list of tuples. + """ + return self._description + + @property + def rowcount(self): + """Returns the number of rows produced or affected + + This property returns the number of rows produced by queries + such as a SELECT, or affected rows when executing DML statements + like INSERT or UPDATE. + + Note that for non-buffered cursors it is impossible to know the + number of rows produced before having fetched them all. For those, + the number of rows will be -1 right after execution, and + incremented when fetching rows. + + Returns an integer. + """ + return self._rowcount + + @property + def lastrowid(self): + """Returns the value generated for an AUTO_INCREMENT column + + Returns the value generated for an AUTO_INCREMENT column by + the previous INSERT or UPDATE statement or None when there is + no such value available. + + Returns a long value or None. + """ + return self._last_insert_id + + +class MySQLCursor(CursorBase): + """Default cursor for interacting with MySQL + + This cursor will execute statements and handle the result. It will + not automatically fetch all rows. + + MySQLCursor should be inherited whenever other functionallity is + required. An example would to change the fetch* member functions + to return dictionaries instead of lists of values. + + Implements the Python Database API Specification v2.0 (PEP-249) + """ + def __init__(self, connection=None): + CursorBase.__init__(self) + self._connection = None + self._stored_results = [] + self._nextrow = (None, None) + self._warnings = None + self._warning_count = 0 + self._executed = None + self._executed_list = [] + self._binary = False + + if connection is not None: + self._set_connection(connection) + + def __iter__(self): + """ + Iteration over the result set which calls self.fetchone() + and returns the next row. + """ + return iter(self.fetchone, None) + + def _set_connection(self, connection): + """Set the connection""" + try: + self._connection = weakref.proxy(connection) + self._connection.is_connected() + except (AttributeError, TypeError): + raise errors.InterfaceError(errno=2048) + + def _reset_result(self): + """Reset the cursor to default""" + self._rowcount = -1 + self._nextrow = (None, None) + self._stored_results = [] + self._warnings = None + self._warning_count = 0 + self._description = None + self._executed = None + self._executed_list = [] + self.reset() + + def _have_unread_result(self): + """Check whether there is an unread result""" + try: + return self._connection.unread_result + except AttributeError: + return False + + def next(self): + """Used for iterating over the result set.""" + return self.__next__() + + def __next__(self): + """ + Used for iterating over the result set. Calles self.fetchone() + to get the next row. + """ + try: + row = self.fetchone() + except errors.InterfaceError: + raise StopIteration + if not row: + raise StopIteration + return row + + def close(self): + """Close the cursor + + Returns True when successful, otherwise False. + """ + if self._connection is None: + return False + + self._connection.handle_unread_result() + self._reset_result() + self._connection = None + + return True + + def _process_params_dict(self, params): + """Process query parameters given as dictionary""" + try: + to_mysql = self._connection.converter.to_mysql + escape = self._connection.converter.escape + quote = self._connection.converter.quote + res = {} + for key, value in list(params.items()): + conv = value + conv = to_mysql(conv) + conv = escape(conv) + conv = quote(conv) + if PY2: + res[key] = conv + else: + res[key.encode()] = conv + except Exception as err: + raise errors.ProgrammingError( + "Failed processing pyformat-parameters; %s" % err) + else: + return res + + def _process_params(self, params): + """Process query parameters.""" + try: + res = params + + to_mysql = self._connection.converter.to_mysql + escape = self._connection.converter.escape + quote = self._connection.converter.quote + + res = [to_mysql(i) for i in res] + res = [escape(i) for i in res] + res = [quote(i) for i in res] + except Exception as err: + raise errors.ProgrammingError( + "Failed processing format-parameters; %s" % err) + else: + return tuple(res) + + def _handle_noresultset(self, res): + """Handles result of execute() when there is no result set + """ + try: + self._rowcount = res['affected_rows'] + self._last_insert_id = res['insert_id'] + self._warning_count = res['warning_count'] + except (KeyError, TypeError) as err: + raise errors.ProgrammingError( + "Failed handling non-resultset; {0}".format(err)) + + self._handle_warnings() + if self._connection.raise_on_warnings is True and self._warnings: + raise errors.get_mysql_exception( + self._warnings[0][1], self._warnings[0][2]) + + def _handle_resultset(self): + """Handles result set + + This method handles the result set and is called after reading + and storing column information in _handle_result(). For non-buffering + cursors, this method is usually doing nothing. + """ + pass + + def _handle_result(self, result): + """ + Handle the result after a command was send. The result can be either + an OK-packet or a dictionary containing column/eof information. + + Raises InterfaceError when result is not a dict() or result is + invalid. + """ + if not isinstance(result, dict): + raise errors.InterfaceError('Result was not a dict()') + + if 'columns' in result: + # Weak test, must be column/eof information + self._description = result['columns'] + self._connection.unread_result = True + self._handle_resultset() + elif 'affected_rows' in result: + # Weak test, must be an OK-packet + self._connection.unread_result = False + self._handle_noresultset(result) + else: + raise errors.InterfaceError('Invalid result') + + def _execute_iter(self, query_iter): + """Generator returns MySQLCursor objects for multiple statements + + This method is only used when multiple statements are executed + by the execute() method. It uses zip() to make an iterator from the + given query_iter (result of MySQLConnection.cmd_query_iter()) and + the list of statements that were executed. + """ + executed_list = RE_SQL_SPLIT_STMTS.split(self._executed) + + i = 0 + while True: + result = next(query_iter) + self._reset_result() + self._handle_result(result) + try: + self._executed = executed_list[i].strip() + i += 1 + except IndexError: + self._executed = executed_list[0] + + yield self + + def execute(self, operation, params=None, multi=False): + """Executes the given operation + + Executes the given operation substituting any markers with + the given parameters. + + For example, getting all rows where id is 5: + cursor.execute("SELECT * FROM t1 WHERE id = %s", (5,)) + + The multi argument should be set to True when executing multiple + statements in one operation. If not set and multiple results are + found, an InterfaceError will be raised. + + If warnings where generated, and connection.get_warnings is True, then + self._warnings will be a list containing these warnings. + + Returns an iterator when multi is True, otherwise None. + """ + if not operation: + return None + + if not self._connection: + raise errors.ProgrammingError("Cursor is not connected") + + self._connection.handle_unread_result() + + self._reset_result() + stmt = '' + + try: + if not isinstance(operation, (bytes, bytearray)): + stmt = operation.encode(self._connection.python_charset) + else: + stmt = operation + except (UnicodeDecodeError, UnicodeEncodeError) as err: + raise errors.ProgrammingError(str(err)) + + if params is not None: + if isinstance(params, dict): + stmt = _bytestr_format_dict( + stmt, self._process_params_dict(params)) + elif isinstance(params, (list, tuple)): + psub = _ParamSubstitutor(self._process_params(params)) + stmt = RE_PY_PARAM.sub(psub, stmt) + if psub.remaining != 0: + raise errors.ProgrammingError( + "Not all parameters were used in the SQL statement") + + self._executed = stmt + if multi: + self._executed_list = [] + return self._execute_iter(self._connection.cmd_query_iter(stmt)) + else: + try: + self._handle_result(self._connection.cmd_query(stmt)) + except errors.InterfaceError: + if self._connection._have_next_result: # pylint: disable=W0212 + raise errors.InterfaceError( + "Use multi=True when executing multiple statements") + raise + return None + + def _batch_insert(self, operation, seq_params): + """Implements multi row insert""" + def remove_comments(match): + """Remove comments from INSERT statements. + + This function is used while removing comments from INSERT + statements. If the matched string is a comment not enclosed + by quotes, it returns an empty string, else the string itself. + """ + if match.group(1): + return "" + else: + return match.group(2) + + tmp = re.sub(RE_SQL_ON_DUPLICATE, '', + re.sub(RE_SQL_COMMENT, remove_comments, operation)) + + matches = re.search(RE_SQL_INSERT_VALUES, tmp) + if not matches: + raise errors.InterfaceError( + "Failed rewriting statement for multi-row INSERT. " + "Check SQL syntax." + ) + fmt = matches.group(1).encode(self._connection.charset) + values = [] + + try: + stmt = operation.encode(self._connection.charset) + for params in seq_params: + tmp = fmt + if isinstance(params, dict): + tmp = _bytestr_format_dict( + tmp, self._process_params_dict(params)) + else: + psub = _ParamSubstitutor(self._process_params(params)) + tmp = RE_PY_PARAM.sub(psub, tmp) + if psub.remaining != 0: + raise errors.ProgrammingError( + "Not all parameters were used in the SQL statement") + #for p in self._process_params(params): + # tmp = tmp.replace(b'%s',p,1) + values.append(tmp) + if fmt in stmt: + stmt = stmt.replace(fmt, b','.join(values), 1) + self._executed = stmt + return stmt + else: + return None + except (UnicodeDecodeError, UnicodeEncodeError) as err: + raise errors.ProgrammingError(str(err)) + except errors.Error: + raise + except Exception as err: + raise errors.InterfaceError( + "Failed executing the operation; %s" % err) + + def executemany(self, operation, seq_params): + """Execute the given operation multiple times + + The executemany() method will execute the operation iterating + over the list of parameters in seq_params. + + Example: Inserting 3 new employees and their phone number + + data = [ + ('Jane','555-001'), + ('Joe', '555-001'), + ('John', '555-003') + ] + stmt = "INSERT INTO employees (name, phone) VALUES ('%s','%s)" + cursor.executemany(stmt, data) + + INSERT statements are optimized by batching the data, that is + using the MySQL multiple rows syntax. + + Results are discarded. If they are needed, consider looping over + data using the execute() method. + """ + if not operation or not seq_params: + return None + self._connection.handle_unread_result() + + try: + _ = iter(seq_params) + except TypeError: + raise errors.ProgrammingError( + "Parameters for query must be an Iterable.") + + # Optimize INSERTs by batching them + if re.match(RE_SQL_INSERT_STMT, operation): + if not seq_params: + self._rowcount = 0 + return + stmt = self._batch_insert(operation, seq_params) + if stmt is not None: + return self.execute(stmt) + + rowcnt = 0 + try: + for params in seq_params: + self.execute(operation, params) + if self.with_rows and self._have_unread_result(): + self.fetchall() + rowcnt += self._rowcount + except (ValueError, TypeError) as err: + raise errors.InterfaceError( + "Failed executing the operation; {0}".format(err)) + except: + # Raise whatever execute() raises + raise + self._rowcount = rowcnt + + def stored_results(self): + """Returns an iterator for stored results + + This method returns an iterator over results which are stored when + callproc() is called. The iterator will provide MySQLCursorBuffered + instances. + + Returns a iterator. + """ + return iter(self._stored_results) + + def callproc(self, procname, args=()): + """Calls a stored procedure with the given arguments + + The arguments will be set during this session, meaning + they will be called like ___arg where + is an enumeration (+1) of the arguments. + + Coding Example: + 1) Defining the Stored Routine in MySQL: + CREATE PROCEDURE multiply(IN pFac1 INT, IN pFac2 INT, OUT pProd INT) + BEGIN + SET pProd := pFac1 * pFac2; + END + + 2) Executing in Python: + args = (5, 5, 0) # 0 is to hold pprod + cursor.callproc('multiply', args) + print(cursor.fetchone()) + + For OUT and INOUT parameters the user should provide the + type of the parameter as well. The argument should be a + tuple with first item as the value of the parameter to pass + and second argument the type of the argument. + + In the above example, one can call callproc method like: + args = (5, 5, (0, 'INT')) + cursor.callproc('multiply', args) + + The type of the argument given in the tuple will be used by + the MySQL CAST function to convert the values in the corresponding + MySQL type (See CAST in MySQL Reference for more information) + + Does not return a value, but a result set will be + available when the CALL-statement execute successfully. + Raises exceptions when something is wrong. + """ + if not procname or not isinstance(procname, str): + raise ValueError("procname must be a string") + + if not isinstance(args, (tuple, list)): + raise ValueError("args must be a sequence") + + argfmt = "@_{name}_arg{index}" + self._stored_results = [] + + results = [] + try: + argnames = [] + argtypes = [] + if args: + for idx, arg in enumerate(args): + argname = argfmt.format(name=procname, index=idx + 1) + argnames.append(argname) + if isinstance(arg, tuple): + argtypes.append(" CAST({0} AS {1})".format(argname, + arg[1])) + self.execute("SET {0}=%s".format(argname), (arg[0],)) + else: + argtypes.append(argname) + self.execute("SET {0}=%s".format(argname), (arg,)) + + call = "CALL {0}({1})".format(procname, ','.join(argnames)) + + # pylint: disable=W0212 + # We disable consuming results temporary to make sure we + # getting all results + can_consume_results = self._connection._consume_results + for result in self._connection.cmd_query_iter(call): + self._connection._consume_results = False + if self._raw: + tmp = MySQLCursorBufferedRaw(self._connection._get_self()) + else: + tmp = MySQLCursorBuffered(self._connection._get_self()) + tmp._executed = "(a result of {0})".format(call) + tmp._handle_result(result) + if tmp._warnings is not None: + self._warnings = tmp._warnings + if 'columns' in result: + results.append(tmp) + self._connection._consume_results = can_consume_results + #pylint: enable=W0212 + + if argnames: + select = "SELECT {0}".format(','.join(argtypes)) + self.execute(select) + self._stored_results = results + return self.fetchone() + else: + self._stored_results = results + return () + + except errors.Error: + raise + except Exception as err: + raise errors.InterfaceError( + "Failed calling stored routine; {0}".format(err)) + + def getlastrowid(self): + """Returns the value generated for an AUTO_INCREMENT column + + Returns the value generated for an AUTO_INCREMENT column by + the previous INSERT or UPDATE statement. + + Returns a long value or None. + """ + return self._last_insert_id + + def _fetch_warnings(self): + """ + Fetch warnings doing a SHOW WARNINGS. Can be called after getting + the result. + + Returns a result set or None when there were no warnings. + """ + res = [] + try: + cur = self._connection.cursor(raw=False) + cur.execute("SHOW WARNINGS") + res = cur.fetchall() + cur.close() + except Exception as err: + raise errors.InterfaceError( + "Failed getting warnings; %s" % err) + + if len(res): + return res + + return None + + def _handle_warnings(self): + """Handle possible warnings after all results are consumed""" + if self._connection.get_warnings is True and self._warning_count: + self._warnings = self._fetch_warnings() + + def _handle_eof(self, eof): + """Handle EOF packet""" + self._connection.unread_result = False + self._nextrow = (None, None) + self._warning_count = eof['warning_count'] + self._handle_warnings() + if self._connection.raise_on_warnings is True and self._warnings: + raise errors.get_mysql_exception( + self._warnings[0][1], self._warnings[0][2]) + + def _fetch_row(self): + """Returns the next row in the result set + + Returns a tuple or None. + """ + if not self._have_unread_result(): + return None + row = None + + if self._nextrow == (None, None): + (row, eof) = self._connection.get_row( + binary=self._binary, columns=self.description) + else: + (row, eof) = self._nextrow + + if row: + self._nextrow = self._connection.get_row( + binary=self._binary, columns=self.description) + eof = self._nextrow[1] + if eof is not None: + self._handle_eof(eof) + if self._rowcount == -1: + self._rowcount = 1 + else: + self._rowcount += 1 + if eof: + self._handle_eof(eof) + + return row + + def fetchone(self): + """Returns next row of a query result set + + Returns a tuple or None. + """ + row = self._fetch_row() + if row: + if hasattr(self._connection, 'converter'): + return self._connection.converter.row_to_python( + row, self.description) + return row + return None + + def fetchmany(self, size=None): + res = [] + cnt = (size or self.arraysize) + while cnt > 0 and self._have_unread_result(): + cnt -= 1 + row = self.fetchone() + if row: + res.append(row) + return res + + def fetchall(self): + if not self._have_unread_result(): + raise errors.InterfaceError("No result set to fetch from.") + (rows, eof) = self._connection.get_rows() + if self._nextrow[0]: + rows.insert(0, self._nextrow[0]) + + if hasattr(self._connection, 'converter'): + row_to_python = self._connection.converter.row_to_python + rows = [row_to_python(row, self.description) for row in rows] + + self._handle_eof(eof) + rowcount = len(rows) + if rowcount >= 0 and self._rowcount == -1: + self._rowcount = 0 + self._rowcount += rowcount + return rows + + @property + def column_names(self): + """Returns column names + + This property returns the columns names as a tuple. + + Returns a tuple. + """ + if not self.description: + return () + return tuple([d[0] for d in self.description]) + + @property + def statement(self): + """Returns the executed statement + + This property returns the executed statement. When multiple + statements were executed, the current statement in the iterator + will be returned. + """ + if self._executed is None: + return None + try: + return self._executed.strip().decode('utf-8') + except (AttributeError, UnicodeDecodeError): + return self._executed.strip() + + @property + def with_rows(self): + """Returns whether the cursor could have rows returned + + This property returns True when column descriptions are available + and possibly also rows, which will need to be fetched. + + Returns True or False. + """ + if not self.description: + return False + return True + + def __str__(self): + fmt = "{class_name}: {stmt}" + if self._executed: + try: + executed = self._executed.decode('utf-8') + except AttributeError: + executed = self._executed + if len(executed) > 40: + executed = executed[:40] + '..' + else: + executed = '(Nothing executed yet)' + return fmt.format(class_name=self.__class__.__name__, stmt=executed) + + +class MySQLCursorBuffered(MySQLCursor): + """Cursor which fetches rows within execute()""" + + def __init__(self, connection=None): + MySQLCursor.__init__(self, connection) + self._rows = None + self._next_row = 0 + + def _handle_resultset(self): + (self._rows, eof) = self._connection.get_rows() + self._rowcount = len(self._rows) + self._handle_eof(eof) + self._next_row = 0 + try: + self._connection.unread_result = False + except: + pass + + def reset(self, free=True): + self._rows = None + + def _fetch_row(self): + row = None + try: + row = self._rows[self._next_row] + except: + return None + else: + self._next_row += 1 + return row + return None + + def fetchall(self): + if self._rows is None: + raise errors.InterfaceError("No result set to fetch from.") + res = [] + if hasattr(self._connection, 'converter'): + for row in self._rows[self._next_row:]: + res.append(self._connection.converter.row_to_python( + row, self.description)) + else: + res = self._rows[self._next_row:] + self._next_row = len(self._rows) + return res + + def fetchmany(self, size=None): + res = [] + cnt = (size or self.arraysize) + while cnt > 0: + cnt -= 1 + row = self.fetchone() + if row: + res.append(row) + + return res + + @property + def with_rows(self): + return self._rows is not None + + +class MySQLCursorRaw(MySQLCursor): + """ + Skips conversion from MySQL datatypes to Python types when fetching rows. + """ + + _raw = True + + def fetchone(self): + row = self._fetch_row() + if row: + return row + return None + + def fetchall(self): + if not self._have_unread_result(): + raise errors.InterfaceError("No result set to fetch from.") + (rows, eof) = self._connection.get_rows() + if self._nextrow[0]: + rows.insert(0, self._nextrow[0]) + self._handle_eof(eof) + rowcount = len(rows) + if rowcount >= 0 and self._rowcount == -1: + self._rowcount = 0 + self._rowcount += rowcount + return rows + + +class MySQLCursorBufferedRaw(MySQLCursorBuffered): + """ + Cursor which skips conversion from MySQL datatypes to Python types when + fetching rows and fetches rows within execute(). + """ + + _raw = True + + def fetchone(self): + row = self._fetch_row() + if row: + return row + return None + + def fetchall(self): + if self._rows is None: + raise errors.InterfaceError("No result set to fetch from.") + return [r for r in self._rows[self._next_row:]] + + @property + def with_rows(self): + return self._rows is not None + + +class MySQLCursorPrepared(MySQLCursor): + """Cursor using MySQL Prepared Statements + """ + def __init__(self, connection=None): + super(MySQLCursorPrepared, self).__init__(connection) + self._rows = None + self._next_row = 0 + self._prepared = None + self._binary = True + self._have_result = None + + def callproc(self, *args, **kwargs): + """Calls a stored procedue + + Not supported with MySQLCursorPrepared. + """ + raise errors.NotSupportedError() + + def close(self): + """Close the cursor + + This method will try to deallocate the prepared statement and close + the cursor. + """ + if self._prepared: + try: + self._connection.cmd_stmt_close(self._prepared['statement_id']) + except errors.Error: + # We tried to deallocate, but it's OK when we fail. + pass + self._prepared = None + super(MySQLCursorPrepared, self).close() + + def _row_to_python(self, rowdata, desc=None): + """Convert row data from MySQL to Python types + + The conversion is done while reading binary data in the + protocol module. + """ + pass + + def _handle_result(self, res): + """Handle result after execution""" + if isinstance(res, dict): + self._connection.unread_result = False + self._have_result = False + self._handle_noresultset(res) + else: + self._description = res[1] + self._connection.unread_result = True + self._have_result = True + + def execute(self, operation, params=(), multi=False): # multi is unused + """Prepare and execute a MySQL Prepared Statement + + This method will preare the given operation and execute it using + the optionally given parameters. + + If the cursor instance already had a prepared statement, it is + first closed. + """ + if operation is not self._executed: + if self._prepared: + self._connection.cmd_stmt_close(self._prepared['statement_id']) + + self._executed = operation + try: + if not isinstance(operation, bytes): + operation = operation.encode(self._connection.charset) + except (UnicodeDecodeError, UnicodeEncodeError) as err: + raise errors.ProgrammingError(str(err)) + + # need to convert %s to ? before sending it to MySQL + if b'%s' in operation: + operation = re.sub(RE_SQL_FIND_PARAM, b'?', operation) + + try: + self._prepared = self._connection.cmd_stmt_prepare(operation) + except errors.Error: + self._executed = None + raise + + self._connection.cmd_stmt_reset(self._prepared['statement_id']) + + if self._prepared['parameters'] and not params: + return + elif len(self._prepared['parameters']) != len(params): + raise errors.ProgrammingError( + errno=1210, + msg="Incorrect number of arguments " \ + "executing prepared statement") + + res = self._connection.cmd_stmt_execute( + self._prepared['statement_id'], + data=params, + parameters=self._prepared['parameters']) + self._handle_result(res) + + def executemany(self, operation, seq_params): + """Prepare and execute a MySQL Prepared Statement many times + + This method will prepare the given operation and execute with each + tuple found the list seq_params. + + If the cursor instance already had a prepared statement, it is + first closed. + + executemany() simply calls execute(). + """ + rowcnt = 0 + try: + for params in seq_params: + self.execute(operation, params) + if self.with_rows and self._have_unread_result(): + self.fetchall() + rowcnt += self._rowcount + except (ValueError, TypeError) as err: + raise errors.InterfaceError( + "Failed executing the operation; {error}".format(error=err)) + except: + # Raise whatever execute() raises + raise + self._rowcount = rowcnt + + def fetchone(self): + """Returns next row of a query result set + + Returns a tuple or None. + """ + return self._fetch_row() or None + + def fetchmany(self, size=None): + res = [] + cnt = (size or self.arraysize) + while cnt > 0 and self._have_unread_result(): + cnt -= 1 + row = self._fetch_row() + if row: + res.append(row) + return res + + def fetchall(self): + if not self._have_unread_result(): + raise errors.InterfaceError("No result set to fetch from.") + (rows, eof) = self._connection.get_rows( + binary=self._binary, columns=self.description) + self._rowcount = len(rows) + self._handle_eof(eof) + return rows + + +class MySQLCursorDict(MySQLCursor): + """ + Cursor fetching rows as dictionaries. + + The fetch methods of this class will return dictionaries instead of tuples. + Each row is a dictionary that looks like: + row = { + "col1": value1, + "col2": value2 + } + """ + def _row_to_python(self, rowdata, desc=None): + """Convert a MySQL text result row to Python types + + Returns a dictionary. + """ + if hasattr(self._connection, 'converter'): + row = self._connection.converter.row_to_python(rowdata, desc) + else: + row = rowdata + + if row: + return dict(zip(self.column_names, row)) + + return None + + def fetchone(self): + """Returns next row of a query result set + """ + row = self._fetch_row() + if row: + return self._row_to_python(row, self.description) + return None + + def fetchall(self): + """Returns all rows of a query result set + """ + if not self._have_unread_result(): + raise errors.InterfaceError(ERR_NO_RESULT_TO_FETCH) + (rows, eof) = self._connection.get_rows() + if self._nextrow[0]: + rows.insert(0, self._nextrow[0]) + res = [self._row_to_python(row, self.description) + for row in rows] + self._handle_eof(eof) + rowcount = len(rows) + if rowcount >= 0 and self._rowcount == -1: + self._rowcount = 0 + self._rowcount += rowcount + return res + + +class MySQLCursorNamedTuple(MySQLCursor): + """ + Cursor fetching rows as named tuple. + + The fetch methods of this class will return namedtuples instead of tuples. + Each row is returned as a namedtuple and the values can be accessed as: + row.col1, row.col2 + """ + def _row_to_python(self, rowdata, desc=None): + """Convert a MySQL text result row to Python types + + Returns a named tuple. + """ + if hasattr(self._connection, 'converter'): + row = self._connection.converter.row_to_python(rowdata, desc) + else: + row = rowdata + + if row: + # pylint: disable=W0201 + self.named_tuple = namedtuple('Row', self.column_names) + # pylint: enable=W0201 + return self.named_tuple(*row) + + def fetchone(self): + """Returns next row of a query result set + """ + row = self._fetch_row() + if row: + if hasattr(self._connection, 'converter'): + return self._row_to_python(row, self.description) + else: + return row + return None + + def fetchall(self): + """Returns all rows of a query result set + """ + if not self._have_unread_result(): + raise errors.InterfaceError(ERR_NO_RESULT_TO_FETCH) + (rows, eof) = self._connection.get_rows() + if self._nextrow[0]: + rows.insert(0, self._nextrow[0]) + + res = [self._row_to_python(row, self.description) + for row in rows] + + self._handle_eof(eof) + rowcount = len(rows) + if rowcount >= 0 and self._rowcount == -1: + self._rowcount = 0 + self._rowcount += rowcount + return res + + +class MySQLCursorBufferedDict(MySQLCursorDict, MySQLCursorBuffered): + """ + Buffered Cursor fetching rows as dictionaries. + """ + def fetchone(self): + """Returns next row of a query result set + """ + row = self._fetch_row() + if row: + return self._row_to_python(row, self.description) + return None + + def fetchall(self): + """Returns all rows of a query result set + """ + if self._rows is None: + raise errors.InterfaceError(ERR_NO_RESULT_TO_FETCH) + res = [] + for row in self._rows[self._next_row:]: + res.append(self._row_to_python( + row, self.description)) + self._next_row = len(self._rows) + return res + + +class MySQLCursorBufferedNamedTuple(MySQLCursorNamedTuple, MySQLCursorBuffered): + """ + Buffered Cursor fetching rows as named tuple. + """ + def fetchone(self): + """Returns next row of a query result set + """ + row = self._fetch_row() + if row: + return self._row_to_python(row, self.description) + return None + + def fetchall(self): + """Returns all rows of a query result set + """ + if self._rows is None: + raise errors.InterfaceError(ERR_NO_RESULT_TO_FETCH) + res = [] + for row in self._rows[self._next_row:]: + res.append(self._row_to_python( + row, self.description)) + self._next_row = len(self._rows) + return res diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/cursor_cext.py b/elitebot/lib/python3.11/site-packages/mysql/connector/cursor_cext.py new file mode 100644 index 0000000..4dd6e9a --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/cursor_cext.py @@ -0,0 +1,810 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Cursor classes using the C Extension +""" + +from collections import namedtuple +import re +import weakref + +from .abstracts import MySQLConnectionAbstract, MySQLCursorAbstract +from .catch23 import PY2, isunicode +from . import errors +from .errorcode import CR_NO_RESULT_SET + +from .cursor import ( + RE_PY_PARAM, RE_SQL_INSERT_STMT, + RE_SQL_ON_DUPLICATE, RE_SQL_COMMENT, RE_SQL_INSERT_VALUES, + RE_SQL_SPLIT_STMTS +) + +from _mysql_connector import MySQLInterfaceError # pylint: disable=F0401 + +class _ParamSubstitutor(object): + + """ + Substitutes parameters into SQL statement. + """ + + def __init__(self, params): + self.params = params + self.index = 0 + + def __call__(self, matchobj): + index = self.index + self.index += 1 + try: + return self.params[index] + except IndexError: + raise errors.ProgrammingError( + "Not enough parameters for the SQL statement") + + @property + def remaining(self): + """Returns number of parameters remaining to be substituted""" + return len(self.params) - self.index + + +class CMySQLCursor(MySQLCursorAbstract): + + """Default cursor for interacting with MySQL using C Extension""" + + _raw = False + _buffered = False + _raw_as_string = False + + def __init__(self, connection): + """Initialize""" + MySQLCursorAbstract.__init__(self) + + self._insert_id = 0 + self._warning_count = 0 + self._warnings = None + self._affected_rows = -1 + self._rowcount = -1 + self._nextrow = None + self._executed = None + self._executed_list = [] + self._stored_results = [] + + if not isinstance(connection, MySQLConnectionAbstract): + raise errors.InterfaceError(errno=2048) + self._cnx = weakref.proxy(connection) + + def reset(self, free=True): + """Reset the cursor + + When free is True (default) the result will be freed. + """ + self._rowcount = -1 + self._nextrow = None + self._affected_rows = -1 + self._insert_id = 0 + self._warning_count = 0 + self._warnings = None + self._warnings = None + self._warning_count = 0 + self._description = None + self._executed = None + self._executed_list = [] + if free and self._cnx: + self._cnx.free_result() + super(CMySQLCursor, self).reset() + + def _fetch_warnings(self): + """Fetch warnings + + Fetch warnings doing a SHOW WARNINGS. Can be called after getting + the result. + + Returns a result set or None when there were no warnings. + + Raises errors.Error (or subclass) on errors. + + Returns list of tuples or None. + """ + warnings = [] + try: + # force freeing result + self._cnx.consume_results() + _ = self._cnx.cmd_query("SHOW WARNINGS") + warnings = self._cnx.get_rows() + self._cnx.consume_results() + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + except Exception as err: + raise errors.InterfaceError( + "Failed getting warnings; {0}".format(str(err))) + + if warnings: + return warnings + + return None + + def _handle_warnings(self): + """Handle possible warnings after all results are consumed""" + if self._cnx.get_warnings is True and self._warning_count: + self._warnings = self._fetch_warnings() + + def _handle_result(self, result): + """Handles the result after statement execution""" + if 'columns' in result: + self._description = result['columns'] + self._rowcount = 0 + self._handle_resultset() + else: + self._insert_id = result['insert_id'] + self._warning_count = result['warning_count'] + self._affected_rows = result['affected_rows'] + self._rowcount = -1 + self._handle_warnings() + if self._cnx.raise_on_warnings is True and self._warnings: + raise errors.get_mysql_exception(*self._warnings[0][1:3]) + + def _handle_resultset(self): + """Handle a result set""" + pass + + def _handle_eof(self): + """Handle end of reading the result + + Raises an errors.Error on errors. + """ + self._warning_count = self._cnx.warning_count + self._handle_warnings() + if self._cnx.raise_on_warnings is True and self._warnings: + raise errors.get_mysql_exception(*self._warnings[0][1:3]) + + if not self._cnx.more_results: + self._cnx.free_result() + + def _execute_iter(self): + """Generator returns MySQLCursor objects for multiple statements + + Deprecated: use nextset() method directly. + + This method is only used when multiple statements are executed + by the execute() method. It uses zip() to make an iterator from the + given query_iter (result of MySQLConnection.cmd_query_iter()) and + the list of statements that were executed. + """ + executed_list = RE_SQL_SPLIT_STMTS.split(self._executed) + i = 0 + self._executed = executed_list[i] + yield self + + while True: + try: + if not self.nextset(): + raise StopIteration + except errors.InterfaceError as exc: + # Result without result set + if exc.errno != CR_NO_RESULT_SET: + raise + i += 1 + self._executed = executed_list[i].strip() + yield self + return + + def execute(self, operation, params=(), multi=False): + """Execute given statement using given parameters + + Deprecated: The multi argument is not needed and nextset() should + be used to handle multiple result sets. + """ + if not operation: + return None + + if not self._cnx: + raise errors.ProgrammingError("Cursor is not connected") + self._cnx.handle_unread_result() + + stmt = '' + self.reset() + + try: + if isunicode(operation): + stmt = operation.encode(self._cnx.python_charset) + else: + stmt = operation + except (UnicodeDecodeError, UnicodeEncodeError) as err: + raise errors.ProgrammingError(str(err)) + + if params: + prepared = self._cnx.prepare_for_mysql(params) + if isinstance(prepared, dict): + for key, value in prepared.items(): + if PY2: + stmt = stmt.replace("%({0})s".format(key), value) + else: + stmt = stmt.replace("%({0})s".format(key).encode(), + value) + elif isinstance(prepared, (list, tuple)): + psub = _ParamSubstitutor(prepared) + stmt = RE_PY_PARAM.sub(psub, stmt) + if psub.remaining != 0: + raise errors.ProgrammingError( + "Not all parameters were used in the SQL statement") + + try: + result = self._cnx.cmd_query(stmt, raw=self._raw, + buffered=self._buffered, + raw_as_string=self._raw_as_string) + except MySQLInterfaceError as exc: + raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, + sqlstate=exc.sqlstate) + + self._executed = stmt + self._handle_result(result) + + if multi: + return self._execute_iter() + + return None + + def _batch_insert(self, operation, seq_params): + """Implements multi row insert""" + def remove_comments(match): + """Remove comments from INSERT statements. + + This function is used while removing comments from INSERT + statements. If the matched string is a comment not enclosed + by quotes, it returns an empty string, else the string itself. + """ + if match.group(1): + return "" + else: + return match.group(2) + + tmp = re.sub(RE_SQL_ON_DUPLICATE, '', + re.sub(RE_SQL_COMMENT, remove_comments, operation)) + + matches = re.search(RE_SQL_INSERT_VALUES, tmp) + if not matches: + raise errors.InterfaceError( + "Failed rewriting statement for multi-row INSERT. " + "Check SQL syntax." + ) + fmt = matches.group(1).encode(self._cnx.charset) + values = [] + + try: + stmt = operation.encode(self._cnx.charset) + for params in seq_params: + tmp = fmt + prepared = self._cnx.prepare_for_mysql(params) + if isinstance(prepared, dict): + for key, value in prepared.items(): + tmp = tmp.replace("%({0})s".format(key).encode(), value) + elif isinstance(prepared, (list, tuple)): + psub = _ParamSubstitutor(prepared) + tmp = RE_PY_PARAM.sub(psub, tmp) + if psub.remaining != 0: + raise errors.ProgrammingError( + "Not all parameters were used in the SQL statement") + values.append(tmp) + + if fmt in stmt: + stmt = stmt.replace(fmt, b','.join(values), 1) + self._executed = stmt + return stmt + else: + return None + except (UnicodeDecodeError, UnicodeEncodeError) as err: + raise errors.ProgrammingError(str(err)) + except Exception as err: + raise errors.InterfaceError( + "Failed executing the operation; %s" % err) + + + def executemany(self, operation, seq_params): + """Execute the given operation multiple times""" + if not operation or not seq_params: + return None + + if not self._cnx: + raise errors.ProgrammingError("Cursor is not connected") + self._cnx.handle_unread_result() + + if not isinstance(seq_params, (list, tuple)): + raise errors.ProgrammingError( + "Parameters for query must be list or tuple.") + + # Optimize INSERTs by batching them + if re.match(RE_SQL_INSERT_STMT, operation): + if not seq_params: + self._rowcount = 0 + return + stmt = self._batch_insert(operation, seq_params) + if stmt is not None: + return self.execute(stmt) + + rowcnt = 0 + try: + for params in seq_params: + self.execute(operation, params) + try: + while True: + if self._description: + rowcnt += len(self._cnx.get_rows()) + else: + rowcnt += self._affected_rows + if not self.nextset(): + break + except StopIteration: + # No more results + pass + + except (ValueError, TypeError) as err: + raise errors.ProgrammingError( + "Failed executing the operation; {0}".format(err)) + + self._rowcount = rowcnt + + @property + def description(self): + """Returns description of columns in a result""" + return self._description + + @property + def rowcount(self): + """Returns the number of rows produced or affected""" + if self._rowcount == -1: + return self._affected_rows + else: + return self._rowcount + + @property + def lastrowid(self): + """Returns the value generated for an AUTO_INCREMENT column""" + return self._insert_id + + def close(self): + """Close the cursor + + The result will be freed. + """ + if not self._cnx: + return False + + self._cnx.handle_unread_result() + self._warnings = None + self._cnx = None + return True + + def callproc(self, procname, args=()): + """Calls a stored procedure with the given arguments""" + if not procname or not isinstance(procname, str): + raise ValueError("procname must be a string") + + if not isinstance(args, (tuple, list)): + raise ValueError("args must be a sequence") + + argfmt = "@_{name}_arg{index}" + self._stored_results = [] + + results = [] + try: + argnames = [] + argtypes = [] + if args: + for idx, arg in enumerate(args): + argname = argfmt.format(name=procname, index=idx + 1) + argnames.append(argname) + if isinstance(arg, tuple): + argtypes.append(" CAST({0} AS {1})".format(argname, + arg[1])) + self.execute("SET {0}=%s".format(argname), (arg[0],)) + else: + argtypes.append(argname) + self.execute("SET {0}=%s".format(argname), (arg,)) + + call = "CALL {0}({1})".format(procname, ','.join(argnames)) + + result = self._cnx.cmd_query(call, raw=self._raw, + raw_as_string=self._raw_as_string) + + results = [] + while self._cnx.result_set_available: + result = self._cnx.fetch_eof_columns() + # pylint: disable=W0212 + if self._raw: + cur = CMySQLCursorBufferedRaw(self._cnx._get_self()) + else: + cur = CMySQLCursorBuffered(self._cnx._get_self()) + cur._executed = "(a result of {0})".format(call) + cur._handle_result(result) + # pylint: enable=W0212 + results.append(cur) + self._cnx.next_result() + self._stored_results = results + self._handle_eof() + + if argnames: + self.reset() + select = "SELECT {0}".format(','.join(argtypes)) + self.execute(select) + + return self.fetchone() + else: + return tuple() + + except errors.Error: + raise + except Exception as err: + raise errors.InterfaceError( + "Failed calling stored routine; {0}".format(err)) + + def nextset(self): + """Skip to the next available result set""" + if not self._cnx.next_result(): + self.reset(free=True) + return None + self.reset(free=False) + + if not self._cnx.result_set_available: + eof = self._cnx.fetch_eof_status() + self._handle_result(eof) + raise errors.InterfaceError(errno=CR_NO_RESULT_SET) + + self._handle_result(self._cnx.fetch_eof_columns()) + return True + + def fetchall(self): + """Returns all rows of a query result set + + Returns a list of tuples. + """ + if not self._cnx.unread_result: + raise errors.InterfaceError("No result set to fetch from.") + rows = self._cnx.get_rows() + if self._nextrow: + rows.insert(0, self._nextrow) + + if not rows: + self._handle_eof() + return [] + + self._rowcount += len(rows) + self._handle_eof() + return rows + + def fetchmany(self, size=1): + """Returns the next set of rows of a result set""" + if self._nextrow: + rows = [self._nextrow] + size -= 1 + else: + rows = [] + + if size and self._cnx.unread_result: + rows.extend(self._cnx.get_rows(size)) + + if rows: + self._nextrow = self._cnx.get_row() + if not self._nextrow and not self._cnx.more_results: + self._cnx.free_result() + + if not rows: + self._handle_eof() + return [] + + self._rowcount += len(rows) + return rows + + def fetchone(self): + """Returns next row of a query result set""" + row = self._nextrow + if not row and self._cnx.unread_result: + row = self._cnx.get_row() + + if row: + self._nextrow = self._cnx.get_row() + if not self._nextrow and not self._cnx.more_results: + self._cnx.free_result() + else: + self._handle_eof() + return None + self._rowcount += 1 + return row + + def __iter__(self): + """Iteration over the result set + + Iteration over the result set which calls self.fetchone() + and returns the next row. + """ + return iter(self.fetchone, None) + + def stored_results(self): + """Returns an iterator for stored results + + This method returns an iterator over results which are stored when + callproc() is called. The iterator will provide MySQLCursorBuffered + instances. + + Returns a iterator. + """ + for i in range(len(self._stored_results)): + yield self._stored_results[i] + + self._stored_results = [] + + if PY2: + def next(self): + """Used for iterating over the result set.""" + return self.__next__() + + def __next__(self): + """Iteration over the result set + Used for iterating over the result set. Calls self.fetchone() + to get the next row. + + Raises StopIteration when no more rows are available. + """ + try: + row = self.fetchone() + except errors.InterfaceError: + raise StopIteration + if not row: + raise StopIteration + return row + + @property + def column_names(self): + """Returns column names + + This property returns the columns names as a tuple. + + Returns a tuple. + """ + if not self.description: + return () + return tuple([d[0] for d in self.description]) + + @property + def statement(self): + """Returns the executed statement + + This property returns the executed statement. When multiple + statements were executed, the current statement in the iterator + will be returned. + """ + try: + return self._executed.strip().decode('utf8') + except AttributeError: + return self._executed.strip() + + @property + def with_rows(self): + """Returns whether the cursor could have rows returned + + This property returns True when column descriptions are available + and possibly also rows, which will need to be fetched. + + Returns True or False. + """ + if self.description: + return True + return False + + def __str__(self): + fmt = "{class_name}: {stmt}" + if self._executed: + try: + executed = self._executed.decode('utf-8') + except AttributeError: + executed = self._executed + if len(executed) > 40: + executed = executed[:40] + '..' + else: + executed = '(Nothing executed yet)' + + return fmt.format(class_name=self.__class__.__name__, stmt=executed) + + +class CMySQLCursorBuffered(CMySQLCursor): + + """Cursor using C Extension buffering results""" + + def __init__(self, connection): + """Initialize""" + super(CMySQLCursorBuffered, self).__init__(connection) + + self._rows = None + self._next_row = 0 + + def _handle_resultset(self): + """Handle a result set""" + self._rows = self._cnx.get_rows() + self._next_row = 0 + self._rowcount = len(self._rows) + self._handle_eof() + + def reset(self, free=True): + """Reset the cursor to default""" + self._rows = None + self._next_row = 0 + super(CMySQLCursorBuffered, self).reset(free=free) + + def _fetch_row(self): + """Returns the next row in the result set + + Returns a tuple or None. + """ + row = None + try: + row = self._rows[self._next_row] + except IndexError: + return None + else: + self._next_row += 1 + + return row + + def fetchall(self): + if self._rows is None: + raise errors.InterfaceError("No result set to fetch from.") + res = self._rows[self._next_row:] + self._next_row = len(self._rows) + return res + + def fetchmany(self, size=1): + res = [] + cnt = size or self.arraysize + while cnt > 0: + cnt -= 1 + row = self._fetch_row() + if row: + res.append(row) + else: + break + return res + + def fetchone(self): + return self._fetch_row() + + +class CMySQLCursorRaw(CMySQLCursor): + + """Cursor using C Extension return raw results""" + + _raw = True + + +class CMySQLCursorBufferedRaw(CMySQLCursorBuffered): + + """Cursor using C Extension buffering raw results""" + + _raw = True + + +class CMySQLCursorDict(CMySQLCursor): + + """Cursor using C Extension returning rows as dictionaries""" + + _raw = False + + def fetchone(self): + """Returns all rows of a query result set + """ + row = super(CMySQLCursorDict, self).fetchone() + if row: + return dict(zip(self.column_names, row)) + else: + return None + + def fetchmany(self, size=1): + """Returns next set of rows as list of dictionaries""" + res = super(CMySQLCursorDict, self).fetchmany(size=size) + return [dict(zip(self.column_names, row)) for row in res] + + def fetchall(self): + """Returns all rows of a query result set as list of dictionaries""" + res = super(CMySQLCursorDict, self).fetchall() + return [dict(zip(self.column_names, row)) for row in res] + + +class CMySQLCursorBufferedDict(CMySQLCursorBuffered): + + """Cursor using C Extension buffering and returning rows as dictionaries""" + + _raw = False + + def _fetch_row(self): + row = super(CMySQLCursorBufferedDict, self)._fetch_row() + if row: + return dict(zip(self.column_names, row)) + else: + return None + + def fetchall(self): + res = super(CMySQLCursorBufferedDict, self).fetchall() + return [dict(zip(self.column_names, row)) for row in res] + + +class CMySQLCursorNamedTuple(CMySQLCursor): + + """Cursor using C Extension returning rows as named tuples""" + + def _handle_resultset(self): + """Handle a result set""" + super(CMySQLCursorNamedTuple, self)._handle_resultset() + # pylint: disable=W0201 + self.named_tuple = namedtuple('Row', self.column_names) + # pylint: enable=W0201 + + def fetchone(self): + """Returns all rows of a query result set + """ + row = super(CMySQLCursorNamedTuple, self).fetchone() + if row: + return self.named_tuple(*row) + else: + return None + + def fetchmany(self, size=1): + """Returns next set of rows as list of named tuples""" + res = super(CMySQLCursorNamedTuple, self).fetchmany(size=size) + return [self.named_tuple(*row) for row in res] + + def fetchall(self): + """Returns all rows of a query result set as list of named tuples""" + res = super(CMySQLCursorNamedTuple, self).fetchall() + return [self.named_tuple(*row) for row in res] + + +class CMySQLCursorBufferedNamedTuple(CMySQLCursorBuffered): + + """Cursor using C Extension buffering and returning rows as named tuples""" + + def _handle_resultset(self): + super(CMySQLCursorBufferedNamedTuple, self)._handle_resultset() + # pylint: disable=W0201 + self.named_tuple = namedtuple('Row', self.column_names) + # pylint: enable=W0201 + + def _fetch_row(self): + row = super(CMySQLCursorBufferedNamedTuple, self)._fetch_row() + if row: + return self.named_tuple(*row) + else: + return None + + def fetchall(self): + res = super(CMySQLCursorBufferedNamedTuple, self).fetchall() + return [self.named_tuple(*row) for row in res] + + +class CMySQLCursorPrepared(CMySQLCursor): + + """Cursor using Prepare Statement + """ + + def __init__(self, connection): + super(CMySQLCursorPrepared, self).__init__(connection) + raise NotImplementedError( + "Alternative: Use connection.MySQLCursorPrepared") + diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/custom_types.py b/elitebot/lib/python3.11/site-packages/mysql/connector/custom_types.py new file mode 100644 index 0000000..1688eae --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/custom_types.py @@ -0,0 +1,45 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Custom Python types used by MySQL Connector/Python""" + + +import sys + + +class HexLiteral(str): + + """Class holding MySQL hex literals""" + + def __new__(cls, str_, charset='utf8'): + if sys.version_info[0] == 2: + hexed = ["%02x" % ord(i) for i in str_.encode(charset)] + else: + hexed = ["%02x" % i for i in str_.encode(charset)] + obj = str.__new__(cls, ''.join(hexed)) + obj.charset = charset + obj.original = str_ + return obj + + def __str__(self): + return '0x' + self diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/dbapi.py b/elitebot/lib/python3.11/site-packages/mysql/connector/dbapi.py new file mode 100644 index 0000000..35cb03b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/dbapi.py @@ -0,0 +1,75 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +""" +This module implements some constructors and singletons as required by the +DB API v2.0 (PEP-249). +""" + +# Python Db API v2 +apilevel = '2.0' +threadsafety = 1 +paramstyle = 'pyformat' + +import time +import datetime + +from . import constants + +class _DBAPITypeObject(object): + + def __init__(self, *values): + self.values = values + + def __eq__(self, other): + if other in self.values: + return True + else: + return False + + def __ne__(self, other): + if other in self.values: + return False + else: + return True + +Date = datetime.date +Time = datetime.time +Timestamp = datetime.datetime + +def DateFromTicks(ticks): + return Date(*time.localtime(ticks)[:3]) + +def TimeFromTicks(ticks): + return Time(*time.localtime(ticks)[3:6]) + +def TimestampFromTicks(ticks): + return Timestamp(*time.localtime(ticks)[:6]) + +Binary = bytes + +STRING = _DBAPITypeObject(*constants.FieldType.get_string_types()) +BINARY = _DBAPITypeObject(*constants.FieldType.get_binary_types()) +NUMBER = _DBAPITypeObject(*constants.FieldType.get_number_types()) +DATETIME = _DBAPITypeObject(*constants.FieldType.get_timestamp_types()) +ROWID = _DBAPITypeObject() diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/__init__.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/base.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/base.py new file mode 100644 index 0000000..7ffc222 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/base.py @@ -0,0 +1,567 @@ +# MySQL Connector/Python - MySQL driver written in Python. + +"""Django database Backend using MySQL Connector/Python + +This Django database backend is heavily based on the MySQL backend coming +with Django. + +Changes include: +* Support for microseconds (MySQL 5.6.3 and later) +* Using INFORMATION_SCHEMA where possible +* Using new defaults for, for example SQL_AUTO_IS_NULL + +Requires and comes with MySQL Connector/Python v1.1 and later: + http://dev.mysql.com/downloads/connector/python/ +""" + + +from __future__ import unicode_literals + +from datetime import datetime +import sys +import warnings + +import django +from django.utils.functional import cached_property + +try: + import mysql.connector + from mysql.connector.conversion import MySQLConverter, MySQLConverterBase + from mysql.connector.catch23 import PY2 +except ImportError as err: + from django.core.exceptions import ImproperlyConfigured + raise ImproperlyConfigured( + "Error loading mysql.connector module: {0}".format(err)) + +try: + version = mysql.connector.__version_info__[0:3] +except AttributeError: + from mysql.connector.version import VERSION + version = VERSION[0:3] + +try: + from _mysql_connector import datetime_to_mysql, time_to_mysql +except ImportError: + HAVE_CEXT = False +else: + HAVE_CEXT = True + +if version < (1, 1): + from django.core.exceptions import ImproperlyConfigured + raise ImproperlyConfigured( + "MySQL Connector/Python v1.1.0 or newer " + "is required; you have %s" % mysql.connector.__version__) + +from django.db import utils +if django.VERSION < (1, 7): + from django.db.backends import util +else: + from django.db.backends import utils as backend_utils +if django.VERSION >= (1, 8): + from django.db.backends.base.base import BaseDatabaseWrapper +else: + from django.db.backends import BaseDatabaseWrapper + +from django.db.backends.signals import connection_created +from django.utils import (six, timezone, dateparse) +from django.conf import settings + +from mysql.connector.django.client import DatabaseClient +from mysql.connector.django.creation import DatabaseCreation +from mysql.connector.django.introspection import DatabaseIntrospection +from mysql.connector.django.validation import DatabaseValidation +from mysql.connector.django.features import DatabaseFeatures +from mysql.connector.django.operations import DatabaseOperations +if django.VERSION >= (1, 7): + from mysql.connector.django.schema import DatabaseSchemaEditor + + +DatabaseError = mysql.connector.DatabaseError +IntegrityError = mysql.connector.IntegrityError +NotSupportedError = mysql.connector.NotSupportedError + + +def adapt_datetime_with_timezone_support(value): + # Equivalent to DateTimeField.get_db_prep_value. Used only by raw SQL. + if settings.USE_TZ: + if timezone.is_naive(value): + warnings.warn("MySQL received a naive datetime (%s)" + " while time zone support is active." % value, + RuntimeWarning) + default_timezone = timezone.get_default_timezone() + value = timezone.make_aware(value, default_timezone) + value = value.astimezone(timezone.utc).replace(tzinfo=None) + if HAVE_CEXT: + return datetime_to_mysql(value) + else: + return value.strftime("%Y-%m-%d %H:%M:%S.%f") + + +class DjangoMySQLConverter(MySQLConverter): + """Custom converter for Django for MySQLConnection""" + def _TIME_to_python(self, value, dsc=None): + """Return MySQL TIME data type as datetime.time() + + Returns datetime.time() + """ + return dateparse.parse_time(value.decode('utf-8')) + + def _DATETIME_to_python(self, value, dsc=None): + """Connector/Python always returns naive datetime.datetime + + Connector/Python always returns naive timestamps since MySQL has + no time zone support. Since Django needs non-naive, we need to add + the UTC time zone. + + Returns datetime.datetime() + """ + if not value: + return None + dt = MySQLConverter._DATETIME_to_python(self, value) + if dt is None: + return None + if settings.USE_TZ and timezone.is_naive(dt): + dt = dt.replace(tzinfo=timezone.utc) + return dt + + def _safetext_to_mysql(self, value): + if PY2: + return self._unicode_to_mysql(value) + else: + return self._str_to_mysql(value) + + def _safebytes_to_mysql(self, value): + return self._bytes_to_mysql(value) + + +class DjangoCMySQLConverter(MySQLConverterBase): + """Custom converter for Django for CMySQLConnection""" + def _TIME_to_python(self, value, dsc=None): + """Return MySQL TIME data type as datetime.time() + + Returns datetime.time() + """ + return dateparse.parse_time(str(value)) + + def _DATETIME_to_python(self, value, dsc=None): + """Connector/Python always returns naive datetime.datetime + + Connector/Python always returns naive timestamps since MySQL has + no time zone support. Since Django needs non-naive, we need to add + the UTC time zone. + + Returns datetime.datetime() + """ + if not value: + return None + if settings.USE_TZ and timezone.is_naive(value): + value = value.replace(tzinfo=timezone.utc) + return value + + +class CursorWrapper(object): + """Wrapper around MySQL Connector/Python's cursor class. + + The cursor class is defined by the options passed to MySQL + Connector/Python. If buffered option is True in those options, + MySQLCursorBuffered will be used. + """ + codes_for_integrityerror = (1048,) + + def __init__(self, cursor): + self.cursor = cursor + + def _execute_wrapper(self, method, query, args): + """Wrapper around execute() and executemany()""" + try: + return method(query, args) + except (mysql.connector.ProgrammingError) as err: + six.reraise(utils.ProgrammingError, + utils.ProgrammingError(err.msg), sys.exc_info()[2]) + except (mysql.connector.IntegrityError) as err: + six.reraise(utils.IntegrityError, + utils.IntegrityError(err.msg), sys.exc_info()[2]) + except mysql.connector.OperationalError as err: + # Map some error codes to IntegrityError, since they seem to be + # misclassified and Django would prefer the more logical place. + if err.args[0] in self.codes_for_integrityerror: + six.reraise(utils.IntegrityError, + utils.IntegrityError(err.msg), sys.exc_info()[2]) + else: + six.reraise(utils.DatabaseError, + utils.DatabaseError(err.msg), sys.exc_info()[2]) + except mysql.connector.DatabaseError as err: + six.reraise(utils.DatabaseError, + utils.DatabaseError(err.msg), sys.exc_info()[2]) + + def _adapt_execute_args_dict(self, args): + if not args: + return args + new_args = dict(args) + for key, value in args.items(): + if isinstance(value, datetime): + new_args[key] = adapt_datetime_with_timezone_support(value) + + return new_args + + def _adapt_execute_args(self, args): + if not args: + return args + new_args = list(args) + for i, arg in enumerate(args): + if isinstance(arg, datetime): + new_args[i] = adapt_datetime_with_timezone_support(arg) + + return tuple(new_args) + + def execute(self, query, args=None): + """Executes the given operation + + This wrapper method around the execute()-method of the cursor is + mainly needed to re-raise using different exceptions. + """ + if isinstance(args, dict): + new_args = self._adapt_execute_args_dict(args) + else: + new_args = self._adapt_execute_args(args) + return self._execute_wrapper(self.cursor.execute, query, new_args) + + def executemany(self, query, args): + """Executes the given operation + + This wrapper method around the executemany()-method of the cursor is + mainly needed to re-raise using different exceptions. + """ + return self._execute_wrapper(self.cursor.executemany, query, args) + + def __getattr__(self, attr): + """Return attribute of wrapped cursor""" + return getattr(self.cursor, attr) + + def __iter__(self): + """Returns iterator over wrapped cursor""" + return iter(self.cursor) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, exc_traceback): + self.close() + + +class DatabaseWrapper(BaseDatabaseWrapper): + vendor = 'mysql' + # This dictionary maps Field objects to their associated MySQL column + # types, as strings. Column-type strings can contain format strings; they'll + # be interpolated against the values of Field.__dict__ before being output. + # If a column type is set to None, it won't be included in the output. + + # Moved from DatabaseCreation class in Django v1.8 + _data_types = { + 'AutoField': 'integer AUTO_INCREMENT', + 'BinaryField': 'longblob', + 'BooleanField': 'bool', + 'CharField': 'varchar(%(max_length)s)', + 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', + 'DateField': 'date', + 'DateTimeField': 'datetime', + 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', + 'DurationField': 'bigint', + 'FileField': 'varchar(%(max_length)s)', + 'FilePathField': 'varchar(%(max_length)s)', + 'FloatField': 'double precision', + 'IntegerField': 'integer', + 'BigIntegerField': 'bigint', + 'IPAddressField': 'char(15)', + 'GenericIPAddressField': 'char(39)', + 'NullBooleanField': 'bool', + 'OneToOneField': 'integer', + 'PositiveIntegerField': 'integer UNSIGNED', + 'PositiveSmallIntegerField': 'smallint UNSIGNED', + 'SlugField': 'varchar(%(max_length)s)', + 'SmallIntegerField': 'smallint', + 'TextField': 'longtext', + 'TimeField': 'time', + 'UUIDField': 'char(32)', + } + + @cached_property + def data_types(self): + if self.features.supports_microsecond_precision: + return dict(self._data_types, DateTimeField='datetime(6)', + TimeField='time(6)') + else: + return self._data_types + + operators = { + 'exact': '= %s', + 'iexact': 'LIKE %s', + 'contains': 'LIKE BINARY %s', + 'icontains': 'LIKE %s', + 'regex': 'REGEXP BINARY %s', + 'iregex': 'REGEXP %s', + 'gt': '> %s', + 'gte': '>= %s', + 'lt': '< %s', + 'lte': '<= %s', + 'startswith': 'LIKE BINARY %s', + 'endswith': 'LIKE BINARY %s', + 'istartswith': 'LIKE %s', + 'iendswith': 'LIKE %s', + } + + # The patterns below are used to generate SQL pattern lookup clauses when + # the right-hand side of the lookup isn't a raw string (it might be an + # expression or the result of a bilateral transformation). + # In those cases, special characters for LIKE operators (e.g. \, *, _) + # should be escaped on database side. + # + # Note: we use str.format() here for readability as '%' is used as a + # wildcard for the LIKE operator. + pattern_esc = (r"REPLACE(REPLACE(REPLACE({}, '\\', '\\\\')," + r" '%%', '\%%'), '_', '\_')") + pattern_ops = { + 'contains': "LIKE BINARY CONCAT('%%', {}, '%%')", + 'icontains': "LIKE CONCAT('%%', {}, '%%')", + 'startswith': "LIKE BINARY CONCAT({}, '%%')", + 'istartswith': "LIKE CONCAT({}, '%%')", + 'endswith': "LIKE BINARY CONCAT('%%', {})", + 'iendswith': "LIKE CONCAT('%%', {})", + } + + SchemaEditorClass = DatabaseSchemaEditor + Database = mysql.connector + + def __init__(self, *args, **kwargs): + super(DatabaseWrapper, self).__init__(*args, **kwargs) + + try: + self._use_pure = self.settings_dict['OPTIONS']['use_pure'] + except KeyError: + self._use_pure = True + + if not self.use_pure: + self.converter = DjangoCMySQLConverter() + else: + self.converter = DjangoMySQLConverter() + self.ops = DatabaseOperations(self) + self.features = DatabaseFeatures(self) + self.client = DatabaseClient(self) + self.creation = DatabaseCreation(self) + self.introspection = DatabaseIntrospection(self) + self.validation = DatabaseValidation(self) + + def _valid_connection(self): + if self.connection: + return self.connection.is_connected() + return False + + def get_connection_params(self): + # Django 1.6 + kwargs = { + 'charset': 'utf8', + 'use_unicode': True, + 'buffered': False, + 'consume_results': True, + } + + settings_dict = self.settings_dict + + if settings_dict['USER']: + kwargs['user'] = settings_dict['USER'] + if settings_dict['NAME']: + kwargs['database'] = settings_dict['NAME'] + if settings_dict['PASSWORD']: + kwargs['passwd'] = settings_dict['PASSWORD'] + if settings_dict['HOST'].startswith('/'): + kwargs['unix_socket'] = settings_dict['HOST'] + elif settings_dict['HOST']: + kwargs['host'] = settings_dict['HOST'] + if settings_dict['PORT']: + kwargs['port'] = int(settings_dict['PORT']) + + # Raise exceptions for database warnings if DEBUG is on + kwargs['raise_on_warnings'] = settings.DEBUG + + kwargs['client_flags'] = [ + # Need potentially affected rows on UPDATE + mysql.connector.constants.ClientFlag.FOUND_ROWS, + ] + try: + kwargs.update(settings_dict['OPTIONS']) + except KeyError: + # OPTIONS missing is OK + pass + + return kwargs + + def get_new_connection(self, conn_params): + # Django 1.6 + if not self.use_pure: + conn_params['converter_class'] = DjangoCMySQLConverter + else: + conn_params['converter_class'] = DjangoMySQLConverter + cnx = mysql.connector.connect(**conn_params) + + return cnx + + def init_connection_state(self): + # Django 1.6 + if self.mysql_version < (5, 5, 3): + # See sysvar_sql_auto_is_null in MySQL Reference manual + self.connection.cmd_query("SET SQL_AUTO_IS_NULL = 0") + + if 'AUTOCOMMIT' in self.settings_dict: + try: + # Django 1.6 + self.set_autocommit(self.settings_dict['AUTOCOMMIT']) + except AttributeError: + self._set_autocommit(self.settings_dict['AUTOCOMMIT']) + + def create_cursor(self): + # Django 1.6 + cursor = self.connection.cursor() + return CursorWrapper(cursor) + + def _connect(self): + """Setup the connection with MySQL""" + self.connection = self.get_new_connection(self.get_connection_params()) + connection_created.send(sender=self.__class__, connection=self) + self.init_connection_state() + + def _cursor(self): + """Return a CursorWrapper object + + Returns a CursorWrapper + """ + try: + # Django 1.6 + return super(DatabaseWrapper, self)._cursor() + except AttributeError: + if not self.connection: + self._connect() + return self.create_cursor() + + def get_server_version(self): + """Returns the MySQL server version of current connection + + Returns a tuple + """ + try: + # Django 1.6 + self.ensure_connection() + except AttributeError: + if not self.connection: + self._connect() + + return self.connection.get_server_version() + + def disable_constraint_checking(self): + """Disables foreign key checks + + Disables foreign key checks, primarily for use in adding rows with + forward references. Always returns True, + to indicate constraint checks need to be re-enabled. + + Returns True + """ + self.cursor().execute('SET @@session.foreign_key_checks = 0') + return True + + def enable_constraint_checking(self): + """Re-enable foreign key checks + + Re-enable foreign key checks after they have been disabled. + """ + # Override needs_rollback in case constraint_checks_disabled is + # nested inside transaction.atomic. + if django.VERSION >= (1, 6): + self.needs_rollback, needs_rollback = False, self.needs_rollback + try: + self.cursor().execute('SET @@session.foreign_key_checks = 1') + finally: + if django.VERSION >= (1, 6): + self.needs_rollback = needs_rollback + + def check_constraints(self, table_names=None): + """Check rows in tables for invalid foreign key references + + Checks each table name in `table_names` for rows with invalid foreign + key references. This method is intended to be used in conjunction with + `disable_constraint_checking()` and `enable_constraint_checking()`, to + determine if rows with invalid references were entered while + constraint checks were off. + + Raises an IntegrityError on the first invalid foreign key reference + encountered (if any) and provides detailed information about the + invalid reference in the error message. + + Backends can override this method if they can more directly apply + constraint checking (e.g. via "SET CONSTRAINTS ALL IMMEDIATE") + """ + ref_query = """ + SELECT REFERRING.`{0}`, REFERRING.`{1}` FROM `{2}` as REFERRING + LEFT JOIN `{3}` as REFERRED + ON (REFERRING.`{4}` = REFERRED.`{5}`) + WHERE REFERRING.`{6}` IS NOT NULL AND REFERRED.`{7}` IS NULL""" + cursor = self.cursor() + if table_names is None: + table_names = self.introspection.table_names(cursor) + for table_name in table_names: + primary_key_column_name = \ + self.introspection.get_primary_key_column(cursor, table_name) + if not primary_key_column_name: + continue + key_columns = self.introspection.get_key_columns(cursor, + table_name) + for column_name, referenced_table_name, referenced_column_name \ + in key_columns: + cursor.execute(ref_query.format(primary_key_column_name, + column_name, table_name, + referenced_table_name, + column_name, + referenced_column_name, + column_name, + referenced_column_name)) + for bad_row in cursor.fetchall(): + msg = ("The row in table '{0}' with primary key '{1}' has " + "an invalid foreign key: {2}.{3} contains a value " + "'{4}' that does not have a corresponding value in " + "{5}.{6}.".format(table_name, bad_row[0], + table_name, column_name, + bad_row[1], referenced_table_name, + referenced_column_name)) + raise utils.IntegrityError(msg) + + def _rollback(self): + try: + BaseDatabaseWrapper._rollback(self) + except NotSupportedError: + pass + + def _set_autocommit(self, autocommit): + # Django 1.6 + with self.wrap_database_errors: + self.connection.autocommit = autocommit + + def schema_editor(self, *args, **kwargs): + """Returns a new instance of this backend's SchemaEditor""" + # Django 1.7 + return DatabaseSchemaEditor(self, *args, **kwargs) + + def is_usable(self): + # Django 1.6 + return self.connection.is_connected() + + @cached_property + def mysql_version(self): + config = self.get_connection_params() + temp_conn = mysql.connector.connect(**config) + server_version = temp_conn.get_server_version() + temp_conn.close() + + return server_version + + @property + def use_pure(self): + return not HAVE_CEXT or self._use_pure diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/client.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/client.py new file mode 100644 index 0000000..8a3dc3e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/client.py @@ -0,0 +1,57 @@ +# MySQL Connector/Python - MySQL driver written in Python. + +import django +import subprocess + +if django.VERSION >= (1, 8): + from django.db.backends.base.client import BaseDatabaseClient +else: + from django.db.backends import BaseDatabaseClient + + +class DatabaseClient(BaseDatabaseClient): + executable_name = 'mysql' + + @classmethod + def settings_to_cmd_args(cls, settings_dict): + args = [cls.executable_name] + + db = settings_dict['OPTIONS'].get('database', settings_dict['NAME']) + user = settings_dict['OPTIONS'].get('user', + settings_dict['USER']) + passwd = settings_dict['OPTIONS'].get('password', + settings_dict['PASSWORD']) + host = settings_dict['OPTIONS'].get('host', settings_dict['HOST']) + port = settings_dict['OPTIONS'].get('port', settings_dict['PORT']) + defaults_file = settings_dict['OPTIONS'].get('read_default_file') + + # --defaults-file should always be the first option + if defaults_file: + args.append("--defaults-file={0}".format(defaults_file)) + + # We force SQL_MODE to TRADITIONAL + args.append("--init-command=SET @@session.SQL_MODE=TRADITIONAL") + + if user: + args.append("--user={0}".format(user)) + if passwd: + args.append("--password={0}".format(passwd)) + + if host: + if '/' in host: + args.append("--socket={0}".format(host)) + else: + args.append("--host={0}".format(host)) + + if port: + args.append("--port={0}".format(port)) + + if db: + args.append("--database={0}".format(db)) + + return args + + def runshell(self): + args = DatabaseClient.settings_to_cmd_args( + self.connection.settings_dict) + subprocess.call(args) diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/compiler.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/compiler.py new file mode 100644 index 0000000..232ed99 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/compiler.py @@ -0,0 +1,59 @@ +# MySQL Connector/Python - MySQL driver written in Python. + + +import django +from django.db.models.sql import compiler +from django.utils.six.moves import zip_longest + + +class SQLCompiler(compiler.SQLCompiler): + def resolve_columns(self, row, fields=()): + values = [] + index_extra_select = len(self.query.extra_select) + bool_fields = ("BooleanField", "NullBooleanField") + for value, field in zip_longest(row[index_extra_select:], fields): + if (field and field.get_internal_type() in bool_fields and + value in (0, 1)): + value = bool(value) + values.append(value) + return row[:index_extra_select] + tuple(values) + + if django.VERSION >= (1, 8): + def as_subquery_condition(self, alias, columns, compiler): + qn = compiler.quote_name_unless_alias + qn2 = self.connection.ops.quote_name + sql, params = self.as_sql() + return '(%s) IN (%s)' % (', '.join('%s.%s' % (qn(alias), qn2(column)) for column in columns), sql), params + else: + def as_subquery_condition(self, alias, columns, qn): + # Django 1.6 + qn2 = self.connection.ops.quote_name + sql, params = self.as_sql() + column_list = ', '.join( + ['%s.%s' % (qn(alias), qn2(column)) for column in columns]) + return '({0}) IN ({1})'.format(column_list, sql), params + + +class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler): + pass + + +class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler): + pass + + +class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler): + pass + + +class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler): + pass + +if django.VERSION < (1, 8): + class SQLDateCompiler(compiler.SQLDateCompiler, SQLCompiler): + pass + + if django.VERSION >= (1, 6): + class SQLDateTimeCompiler(compiler.SQLDateTimeCompiler, SQLCompiler): + # Django 1.6 + pass diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/creation.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/creation.py new file mode 100644 index 0000000..0937148 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/creation.py @@ -0,0 +1,141 @@ +# MySQL Connector/Python - MySQL driver written in Python. + +import django +from django.db import models + +if django.VERSION >= (1, 8): + from django.db.backends.base.creation import BaseDatabaseCreation +else: + from django.db.backends.creation import BaseDatabaseCreation +if django.VERSION < (1, 7): + from django.db.backends.util import truncate_name +else: + from django.db.backends.utils import truncate_name + +class DatabaseCreation(BaseDatabaseCreation): + """Maps Django Field object with MySQL data types + """ + def __init__(self, connection): + super(DatabaseCreation, self).__init__(connection) + + if django.VERSION < (1, 8): + self.data_types = { + 'AutoField': 'integer AUTO_INCREMENT', + 'BinaryField': 'longblob', + 'BooleanField': 'bool', + 'CharField': 'varchar(%(max_length)s)', + 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', + 'DateField': 'date', + 'DateTimeField': 'datetime', # ms support set later + 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', + 'FileField': 'varchar(%(max_length)s)', + 'FilePathField': 'varchar(%(max_length)s)', + 'FloatField': 'double precision', + 'IntegerField': 'integer', + 'BigIntegerField': 'bigint', + 'IPAddressField': 'char(15)', + + 'GenericIPAddressField': 'char(39)', + 'NullBooleanField': 'bool', + 'OneToOneField': 'integer', + 'PositiveIntegerField': 'integer UNSIGNED', + 'PositiveSmallIntegerField': 'smallint UNSIGNED', + 'SlugField': 'varchar(%(max_length)s)', + 'SmallIntegerField': 'smallint', + 'TextField': 'longtext', + 'TimeField': 'time', # ms support set later + } + + # Support for microseconds + if self.connection.mysql_version >= (5, 6, 4): + self.data_types.update({ + 'DateTimeField': 'datetime(6)', + 'TimeField': 'time(6)', + }) + + def sql_table_creation_suffix(self): + suffix = [] + if django.VERSION < (1, 7): + if self.connection.settings_dict['TEST_CHARSET']: + suffix.append('CHARACTER SET {0}'.format( + self.connection.settings_dict['TEST_CHARSET'])) + if self.connection.settings_dict['TEST_COLLATION']: + suffix.append('COLLATE {0}'.format( + self.connection.settings_dict['TEST_COLLATION'])) + + else: + test_settings = self.connection.settings_dict['TEST'] + if test_settings['CHARSET']: + suffix.append('CHARACTER SET %s' % test_settings['CHARSET']) + if test_settings['COLLATION']: + suffix.append('COLLATE %s' % test_settings['COLLATION']) + + return ' '.join(suffix) + + if django.VERSION < (1, 6): + def sql_for_inline_foreign_key_references(self, field, known_models, + style): + "All inline references are pending under MySQL" + return [], True + else: + def sql_for_inline_foreign_key_references(self, model, field, + known_models, style): + "All inline references are pending under MySQL" + return [], True + + def sql_for_inline_many_to_many_references(self, model, field, style): + opts = model._meta + qn = self.connection.ops.quote_name + + columndef = ' {column} {type} {options},' + table_output = [ + columndef.format( + column=style.SQL_FIELD(qn(field.m2m_column_name())), + type=style.SQL_COLTYPE(models.ForeignKey(model).db_type( + connection=self.connection)), + options=style.SQL_KEYWORD('NOT NULL') + ), + columndef.format( + column=style.SQL_FIELD(qn(field.m2m_reverse_name())), + type=style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type( + connection=self.connection)), + options=style.SQL_KEYWORD('NOT NULL') + ), + ] + + deferred = [ + (field.m2m_db_table(), field.m2m_column_name(), opts.db_table, + opts.pk.column), + (field.m2m_db_table(), field.m2m_reverse_name(), + field.rel.to._meta.db_table, field.rel.to._meta.pk.column) + ] + return table_output, deferred + + def sql_destroy_indexes_for_fields(self, model, fields, style): + # Django 1.6 + if len(fields) == 1 and fields[0].db_tablespace: + tablespace_sql = self.connection.ops.tablespace_sql( + fields[0].db_tablespace) + elif model._meta.db_tablespace: + tablespace_sql = self.connection.ops.tablespace_sql( + model._meta.db_tablespace) + else: + tablespace_sql = "" + if tablespace_sql: + tablespace_sql = " " + tablespace_sql + + field_names = [] + qn = self.connection.ops.quote_name + for f in fields: + field_names.append(style.SQL_FIELD(qn(f.column))) + + index_name = "{0}_{1}".format(model._meta.db_table, + self._digest([f.name for f in fields])) + + return [ + style.SQL_KEYWORD("DROP INDEX") + " " + + style.SQL_TABLE(qn(truncate_name(index_name, + self.connection.ops.max_name_length()))) + " " + + style.SQL_KEYWORD("ON") + " " + + style.SQL_TABLE(qn(model._meta.db_table)) + ";", + ] diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/features.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/features.py new file mode 100644 index 0000000..cc4c9b7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/features.py @@ -0,0 +1,127 @@ +# MySQL Connector/Python - MySQL driver written in Python. + +# New file added for Django 1.8 + +import django +if django.VERSION >= (1, 8): + from django.db.backends.base.features import BaseDatabaseFeatures +else: + from django.db.backends import BaseDatabaseFeatures +from django.utils.functional import cached_property +from django.utils import six + +try: + import pytz + HAVE_PYTZ = True +except ImportError: + HAVE_PYTZ = False + + +class DatabaseFeatures(BaseDatabaseFeatures): + """Features specific to MySQL + + Microsecond precision is supported since MySQL 5.6.3 and turned on + by default if this MySQL version is used. + """ + empty_fetchmany_value = [] + update_can_self_select = False + allows_group_by_pk = True + related_fields_match_type = True + allow_sliced_subqueries = False + has_bulk_insert = True + has_select_for_update = True + has_select_for_update_nowait = False + supports_forward_references = False + supports_regex_backreferencing = False + supports_date_lookup_using_string = False + can_introspect_autofield = True + can_introspect_binary_field = False + can_introspect_small_integer_field = True + supports_timezones = False + requires_explicit_null_ordering_when_grouping = True + allows_auto_pk_0 = False + allows_primary_key_0 = False + uses_savepoints = True + atomic_transactions = False + supports_column_check_constraints = False + + if django.VERSION < (1, 8): + supports_long_model_names = False + supports_binary_field = six.PY2 + can_introspect_boolean_field = False + + def __init__(self, connection): + super(DatabaseFeatures, self).__init__(connection) + + @cached_property + def supports_microsecond_precision(self): + if self.connection.mysql_version >= (5, 6, 3): + return True + return False + + @cached_property + def mysql_storage_engine(self): + """Get default storage engine of MySQL + + This method creates a table without ENGINE table option and inspects + which engine was used. + + Used by Django tests. + """ + tblname = 'INTROSPECT_TEST' + + droptable = 'DROP TABLE IF EXISTS {table}'.format(table=tblname) + with self.connection.cursor() as cursor: + cursor.execute(droptable) + cursor.execute('CREATE TABLE {table} (X INT)'.format(table=tblname)) + + if self.connection.mysql_version >= (5, 0, 0): + cursor.execute( + "SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES " + "WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s", + (self.connection.settings_dict['NAME'], tblname)) + engine = cursor.fetchone()[0] + else: + # Very old MySQL servers.. + cursor.execute("SHOW TABLE STATUS WHERE Name='{table}'".format( + table=tblname)) + engine = cursor.fetchone()[1] + cursor.execute(droptable) + + self._cached_storage_engine = engine + return engine + + @cached_property + def _disabled_supports_transactions(self): + return self.mysql_storage_engine == 'InnoDB' + + @cached_property + def can_introspect_foreign_keys(self): + """Confirm support for introspected foreign keys + + Only the InnoDB storage engine supports Foreigen Key (not taking + into account MySQL Cluster here). + """ + return self.mysql_storage_engine == 'InnoDB' + + @cached_property + def has_zoneinfo_database(self): + """Tests if the time zone definitions are installed + + MySQL accepts full time zones names (eg. Africa/Nairobi) but rejects + abbreviations (eg. EAT). When pytz isn't installed and the current + time zone is LocalTimezone (the only sensible value in this context), + the current time zone name will be an abbreviation. As a consequence, + MySQL cannot perform time zone conversions reliably. + """ + # Django 1.6 + if not HAVE_PYTZ: + return False + + with self.connection.cursor() as cursor: + cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1") + return cursor.fetchall() != [] + + def introspected_boolean_field_type(self, *args, **kwargs): + # New in Django 1.8 + return 'IntegerField' diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/introspection.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/introspection.py new file mode 100644 index 0000000..77e5503 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/introspection.py @@ -0,0 +1,322 @@ +# MySQL Connector/Python - MySQL driver written in Python. + + +import re +from collections import namedtuple + +import django +if django.VERSION >= (1, 8): + from django.db.backends.base.introspection import ( + BaseDatabaseIntrospection, FieldInfo, TableInfo + ) +else: + from django.db.backends import BaseDatabaseIntrospection + +if django.VERSION >= (1, 6): + if django.VERSION < (1, 8): + from django.db.backends import FieldInfo + from django.utils.encoding import force_text + if django.VERSION >= (1, 7): + from django.utils.datastructures import OrderedSet + +from mysql.connector.constants import FieldType + +foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) " + r"REFERENCES `([^`]*)` \(`([^`]*)`\)") + +if django.VERSION >= (1, 8): + FieldInfo = namedtuple('FieldInfo', FieldInfo._fields + ('extra',)) + + +class DatabaseIntrospection(BaseDatabaseIntrospection): + data_types_reverse = { + FieldType.BLOB: 'TextField', + FieldType.DECIMAL: 'DecimalField', + FieldType.NEWDECIMAL: 'DecimalField', + FieldType.DATE: 'DateField', + FieldType.DATETIME: 'DateTimeField', + FieldType.DOUBLE: 'FloatField', + FieldType.FLOAT: 'FloatField', + FieldType.INT24: 'IntegerField', + FieldType.LONG: 'IntegerField', + FieldType.LONGLONG: 'BigIntegerField', + FieldType.SHORT: ( + 'IntegerField' if django.VERSION < (1, 8) else 'SmallIntegerField' + ), + FieldType.STRING: 'CharField', + FieldType.TIME: 'TimeField', + FieldType.TIMESTAMP: 'DateTimeField', + FieldType.TINY: 'IntegerField', + FieldType.TINY_BLOB: 'TextField', + FieldType.MEDIUM_BLOB: 'TextField', + FieldType.LONG_BLOB: 'TextField', + FieldType.VAR_STRING: 'CharField', + } + + def get_field_type(self, data_type, description): + field_type = super(DatabaseIntrospection, self).get_field_type( + data_type, description) + if (field_type == 'IntegerField' + and 'auto_increment' in description.extra): + return 'AutoField' + return field_type + + def get_table_list(self, cursor): + """Returns a list of table names in the current database.""" + cursor.execute("SHOW FULL TABLES") + if django.VERSION >= (1, 8): + return [ + TableInfo(row[0], {'BASE TABLE': 't', 'VIEW': 'v'}.get(row[1])) + for row in cursor.fetchall() + ] + else: + return [row[0] for row in cursor.fetchall()] + + if django.VERSION >= (1, 8): + def get_table_description(self, cursor, table_name): + """ + Returns a description of the table, with the DB-API + cursor.description interface." + """ + # - information_schema database gives more accurate results for + # some figures: + # - varchar length returned by cursor.description is an internal + # length, not visible length (#5725) + # - precision and scale (for decimal fields) (#5014) + # - auto_increment is not available in cursor.description + InfoLine = namedtuple( + 'InfoLine', + 'col_name data_type max_len num_prec num_scale extra' + ) + cursor.execute(""" + SELECT column_name, data_type, character_maximum_length, + numeric_precision, numeric_scale, extra + FROM information_schema.columns + WHERE table_name = %s AND table_schema = DATABASE()""", + [table_name]) + field_info = dict( + (line[0], InfoLine(*line)) for line in cursor.fetchall() + ) + + cursor.execute("SELECT * FROM %s LIMIT 1" + % self.connection.ops.quote_name(table_name)) + to_int = lambda i: int(i) if i is not None else i + fields = [] + for line in cursor.description: + col_name = force_text(line[0]) + fields.append( + FieldInfo(*((col_name,) + + line[1:3] + + (to_int(field_info[col_name].max_len) + or line[3], + to_int(field_info[col_name].num_prec) + or line[4], + to_int(field_info[col_name].num_scale) + or line[5]) + + (line[6],) + + (field_info[col_name].extra,))) + ) + return fields + else: + def get_table_description(self, cursor, table_name): + """ + Returns a description of the table, with the DB-API + cursor.description interface. + """ + # varchar length returned by cursor.description is an internal + # length not visible length (#5725), use information_schema database + # to fix this + cursor.execute( + "SELECT column_name, character_maximum_length " + "FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE table_name = %s AND table_schema = DATABASE() " + "AND character_maximum_length IS NOT NULL", [table_name]) + length_map = dict(cursor.fetchall()) + + # Also getting precision and scale from + # information_schema (see #5014) + cursor.execute( + "SELECT column_name, numeric_precision, numeric_scale FROM " + "INFORMATION_SCHEMA.COLUMNS WHERE table_name = %s AND " + "table_schema = DATABASE() AND data_type='decimal'", + [table_name]) + numeric_map = dict((line[0], tuple([int(n) for n in line[1:]])) + for line in cursor.fetchall()) + + cursor.execute("SELECT * FROM {0} LIMIT 1".format( + self.connection.ops.quote_name(table_name))) + + if django.VERSION >= (1, 6): + return [FieldInfo(*((force_text(line[0]),) + + line[1:3] + + (length_map.get(line[0], line[3]),) + + numeric_map.get(line[0], line[4:6]) + + (line[6],))) + for line in cursor.description] + else: + return [ + line[:3] + (length_map.get(line[0], line[3]),) + line[4:] + for line in cursor.description + ] + + def _name_to_index(self, cursor, table_name): + """ + Returns a dictionary of {field_name: field_index} for the given table. + Indexes are 0-based. + """ + return dict((d[0], i) for i, d in enumerate( + self.get_table_description(cursor, table_name))) + + def get_relations(self, cursor, table_name): + """ + Returns a dictionary of {field_index: (field_index_other_table, + other_table)} + representing all relationships to the given table. Indexes are 0-based. + """ + constraints = self.get_key_columns(cursor, table_name) + relations = {} + if django.VERSION >= (1, 8): + for my_fieldname, other_table, other_field in constraints: + relations[my_fieldname] = (other_field, other_table) + return relations + else: + my_field_dict = self._name_to_index(cursor, table_name) + for my_fieldname, other_table, other_field in constraints: + other_field_index = self._name_to_index( + cursor, other_table)[other_field] + my_field_index = my_field_dict[my_fieldname] + relations[my_field_index] = (other_field_index, other_table) + return relations + + def get_key_columns(self, cursor, table_name): + """ + Returns a list of (column_name, referenced_table_name, + referenced_column_name) for all key columns in given table. + """ + key_columns = [] + cursor.execute( + "SELECT column_name, referenced_table_name, referenced_column_name " + "FROM information_schema.key_column_usage " + "WHERE table_name = %s " + "AND table_schema = DATABASE() " + "AND referenced_table_name IS NOT NULL " + "AND referenced_column_name IS NOT NULL", [table_name]) + key_columns.extend(cursor.fetchall()) + return key_columns + + def get_indexes(self, cursor, table_name): + cursor.execute("SHOW INDEX FROM {0}" + "".format(self.connection.ops.quote_name(table_name))) + # Do a two-pass search for indexes: on first pass check which indexes + # are multicolumn, on second pass check which single-column indexes + # are present. + rows = list(cursor.fetchall()) + multicol_indexes = set() + for row in rows: + if row[3] > 1: + multicol_indexes.add(row[2]) + indexes = {} + for row in rows: + if row[2] in multicol_indexes: + continue + if row[4] not in indexes: + indexes[row[4]] = {'primary_key': False, 'unique': False} + # It's possible to have the unique and PK constraints in + # separate indexes. + if row[2] == 'PRIMARY': + indexes[row[4]]['primary_key'] = True + if not row[1]: + indexes[row[4]]['unique'] = True + return indexes + + def get_primary_key_column(self, cursor, table_name): + """ + Returns the name of the primary key column for the given table + """ + # Django 1.6 + for column in self.get_indexes(cursor, table_name).items(): + if column[1]['primary_key']: + return column[0] + return None + + def get_storage_engine(self, cursor, table_name): + """ + Retrieves the storage engine for a given table. Returns the default + storage engine if the table doesn't exist. + """ + cursor.execute( + "SELECT engine " + "FROM information_schema.tables " + "WHERE table_name = %s", [table_name]) + result = cursor.fetchone() + if not result: + return self.connection.features.mysql_storage_engine + return result[0] + + def get_constraints(self, cursor, table_name): + """ + Retrieves any constraints or keys (unique, pk, fk, check, index) across + one or more columns. + """ + # Django 1.7 + constraints = {} + # Get the actual constraint names and columns + name_query = ( + "SELECT kc.`constraint_name`, kc.`column_name`, " + "kc.`referenced_table_name`, kc.`referenced_column_name` " + "FROM information_schema.key_column_usage AS kc " + "WHERE " + "kc.table_schema = %s AND " + "kc.table_name = %s" + ) + cursor.execute(name_query, [self.connection.settings_dict['NAME'], + table_name]) + for constraint, column, ref_table, ref_column in cursor.fetchall(): + if constraint not in constraints: + constraints[constraint] = { + 'columns': OrderedSet(), + 'primary_key': False, + 'unique': False, + 'index': False, + 'check': False, + 'foreign_key': ( + (ref_table, ref_column) if ref_column else None, + ) + } + constraints[constraint]['columns'].add(column) + # Now get the constraint types + type_query = """ + SELECT c.constraint_name, c.constraint_type + FROM information_schema.table_constraints AS c + WHERE + c.table_schema = %s AND + c.table_name = %s + """ + cursor.execute(type_query, [self.connection.settings_dict['NAME'], + table_name]) + for constraint, kind in cursor.fetchall(): + if kind.lower() == "primary key": + constraints[constraint]['primary_key'] = True + constraints[constraint]['unique'] = True + elif kind.lower() == "unique": + constraints[constraint]['unique'] = True + # Now add in the indexes + cursor.execute("SHOW INDEX FROM %s" % self.connection.ops.quote_name( + table_name)) + for table, non_unique, index, colseq, column in [x[:5] for x in + cursor.fetchall()]: + if index not in constraints: + constraints[index] = { + 'columns': OrderedSet(), + 'primary_key': False, + 'unique': False, + 'index': True, + 'check': False, + 'foreign_key': None, + } + constraints[index]['index'] = True + constraints[index]['columns'].add(column) + # Convert the sorted sets to lists + for constraint in constraints.values(): + constraint['columns'] = list(constraint['columns']) + return constraints diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/operations.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/operations.py new file mode 100644 index 0000000..127750d --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/operations.py @@ -0,0 +1,308 @@ +# MySQL Connector/Python - MySQL driver written in Python. + +# New file added for Django 1.8 + +from __future__ import unicode_literals + +import uuid + +import django +from django.conf import settings +if django.VERSION >= (1, 8): + from django.db.backends.base.operations import BaseDatabaseOperations +else: + from django.db.backends import BaseDatabaseOperations +from django.utils import six, timezone +from django.utils.encoding import force_text + +try: + from _mysql_connector import datetime_to_mysql, time_to_mysql +except ImportError: + HAVE_CEXT = False +else: + HAVE_CEXT = True + + +class DatabaseOperations(BaseDatabaseOperations): + compiler_module = "mysql.connector.django.compiler" + + # MySQL stores positive fields as UNSIGNED ints. + if django.VERSION >= (1, 7): + integer_field_ranges = dict(BaseDatabaseOperations.integer_field_ranges, + PositiveSmallIntegerField=(0, 4294967295), + PositiveIntegerField=( + 0, 18446744073709551615),) + + def date_extract_sql(self, lookup_type, field_name): + # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html + if lookup_type == 'week_day': + # DAYOFWEEK() returns an integer, 1-7, Sunday=1. + # Note: WEEKDAY() returns 0-6, Monday=0. + return "DAYOFWEEK({0})".format(field_name) + else: + return "EXTRACT({0} FROM {1})".format( + lookup_type.upper(), field_name) + + def date_trunc_sql(self, lookup_type, field_name): + """Returns SQL simulating DATE_TRUNC + + This function uses MySQL functions DATE_FORMAT and CAST to + simulate DATE_TRUNC. + + The field_name is returned when lookup_type is not supported. + """ + fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] + format = ('%Y-', '%m', '-%d', ' %H:', '%i', ':%S') + format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') + try: + i = fields.index(lookup_type) + 1 + except ValueError: + # Wrong lookup type, just return the value from MySQL as-is + sql = field_name + else: + format_str = ''.join([f for f in format[:i]] + + [f for f in format_def[i:]]) + sql = "CAST(DATE_FORMAT({0}, '{1}') AS DATETIME)".format( + field_name, format_str) + return sql + + def datetime_extract_sql(self, lookup_type, field_name, tzname): + # Django 1.6 + if settings.USE_TZ: + field_name = "CONVERT_TZ({0}, 'UTC', %s)".format(field_name) + params = [tzname] + else: + params = [] + + # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html + if lookup_type == 'week_day': + # DAYOFWEEK() returns an integer, 1-7, Sunday=1. + # Note: WEEKDAY() returns 0-6, Monday=0. + sql = "DAYOFWEEK({0})".format(field_name) + else: + sql = "EXTRACT({0} FROM {1})".format(lookup_type.upper(), + field_name) + return sql, params + + def datetime_trunc_sql(self, lookup_type, field_name, tzname): + # Django 1.6 + if settings.USE_TZ: + field_name = "CONVERT_TZ({0}, 'UTC', %s)".format(field_name) + params = [tzname] + else: + params = [] + fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] + format_ = ('%Y-', '%m', '-%d', ' %H:', '%i', ':%S') + format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') + try: + i = fields.index(lookup_type) + 1 + except ValueError: + sql = field_name + else: + format_str = ''.join([f for f in format_[:i]] + + [f for f in format_def[i:]]) + sql = "CAST(DATE_FORMAT({0}, '{1}') AS DATETIME)".format( + field_name, format_str) + return sql, params + + if django.VERSION >= (1, 8): + def date_interval_sql(self, timedelta): + """Returns SQL for calculating date/time intervals + """ + return "INTERVAL '%d 0:0:%d:%d' DAY_MICROSECOND" % ( + timedelta.days, timedelta.seconds, timedelta.microseconds), [] + else: + def date_interval_sql(self, sql, connector, timedelta): + """Returns SQL for calculating date/time intervals + """ + fmt = ( + "({sql} {connector} INTERVAL '{days} " + "0:0:{secs}:{msecs}' DAY_MICROSECOND)" + ) + return fmt.format( + sql=sql, + connector=connector, + days=timedelta.days, + secs=timedelta.seconds, + msecs=timedelta.microseconds + ) + + def format_for_duration_arithmetic(self, sql): + if self.connection.features.supports_microsecond_precision: + return 'INTERVAL %s MICROSECOND' % sql + else: + return 'INTERVAL FLOOR(%s / 1000000) SECOND' % sql + + def drop_foreignkey_sql(self): + return "DROP FOREIGN KEY" + + def force_no_ordering(self): + """ + "ORDER BY NULL" prevents MySQL from implicitly ordering by grouped + columns. If no ordering would otherwise be applied, we don't want any + implicit sorting going on. + """ + if django.VERSION >= (1, 8): + return [(None, ("NULL", [], False))] + else: + return ["NULL"] + + def fulltext_search_sql(self, field_name): + return 'MATCH ({0}) AGAINST (%s IN BOOLEAN MODE)'.format(field_name) + + def last_executed_query(self, cursor, sql, params): + return force_text(cursor.statement, errors='replace') + + def no_limit_value(self): + # 2**64 - 1, as recommended by the MySQL documentation + return 18446744073709551615 + + def quote_name(self, name): + if name.startswith("`") and name.endswith("`"): + return name # Quoting once is enough. + return "`{0}`".format(name) + + def random_function_sql(self): + return 'RAND()' + + def sql_flush(self, style, tables, sequences, allow_cascade=False): + if tables: + sql = ['SET FOREIGN_KEY_CHECKS = 0;'] + for table in tables: + sql.append('{keyword} {table};'.format( + keyword=style.SQL_KEYWORD('TRUNCATE'), + table=style.SQL_FIELD(self.quote_name(table)))) + sql.append('SET FOREIGN_KEY_CHECKS = 1;') + sql.extend(self.sequence_reset_by_name_sql(style, sequences)) + return sql + else: + return [] + + def validate_autopk_value(self, value): + # MySQLism: zero in AUTO_INCREMENT field does not work. Refs #17653. + if value == 0: + raise ValueError('The database backend does not accept 0 as a ' + 'value for AutoField.') + return value + + def value_to_db_datetime(self, value): + if value is None: + return None + # MySQL doesn't support tz-aware times + if timezone.is_aware(value): + if settings.USE_TZ: + value = value.astimezone(timezone.utc).replace(tzinfo=None) + else: + raise ValueError( + "MySQL backend does not support timezone-aware times." + ) + if not self.connection.features.supports_microsecond_precision: + value = value.replace(microsecond=0) + if not self.connection.use_pure: + return datetime_to_mysql(value) + return self.connection.converter.to_mysql(value) + + def value_to_db_time(self, value): + if value is None: + return None + + # MySQL doesn't support tz-aware times + if timezone.is_aware(value): + raise ValueError("MySQL backend does not support timezone-aware " + "times.") + + if not self.connection.use_pure: + return time_to_mysql(value) + return self.connection.converter.to_mysql(value) + + def max_name_length(self): + return 64 + + def bulk_insert_sql(self, fields, num_values): + items_sql = "({0})".format(", ".join(["%s"] * len(fields))) + return "VALUES " + ", ".join([items_sql] * num_values) + + if django.VERSION < (1, 8): + def year_lookup_bounds(self, value): + # Again, no microseconds + first = '{0}-01-01 00:00:00' + second = '{0}-12-31 23:59:59.999999' + return [first.format(value), second.format(value)] + + def year_lookup_bounds_for_datetime_field(self, value): + # Django 1.6 + # Again, no microseconds + first, second = super(DatabaseOperations, + self).year_lookup_bounds_for_datetime_field(value) + if self.connection.mysql_version >= (5, 6, 4): + return [first.replace(microsecond=0), second] + else: + return [first.replace(microsecond=0), + second.replace(microsecond=0)] + + def sequence_reset_by_name_sql(self, style, sequences): + # Truncate already resets the AUTO_INCREMENT field from + # MySQL version 5.0.13 onwards. Refs #16961. + res = [] + if self.connection.mysql_version < (5, 0, 13): + fmt = "{alter} {table} {{tablename}} {auto_inc} {field};".format( + alter=style.SQL_KEYWORD('ALTER'), + table=style.SQL_KEYWORD('TABLE'), + auto_inc=style.SQL_KEYWORD('AUTO_INCREMENT'), + field=style.SQL_FIELD('= 1') + ) + for sequence in sequences: + tablename = style.SQL_TABLE(self.quote_name(sequence['table'])) + res.append(fmt.format(tablename=tablename)) + return res + return res + + def savepoint_create_sql(self, sid): + return "SAVEPOINT {0}".format(sid) + + def savepoint_commit_sql(self, sid): + return "RELEASE SAVEPOINT {0}".format(sid) + + def savepoint_rollback_sql(self, sid): + return "ROLLBACK TO SAVEPOINT {0}".format(sid) + + def combine_expression(self, connector, sub_expressions): + """ + MySQL requires special cases for ^ operators in query expressions + """ + if connector == '^': + return 'POW(%s)' % ','.join(sub_expressions) + return super(DatabaseOperations, self).combine_expression( + connector, sub_expressions) + + def get_db_converters(self, expression): + # New in Django 1.8 + converters = super(DatabaseOperations, self).get_db_converters( + expression) + internal_type = expression.output_field.get_internal_type() + if internal_type in ['BooleanField', 'NullBooleanField']: + converters.append(self.convert_booleanfield_value) + if internal_type == 'UUIDField': + converters.append(self.convert_uuidfield_value) + if internal_type == 'TextField': + converters.append(self.convert_textfield_value) + return converters + + def convert_booleanfield_value(self, value, + expression, connection, context): + # New in Django 1.8 + if value in (0, 1): + value = bool(value) + return value + + def convert_uuidfield_value(self, value, expression, connection, context): + # New in Django 1.8 + if value is not None: + value = uuid.UUID(value) + return value + + def convert_textfield_value(self, value, expression, connection, context): + # New in Django 1.8 + if value is not None: + value = force_text(value) + return value diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/schema.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/schema.py new file mode 100644 index 0000000..3dfde53 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/schema.py @@ -0,0 +1,86 @@ +# MySQL Connector/Python - MySQL driver written in Python. + +# New file added for Django 1.7 + +import django +if django.VERSION >= (1, 8): + from django.db.backends.base.schema import BaseDatabaseSchemaEditor +else: + from django.db.backends.schema import BaseDatabaseSchemaEditor +from django.db.models import NOT_PROVIDED + + +class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): + + sql_rename_table = "RENAME TABLE %(old_table)s TO %(new_table)s" + + sql_alter_column_null = "MODIFY %(column)s %(type)s NULL" + sql_alter_column_not_null = "MODIFY %(column)s %(type)s NOT NULL" + sql_alter_column_type = "MODIFY %(column)s %(type)s" + sql_rename_column = "ALTER TABLE %(table)s CHANGE %(old_column)s " \ + "%(new_column)s %(type)s" + + sql_delete_unique = "ALTER TABLE %(table)s DROP INDEX %(name)s" + + sql_create_fk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s FOREIGN " \ + "KEY (%(column)s) REFERENCES %(to_table)s (%(to_column)s)" + sql_delete_fk = "ALTER TABLE %(table)s DROP FOREIGN KEY %(name)s" + + sql_delete_index = "DROP INDEX %(name)s ON %(table)s" + + alter_string_set_null = 'MODIFY %(column)s %(type)s NULL;' + alter_string_drop_null = 'MODIFY %(column)s %(type)s NOT NULL;' + + sql_create_pk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s " \ + "PRIMARY KEY (%(columns)s)" + sql_delete_pk = "ALTER TABLE %(table)s DROP PRIMARY KEY" + + def quote_value(self, value): + # Inner import to allow module to fail to load gracefully + from mysql.connector.conversion import MySQLConverter + return MySQLConverter.quote(MySQLConverter.escape(value)) + + def skip_default(self, field): + """ + MySQL doesn't accept default values for longtext and longblob + and implicitly treats these columns as nullable. + """ + return field.db_type(self.connection) in ('longtext', 'longblob') + + def add_field(self, model, field): + super(DatabaseSchemaEditor, self).add_field(model, field) + + # Simulate the effect of a one-off default. + if (self.skip_default(field) + and field.default not in (None, NOT_PROVIDED)): + effective_default = self.effective_default(field) + self.execute('UPDATE %(table)s SET %(column)s = %%s' % { + 'table': self.quote_name(model._meta.db_table), + 'column': self.quote_name(field.column), + }, [effective_default]) + + def _model_indexes_sql(self, model): + # New in Django 1.8 + storage = self.connection.introspection.get_storage_engine( + self.connection.cursor(), model._meta.db_table + ) + if storage == "InnoDB": + for field in model._meta.local_fields: + if (field.db_index and not field.unique + and field.get_internal_type() == "ForeignKey"): + # Temporary setting db_index to False (in memory) to + # disable index creation for FKs (index automatically + # created by MySQL) + field.db_index = False + return super(DatabaseSchemaEditor, self)._model_indexes_sql(model) + + def _alter_column_type_sql(self, table, old_field, new_field, new_type): + # New in Django 1.8 + # Keep null property of old field, if it has changed, it will be + # handled separately + if old_field.null: + new_type += " NULL" + else: + new_type += " NOT NULL" + return super(DatabaseSchemaEditor, self)._alter_column_type_sql( + table, old_field, new_field, new_type) diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/django/validation.py b/elitebot/lib/python3.11/site-packages/mysql/connector/django/validation.py new file mode 100644 index 0000000..75c29ef --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/django/validation.py @@ -0,0 +1,65 @@ +# MySQL Connector/Python - MySQL driver written in Python. + +import django + +if django.VERSION >= (1, 8): + from django.db.backends.base.validation import BaseDatabaseValidation +else: + from django.db.backends import BaseDatabaseValidation + +if django.VERSION < (1, 7): + from django.db import models +else: + from django.core import checks + from django.db import connection + + +class DatabaseValidation(BaseDatabaseValidation): + if django.VERSION < (1, 7): + def validate_field(self, errors, opts, f): + """ + MySQL has the following field length restriction: + No character (varchar) fields can have a length exceeding 255 + characters if they have a unique index on them. + """ + varchar_fields = (models.CharField, + models.CommaSeparatedIntegerField, + models.SlugField) + if isinstance(f, varchar_fields) and f.max_length > 255 and f.unique: + msg = ('"%(name)s": %(cls)s cannot have a "max_length" greater ' + 'than 255 when using "unique=True".') + errors.add(opts, msg % {'name': f.name, + 'cls': f.__class__.__name__}) + + else: + def check_field(self, field, **kwargs): + """ + MySQL has the following field length restriction: + No character (varchar) fields can have a length exceeding 255 + characters if they have a unique index on them. + """ + # Django 1.7 + errors = super(DatabaseValidation, self).check_field(field, + **kwargs) + + # Ignore any related fields. + if getattr(field, 'rel', None) is None: + field_type = field.db_type(connection) + + if field_type is None: + return errors + + if (field_type.startswith('varchar') # Look for CharFields... + and field.unique # ... that are unique + and (field.max_length is None or + int(field.max_length) > 255)): + errors.append( + checks.Error( + ('MySQL does not allow unique CharFields to have a ' + 'max_length > 255.'), + hint=None, + obj=field, + id='mysql.E001', + ) + ) + return errors diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/errorcode.py b/elitebot/lib/python3.11/site-packages/mysql/connector/errorcode.py new file mode 100644 index 0000000..6304811 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/errorcode.py @@ -0,0 +1,1159 @@ +# -*- coding: utf-8 -*- + +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# This file was auto-generated. +_GENERATED_ON = '2015-12-13' +_MYSQL_VERSION = (5, 7, 10) + +"""This module contains the MySQL Server and Client error codes""" + +# Start MySQL Errors +ER_HASHCHK = 1000 +ER_NISAMCHK = 1001 +ER_NO = 1002 +ER_YES = 1003 +ER_CANT_CREATE_FILE = 1004 +ER_CANT_CREATE_TABLE = 1005 +ER_CANT_CREATE_DB = 1006 +ER_DB_CREATE_EXISTS = 1007 +ER_DB_DROP_EXISTS = 1008 +ER_DB_DROP_DELETE = 1009 +ER_DB_DROP_RMDIR = 1010 +ER_CANT_DELETE_FILE = 1011 +ER_CANT_FIND_SYSTEM_REC = 1012 +ER_CANT_GET_STAT = 1013 +ER_CANT_GET_WD = 1014 +ER_CANT_LOCK = 1015 +ER_CANT_OPEN_FILE = 1016 +ER_FILE_NOT_FOUND = 1017 +ER_CANT_READ_DIR = 1018 +ER_CANT_SET_WD = 1019 +ER_CHECKREAD = 1020 +ER_DISK_FULL = 1021 +ER_DUP_KEY = 1022 +ER_ERROR_ON_CLOSE = 1023 +ER_ERROR_ON_READ = 1024 +ER_ERROR_ON_RENAME = 1025 +ER_ERROR_ON_WRITE = 1026 +ER_FILE_USED = 1027 +ER_FILSORT_ABORT = 1028 +ER_FORM_NOT_FOUND = 1029 +ER_GET_ERRNO = 1030 +ER_ILLEGAL_HA = 1031 +ER_KEY_NOT_FOUND = 1032 +ER_NOT_FORM_FILE = 1033 +ER_NOT_KEYFILE = 1034 +ER_OLD_KEYFILE = 1035 +ER_OPEN_AS_READONLY = 1036 +ER_OUTOFMEMORY = 1037 +ER_OUT_OF_SORTMEMORY = 1038 +ER_UNEXPECTED_EOF = 1039 +ER_CON_COUNT_ERROR = 1040 +ER_OUT_OF_RESOURCES = 1041 +ER_BAD_HOST_ERROR = 1042 +ER_HANDSHAKE_ERROR = 1043 +ER_DBACCESS_DENIED_ERROR = 1044 +ER_ACCESS_DENIED_ERROR = 1045 +ER_NO_DB_ERROR = 1046 +ER_UNKNOWN_COM_ERROR = 1047 +ER_BAD_NULL_ERROR = 1048 +ER_BAD_DB_ERROR = 1049 +ER_TABLE_EXISTS_ERROR = 1050 +ER_BAD_TABLE_ERROR = 1051 +ER_NON_UNIQ_ERROR = 1052 +ER_SERVER_SHUTDOWN = 1053 +ER_BAD_FIELD_ERROR = 1054 +ER_WRONG_FIELD_WITH_GROUP = 1055 +ER_WRONG_GROUP_FIELD = 1056 +ER_WRONG_SUM_SELECT = 1057 +ER_WRONG_VALUE_COUNT = 1058 +ER_TOO_LONG_IDENT = 1059 +ER_DUP_FIELDNAME = 1060 +ER_DUP_KEYNAME = 1061 +ER_DUP_ENTRY = 1062 +ER_WRONG_FIELD_SPEC = 1063 +ER_PARSE_ERROR = 1064 +ER_EMPTY_QUERY = 1065 +ER_NONUNIQ_TABLE = 1066 +ER_INVALID_DEFAULT = 1067 +ER_MULTIPLE_PRI_KEY = 1068 +ER_TOO_MANY_KEYS = 1069 +ER_TOO_MANY_KEY_PARTS = 1070 +ER_TOO_LONG_KEY = 1071 +ER_KEY_COLUMN_DOES_NOT_EXITS = 1072 +ER_BLOB_USED_AS_KEY = 1073 +ER_TOO_BIG_FIELDLENGTH = 1074 +ER_WRONG_AUTO_KEY = 1075 +ER_READY = 1076 +ER_NORMAL_SHUTDOWN = 1077 +ER_GOT_SIGNAL = 1078 +ER_SHUTDOWN_COMPLETE = 1079 +ER_FORCING_CLOSE = 1080 +ER_IPSOCK_ERROR = 1081 +ER_NO_SUCH_INDEX = 1082 +ER_WRONG_FIELD_TERMINATORS = 1083 +ER_BLOBS_AND_NO_TERMINATED = 1084 +ER_TEXTFILE_NOT_READABLE = 1085 +ER_FILE_EXISTS_ERROR = 1086 +ER_LOAD_INFO = 1087 +ER_ALTER_INFO = 1088 +ER_WRONG_SUB_KEY = 1089 +ER_CANT_REMOVE_ALL_FIELDS = 1090 +ER_CANT_DROP_FIELD_OR_KEY = 1091 +ER_INSERT_INFO = 1092 +ER_UPDATE_TABLE_USED = 1093 +ER_NO_SUCH_THREAD = 1094 +ER_KILL_DENIED_ERROR = 1095 +ER_NO_TABLES_USED = 1096 +ER_TOO_BIG_SET = 1097 +ER_NO_UNIQUE_LOGFILE = 1098 +ER_TABLE_NOT_LOCKED_FOR_WRITE = 1099 +ER_TABLE_NOT_LOCKED = 1100 +ER_BLOB_CANT_HAVE_DEFAULT = 1101 +ER_WRONG_DB_NAME = 1102 +ER_WRONG_TABLE_NAME = 1103 +ER_TOO_BIG_SELECT = 1104 +ER_UNKNOWN_ERROR = 1105 +ER_UNKNOWN_PROCEDURE = 1106 +ER_WRONG_PARAMCOUNT_TO_PROCEDURE = 1107 +ER_WRONG_PARAMETERS_TO_PROCEDURE = 1108 +ER_UNKNOWN_TABLE = 1109 +ER_FIELD_SPECIFIED_TWICE = 1110 +ER_INVALID_GROUP_FUNC_USE = 1111 +ER_UNSUPPORTED_EXTENSION = 1112 +ER_TABLE_MUST_HAVE_COLUMNS = 1113 +ER_RECORD_FILE_FULL = 1114 +ER_UNKNOWN_CHARACTER_SET = 1115 +ER_TOO_MANY_TABLES = 1116 +ER_TOO_MANY_FIELDS = 1117 +ER_TOO_BIG_ROWSIZE = 1118 +ER_STACK_OVERRUN = 1119 +ER_WRONG_OUTER_JOIN = 1120 +ER_NULL_COLUMN_IN_INDEX = 1121 +ER_CANT_FIND_UDF = 1122 +ER_CANT_INITIALIZE_UDF = 1123 +ER_UDF_NO_PATHS = 1124 +ER_UDF_EXISTS = 1125 +ER_CANT_OPEN_LIBRARY = 1126 +ER_CANT_FIND_DL_ENTRY = 1127 +ER_FUNCTION_NOT_DEFINED = 1128 +ER_HOST_IS_BLOCKED = 1129 +ER_HOST_NOT_PRIVILEGED = 1130 +ER_PASSWORD_ANONYMOUS_USER = 1131 +ER_PASSWORD_NOT_ALLOWED = 1132 +ER_PASSWORD_NO_MATCH = 1133 +ER_UPDATE_INFO = 1134 +ER_CANT_CREATE_THREAD = 1135 +ER_WRONG_VALUE_COUNT_ON_ROW = 1136 +ER_CANT_REOPEN_TABLE = 1137 +ER_INVALID_USE_OF_NULL = 1138 +ER_REGEXP_ERROR = 1139 +ER_MIX_OF_GROUP_FUNC_AND_FIELDS = 1140 +ER_NONEXISTING_GRANT = 1141 +ER_TABLEACCESS_DENIED_ERROR = 1142 +ER_COLUMNACCESS_DENIED_ERROR = 1143 +ER_ILLEGAL_GRANT_FOR_TABLE = 1144 +ER_GRANT_WRONG_HOST_OR_USER = 1145 +ER_NO_SUCH_TABLE = 1146 +ER_NONEXISTING_TABLE_GRANT = 1147 +ER_NOT_ALLOWED_COMMAND = 1148 +ER_SYNTAX_ERROR = 1149 +ER_UNUSED1 = 1150 +ER_UNUSED2 = 1151 +ER_ABORTING_CONNECTION = 1152 +ER_NET_PACKET_TOO_LARGE = 1153 +ER_NET_READ_ERROR_FROM_PIPE = 1154 +ER_NET_FCNTL_ERROR = 1155 +ER_NET_PACKETS_OUT_OF_ORDER = 1156 +ER_NET_UNCOMPRESS_ERROR = 1157 +ER_NET_READ_ERROR = 1158 +ER_NET_READ_INTERRUPTED = 1159 +ER_NET_ERROR_ON_WRITE = 1160 +ER_NET_WRITE_INTERRUPTED = 1161 +ER_TOO_LONG_STRING = 1162 +ER_TABLE_CANT_HANDLE_BLOB = 1163 +ER_TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164 +ER_UNUSED3 = 1165 +ER_WRONG_COLUMN_NAME = 1166 +ER_WRONG_KEY_COLUMN = 1167 +ER_WRONG_MRG_TABLE = 1168 +ER_DUP_UNIQUE = 1169 +ER_BLOB_KEY_WITHOUT_LENGTH = 1170 +ER_PRIMARY_CANT_HAVE_NULL = 1171 +ER_TOO_MANY_ROWS = 1172 +ER_REQUIRES_PRIMARY_KEY = 1173 +ER_NO_RAID_COMPILED = 1174 +ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175 +ER_KEY_DOES_NOT_EXITS = 1176 +ER_CHECK_NO_SUCH_TABLE = 1177 +ER_CHECK_NOT_IMPLEMENTED = 1178 +ER_CANT_DO_THIS_DURING_AN_TRANSACTION = 1179 +ER_ERROR_DURING_COMMIT = 1180 +ER_ERROR_DURING_ROLLBACK = 1181 +ER_ERROR_DURING_FLUSH_LOGS = 1182 +ER_ERROR_DURING_CHECKPOINT = 1183 +ER_NEW_ABORTING_CONNECTION = 1184 +ER_DUMP_NOT_IMPLEMENTED = 1185 +ER_FLUSH_MASTER_BINLOG_CLOSED = 1186 +ER_INDEX_REBUILD = 1187 +ER_MASTER = 1188 +ER_MASTER_NET_READ = 1189 +ER_MASTER_NET_WRITE = 1190 +ER_FT_MATCHING_KEY_NOT_FOUND = 1191 +ER_LOCK_OR_ACTIVE_TRANSACTION = 1192 +ER_UNKNOWN_SYSTEM_VARIABLE = 1193 +ER_CRASHED_ON_USAGE = 1194 +ER_CRASHED_ON_REPAIR = 1195 +ER_WARNING_NOT_COMPLETE_ROLLBACK = 1196 +ER_TRANS_CACHE_FULL = 1197 +ER_SLAVE_MUST_STOP = 1198 +ER_SLAVE_NOT_RUNNING = 1199 +ER_BAD_SLAVE = 1200 +ER_MASTER_INFO = 1201 +ER_SLAVE_THREAD = 1202 +ER_TOO_MANY_USER_CONNECTIONS = 1203 +ER_SET_CONSTANTS_ONLY = 1204 +ER_LOCK_WAIT_TIMEOUT = 1205 +ER_LOCK_TABLE_FULL = 1206 +ER_READ_ONLY_TRANSACTION = 1207 +ER_DROP_DB_WITH_READ_LOCK = 1208 +ER_CREATE_DB_WITH_READ_LOCK = 1209 +ER_WRONG_ARGUMENTS = 1210 +ER_NO_PERMISSION_TO_CREATE_USER = 1211 +ER_UNION_TABLES_IN_DIFFERENT_DIR = 1212 +ER_LOCK_DEADLOCK = 1213 +ER_TABLE_CANT_HANDLE_FT = 1214 +ER_CANNOT_ADD_FOREIGN = 1215 +ER_NO_REFERENCED_ROW = 1216 +ER_ROW_IS_REFERENCED = 1217 +ER_CONNECT_TO_MASTER = 1218 +ER_QUERY_ON_MASTER = 1219 +ER_ERROR_WHEN_EXECUTING_COMMAND = 1220 +ER_WRONG_USAGE = 1221 +ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222 +ER_CANT_UPDATE_WITH_READLOCK = 1223 +ER_MIXING_NOT_ALLOWED = 1224 +ER_DUP_ARGUMENT = 1225 +ER_USER_LIMIT_REACHED = 1226 +ER_SPECIFIC_ACCESS_DENIED_ERROR = 1227 +ER_LOCAL_VARIABLE = 1228 +ER_GLOBAL_VARIABLE = 1229 +ER_NO_DEFAULT = 1230 +ER_WRONG_VALUE_FOR_VAR = 1231 +ER_WRONG_TYPE_FOR_VAR = 1232 +ER_VAR_CANT_BE_READ = 1233 +ER_CANT_USE_OPTION_HERE = 1234 +ER_NOT_SUPPORTED_YET = 1235 +ER_MASTER_FATAL_ERROR_READING_BINLOG = 1236 +ER_SLAVE_IGNORED_TABLE = 1237 +ER_INCORRECT_GLOBAL_LOCAL_VAR = 1238 +ER_WRONG_FK_DEF = 1239 +ER_KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240 +ER_OPERAND_COLUMNS = 1241 +ER_SUBQUERY_NO_1_ROW = 1242 +ER_UNKNOWN_STMT_HANDLER = 1243 +ER_CORRUPT_HELP_DB = 1244 +ER_CYCLIC_REFERENCE = 1245 +ER_AUTO_CONVERT = 1246 +ER_ILLEGAL_REFERENCE = 1247 +ER_DERIVED_MUST_HAVE_ALIAS = 1248 +ER_SELECT_REDUCED = 1249 +ER_TABLENAME_NOT_ALLOWED_HERE = 1250 +ER_NOT_SUPPORTED_AUTH_MODE = 1251 +ER_SPATIAL_CANT_HAVE_NULL = 1252 +ER_COLLATION_CHARSET_MISMATCH = 1253 +ER_SLAVE_WAS_RUNNING = 1254 +ER_SLAVE_WAS_NOT_RUNNING = 1255 +ER_TOO_BIG_FOR_UNCOMPRESS = 1256 +ER_ZLIB_Z_MEM_ERROR = 1257 +ER_ZLIB_Z_BUF_ERROR = 1258 +ER_ZLIB_Z_DATA_ERROR = 1259 +ER_CUT_VALUE_GROUP_CONCAT = 1260 +ER_WARN_TOO_FEW_RECORDS = 1261 +ER_WARN_TOO_MANY_RECORDS = 1262 +ER_WARN_NULL_TO_NOTNULL = 1263 +ER_WARN_DATA_OUT_OF_RANGE = 1264 +WARN_DATA_TRUNCATED = 1265 +ER_WARN_USING_OTHER_HANDLER = 1266 +ER_CANT_AGGREGATE_2COLLATIONS = 1267 +ER_DROP_USER = 1268 +ER_REVOKE_GRANTS = 1269 +ER_CANT_AGGREGATE_3COLLATIONS = 1270 +ER_CANT_AGGREGATE_NCOLLATIONS = 1271 +ER_VARIABLE_IS_NOT_STRUCT = 1272 +ER_UNKNOWN_COLLATION = 1273 +ER_SLAVE_IGNORED_SSL_PARAMS = 1274 +ER_SERVER_IS_IN_SECURE_AUTH_MODE = 1275 +ER_WARN_FIELD_RESOLVED = 1276 +ER_BAD_SLAVE_UNTIL_COND = 1277 +ER_MISSING_SKIP_SLAVE = 1278 +ER_UNTIL_COND_IGNORED = 1279 +ER_WRONG_NAME_FOR_INDEX = 1280 +ER_WRONG_NAME_FOR_CATALOG = 1281 +ER_WARN_QC_RESIZE = 1282 +ER_BAD_FT_COLUMN = 1283 +ER_UNKNOWN_KEY_CACHE = 1284 +ER_WARN_HOSTNAME_WONT_WORK = 1285 +ER_UNKNOWN_STORAGE_ENGINE = 1286 +ER_WARN_DEPRECATED_SYNTAX = 1287 +ER_NON_UPDATABLE_TABLE = 1288 +ER_FEATURE_DISABLED = 1289 +ER_OPTION_PREVENTS_STATEMENT = 1290 +ER_DUPLICATED_VALUE_IN_TYPE = 1291 +ER_TRUNCATED_WRONG_VALUE = 1292 +ER_TOO_MUCH_AUTO_TIMESTAMP_COLS = 1293 +ER_INVALID_ON_UPDATE = 1294 +ER_UNSUPPORTED_PS = 1295 +ER_GET_ERRMSG = 1296 +ER_GET_TEMPORARY_ERRMSG = 1297 +ER_UNKNOWN_TIME_ZONE = 1298 +ER_WARN_INVALID_TIMESTAMP = 1299 +ER_INVALID_CHARACTER_STRING = 1300 +ER_WARN_ALLOWED_PACKET_OVERFLOWED = 1301 +ER_CONFLICTING_DECLARATIONS = 1302 +ER_SP_NO_RECURSIVE_CREATE = 1303 +ER_SP_ALREADY_EXISTS = 1304 +ER_SP_DOES_NOT_EXIST = 1305 +ER_SP_DROP_FAILED = 1306 +ER_SP_STORE_FAILED = 1307 +ER_SP_LILABEL_MISMATCH = 1308 +ER_SP_LABEL_REDEFINE = 1309 +ER_SP_LABEL_MISMATCH = 1310 +ER_SP_UNINIT_VAR = 1311 +ER_SP_BADSELECT = 1312 +ER_SP_BADRETURN = 1313 +ER_SP_BADSTATEMENT = 1314 +ER_UPDATE_LOG_DEPRECATED_IGNORED = 1315 +ER_UPDATE_LOG_DEPRECATED_TRANSLATED = 1316 +ER_QUERY_INTERRUPTED = 1317 +ER_SP_WRONG_NO_OF_ARGS = 1318 +ER_SP_COND_MISMATCH = 1319 +ER_SP_NORETURN = 1320 +ER_SP_NORETURNEND = 1321 +ER_SP_BAD_CURSOR_QUERY = 1322 +ER_SP_BAD_CURSOR_SELECT = 1323 +ER_SP_CURSOR_MISMATCH = 1324 +ER_SP_CURSOR_ALREADY_OPEN = 1325 +ER_SP_CURSOR_NOT_OPEN = 1326 +ER_SP_UNDECLARED_VAR = 1327 +ER_SP_WRONG_NO_OF_FETCH_ARGS = 1328 +ER_SP_FETCH_NO_DATA = 1329 +ER_SP_DUP_PARAM = 1330 +ER_SP_DUP_VAR = 1331 +ER_SP_DUP_COND = 1332 +ER_SP_DUP_CURS = 1333 +ER_SP_CANT_ALTER = 1334 +ER_SP_SUBSELECT_NYI = 1335 +ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336 +ER_SP_VARCOND_AFTER_CURSHNDLR = 1337 +ER_SP_CURSOR_AFTER_HANDLER = 1338 +ER_SP_CASE_NOT_FOUND = 1339 +ER_FPARSER_TOO_BIG_FILE = 1340 +ER_FPARSER_BAD_HEADER = 1341 +ER_FPARSER_EOF_IN_COMMENT = 1342 +ER_FPARSER_ERROR_IN_PARAMETER = 1343 +ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344 +ER_VIEW_NO_EXPLAIN = 1345 +ER_FRM_UNKNOWN_TYPE = 1346 +ER_WRONG_OBJECT = 1347 +ER_NONUPDATEABLE_COLUMN = 1348 +ER_VIEW_SELECT_DERIVED_UNUSED = 1349 +ER_VIEW_SELECT_CLAUSE = 1350 +ER_VIEW_SELECT_VARIABLE = 1351 +ER_VIEW_SELECT_TMPTABLE = 1352 +ER_VIEW_WRONG_LIST = 1353 +ER_WARN_VIEW_MERGE = 1354 +ER_WARN_VIEW_WITHOUT_KEY = 1355 +ER_VIEW_INVALID = 1356 +ER_SP_NO_DROP_SP = 1357 +ER_SP_GOTO_IN_HNDLR = 1358 +ER_TRG_ALREADY_EXISTS = 1359 +ER_TRG_DOES_NOT_EXIST = 1360 +ER_TRG_ON_VIEW_OR_TEMP_TABLE = 1361 +ER_TRG_CANT_CHANGE_ROW = 1362 +ER_TRG_NO_SUCH_ROW_IN_TRG = 1363 +ER_NO_DEFAULT_FOR_FIELD = 1364 +ER_DIVISION_BY_ZERO = 1365 +ER_TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366 +ER_ILLEGAL_VALUE_FOR_TYPE = 1367 +ER_VIEW_NONUPD_CHECK = 1368 +ER_VIEW_CHECK_FAILED = 1369 +ER_PROCACCESS_DENIED_ERROR = 1370 +ER_RELAY_LOG_FAIL = 1371 +ER_PASSWD_LENGTH = 1372 +ER_UNKNOWN_TARGET_BINLOG = 1373 +ER_IO_ERR_LOG_INDEX_READ = 1374 +ER_BINLOG_PURGE_PROHIBITED = 1375 +ER_FSEEK_FAIL = 1376 +ER_BINLOG_PURGE_FATAL_ERR = 1377 +ER_LOG_IN_USE = 1378 +ER_LOG_PURGE_UNKNOWN_ERR = 1379 +ER_RELAY_LOG_INIT = 1380 +ER_NO_BINARY_LOGGING = 1381 +ER_RESERVED_SYNTAX = 1382 +ER_WSAS_FAILED = 1383 +ER_DIFF_GROUPS_PROC = 1384 +ER_NO_GROUP_FOR_PROC = 1385 +ER_ORDER_WITH_PROC = 1386 +ER_LOGGING_PROHIBIT_CHANGING_OF = 1387 +ER_NO_FILE_MAPPING = 1388 +ER_WRONG_MAGIC = 1389 +ER_PS_MANY_PARAM = 1390 +ER_KEY_PART_0 = 1391 +ER_VIEW_CHECKSUM = 1392 +ER_VIEW_MULTIUPDATE = 1393 +ER_VIEW_NO_INSERT_FIELD_LIST = 1394 +ER_VIEW_DELETE_MERGE_VIEW = 1395 +ER_CANNOT_USER = 1396 +ER_XAER_NOTA = 1397 +ER_XAER_INVAL = 1398 +ER_XAER_RMFAIL = 1399 +ER_XAER_OUTSIDE = 1400 +ER_XAER_RMERR = 1401 +ER_XA_RBROLLBACK = 1402 +ER_NONEXISTING_PROC_GRANT = 1403 +ER_PROC_AUTO_GRANT_FAIL = 1404 +ER_PROC_AUTO_REVOKE_FAIL = 1405 +ER_DATA_TOO_LONG = 1406 +ER_SP_BAD_SQLSTATE = 1407 +ER_STARTUP = 1408 +ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409 +ER_CANT_CREATE_USER_WITH_GRANT = 1410 +ER_WRONG_VALUE_FOR_TYPE = 1411 +ER_TABLE_DEF_CHANGED = 1412 +ER_SP_DUP_HANDLER = 1413 +ER_SP_NOT_VAR_ARG = 1414 +ER_SP_NO_RETSET = 1415 +ER_CANT_CREATE_GEOMETRY_OBJECT = 1416 +ER_FAILED_ROUTINE_BREAK_BINLOG = 1417 +ER_BINLOG_UNSAFE_ROUTINE = 1418 +ER_BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419 +ER_EXEC_STMT_WITH_OPEN_CURSOR = 1420 +ER_STMT_HAS_NO_OPEN_CURSOR = 1421 +ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422 +ER_NO_DEFAULT_FOR_VIEW_FIELD = 1423 +ER_SP_NO_RECURSION = 1424 +ER_TOO_BIG_SCALE = 1425 +ER_TOO_BIG_PRECISION = 1426 +ER_M_BIGGER_THAN_D = 1427 +ER_WRONG_LOCK_OF_SYSTEM_TABLE = 1428 +ER_CONNECT_TO_FOREIGN_DATA_SOURCE = 1429 +ER_QUERY_ON_FOREIGN_DATA_SOURCE = 1430 +ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431 +ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432 +ER_FOREIGN_DATA_STRING_INVALID = 1433 +ER_CANT_CREATE_FEDERATED_TABLE = 1434 +ER_TRG_IN_WRONG_SCHEMA = 1435 +ER_STACK_OVERRUN_NEED_MORE = 1436 +ER_TOO_LONG_BODY = 1437 +ER_WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438 +ER_TOO_BIG_DISPLAYWIDTH = 1439 +ER_XAER_DUPID = 1440 +ER_DATETIME_FUNCTION_OVERFLOW = 1441 +ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442 +ER_VIEW_PREVENT_UPDATE = 1443 +ER_PS_NO_RECURSION = 1444 +ER_SP_CANT_SET_AUTOCOMMIT = 1445 +ER_MALFORMED_DEFINER = 1446 +ER_VIEW_FRM_NO_USER = 1447 +ER_VIEW_OTHER_USER = 1448 +ER_NO_SUCH_USER = 1449 +ER_FORBID_SCHEMA_CHANGE = 1450 +ER_ROW_IS_REFERENCED_2 = 1451 +ER_NO_REFERENCED_ROW_2 = 1452 +ER_SP_BAD_VAR_SHADOW = 1453 +ER_TRG_NO_DEFINER = 1454 +ER_OLD_FILE_FORMAT = 1455 +ER_SP_RECURSION_LIMIT = 1456 +ER_SP_PROC_TABLE_CORRUPT = 1457 +ER_SP_WRONG_NAME = 1458 +ER_TABLE_NEEDS_UPGRADE = 1459 +ER_SP_NO_AGGREGATE = 1460 +ER_MAX_PREPARED_STMT_COUNT_REACHED = 1461 +ER_VIEW_RECURSIVE = 1462 +ER_NON_GROUPING_FIELD_USED = 1463 +ER_TABLE_CANT_HANDLE_SPKEYS = 1464 +ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA = 1465 +ER_REMOVED_SPACES = 1466 +ER_AUTOINC_READ_FAILED = 1467 +ER_USERNAME = 1468 +ER_HOSTNAME = 1469 +ER_WRONG_STRING_LENGTH = 1470 +ER_NON_INSERTABLE_TABLE = 1471 +ER_ADMIN_WRONG_MRG_TABLE = 1472 +ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT = 1473 +ER_NAME_BECOMES_EMPTY = 1474 +ER_AMBIGUOUS_FIELD_TERM = 1475 +ER_FOREIGN_SERVER_EXISTS = 1476 +ER_FOREIGN_SERVER_DOESNT_EXIST = 1477 +ER_ILLEGAL_HA_CREATE_OPTION = 1478 +ER_PARTITION_REQUIRES_VALUES_ERROR = 1479 +ER_PARTITION_WRONG_VALUES_ERROR = 1480 +ER_PARTITION_MAXVALUE_ERROR = 1481 +ER_PARTITION_SUBPARTITION_ERROR = 1482 +ER_PARTITION_SUBPART_MIX_ERROR = 1483 +ER_PARTITION_WRONG_NO_PART_ERROR = 1484 +ER_PARTITION_WRONG_NO_SUBPART_ERROR = 1485 +ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR = 1486 +ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR = 1487 +ER_FIELD_NOT_FOUND_PART_ERROR = 1488 +ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR = 1489 +ER_INCONSISTENT_PARTITION_INFO_ERROR = 1490 +ER_PARTITION_FUNC_NOT_ALLOWED_ERROR = 1491 +ER_PARTITIONS_MUST_BE_DEFINED_ERROR = 1492 +ER_RANGE_NOT_INCREASING_ERROR = 1493 +ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR = 1494 +ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR = 1495 +ER_PARTITION_ENTRY_ERROR = 1496 +ER_MIX_HANDLER_ERROR = 1497 +ER_PARTITION_NOT_DEFINED_ERROR = 1498 +ER_TOO_MANY_PARTITIONS_ERROR = 1499 +ER_SUBPARTITION_ERROR = 1500 +ER_CANT_CREATE_HANDLER_FILE = 1501 +ER_BLOB_FIELD_IN_PART_FUNC_ERROR = 1502 +ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF = 1503 +ER_NO_PARTS_ERROR = 1504 +ER_PARTITION_MGMT_ON_NONPARTITIONED = 1505 +ER_FOREIGN_KEY_ON_PARTITIONED = 1506 +ER_DROP_PARTITION_NON_EXISTENT = 1507 +ER_DROP_LAST_PARTITION = 1508 +ER_COALESCE_ONLY_ON_HASH_PARTITION = 1509 +ER_REORG_HASH_ONLY_ON_SAME_NO = 1510 +ER_REORG_NO_PARAM_ERROR = 1511 +ER_ONLY_ON_RANGE_LIST_PARTITION = 1512 +ER_ADD_PARTITION_SUBPART_ERROR = 1513 +ER_ADD_PARTITION_NO_NEW_PARTITION = 1514 +ER_COALESCE_PARTITION_NO_PARTITION = 1515 +ER_REORG_PARTITION_NOT_EXIST = 1516 +ER_SAME_NAME_PARTITION = 1517 +ER_NO_BINLOG_ERROR = 1518 +ER_CONSECUTIVE_REORG_PARTITIONS = 1519 +ER_REORG_OUTSIDE_RANGE = 1520 +ER_PARTITION_FUNCTION_FAILURE = 1521 +ER_PART_STATE_ERROR = 1522 +ER_LIMITED_PART_RANGE = 1523 +ER_PLUGIN_IS_NOT_LOADED = 1524 +ER_WRONG_VALUE = 1525 +ER_NO_PARTITION_FOR_GIVEN_VALUE = 1526 +ER_FILEGROUP_OPTION_ONLY_ONCE = 1527 +ER_CREATE_FILEGROUP_FAILED = 1528 +ER_DROP_FILEGROUP_FAILED = 1529 +ER_TABLESPACE_AUTO_EXTEND_ERROR = 1530 +ER_WRONG_SIZE_NUMBER = 1531 +ER_SIZE_OVERFLOW_ERROR = 1532 +ER_ALTER_FILEGROUP_FAILED = 1533 +ER_BINLOG_ROW_LOGGING_FAILED = 1534 +ER_BINLOG_ROW_WRONG_TABLE_DEF = 1535 +ER_BINLOG_ROW_RBR_TO_SBR = 1536 +ER_EVENT_ALREADY_EXISTS = 1537 +ER_EVENT_STORE_FAILED = 1538 +ER_EVENT_DOES_NOT_EXIST = 1539 +ER_EVENT_CANT_ALTER = 1540 +ER_EVENT_DROP_FAILED = 1541 +ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG = 1542 +ER_EVENT_ENDS_BEFORE_STARTS = 1543 +ER_EVENT_EXEC_TIME_IN_THE_PAST = 1544 +ER_EVENT_OPEN_TABLE_FAILED = 1545 +ER_EVENT_NEITHER_M_EXPR_NOR_M_AT = 1546 +ER_OBSOLETE_COL_COUNT_DOESNT_MATCH_CORRUPTED = 1547 +ER_OBSOLETE_CANNOT_LOAD_FROM_TABLE = 1548 +ER_EVENT_CANNOT_DELETE = 1549 +ER_EVENT_COMPILE_ERROR = 1550 +ER_EVENT_SAME_NAME = 1551 +ER_EVENT_DATA_TOO_LONG = 1552 +ER_DROP_INDEX_FK = 1553 +ER_WARN_DEPRECATED_SYNTAX_WITH_VER = 1554 +ER_CANT_WRITE_LOCK_LOG_TABLE = 1555 +ER_CANT_LOCK_LOG_TABLE = 1556 +ER_FOREIGN_DUPLICATE_KEY_OLD_UNUSED = 1557 +ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE = 1558 +ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR = 1559 +ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT = 1560 +ER_NDB_CANT_SWITCH_BINLOG_FORMAT = 1561 +ER_PARTITION_NO_TEMPORARY = 1562 +ER_PARTITION_CONST_DOMAIN_ERROR = 1563 +ER_PARTITION_FUNCTION_IS_NOT_ALLOWED = 1564 +ER_DDL_LOG_ERROR = 1565 +ER_NULL_IN_VALUES_LESS_THAN = 1566 +ER_WRONG_PARTITION_NAME = 1567 +ER_CANT_CHANGE_TX_CHARACTERISTICS = 1568 +ER_DUP_ENTRY_AUTOINCREMENT_CASE = 1569 +ER_EVENT_MODIFY_QUEUE_ERROR = 1570 +ER_EVENT_SET_VAR_ERROR = 1571 +ER_PARTITION_MERGE_ERROR = 1572 +ER_CANT_ACTIVATE_LOG = 1573 +ER_RBR_NOT_AVAILABLE = 1574 +ER_BASE64_DECODE_ERROR = 1575 +ER_EVENT_RECURSION_FORBIDDEN = 1576 +ER_EVENTS_DB_ERROR = 1577 +ER_ONLY_INTEGERS_ALLOWED = 1578 +ER_UNSUPORTED_LOG_ENGINE = 1579 +ER_BAD_LOG_STATEMENT = 1580 +ER_CANT_RENAME_LOG_TABLE = 1581 +ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT = 1582 +ER_WRONG_PARAMETERS_TO_NATIVE_FCT = 1583 +ER_WRONG_PARAMETERS_TO_STORED_FCT = 1584 +ER_NATIVE_FCT_NAME_COLLISION = 1585 +ER_DUP_ENTRY_WITH_KEY_NAME = 1586 +ER_BINLOG_PURGE_EMFILE = 1587 +ER_EVENT_CANNOT_CREATE_IN_THE_PAST = 1588 +ER_EVENT_CANNOT_ALTER_IN_THE_PAST = 1589 +ER_SLAVE_INCIDENT = 1590 +ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT = 1591 +ER_BINLOG_UNSAFE_STATEMENT = 1592 +ER_SLAVE_FATAL_ERROR = 1593 +ER_SLAVE_RELAY_LOG_READ_FAILURE = 1594 +ER_SLAVE_RELAY_LOG_WRITE_FAILURE = 1595 +ER_SLAVE_CREATE_EVENT_FAILURE = 1596 +ER_SLAVE_MASTER_COM_FAILURE = 1597 +ER_BINLOG_LOGGING_IMPOSSIBLE = 1598 +ER_VIEW_NO_CREATION_CTX = 1599 +ER_VIEW_INVALID_CREATION_CTX = 1600 +ER_SR_INVALID_CREATION_CTX = 1601 +ER_TRG_CORRUPTED_FILE = 1602 +ER_TRG_NO_CREATION_CTX = 1603 +ER_TRG_INVALID_CREATION_CTX = 1604 +ER_EVENT_INVALID_CREATION_CTX = 1605 +ER_TRG_CANT_OPEN_TABLE = 1606 +ER_CANT_CREATE_SROUTINE = 1607 +ER_NEVER_USED = 1608 +ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT = 1609 +ER_SLAVE_CORRUPT_EVENT = 1610 +ER_LOAD_DATA_INVALID_COLUMN_UNUSED = 1611 +ER_LOG_PURGE_NO_FILE = 1612 +ER_XA_RBTIMEOUT = 1613 +ER_XA_RBDEADLOCK = 1614 +ER_NEED_REPREPARE = 1615 +ER_DELAYED_NOT_SUPPORTED = 1616 +WARN_NO_MASTER_INFO = 1617 +WARN_OPTION_IGNORED = 1618 +ER_PLUGIN_DELETE_BUILTIN = 1619 +WARN_PLUGIN_BUSY = 1620 +ER_VARIABLE_IS_READONLY = 1621 +ER_WARN_ENGINE_TRANSACTION_ROLLBACK = 1622 +ER_SLAVE_HEARTBEAT_FAILURE = 1623 +ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE = 1624 +ER_NDB_REPLICATION_SCHEMA_ERROR = 1625 +ER_CONFLICT_FN_PARSE_ERROR = 1626 +ER_EXCEPTIONS_WRITE_ERROR = 1627 +ER_TOO_LONG_TABLE_COMMENT = 1628 +ER_TOO_LONG_FIELD_COMMENT = 1629 +ER_FUNC_INEXISTENT_NAME_COLLISION = 1630 +ER_DATABASE_NAME = 1631 +ER_TABLE_NAME = 1632 +ER_PARTITION_NAME = 1633 +ER_SUBPARTITION_NAME = 1634 +ER_TEMPORARY_NAME = 1635 +ER_RENAMED_NAME = 1636 +ER_TOO_MANY_CONCURRENT_TRXS = 1637 +WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED = 1638 +ER_DEBUG_SYNC_TIMEOUT = 1639 +ER_DEBUG_SYNC_HIT_LIMIT = 1640 +ER_DUP_SIGNAL_SET = 1641 +ER_SIGNAL_WARN = 1642 +ER_SIGNAL_NOT_FOUND = 1643 +ER_SIGNAL_EXCEPTION = 1644 +ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER = 1645 +ER_SIGNAL_BAD_CONDITION_TYPE = 1646 +WARN_COND_ITEM_TRUNCATED = 1647 +ER_COND_ITEM_TOO_LONG = 1648 +ER_UNKNOWN_LOCALE = 1649 +ER_SLAVE_IGNORE_SERVER_IDS = 1650 +ER_QUERY_CACHE_DISABLED = 1651 +ER_SAME_NAME_PARTITION_FIELD = 1652 +ER_PARTITION_COLUMN_LIST_ERROR = 1653 +ER_WRONG_TYPE_COLUMN_VALUE_ERROR = 1654 +ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR = 1655 +ER_MAXVALUE_IN_VALUES_IN = 1656 +ER_TOO_MANY_VALUES_ERROR = 1657 +ER_ROW_SINGLE_PARTITION_FIELD_ERROR = 1658 +ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD = 1659 +ER_PARTITION_FIELDS_TOO_LONG = 1660 +ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE = 1661 +ER_BINLOG_ROW_MODE_AND_STMT_ENGINE = 1662 +ER_BINLOG_UNSAFE_AND_STMT_ENGINE = 1663 +ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE = 1664 +ER_BINLOG_STMT_MODE_AND_ROW_ENGINE = 1665 +ER_BINLOG_ROW_INJECTION_AND_STMT_MODE = 1666 +ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE = 1667 +ER_BINLOG_UNSAFE_LIMIT = 1668 +ER_UNUSED4 = 1669 +ER_BINLOG_UNSAFE_SYSTEM_TABLE = 1670 +ER_BINLOG_UNSAFE_AUTOINC_COLUMNS = 1671 +ER_BINLOG_UNSAFE_UDF = 1672 +ER_BINLOG_UNSAFE_SYSTEM_VARIABLE = 1673 +ER_BINLOG_UNSAFE_SYSTEM_FUNCTION = 1674 +ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS = 1675 +ER_MESSAGE_AND_STATEMENT = 1676 +ER_SLAVE_CONVERSION_FAILED = 1677 +ER_SLAVE_CANT_CREATE_CONVERSION = 1678 +ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT = 1679 +ER_PATH_LENGTH = 1680 +ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT = 1681 +ER_WRONG_NATIVE_TABLE_STRUCTURE = 1682 +ER_WRONG_PERFSCHEMA_USAGE = 1683 +ER_WARN_I_S_SKIPPED_TABLE = 1684 +ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT = 1685 +ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT = 1686 +ER_SPATIAL_MUST_HAVE_GEOM_COL = 1687 +ER_TOO_LONG_INDEX_COMMENT = 1688 +ER_LOCK_ABORTED = 1689 +ER_DATA_OUT_OF_RANGE = 1690 +ER_WRONG_SPVAR_TYPE_IN_LIMIT = 1691 +ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE = 1692 +ER_BINLOG_UNSAFE_MIXED_STATEMENT = 1693 +ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN = 1694 +ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN = 1695 +ER_FAILED_READ_FROM_PAR_FILE = 1696 +ER_VALUES_IS_NOT_INT_TYPE_ERROR = 1697 +ER_ACCESS_DENIED_NO_PASSWORD_ERROR = 1698 +ER_SET_PASSWORD_AUTH_PLUGIN = 1699 +ER_GRANT_PLUGIN_USER_EXISTS = 1700 +ER_TRUNCATE_ILLEGAL_FK = 1701 +ER_PLUGIN_IS_PERMANENT = 1702 +ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN = 1703 +ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX = 1704 +ER_STMT_CACHE_FULL = 1705 +ER_MULTI_UPDATE_KEY_CONFLICT = 1706 +ER_TABLE_NEEDS_REBUILD = 1707 +WARN_OPTION_BELOW_LIMIT = 1708 +ER_INDEX_COLUMN_TOO_LONG = 1709 +ER_ERROR_IN_TRIGGER_BODY = 1710 +ER_ERROR_IN_UNKNOWN_TRIGGER_BODY = 1711 +ER_INDEX_CORRUPT = 1712 +ER_UNDO_RECORD_TOO_BIG = 1713 +ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT = 1714 +ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE = 1715 +ER_BINLOG_UNSAFE_REPLACE_SELECT = 1716 +ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT = 1717 +ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT = 1718 +ER_BINLOG_UNSAFE_UPDATE_IGNORE = 1719 +ER_PLUGIN_NO_UNINSTALL = 1720 +ER_PLUGIN_NO_INSTALL = 1721 +ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT = 1722 +ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC = 1723 +ER_BINLOG_UNSAFE_INSERT_TWO_KEYS = 1724 +ER_TABLE_IN_FK_CHECK = 1725 +ER_UNSUPPORTED_ENGINE = 1726 +ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST = 1727 +ER_CANNOT_LOAD_FROM_TABLE_V2 = 1728 +ER_MASTER_DELAY_VALUE_OUT_OF_RANGE = 1729 +ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT = 1730 +ER_PARTITION_EXCHANGE_DIFFERENT_OPTION = 1731 +ER_PARTITION_EXCHANGE_PART_TABLE = 1732 +ER_PARTITION_EXCHANGE_TEMP_TABLE = 1733 +ER_PARTITION_INSTEAD_OF_SUBPARTITION = 1734 +ER_UNKNOWN_PARTITION = 1735 +ER_TABLES_DIFFERENT_METADATA = 1736 +ER_ROW_DOES_NOT_MATCH_PARTITION = 1737 +ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX = 1738 +ER_WARN_INDEX_NOT_APPLICABLE = 1739 +ER_PARTITION_EXCHANGE_FOREIGN_KEY = 1740 +ER_NO_SUCH_KEY_VALUE = 1741 +ER_RPL_INFO_DATA_TOO_LONG = 1742 +ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE = 1743 +ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE = 1744 +ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX = 1745 +ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT = 1746 +ER_PARTITION_CLAUSE_ON_NONPARTITIONED = 1747 +ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET = 1748 +ER_NO_SUCH_PARTITION__UNUSED = 1749 +ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE = 1750 +ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE = 1751 +ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE = 1752 +ER_MTS_FEATURE_IS_NOT_SUPPORTED = 1753 +ER_MTS_UPDATED_DBS_GREATER_MAX = 1754 +ER_MTS_CANT_PARALLEL = 1755 +ER_MTS_INCONSISTENT_DATA = 1756 +ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING = 1757 +ER_DA_INVALID_CONDITION_NUMBER = 1758 +ER_INSECURE_PLAIN_TEXT = 1759 +ER_INSECURE_CHANGE_MASTER = 1760 +ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO = 1761 +ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO = 1762 +ER_SQLTHREAD_WITH_SECURE_SLAVE = 1763 +ER_TABLE_HAS_NO_FT = 1764 +ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER = 1765 +ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION = 1766 +ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST = 1767 +ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION = 1768 +ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION = 1769 +ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL = 1770 +ER_SKIPPING_LOGGED_TRANSACTION = 1771 +ER_MALFORMED_GTID_SET_SPECIFICATION = 1772 +ER_MALFORMED_GTID_SET_ENCODING = 1773 +ER_MALFORMED_GTID_SPECIFICATION = 1774 +ER_GNO_EXHAUSTED = 1775 +ER_BAD_SLAVE_AUTO_POSITION = 1776 +ER_AUTO_POSITION_REQUIRES_GTID_MODE_NOT_OFF = 1777 +ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET = 1778 +ER_GTID_MODE_ON_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON = 1779 +ER_GTID_MODE_REQUIRES_BINLOG = 1780 +ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF = 1781 +ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON = 1782 +ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF = 1783 +ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF__UNUSED = 1784 +ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE = 1785 +ER_GTID_UNSAFE_CREATE_SELECT = 1786 +ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION = 1787 +ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME = 1788 +ER_MASTER_HAS_PURGED_REQUIRED_GTIDS = 1789 +ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID = 1790 +ER_UNKNOWN_EXPLAIN_FORMAT = 1791 +ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION = 1792 +ER_TOO_LONG_TABLE_PARTITION_COMMENT = 1793 +ER_SLAVE_CONFIGURATION = 1794 +ER_INNODB_FT_LIMIT = 1795 +ER_INNODB_NO_FT_TEMP_TABLE = 1796 +ER_INNODB_FT_WRONG_DOCID_COLUMN = 1797 +ER_INNODB_FT_WRONG_DOCID_INDEX = 1798 +ER_INNODB_ONLINE_LOG_TOO_BIG = 1799 +ER_UNKNOWN_ALTER_ALGORITHM = 1800 +ER_UNKNOWN_ALTER_LOCK = 1801 +ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS = 1802 +ER_MTS_RECOVERY_FAILURE = 1803 +ER_MTS_RESET_WORKERS = 1804 +ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2 = 1805 +ER_SLAVE_SILENT_RETRY_TRANSACTION = 1806 +ER_DISCARD_FK_CHECKS_RUNNING = 1807 +ER_TABLE_SCHEMA_MISMATCH = 1808 +ER_TABLE_IN_SYSTEM_TABLESPACE = 1809 +ER_IO_READ_ERROR = 1810 +ER_IO_WRITE_ERROR = 1811 +ER_TABLESPACE_MISSING = 1812 +ER_TABLESPACE_EXISTS = 1813 +ER_TABLESPACE_DISCARDED = 1814 +ER_INTERNAL_ERROR = 1815 +ER_INNODB_IMPORT_ERROR = 1816 +ER_INNODB_INDEX_CORRUPT = 1817 +ER_INVALID_YEAR_COLUMN_LENGTH = 1818 +ER_NOT_VALID_PASSWORD = 1819 +ER_MUST_CHANGE_PASSWORD = 1820 +ER_FK_NO_INDEX_CHILD = 1821 +ER_FK_NO_INDEX_PARENT = 1822 +ER_FK_FAIL_ADD_SYSTEM = 1823 +ER_FK_CANNOT_OPEN_PARENT = 1824 +ER_FK_INCORRECT_OPTION = 1825 +ER_FK_DUP_NAME = 1826 +ER_PASSWORD_FORMAT = 1827 +ER_FK_COLUMN_CANNOT_DROP = 1828 +ER_FK_COLUMN_CANNOT_DROP_CHILD = 1829 +ER_FK_COLUMN_NOT_NULL = 1830 +ER_DUP_INDEX = 1831 +ER_FK_COLUMN_CANNOT_CHANGE = 1832 +ER_FK_COLUMN_CANNOT_CHANGE_CHILD = 1833 +ER_UNUSED5 = 1834 +ER_MALFORMED_PACKET = 1835 +ER_READ_ONLY_MODE = 1836 +ER_GTID_NEXT_TYPE_UNDEFINED_GROUP = 1837 +ER_VARIABLE_NOT_SETTABLE_IN_SP = 1838 +ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF = 1839 +ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY = 1840 +ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY = 1841 +ER_GTID_PURGED_WAS_CHANGED = 1842 +ER_GTID_EXECUTED_WAS_CHANGED = 1843 +ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES = 1844 +ER_ALTER_OPERATION_NOT_SUPPORTED = 1845 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON = 1846 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY = 1847 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION = 1848 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME = 1849 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE = 1850 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK = 1851 +ER_UNUSED6 = 1852 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK = 1853 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC = 1854 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS = 1855 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS = 1856 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS = 1857 +ER_SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE = 1858 +ER_DUP_UNKNOWN_IN_INDEX = 1859 +ER_IDENT_CAUSES_TOO_LONG_PATH = 1860 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL = 1861 +ER_MUST_CHANGE_PASSWORD_LOGIN = 1862 +ER_ROW_IN_WRONG_PARTITION = 1863 +ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX = 1864 +ER_INNODB_NO_FT_USES_PARSER = 1865 +ER_BINLOG_LOGICAL_CORRUPTION = 1866 +ER_WARN_PURGE_LOG_IN_USE = 1867 +ER_WARN_PURGE_LOG_IS_ACTIVE = 1868 +ER_AUTO_INCREMENT_CONFLICT = 1869 +WARN_ON_BLOCKHOLE_IN_RBR = 1870 +ER_SLAVE_MI_INIT_REPOSITORY = 1871 +ER_SLAVE_RLI_INIT_REPOSITORY = 1872 +ER_ACCESS_DENIED_CHANGE_USER_ERROR = 1873 +ER_INNODB_READ_ONLY = 1874 +ER_STOP_SLAVE_SQL_THREAD_TIMEOUT = 1875 +ER_STOP_SLAVE_IO_THREAD_TIMEOUT = 1876 +ER_TABLE_CORRUPT = 1877 +ER_TEMP_FILE_WRITE_FAILURE = 1878 +ER_INNODB_FT_AUX_NOT_HEX_ID = 1879 +ER_OLD_TEMPORALS_UPGRADED = 1880 +ER_INNODB_FORCED_RECOVERY = 1881 +ER_AES_INVALID_IV = 1882 +ER_PLUGIN_CANNOT_BE_UNINSTALLED = 1883 +ER_GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_GTID_GROUP = 1884 +ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER = 1885 +ER_FILE_CORRUPT = 3000 +ER_ERROR_ON_MASTER = 3001 +ER_INCONSISTENT_ERROR = 3002 +ER_STORAGE_ENGINE_NOT_LOADED = 3003 +ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER = 3004 +ER_WARN_LEGACY_SYNTAX_CONVERTED = 3005 +ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN = 3006 +ER_CANNOT_DISCARD_TEMPORARY_TABLE = 3007 +ER_FK_DEPTH_EXCEEDED = 3008 +ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2 = 3009 +ER_WARN_TRIGGER_DOESNT_HAVE_CREATED = 3010 +ER_REFERENCED_TRG_DOES_NOT_EXIST = 3011 +ER_EXPLAIN_NOT_SUPPORTED = 3012 +ER_INVALID_FIELD_SIZE = 3013 +ER_MISSING_HA_CREATE_OPTION = 3014 +ER_ENGINE_OUT_OF_MEMORY = 3015 +ER_PASSWORD_EXPIRE_ANONYMOUS_USER = 3016 +ER_SLAVE_SQL_THREAD_MUST_STOP = 3017 +ER_NO_FT_MATERIALIZED_SUBQUERY = 3018 +ER_INNODB_UNDO_LOG_FULL = 3019 +ER_INVALID_ARGUMENT_FOR_LOGARITHM = 3020 +ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP = 3021 +ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO = 3022 +ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS = 3023 +ER_QUERY_TIMEOUT = 3024 +ER_NON_RO_SELECT_DISABLE_TIMER = 3025 +ER_DUP_LIST_ENTRY = 3026 +ER_SQL_MODE_NO_EFFECT = 3027 +ER_AGGREGATE_ORDER_FOR_UNION = 3028 +ER_AGGREGATE_ORDER_NON_AGG_QUERY = 3029 +ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR = 3030 +ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER = 3031 +ER_SERVER_OFFLINE_MODE = 3032 +ER_GIS_DIFFERENT_SRIDS = 3033 +ER_GIS_UNSUPPORTED_ARGUMENT = 3034 +ER_GIS_UNKNOWN_ERROR = 3035 +ER_GIS_UNKNOWN_EXCEPTION = 3036 +ER_GIS_INVALID_DATA = 3037 +ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION = 3038 +ER_BOOST_GEOMETRY_CENTROID_EXCEPTION = 3039 +ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION = 3040 +ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION = 3041 +ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION = 3042 +ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION = 3043 +ER_STD_BAD_ALLOC_ERROR = 3044 +ER_STD_DOMAIN_ERROR = 3045 +ER_STD_LENGTH_ERROR = 3046 +ER_STD_INVALID_ARGUMENT = 3047 +ER_STD_OUT_OF_RANGE_ERROR = 3048 +ER_STD_OVERFLOW_ERROR = 3049 +ER_STD_RANGE_ERROR = 3050 +ER_STD_UNDERFLOW_ERROR = 3051 +ER_STD_LOGIC_ERROR = 3052 +ER_STD_RUNTIME_ERROR = 3053 +ER_STD_UNKNOWN_EXCEPTION = 3054 +ER_GIS_DATA_WRONG_ENDIANESS = 3055 +ER_CHANGE_MASTER_PASSWORD_LENGTH = 3056 +ER_USER_LOCK_WRONG_NAME = 3057 +ER_USER_LOCK_DEADLOCK = 3058 +ER_REPLACE_INACCESSIBLE_ROWS = 3059 +ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS = 3060 +ER_ILLEGAL_USER_VAR = 3061 +ER_GTID_MODE_OFF = 3062 +ER_UNSUPPORTED_BY_REPLICATION_THREAD = 3063 +ER_INCORRECT_TYPE = 3064 +ER_FIELD_IN_ORDER_NOT_SELECT = 3065 +ER_AGGREGATE_IN_ORDER_NOT_SELECT = 3066 +ER_INVALID_RPL_WILD_TABLE_FILTER_PATTERN = 3067 +ER_NET_OK_PACKET_TOO_LARGE = 3068 +ER_INVALID_JSON_DATA = 3069 +ER_INVALID_GEOJSON_MISSING_MEMBER = 3070 +ER_INVALID_GEOJSON_WRONG_TYPE = 3071 +ER_INVALID_GEOJSON_UNSPECIFIED = 3072 +ER_DIMENSION_UNSUPPORTED = 3073 +ER_SLAVE_CHANNEL_DOES_NOT_EXIST = 3074 +ER_SLAVE_MULTIPLE_CHANNELS_HOST_PORT = 3075 +ER_SLAVE_CHANNEL_NAME_INVALID_OR_TOO_LONG = 3076 +ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY = 3077 +ER_SLAVE_CHANNEL_DELETE = 3078 +ER_SLAVE_MULTIPLE_CHANNELS_CMD = 3079 +ER_SLAVE_MAX_CHANNELS_EXCEEDED = 3080 +ER_SLAVE_CHANNEL_MUST_STOP = 3081 +ER_SLAVE_CHANNEL_NOT_RUNNING = 3082 +ER_SLAVE_CHANNEL_WAS_RUNNING = 3083 +ER_SLAVE_CHANNEL_WAS_NOT_RUNNING = 3084 +ER_SLAVE_CHANNEL_SQL_THREAD_MUST_STOP = 3085 +ER_SLAVE_CHANNEL_SQL_SKIP_COUNTER = 3086 +ER_WRONG_FIELD_WITH_GROUP_V2 = 3087 +ER_MIX_OF_GROUP_FUNC_AND_FIELDS_V2 = 3088 +ER_WARN_DEPRECATED_SYSVAR_UPDATE = 3089 +ER_WARN_DEPRECATED_SQLMODE = 3090 +ER_CANNOT_LOG_PARTIAL_DROP_DATABASE_WITH_GTID = 3091 +ER_GROUP_REPLICATION_CONFIGURATION = 3092 +ER_GROUP_REPLICATION_RUNNING = 3093 +ER_GROUP_REPLICATION_APPLIER_INIT_ERROR = 3094 +ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT = 3095 +ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR = 3096 +ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR = 3097 +ER_BEFORE_DML_VALIDATION_ERROR = 3098 +ER_PREVENTS_VARIABLE_WITHOUT_RBR = 3099 +ER_RUN_HOOK_ERROR = 3100 +ER_TRANSACTION_ROLLBACK_DURING_COMMIT = 3101 +ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED = 3102 +ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN = 3103 +ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN = 3104 +ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN = 3105 +ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN = 3106 +ER_GENERATED_COLUMN_NON_PRIOR = 3107 +ER_DEPENDENT_BY_GENERATED_COLUMN = 3108 +ER_GENERATED_COLUMN_REF_AUTO_INC = 3109 +ER_FEATURE_NOT_AVAILABLE = 3110 +ER_CANT_SET_GTID_MODE = 3111 +ER_CANT_USE_AUTO_POSITION_WITH_GTID_MODE_OFF = 3112 +ER_CANT_REPLICATE_ANONYMOUS_WITH_AUTO_POSITION = 3113 +ER_CANT_REPLICATE_ANONYMOUS_WITH_GTID_MODE_ON = 3114 +ER_CANT_REPLICATE_GTID_WITH_GTID_MODE_OFF = 3115 +ER_CANT_SET_ENFORCE_GTID_CONSISTENCY_ON_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS = 3116 +ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS = 3117 +ER_ACCOUNT_HAS_BEEN_LOCKED = 3118 +ER_WRONG_TABLESPACE_NAME = 3119 +ER_TABLESPACE_IS_NOT_EMPTY = 3120 +ER_WRONG_FILE_NAME = 3121 +ER_BOOST_GEOMETRY_INCONSISTENT_TURNS_EXCEPTION = 3122 +ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR = 3123 +ER_WARN_BAD_MAX_EXECUTION_TIME = 3124 +ER_WARN_UNSUPPORTED_MAX_EXECUTION_TIME = 3125 +ER_WARN_CONFLICTING_HINT = 3126 +ER_WARN_UNKNOWN_QB_NAME = 3127 +ER_UNRESOLVED_HINT_NAME = 3128 +ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE = 3129 +ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED = 3130 +ER_LOCKING_SERVICE_WRONG_NAME = 3131 +ER_LOCKING_SERVICE_DEADLOCK = 3132 +ER_LOCKING_SERVICE_TIMEOUT = 3133 +ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED = 3134 +ER_SQL_MODE_MERGED = 3135 +ER_VTOKEN_PLUGIN_TOKEN_MISMATCH = 3136 +ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND = 3137 +ER_CANT_SET_VARIABLE_WHEN_OWNING_GTID = 3138 +ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED = 3139 +ER_INVALID_JSON_TEXT = 3140 +ER_INVALID_JSON_TEXT_IN_PARAM = 3141 +ER_INVALID_JSON_BINARY_DATA = 3142 +ER_INVALID_JSON_PATH = 3143 +ER_INVALID_JSON_CHARSET = 3144 +ER_INVALID_JSON_CHARSET_IN_FUNCTION = 3145 +ER_INVALID_TYPE_FOR_JSON = 3146 +ER_INVALID_CAST_TO_JSON = 3147 +ER_INVALID_JSON_PATH_CHARSET = 3148 +ER_INVALID_JSON_PATH_WILDCARD = 3149 +ER_JSON_VALUE_TOO_BIG = 3150 +ER_JSON_KEY_TOO_BIG = 3151 +ER_JSON_USED_AS_KEY = 3152 +ER_JSON_VACUOUS_PATH = 3153 +ER_JSON_BAD_ONE_OR_ALL_ARG = 3154 +ER_NUMERIC_JSON_VALUE_OUT_OF_RANGE = 3155 +ER_INVALID_JSON_VALUE_FOR_CAST = 3156 +ER_JSON_DOCUMENT_TOO_DEEP = 3157 +ER_JSON_DOCUMENT_NULL_KEY = 3158 +ER_SECURE_TRANSPORT_REQUIRED = 3159 +ER_NO_SECURE_TRANSPORTS_CONFIGURED = 3160 +ER_DISABLED_STORAGE_ENGINE = 3161 +ER_USER_DOES_NOT_EXIST = 3162 +ER_USER_ALREADY_EXISTS = 3163 +ER_AUDIT_API_ABORT = 3164 +ER_INVALID_JSON_PATH_ARRAY_CELL = 3165 +ER_BUFPOOL_RESIZE_INPROGRESS = 3166 +ER_FEATURE_DISABLED_SEE_DOC = 3167 +ER_SERVER_ISNT_AVAILABLE = 3168 +ER_SESSION_WAS_KILLED = 3169 +ER_CAPACITY_EXCEEDED = 3170 +ER_CAPACITY_EXCEEDED_IN_RANGE_OPTIMIZER = 3171 +ER_TABLE_NEEDS_UPG_PART = 3172 +ER_CANT_WAIT_FOR_EXECUTED_GTID_SET_WHILE_OWNING_A_GTID = 3173 +ER_CANNOT_ADD_FOREIGN_BASE_COL_VIRTUAL = 3174 +ER_CANNOT_CREATE_VIRTUAL_INDEX_CONSTRAINT = 3175 +CR_UNKNOWN_ERROR = 2000 +CR_SOCKET_CREATE_ERROR = 2001 +CR_CONNECTION_ERROR = 2002 +CR_CONN_HOST_ERROR = 2003 +CR_IPSOCK_ERROR = 2004 +CR_UNKNOWN_HOST = 2005 +CR_SERVER_GONE_ERROR = 2006 +CR_VERSION_ERROR = 2007 +CR_OUT_OF_MEMORY = 2008 +CR_WRONG_HOST_INFO = 2009 +CR_LOCALHOST_CONNECTION = 2010 +CR_TCP_CONNECTION = 2011 +CR_SERVER_HANDSHAKE_ERR = 2012 +CR_SERVER_LOST = 2013 +CR_COMMANDS_OUT_OF_SYNC = 2014 +CR_NAMEDPIPE_CONNECTION = 2015 +CR_NAMEDPIPEWAIT_ERROR = 2016 +CR_NAMEDPIPEOPEN_ERROR = 2017 +CR_NAMEDPIPESETSTATE_ERROR = 2018 +CR_CANT_READ_CHARSET = 2019 +CR_NET_PACKET_TOO_LARGE = 2020 +CR_EMBEDDED_CONNECTION = 2021 +CR_PROBE_SLAVE_STATUS = 2022 +CR_PROBE_SLAVE_HOSTS = 2023 +CR_PROBE_SLAVE_CONNECT = 2024 +CR_PROBE_MASTER_CONNECT = 2025 +CR_SSL_CONNECTION_ERROR = 2026 +CR_MALFORMED_PACKET = 2027 +CR_WRONG_LICENSE = 2028 +CR_NULL_POINTER = 2029 +CR_NO_PREPARE_STMT = 2030 +CR_PARAMS_NOT_BOUND = 2031 +CR_DATA_TRUNCATED = 2032 +CR_NO_PARAMETERS_EXISTS = 2033 +CR_INVALID_PARAMETER_NO = 2034 +CR_INVALID_BUFFER_USE = 2035 +CR_UNSUPPORTED_PARAM_TYPE = 2036 +CR_SHARED_MEMORY_CONNECTION = 2037 +CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR = 2038 +CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR = 2039 +CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR = 2040 +CR_SHARED_MEMORY_CONNECT_MAP_ERROR = 2041 +CR_SHARED_MEMORY_FILE_MAP_ERROR = 2042 +CR_SHARED_MEMORY_MAP_ERROR = 2043 +CR_SHARED_MEMORY_EVENT_ERROR = 2044 +CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR = 2045 +CR_SHARED_MEMORY_CONNECT_SET_ERROR = 2046 +CR_CONN_UNKNOW_PROTOCOL = 2047 +CR_INVALID_CONN_HANDLE = 2048 +CR_UNUSED_1 = 2049 +CR_FETCH_CANCELED = 2050 +CR_NO_DATA = 2051 +CR_NO_STMT_METADATA = 2052 +CR_NO_RESULT_SET = 2053 +CR_NOT_IMPLEMENTED = 2054 +CR_SERVER_LOST_EXTENDED = 2055 +CR_STMT_CLOSED = 2056 +CR_NEW_STMT_METADATA = 2057 +CR_ALREADY_CONNECTED = 2058 +CR_AUTH_PLUGIN_CANNOT_LOAD = 2059 +CR_DUPLICATE_CONNECTION_ATTR = 2060 +CR_AUTH_PLUGIN_ERR = 2061 +CR_INSECURE_API_ERR = 2062 +# End MySQL Errors + diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/errors.py b/elitebot/lib/python3.11/site-packages/mysql/connector/errors.py new file mode 100644 index 0000000..ea354f2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/errors.py @@ -0,0 +1,304 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Python exceptions +""" + +from . import utils +from .locales import get_client_error +from .catch23 import PY2 + +# _CUSTOM_ERROR_EXCEPTIONS holds custom exceptions and is ued by the +# function custom_error_exception. _ERROR_EXCEPTIONS (at bottom of module) +# is similar, but hardcoded exceptions. +_CUSTOM_ERROR_EXCEPTIONS = {} + + +def custom_error_exception(error=None, exception=None): + """Define custom exceptions for MySQL server errors + + This function defines custom exceptions for MySQL server errors and + returns the current set customizations. + + If error is a MySQL Server error number, then you have to pass also the + exception class. + + The error argument can also be a dictionary in which case the key is + the server error number, and value the exception to be raised. + + If none of the arguments are given, then custom_error_exception() will + simply return the current set customizations. + + To reset the customizations, simply supply an empty dictionary. + + Examples: + import mysql.connector + from mysql.connector import errorcode + + # Server error 1028 should raise a DatabaseError + mysql.connector.custom_error_exception( + 1028, mysql.connector.DatabaseError) + + # Or using a dictionary: + mysql.connector.custom_error_exception({ + 1028: mysql.connector.DatabaseError, + 1029: mysql.connector.OperationalError, + }) + + # Reset + mysql.connector.custom_error_exception({}) + + Returns a dictionary. + """ + global _CUSTOM_ERROR_EXCEPTIONS # pylint: disable=W0603 + + if isinstance(error, dict) and not len(error): + _CUSTOM_ERROR_EXCEPTIONS = {} + return _CUSTOM_ERROR_EXCEPTIONS + + if not error and not exception: + return _CUSTOM_ERROR_EXCEPTIONS + + if not isinstance(error, (int, dict)): + raise ValueError( + "The error argument should be either an integer or dictionary") + + if isinstance(error, int): + error = {error: exception} + + for errno, exception in error.items(): + if not isinstance(errno, int): + raise ValueError("error number should be an integer") + try: + if not issubclass(exception, Exception): + raise TypeError + except TypeError: + raise ValueError("exception should be subclass of Exception") + _CUSTOM_ERROR_EXCEPTIONS[errno] = exception + + return _CUSTOM_ERROR_EXCEPTIONS + +def get_mysql_exception(errno, msg=None, sqlstate=None): + """Get the exception matching the MySQL error + + This function will return an exception based on the SQLState. The given + message will be passed on in the returned exception. + + The exception returned can be customized using the + mysql.connector.custom_error_exception() function. + + Returns an Exception + """ + try: + return _CUSTOM_ERROR_EXCEPTIONS[errno]( + msg=msg, errno=errno, sqlstate=sqlstate) + except KeyError: + # Error was not mapped to particular exception + pass + + try: + return _ERROR_EXCEPTIONS[errno]( + msg=msg, errno=errno, sqlstate=sqlstate) + except KeyError: + # Error was not mapped to particular exception + pass + + if not sqlstate: + return DatabaseError(msg=msg, errno=errno) + + try: + return _SQLSTATE_CLASS_EXCEPTION[sqlstate[0:2]]( + msg=msg, errno=errno, sqlstate=sqlstate) + except KeyError: + # Return default InterfaceError + return DatabaseError(msg=msg, errno=errno, sqlstate=sqlstate) + +def get_exception(packet): + """Returns an exception object based on the MySQL error + + Returns an exception object based on the MySQL error in the given + packet. + + Returns an Error-Object. + """ + errno = errmsg = None + + try: + if packet[4] != 255: + raise ValueError("Packet is not an error packet") + except IndexError as err: + return InterfaceError("Failed getting Error information (%r)" % err) + + sqlstate = None + try: + packet = packet[5:] + (packet, errno) = utils.read_int(packet, 2) + if packet[0] != 35: + # Error without SQLState + if isinstance(packet, (bytes, bytearray)): + errmsg = packet.decode('utf8') + else: + errmsg = packet + else: + (packet, sqlstate) = utils.read_bytes(packet[1:], 5) + sqlstate = sqlstate.decode('utf8') + errmsg = packet.decode('utf8') + except Exception as err: # pylint: disable=W0703 + return InterfaceError("Failed getting Error information (%r)" % err) + else: + return get_mysql_exception(errno, errmsg, sqlstate) + + +class Error(Exception): + """Exception that is base class for all other error exceptions""" + def __init__(self, msg=None, errno=None, values=None, sqlstate=None): + super(Error, self).__init__() + self.msg = msg + self._full_msg = self.msg + self.errno = errno or -1 + self.sqlstate = sqlstate + + if not self.msg and (2000 <= self.errno < 3000): + self.msg = get_client_error(self.errno) + if values is not None: + try: + self.msg = self.msg % values + except TypeError as err: + self.msg = "{0} (Warning: {1})".format(self.msg, str(err)) + elif not self.msg: + self._full_msg = self.msg = 'Unknown error' + + if self.msg and self.errno != -1: + fields = { + 'errno': self.errno, + 'msg': self.msg.encode('utf8') if PY2 else self.msg + } + if self.sqlstate: + fmt = '{errno} ({state}): {msg}' + fields['state'] = self.sqlstate + else: + fmt = '{errno}: {msg}' + self._full_msg = fmt.format(**fields) + + self.args = (self.errno, self._full_msg, self.sqlstate) + + def __str__(self): + return self._full_msg + + +class Warning(Exception): # pylint: disable=W0622 + """Exception for important warnings""" + pass + + +class InterfaceError(Error): + """Exception for errors related to the interface""" + pass + + +class DatabaseError(Error): + """Exception for errors related to the database""" + pass + + +class InternalError(DatabaseError): + """Exception for errors internal database errors""" + pass + + +class OperationalError(DatabaseError): + """Exception for errors related to the database's operation""" + pass + + +class ProgrammingError(DatabaseError): + """Exception for errors programming errors""" + pass + + +class IntegrityError(DatabaseError): + """Exception for errors regarding relational integrity""" + pass + + +class DataError(DatabaseError): + """Exception for errors reporting problems with processed data""" + pass + + +class NotSupportedError(DatabaseError): + """Exception for errors when an unsupported database feature was used""" + pass + + +class PoolError(Error): + """Exception for errors relating to connection pooling""" + pass + + +class MySQLFabricError(Error): + """Exception for errors relating to MySQL Fabric""" + +_SQLSTATE_CLASS_EXCEPTION = { + '02': DataError, # no data + '07': DatabaseError, # dynamic SQL error + '08': OperationalError, # connection exception + '0A': NotSupportedError, # feature not supported + '21': DataError, # cardinality violation + '22': DataError, # data exception + '23': IntegrityError, # integrity constraint violation + '24': ProgrammingError, # invalid cursor state + '25': ProgrammingError, # invalid transaction state + '26': ProgrammingError, # invalid SQL statement name + '27': ProgrammingError, # triggered data change violation + '28': ProgrammingError, # invalid authorization specification + '2A': ProgrammingError, # direct SQL syntax error or access rule violation + '2B': DatabaseError, # dependent privilege descriptors still exist + '2C': ProgrammingError, # invalid character set name + '2D': DatabaseError, # invalid transaction termination + '2E': DatabaseError, # invalid connection name + '33': DatabaseError, # invalid SQL descriptor name + '34': ProgrammingError, # invalid cursor name + '35': ProgrammingError, # invalid condition number + '37': ProgrammingError, # dynamic SQL syntax error or access rule violation + '3C': ProgrammingError, # ambiguous cursor name + '3D': ProgrammingError, # invalid catalog name + '3F': ProgrammingError, # invalid schema name + '40': InternalError, # transaction rollback + '42': ProgrammingError, # syntax error or access rule violation + '44': InternalError, # with check option violation + 'HZ': OperationalError, # remote database access + 'XA': IntegrityError, + '0K': OperationalError, + 'HY': DatabaseError, # default when no SQLState provided by MySQL server +} + +_ERROR_EXCEPTIONS = { + 1243: ProgrammingError, + 1210: ProgrammingError, + 2002: InterfaceError, + 2013: OperationalError, + 2049: NotSupportedError, + 2055: OperationalError, + 2061: InterfaceError, +} diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/__init__.py b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/__init__.py new file mode 100644 index 0000000..b3d6a06 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/__init__.py @@ -0,0 +1,70 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""MySQL Fabric support""" + + +from collections import namedtuple + +# Order of field_names must match how Fabric is returning the data +FabricMySQLServer = namedtuple( + 'FabricMySQLServer', + ['uuid', 'group', 'host', 'port', 'mode', 'status', 'weight'] + ) + +# Order of field_names must match how Fabric is returning the data +FabricShard = namedtuple( + 'FabricShard', + ['database', 'table', 'column', 'key', + 'shard', 'shard_type', 'group', 'global_group'] + ) + +from .connection import ( + MODE_READONLY, MODE_READWRITE, + STATUS_PRIMARY, STATUS_SECONDARY, + SCOPE_GLOBAL, SCOPE_LOCAL, + Fabric, FabricConnection, + MySQLFabricConnection, + FabricSet, +) + + +def connect(**kwargs): + """Create a MySQLFabricConnection object""" + return MySQLFabricConnection(**kwargs) + +__all__ = [ + 'MODE_READWRITE', + 'MODE_READONLY', + 'STATUS_PRIMARY', + 'STATUS_SECONDARY', + 'SCOPE_GLOBAL', + 'SCOPE_LOCAL', + 'FabricMySQLServer', + 'FabricShard', + 'connect', + 'Fabric', + 'FabricConnection', + 'MySQLFabricConnection', + 'FabricSet', +] diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/balancing.py b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/balancing.py new file mode 100644 index 0000000..8ebf50b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/balancing.py @@ -0,0 +1,159 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Implementing load balancing""" + + +import decimal + + +def _calc_ratio(part, whole): + """Calculate ratio + + Returns int + """ + return int((part/whole*100).quantize( + decimal.Decimal('1'), rounding=decimal.ROUND_HALF_DOWN)) + + +class BaseScheduling(object): + + """Base class for all scheduling classes dealing with load balancing""" + + def __init__(self): + """Initialize""" + self._members = [] + self._ratios = [] + + def set_members(self, *args): + """Set members and ratios + + This methods sets the members using the arguments passed. Each + argument must be a sequence where the second item is the weight. + The first element is an identifier. For example: + + ('server1', 0.6), ('server2', 0.8) + + Setting members means that the load will be reset. If the members + are the same as previously set, nothing will be reset or set. + + If no arguments were given the members will be set to an empty + list. + + Raises ValueError when weight can't be converted to a Decimal. + """ + raise NotImplementedError + + def get_next(self): + """Returns the next member""" + raise NotImplementedError + + @property + def members(self): + """Returns the members of this loadbalancer""" + return self._members + + @property + def ratios(self): + """Returns the ratios for all members""" + return self._ratios + + +class WeightedRoundRobin(BaseScheduling): + + """Class for doing Weighted Round Robin balancing""" + + def __init__(self, *args): + """Initializing""" + super(WeightedRoundRobin, self).__init__() + self._load = [] + self._next_member = 0 + self._nr_members = 0 + + if args: + self.set_members(*args) + + @property + def load(self): + """Returns the current load""" + return self._load + + def set_members(self, *args): + if not args: + # Reset members if nothing was given + self._members = [] + return + new_members = [] + for member in args: + member = list(member) + try: + member[1] = decimal.Decimal(str(member[1])) + except decimal.InvalidOperation: + raise ValueError("Member '{member}' is invalid".format( + member=member)) + new_members.append(tuple(member)) + + new_members.sort(key=lambda x: x[1], reverse=True) + if self._members == new_members: + return + self._members = new_members + self._nr_members = len(new_members) + + min_weight = min(i[1] for i in self._members) + self._ratios = [] + for _, weight in self._members: + self._ratios.append(int(weight/min_weight * 100)) + self.reset() + + def reset(self): + """Reset the load""" + self._next_member = 0 + self._load = [0] * self._nr_members + + def get_next(self): + """Returns the next member""" + if self._ratios == self._load: + self.reset() + + # Figure out the member to return + current = self._next_member + + while self._load[current] == self._ratios[current]: + current = (current + 1) % self._nr_members + + # Update the load and set next member + self._load[current] += 1 + self._next_member = (current + 1) % self._nr_members + + # Return current + return self._members[current] + + def __repr__(self): + return "{class_}(load={load}, ratios={ratios})".format( + class_=self.__class__, + load=self.load, + ratios=self.ratios + ) + + def __eq__(self, other): + return self._members == other.members diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/caching.py b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/caching.py new file mode 100644 index 0000000..a24d6b1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/caching.py @@ -0,0 +1,281 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Implementing caching mechanisms for MySQL Fabric""" + + +import bisect +from datetime import datetime, timedelta +from hashlib import sha1 +import logging +import threading + +from . import FabricShard + +_LOGGER = logging.getLogger('myconnpy-fabric') +_CACHE_TTL = 1 * 60 # 1 minute + + +def insort_right_rev(alist, new_element, low=0, high=None): + """Similar to bisect.insort_right but for reverse sorted lists + + This code is similar to the Python code found in Lib/bisect.py. + We simply change the comparison from 'less than' to 'greater than'. + """ + + if low < 0: + raise ValueError('low must be non-negative') + if high is None: + high = len(alist) + while low < high: + middle = (low + high) // 2 + if new_element > alist[middle]: + high = middle + else: + low = middle + 1 + alist.insert(low, new_element) + + +class CacheEntry(object): + + """Base class for MySQL Fabric cache entries""" + + def __init__(self, version=None, fabric_uuid=None, ttl=_CACHE_TTL): + self.version = version + self.fabric_uuid = fabric_uuid + self.last_updated = datetime.utcnow() + self._ttl = ttl + + @classmethod + def hash_index(cls, part1, part2=None): + """Create hash for indexing""" + raise NotImplementedError + + @property + def invalid(self): + """Returns True if entry is not valid any longer + + This property returns True when the entry is not valid any longer. + The entry is valid when now > (last updated + ttl), where ttl is + in seconds. + """ + if not self.last_updated: + return False + atime = self.last_updated + timedelta(seconds=self._ttl) + return datetime.utcnow() > atime + + def reset_ttl(self): + """Reset the Time to Live""" + self.last_updated = datetime.utcnow() + + def invalidate(self): + """Invalidates the cache entry""" + self.last_updated = None + + +class CacheShardTable(CacheEntry): + + """Cache entry for a Fabric sharded table""" + + def __init__(self, shard, version=None, fabric_uuid=None): + if not isinstance(shard, FabricShard): + raise ValueError("shard argument must be a FabricShard instance") + super(CacheShardTable, self).__init__(version=version, + fabric_uuid=fabric_uuid) + self.partitioning = {} + self._shard = shard + self.keys = [] + self.keys_reversed = [] + + if shard.key and shard.group: + self.add_partition(shard.key, shard.group) + + def __getattr__(self, attr): + return getattr(self._shard, attr) + + def add_partition(self, key, group): + """Add sharding information for a group""" + if self.shard_type == 'RANGE': + key = int(key) + elif self.shard_type == 'RANGE_DATETIME': + try: + if ':' in key: + key = datetime.strptime(key, "%Y-%m-%d %H:%M:%S") + else: + key = datetime.strptime(key, "%Y-%m-%d").date() + except: + raise ValueError( + "RANGE_DATETIME key could not be parsed, was: {0}".format( + key + )) + elif self.shard_type == 'RANGE_STRING': + pass + elif self.shard_type == "HASH": + pass + else: + raise ValueError("Unsupported sharding type {0}".format( + self.shard_type + )) + self.partitioning[key] = { + 'group': group, + } + self.reset_ttl() + bisect.insort_right(self.keys, key) + insort_right_rev(self.keys_reversed, key) + + @classmethod + def hash_index(cls, part1, part2=None): + """Create hash for indexing""" + return sha1(part1.encode('utf-8') + part2.encode('utf-8')).hexdigest() + + def __repr__(self): + return "{class_}({database}.{table}.{column})".format( + class_=self.__class__, + database=self.database, + table=self.table, + column=self.column + ) + + +class CacheGroup(CacheEntry): + """Cache entry for a Fabric group""" + def __init__(self, group_name, servers): + super(CacheGroup, self).__init__(version=None, fabric_uuid=None) + self.group_name = group_name + self.servers = servers + + @classmethod + def hash_index(cls, part1, part2=None): + """Create hash for indexing""" + return sha1(part1.encode('utf-8')).hexdigest() + + def __repr__(self): + return "{class_}({group})".format( + class_=self.__class__, + group=self.group_name, + ) + +class FabricCache(object): + """Singleton class for caching Fabric data + + Only one instance of this class can exists globally. + """ + def __init__(self, ttl=_CACHE_TTL): + self._ttl = ttl + self._sharding = {} + self._groups = {} + self.__sharding_lock = threading.Lock() + self.__groups_lock = threading.Lock() + + def remove_group(self, entry_hash): + """Remove cache entry for group""" + with self.__groups_lock: + try: + del self._groups[entry_hash] + except KeyError: + # not cached, that's OK + pass + else: + _LOGGER.debug("Group removed from cache") + + def remove_shardtable(self, entry_hash): + """Remove cache entry for shard""" + with self.__sharding_lock: + try: + del self._sharding[entry_hash] + except KeyError: + # not cached, that's OK + pass + + def sharding_cache_table(self, shard, version=None, fabric_uuid=None): + """Cache information about a shard""" + entry_hash = CacheShardTable.hash_index(shard.database, shard.table) + + with self.__sharding_lock: + try: + entry = self._sharding[entry_hash] + entry.add_partition(shard.key, shard.group) + except KeyError: + # New cache entry + entry = CacheShardTable(shard, version=version, + fabric_uuid=fabric_uuid) + self._sharding[entry_hash] = entry + + def cache_group(self, group_name, servers): + """Cache information about a group""" + entry_hash = CacheGroup.hash_index(group_name) + + with self.__groups_lock: + try: + entry = self._groups[entry_hash] + entry.servers = servers + entry.reset_ttl() + _LOGGER.debug("Recaching group {0} with {1}".format( + group_name, servers)) + except KeyError: + # New cache entry + entry = CacheGroup(group_name, servers) + self._groups[entry_hash] = entry + _LOGGER.debug("Caching group {0} with {1}".format( + group_name, servers)) + + def sharding_search(self, database, table): + """Search cache for a shard based on database and table""" + entry_hash = CacheShardTable.hash_index(database, table) + + entry = None + try: + entry = self._sharding[entry_hash] + if entry.invalid: + _LOGGER.debug("{0} invalidated".format(entry)) + self.remove_shardtable(entry_hash) + return None + except KeyError: + # Nothing in cache + return None + + return entry + + def group_search(self, group_name): + """Search cache for a group based on its name""" + entry_hash = CacheGroup.hash_index(group_name) + + entry = None + try: + entry = self._groups[entry_hash] + if entry.invalid: + _LOGGER.debug("{0} invalidated".format(entry)) + self.remove_group(entry_hash) + return None + except KeyError: + # Nothing in cache + return None + + return entry + + def __repr__(self): + return "{class_}(groups={nrgroups},shards={nrshards})".format( + class_=self.__class__, + nrgroups=len(self._groups), + nrshards=len(self._sharding) + ) diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/connection.py b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/connection.py new file mode 100644 index 0000000..44da175 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/fabric/connection.py @@ -0,0 +1,1623 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Implementing communication with MySQL Fabric""" + +import sys +import datetime +import time +import uuid +from base64 import b16decode +from bisect import bisect +from hashlib import md5 +import logging +import socket +import collections + +# pylint: disable=F0401,E0611 +try: + from xmlrpclib import Fault, ServerProxy, Transport + import urllib2 + from httplib import BadStatusLine +except ImportError: + # Python v3 + from xmlrpc.client import Fault, ServerProxy, Transport + import urllib.request as urllib2 + from http.client import BadStatusLine + +if sys.version_info[0] == 2: + try: + from httplib import HTTPSConnection + except ImportError: + HAVE_SSL = False + else: + HAVE_SSL = True +else: + try: + from http.client import HTTPSConnection + except ImportError: + HAVE_SSL = False + else: + HAVE_SSL = True +# pylint: enable=F0401,E0611 + +import mysql.connector +from ..connection import MySQLConnection +from ..conversion import MySQLConverter +from ..pooling import MySQLConnectionPool +from ..errors import ( + Error, InterfaceError, NotSupportedError, MySQLFabricError, InternalError, + DatabaseError +) +from ..cursor import ( + MySQLCursor, MySQLCursorBuffered, + MySQLCursorRaw, MySQLCursorBufferedRaw +) +from .. import errorcode +from . import FabricMySQLServer, FabricShard +from .caching import FabricCache +from .balancing import WeightedRoundRobin +from .. import version +from ..catch23 import PY2, isunicode, UNICODE_TYPES + +RESET_CACHE_ON_ERROR = ( + errorcode.CR_SERVER_LOST, + errorcode.ER_OPTION_PREVENTS_STATEMENT, +) + + +# Errors to be reported to Fabric +REPORT_ERRORS = ( + errorcode.CR_SERVER_LOST, + errorcode.CR_SERVER_GONE_ERROR, + errorcode.CR_CONN_HOST_ERROR, + errorcode.CR_CONNECTION_ERROR, + errorcode.CR_IPSOCK_ERROR, +) +REPORT_ERRORS_EXTRA = [] + +DEFAULT_FABRIC_PROTOCOL = 'xmlrpc' + +MYSQL_FABRIC_PORT = { + 'xmlrpc': 32274, + 'mysql': 32275 +} + +FABRICS = {} + +# For attempting to connect with Fabric +_CNX_ATTEMPT_DELAY = 1 +_CNX_ATTEMPT_MAX = 3 + +_GETCNX_ATTEMPT_DELAY = 1 +_GETCNX_ATTEMPT_MAX = 3 + +MODE_READONLY = 1 +MODE_WRITEONLY = 2 +MODE_READWRITE = 3 + +STATUS_FAULTY = 0 +STATUS_SPARE = 1 +STATUS_SECONDARY = 2 +STATUS_PRIMARY = 3 + +SCOPE_GLOBAL = 'GLOBAL' +SCOPE_LOCAL = 'LOCAL' + +_SERVER_STATUS_FAULTY = 'FAULTY' + +_CNX_PROPERTIES = { + # name: ((valid_types), description, default) + 'group': ((str,), "Name of group of servers", None), + 'key': (tuple([int, str, datetime.datetime, + datetime.date] + list(UNICODE_TYPES)), + "Sharding key", None), + 'tables': ((tuple, list), "List of tables in query", None), + 'mode': ((int,), "Read-Only, Write-Only or Read-Write", MODE_READWRITE), + 'shard': ((str,), "Identity of the shard for direct connection", None), + 'mapping': ((str,), "", None), + 'scope': ((str,), "GLOBAL for accessing Global Group, or LOCAL", + SCOPE_LOCAL), + 'attempts': ((int,), "Attempts for getting connection", + _GETCNX_ATTEMPT_MAX), + 'attempt_delay': ((int,), "Seconds to wait between each attempt", + _GETCNX_ATTEMPT_DELAY), +} + +_LOGGER = logging.getLogger('myconnpy-fabric') + + +class MySQLRPCProtocol(object): + """Class using MySQL protocol to query Fabric. + """ + def __init__(self, fabric, host, port, connect_attempts, connect_delay): + self.converter = MySQLConverter() + self.handler = FabricMySQLConnection(fabric, host, port, + connect_attempts, + connect_delay) + self.handler.connect() + + def _process_params_dict(self, params): + """Process query parameters given as dictionary""" + try: + res = [] + for key, value in list(params.items()): + conv = value + conv = self.converter.to_mysql(conv) + conv = self.converter.escape(conv) + conv = self.converter.quote(conv) + res.append("{0}={1}".format(key, str(conv))) + except Exception as err: + raise mysql.connector.errors.ProgrammingError( + "Failed processing pyformat-parameters; %s" % err) + else: + return res + + def _process_params(self, params): + """Process query parameters.""" + try: + res = params + res = [self.converter.to_mysql(i) for i in res] + res = [self.converter.escape(i) for i in res] + res = [self.converter.quote(i) for i in res] + res = [str(i) for i in res] + except Exception as err: + raise mysql.connector.errors.ProgrammingError( + "Failed processing format-parameters; %s" % err) + else: + return tuple(res) + + def _execute_cmd(self, stmt, params=None): + """Executes the given query + + Returns a list containing response from Fabric + """ + if not params: + params = () + cur = self.handler.connection.cursor(dictionary=True) + results = [] + + for res in cur.execute(stmt, params, multi=True): + results.append(res.fetchall()) + + return results + + def create_params(self, *args, **kwargs): + """Process arguments to create query parameters. + """ + params = [] + if args: + args = self._process_params(args) + params.extend(args) + if kwargs: + kwargs = self._process_params_dict(kwargs) + params.extend(kwargs) + + params = ', '.join(params) + return params + + def execute(self, group, command, *args, **kwargs): + """Executes the given command with MySQL protocol + + Executes the given command with the given parameters. + + Returns an iterator to navigate to navigate through the result set + returned by Fabric + """ + params = self.create_params(*args, **kwargs) + cmd = "CALL {0}.{1}({2})".format(group, command, params) + + fab_set = None + try: + data = self._execute_cmd(cmd) + fab_set = FabricMySQLSet(data) + except (Fault, socket.error, InterfaceError) as exc: + msg = "Executing {group}.{command} failed: {error}".format( + group=group, command=command, error=str(exc)) + raise InterfaceError(msg) + + return fab_set + + +class XMLRPCProtocol(object): + """Class using XML-RPC protocol to query Fabric. + """ + def __init__(self, fabric, host, port, connect_attempts, connect_delay): + self.handler = FabricXMLRPCConnection(fabric, host, port, + connect_attempts, connect_delay) + self.handler.connect() + + def execute(self, group, command, *args, **kwargs): + """Executes the given command with XML-RPC protocol + + Executes the given command with the given parameters + + Returns an iterator to navigate to navigate through the result set + returned by Fabric + """ + try: + grp = getattr(self.handler.proxy, group) + cmd = getattr(grp, command) + except AttributeError as exc: + raise ValueError("{group}.{command} not available ({err})".format( + group=group, command=command, err=str(exc))) + + fab_set = None + try: + data = cmd(*args, **kwargs) + fab_set = FabricSet(data) + except (Fault, socket.error, InterfaceError) as exc: + msg = "Executing {group}.{command} failed: {error}".format( + group=group, command=command, error=str(exc)) + raise InterfaceError(msg) + + return fab_set + + +class FabricMySQLResponse(object): + """Class used to parse a response got from Fabric with MySQL protocol. + """ + def __init__(self, data): + info = data[0][0] + (fabric_uuid_str, ttl, error) = (info['fabric_uuid'], info['ttl'], + info['message']) + if error: + raise InterfaceError(error) + + self.fabric_uuid_str = fabric_uuid_str + self.ttl = ttl + self.coded_rows = data[1] + + +class FabricMySQLSet(FabricMySQLResponse): + """Iterator to navigate through the result set returned from Fabric + with MySQL Protocol. + """ + def __init__(self, data): + """Initialize the FabricSet object. + """ + super(FabricMySQLSet, self).__init__(data) + self.__names = self.coded_rows[0].keys() + self.__rows = self.coded_rows + self.__result = collections.namedtuple('ResultSet', self.__names) + + def rowcount(self): + """The number of rows in the result set. + """ + return len(self.__rows) + + def rows(self): + """Iterate over the rows of the result set. + + Each row is a named tuple. + """ + for row in self.__rows: + yield self.__result(**row) + + def row(self, index): + """Indexing method for a row. + + Each row is a named tuple. + """ + return self.__result(**self.__rows[index]) + + +class FabricResponse(object): + """Class used to parse a response got from Fabric. + """ + + SUPPORTED_VERSION = 1 + + def __init__(self, data): + """Initialize the FabricResponse object + """ + (format_version, fabric_uuid_str, ttl, error, rows) = data + if error: + raise InterfaceError(error) + if format_version != FabricResponse.SUPPORTED_VERSION: + raise InterfaceError( + "Supported protocol has version {sversion}. Got a response " + "from MySQL Fabric with version {gversion}.".format( + sversion=FabricResponse.SUPPORTED_VERSION, + gversion=format_version) + ) + self.format_version = format_version + self.fabric_uuid_str = fabric_uuid_str + self.ttl = ttl + self.coded_rows = rows + + +class FabricSet(FabricResponse): + """Iterator to navigate through the result set returned from Fabric + """ + def __init__(self, data): + """Initialize the FabricSet object. + """ + super(FabricSet, self).__init__(data) + assert len(self.coded_rows) == 1 + self.__names = self.coded_rows[0]['info']['names'] + self.__rows = self.coded_rows[0]['rows'] + assert all(len(self.__names) == len(row) for row in self.__rows) or \ + len(self.__rows) == 0 + self.__result = collections.namedtuple('ResultSet', self.__names) + + def rowcount(self): + """The number of rows in the result set. + """ + return len(self.__rows) + + def rows(self): + """Iterate over the rows of the result set. + + Each row is a named tuple. + """ + for row in self.__rows: + yield self.__result(*row) + + def row(self, index): + """Indexing method for a row. + + Each row is a named tuple. + """ + return self.__result(*self.__rows[index]) + + +def extra_failure_report(error_codes): + """Add MySQL error to be reported to Fabric + + This function adds error_codes to the error list to be reported to + Fabric. To reset the custom error reporting list, pass None or empty + list. + + The error_codes argument can be either a MySQL error code defined in the + errorcode module, or list of error codes. + + Raises AttributeError when code is not an int. + """ + global REPORT_ERRORS_EXTRA # pylint: disable=W0603 + + if not error_codes: + REPORT_ERRORS_EXTRA = [] + + if not isinstance(error_codes, (list, tuple)): + error_codes = [error_codes] + + for code in error_codes: + if not isinstance(code, int) or not (code >= 1000 and code < 3000): + raise AttributeError("Unknown or invalid error code.") + REPORT_ERRORS_EXTRA.append(code) + + +def _fabric_xmlrpc_uri(host, port): + """Create an XMLRPC URI for connecting to Fabric + + This method will create a URI using the host and TCP/IP + port suitable for connecting to a MySQL Fabric instance. + + Returns a URI. + """ + return 'http://{host}:{port}'.format(host=host, port=port) + + +def _fabric_server_uuid(host, port): + """Create a UUID using host and port""" + return uuid.uuid3(uuid.NAMESPACE_URL, _fabric_xmlrpc_uri(host, port)) + + +def _validate_ssl_args(ssl_ca, ssl_key, ssl_cert): + """Validate the SSL argument. + + Raises AttributeError is required argument is not set. + + Returns dict or None. + """ + if not HAVE_SSL: + raise InterfaceError("Python does not support SSL") + if any([ssl_ca, ssl_key, ssl_cert]): + if not ssl_ca: + raise AttributeError("Missing ssl_ca argument.") + if (ssl_key or ssl_cert) and not (ssl_key and ssl_cert): + raise AttributeError( + "ssl_key and ssl_cert need to be both " + "specified, or neither." + ) + return { + 'ca': ssl_ca, + 'key': ssl_key, + 'cert': ssl_cert, + } + + return None + + +if HAVE_SSL: + class FabricHTTPSHandler(urllib2.HTTPSHandler): + + """Class handling HTTPS connections""" + + def __init__(self, ssl_config): #pylint: disable=E1002 + """Initialize""" + if PY2: + urllib2.HTTPSHandler.__init__(self) + else: + super().__init__() # pylint: disable=W0104 + self._ssl_config = ssl_config + + def https_open(self, req): + """Open HTTPS connection""" + return self.do_open(self.get_https_connection, req) + + def get_https_connection(self, host, timeout=300): + """Returns a HTTPSConnection""" + return HTTPSConnection( + host, + key_file=self._ssl_config['key'], + cert_file=self._ssl_config['cert'] + ) + + +class FabricTransport(Transport): + + """Custom XMLRPC Transport for Fabric""" + + user_agent = 'MySQL Connector Python/{0}'.format(version.VERSION_TEXT) + + def __init__(self, username, password, #pylint: disable=E1002 + verbose=0, use_datetime=False, https_handler=None): + """Initialize""" + if PY2: + Transport.__init__(self, use_datetime=False) + else: + super().__init__(use_datetime=False) + self._username = username + self._password = password + self._use_datetime = use_datetime + self.verbose = verbose + self._username = username + self._password = password + + self._handlers = [] + + if self._username and self._password: + self._passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() + self._auth_handler = urllib2.HTTPDigestAuthHandler(self._passmgr) + else: + self._auth_handler = None + self._passmgr = None + + if https_handler: + self._handlers.append(https_handler) + self._scheme = 'https' + else: + self._scheme = 'http' + + if self._auth_handler: + self._handlers.append(self._auth_handler) + + def request(self, host, handler, request_body, verbose=0): + """Send XMLRPC request""" + uri = '{scheme}://{host}{handler}'.format(scheme=self._scheme, + host=host, handler=handler) + + if self._passmgr: + self._passmgr.add_password(None, uri, self._username, + self._password) + if self.verbose: + _LOGGER.debug("FabricTransport: {0}".format(uri)) + + opener = urllib2.build_opener(*self._handlers) + + headers = { + 'Content-Type': 'text/xml', + 'User-Agent': self.user_agent, + } + req = urllib2.Request(uri, request_body, headers=headers) + + try: + return self.parse_response(opener.open(req)) + except (urllib2.URLError, urllib2.HTTPError) as exc: + try: + code = -1 + if exc.code == 400: + reason = 'Permission denied' + code = exc.code + else: + reason = exc.reason + msg = "{reason} ({code})".format(reason=reason, code=code) + except AttributeError: + if 'SSL' in str(exc): + msg = "SSL error" + else: + msg = str(exc) + raise InterfaceError("Connection with Fabric failed: " + msg) + except BadStatusLine: + raise InterfaceError("Connection with Fabric failed: check SSL") + + +class Fabric(object): + + """Class managing MySQL Fabric instances""" + + def __init__(self, host, username=None, password=None, + port=None, + connect_attempts=_CNX_ATTEMPT_MAX, + connect_delay=_CNX_ATTEMPT_DELAY, + report_errors=False, + ssl_ca=None, ssl_key=None, ssl_cert=None, user=None, + protocol=DEFAULT_FABRIC_PROTOCOL): + """Initialize""" + if protocol == 'xmlrpc': + self._protocol_class = XMLRPCProtocol + elif protocol == 'mysql': + self._protocol_class = MySQLRPCProtocol + else: + raise InterfaceError( + "Protocol not supported by MySQL Fabric," + " was '{}'".format(protocol)) + + if not port: + port = MYSQL_FABRIC_PORT[protocol] + + self._fabric_instances = {} + self._fabric_uuid = None + self._ttl = 1 * 60 # one minute by default + self._version_token = None + self._connect_attempts = connect_attempts + self._connect_delay = connect_delay + self._cache = FabricCache() + self._group_balancers = {} + self._init_host = host + self._init_port = port + self._ssl = _validate_ssl_args(ssl_ca, ssl_key, ssl_cert) + self._report_errors = report_errors + self._protocol = protocol + if user and username: + raise ValueError("can not specify both user and username") + self._username = user or username + self._password = password + + @property + def username(self): + """Return username used to authenticate with Fabric""" + return self._username + + @property + def password(self): + """Return password used to authenticate with Fabric""" + return self._password + + @property + def ssl_config(self): + """Return the SSL configuration""" + return self._ssl + + def seed(self, host=None, port=None): + """Get MySQL Fabric Instances + + This method uses host and port to connect to a MySQL Fabric server + and get all the instances managing the same metadata. + + Raises InterfaceError on errors. + """ + host = host or self._init_host + port = port or self._init_port + + fabinst = self._protocol_class(self, host, port, + connect_attempts=self._connect_attempts, + connect_delay=self._connect_delay) + + fabric_uuid, fabric_version, ttl, fabrics = self.get_fabric_servers( + fabinst) + + if not fabrics: + # Raise, something went wrong. + raise InterfaceError("Failed getting list of Fabric servers") + + if self._version_token == fabric_version: + return + + _LOGGER.info( + "Loading Fabric configuration version {version}".format( + version=fabric_version)) + self._fabric_uuid = fabric_uuid + self._version_token = fabric_version + if ttl > 0: + self._ttl = ttl + + # Update the Fabric servers + for fabric in fabrics: + inst = self._protocol_class(self, fabric['host'], fabric['port'], + connect_attempts=self._connect_attempts, + connect_delay=self._connect_delay) + inst_uuid = inst.handler.uuid + if inst_uuid not in self._fabric_instances: + self._fabric_instances[inst_uuid] = inst + _LOGGER.debug( + "Added new Fabric server {host}:{port}".format( + host=inst.handler.host, port=inst.handler.port)) + + def reset_cache(self, group=None): + """Reset cached information + + This method destroys all cached information. + """ + if group: + _LOGGER.debug("Resetting cache for group '{group}'".format( + group=group)) + self.get_group_servers(group, use_cache=False) + else: + _LOGGER.debug("Resetting cache") + self._cache = FabricCache() + + def get_instance(self): + """Get a MySQL Fabric Instance + + This method will get the next available MySQL Fabric Instance. + + Raises InterfaceError when no instance is available or connected. + """ + nxt = 0 + errmsg = "No MySQL Fabric instance available" + if not self._fabric_instances: + raise InterfaceError(errmsg + " (not seeded?)") + if PY2: + instance_list = self._fabric_instances.keys() + inst = self._fabric_instances[instance_list[nxt]] + else: + inst = self._fabric_instances[list(self._fabric_instances)[nxt]] + if not inst.handler.is_connected: + inst.handler.connect() + return inst + + def report_failure(self, server_uuid, errno): + """Report failure to Fabric + + This method sets the status of a MySQL server identified by + server_uuid. + """ + if not self._report_errors: + return + + errno = int(errno) + current_host = socket.getfqdn() + + if errno in REPORT_ERRORS or errno in REPORT_ERRORS_EXTRA: + _LOGGER.debug("Reporting error %d of server %s", errno, + server_uuid) + inst = self.get_instance() + try: + data = inst.execute('threat', 'report_failure', + server_uuid, current_host, errno) + FabricResponse(data) + except (Fault, socket.error) as exc: + _LOGGER.debug("Failed reporting server to Fabric (%s)", + str(exc)) + # Not requiring further action + + def get_fabric_servers(self, fabric_cnx=None): + """Get all MySQL Fabric instances + + This method looks up the other MySQL Fabric instances which uses + the same metadata. The returned list contains dictionaries with + connection information such ass host and port. For example: + + [ + {'host': 'fabric_prod_1.example.com', 'port': 32274 }, + {'host': 'fabric_prod_2.example.com', 'port': 32274 }, + ] + + Returns a list of dictionaries + """ + inst = fabric_cnx or self.get_instance() + result = [] + err_msg = "Looking up Fabric servers failed using {host}:{port}: {err}" + try: + fset = inst.execute('dump', 'fabric_nodes', + "protocol." + self._protocol) + + for row in fset.rows(): + result.append({'host': row.host, 'port': row.port}) + except (Fault, socket.error) as exc: + msg = err_msg.format(err=str(exc), host=inst.handler.host, + port=inst.handler.port) + raise InterfaceError(msg) + except (TypeError, AttributeError) as exc: + msg = err_msg.format( + err="No Fabric server available ({0})".format(exc), + host=inst.handler.host, port=inst.handler.port) + raise InterfaceError(msg) + + try: + fabric_uuid = uuid.UUID(fset.fabric_uuid_str) + except TypeError: + fabric_uuid = uuid.uuid4() + + fabric_version = 0 + + return fabric_uuid, fabric_version, fset.ttl, result + + def get_group_servers(self, group, use_cache=True): + """Get all MySQL servers in a group + + This method returns information about all MySQL part of the + given high-availability group. When use_cache is set to + True, the cached information will be used. + + Raises InterfaceError on errors. + + Returns list of FabricMySQLServer objects. + """ + # Get group information from cache + if use_cache: + entry = self._cache.group_search(group) + if entry: + # Cache group information + return entry.servers + + inst = self.get_instance() + result = [] + try: + fset = inst.execute('dump', 'servers', self._version_token, group) + except (Fault, socket.error) as exc: + msg = ("Looking up MySQL servers failed for group " + "{group}: {error}").format(error=str(exc), group=group) + raise InterfaceError(msg) + + weights = [] + for row in fset.rows(): + # We make sure, when using local groups, we skip the global group + if row.group_id == group: + mysqlserver = FabricMySQLServer( + row.server_uuid, row.group_id, row.host, row.port, + row.mode, row.status, row.weight + ) + result.append(mysqlserver) + if mysqlserver.status == STATUS_SECONDARY: + weights.append((mysqlserver.uuid, mysqlserver.weight)) + + self._cache.cache_group(group, result) + if weights: + self._group_balancers[group] = WeightedRoundRobin(*weights) + + return result + + def get_group_server(self, group, mode=None, status=None): + """Get a MySQL server from a group + + The method uses MySQL Fabric to get the correct MySQL server + for the specified group. You can specify mode or status, but + not both. + + The mode argument will decide whether the primary or a secondary + server is returned. When no secondary server is available, the + primary is returned. + + Status is used to force getting either a primary or a secondary. + + The returned tuple contains host, port and uuid. + + Raises InterfaceError on errors; ValueError when both mode + and status are given. + + Returns a FabricMySQLServer object. + """ + if mode and status: + raise ValueError( + "Either mode or status must be given, not both") + + errmsg = "No MySQL server available for group '{group}'" + + servers = self.get_group_servers(group, use_cache=True) + if not servers: + raise InterfaceError(errmsg.format(group=group)) + + # Get the Master and return list (host, port, UUID) + primary = None + secondary = [] + for server in servers: + if server.status == STATUS_SECONDARY: + secondary.append(server) + elif server.status == STATUS_PRIMARY: + primary = server + + if mode in (MODE_WRITEONLY, MODE_READWRITE) or status == STATUS_PRIMARY: + if not primary: + self.reset_cache(group=group) + raise InterfaceError((errmsg + ' {query}={value}').format( + query='status' if status else 'mode', + group=group, + value=status or mode)) + return primary + + # Return primary if no secondary is available + if not secondary and primary: + return primary + elif group in self._group_balancers: + next_secondary = self._group_balancers[group].get_next()[0] + for mysqlserver in secondary: + if next_secondary == mysqlserver.uuid: + return mysqlserver + + self.reset_cache(group=group) + raise InterfaceError(errmsg.format(group=group, mode=mode)) + + def get_sharding_information(self, tables=None, database=None): + """Get and cache the sharding information for given tables + + This method is fetching sharding information from MySQL Fabric + and caches the result. The tables argument must be sequence + of sequences contain the name of the database and table. If no + database is given, the value for the database argument will + be used. + + Examples: + tables = [('salary',), ('employees',)] + get_sharding_information(tables, database='employees') + + tables = [('salary', 'employees'), ('employees', employees)] + get_sharding_information(tables) + + Raises InterfaceError on errors; ValueError when something is wrong + with the tables argument. + """ + if not isinstance(tables, (list, tuple)): + raise ValueError("tables should be a sequence") + + patterns = [] + for table in tables: + if not isinstance(table, (list, tuple)) and not database: + raise ValueError("No database specified for table {0}".format( + table)) + + if isinstance(table, (list, tuple)): + dbase = table[1] + tbl = table[0] + else: + dbase = database + tbl = table + patterns.append("{0}.{1}".format(dbase, tbl)) + + inst = self.get_instance() + try: + + fset = inst.execute( + 'dump', 'sharding_information', self._version_token, + ','.join(patterns) + ) + except (Fault, socket.error) as exc: + msg = "Looking up sharding information failed : {error}".format( + error=str(exc)) + raise InterfaceError(msg) + + for row in fset.rows(): + self._cache.sharding_cache_table( + FabricShard(row.schema_name, row.table_name, row.column_name, + row.lower_bound, row.shard_id, row.type_name, + row.group_id, row.global_group) + ) + + def get_shard_server(self, tables, key, scope=SCOPE_LOCAL, mode=None): + """Get MySQL server information for a particular shard + + Raises DatabaseError when the table is unknown or when tables are not + on the same shard. ValueError is raised when there is a problem + with the methods arguments. InterfaceError is raised for other errors. + """ + if not isinstance(tables, (list, tuple)): + raise ValueError("tables should be a sequence") + + groups = [] + + for dbobj in tables: + try: + database, table = dbobj.split('.') + except ValueError: + raise ValueError( + "tables should be given as ., " + "was {0}".format(dbobj)) + + entry = self._cache.sharding_search(database, table) + if not entry: + self.get_sharding_information((table,), database) + entry = self._cache.sharding_search(database, table) + if not entry: + raise DatabaseError( + errno=errorcode.ER_BAD_TABLE_ERROR, + msg="Unknown table '{database}.{table}'".format( + database=database, table=table)) + + if scope == 'GLOBAL': + return self.get_group_server(entry.global_group, mode=mode) + + if entry.shard_type == 'RANGE': + try: + range_key = int(key) + except ValueError: + raise ValueError("Key must be an integer for RANGE") + partitions = entry.keys + index = partitions[bisect(partitions, range_key) - 1] + partition = entry.partitioning[index] + elif entry.shard_type == 'RANGE_DATETIME': + if not isinstance(key, (datetime.date, datetime.datetime)): + raise ValueError( + "Key must be datetime.date or datetime.datetime for " + "RANGE_DATETIME") + index = None + for partkey in entry.keys_reversed: + if key >= partkey: + index = partkey + break + try: + partition = entry.partitioning[index] + except KeyError: + raise ValueError("Key invalid; was '{0}'".format(key)) + elif entry.shard_type == 'RANGE_STRING': + if not isunicode(key): + raise ValueError("Key must be a unicode value") + index = None + for partkey in entry.keys_reversed: + if key >= partkey: + index = partkey + break + try: + partition = entry.partitioning[index] + except KeyError: + raise ValueError("Key invalid; was '{0}'".format(key)) + elif entry.shard_type == 'HASH': + md5key = md5(str(key)) + index = entry.keys_reversed[-1] + for partkey in entry.keys_reversed: + if md5key.digest() >= b16decode(partkey): + index = partkey + break + partition = entry.partitioning[index] + else: + raise InterfaceError( + "Unsupported sharding type {0}".format(entry.shard_type)) + + groups.append(partition['group']) + if not all(group == groups[0] for group in groups): + raise DatabaseError( + "Tables are located in different shards.") + + return self.get_group_server(groups[0], mode=mode) + + def execute(self, group, command, *args, **kwargs): + """Execute a Fabric command from given group + + This method will execute the given Fabric command from the given group + using the given arguments. It returns an instance of FabricSet. + + Raises ValueError when group.command is not valid and raises + InterfaceError when an error occurs while executing. + + Returns FabricSet. + """ + inst = self.get_instance() + return inst.execute(group, command, *args, **kwargs) + + +class FabricConnection(object): + """Base Class for a class holding a connection to a MySQL Fabric server + """ + def __init__(self, fabric, host, + port=MYSQL_FABRIC_PORT[DEFAULT_FABRIC_PROTOCOL], + connect_attempts=_CNX_ATTEMPT_MAX, + connect_delay=_CNX_ATTEMPT_DELAY): + """Initialize""" + if not isinstance(fabric, Fabric): + raise ValueError("fabric must be instance of class Fabric") + self._fabric = fabric + self._host = host + self._port = port + self._connect_attempts = connect_attempts + self._connect_delay = connect_delay + + @property + def host(self): + """Returns server IP or name of current Fabric connection""" + return self._host + + @property + def port(self): + """Returns TCP/IP port of current Fabric connection""" + return self._port + + @property + def uuid(self): + """Returns UUID of the Fabric server we are connected with""" + return _fabric_server_uuid(self._host, self._port) + + def connect(self): + """Connect with MySQL Fabric""" + pass + + @property + def is_connected(self): + """Check whether connection with Fabric is valid + + Return True if we can still interact with the Fabric server; False + if Not. + + Returns True or False. + """ + pass + + def __repr__(self): + return "{class_}(host={host}, port={port})".format( + class_=self.__class__, + host=self._host, + port=self._port, + ) + + +class FabricXMLRPCConnection(FabricConnection): + + """Class holding a connection to a MySQL Fabric server through XML-RPC""" + + def __init__(self, fabric, host, port=MYSQL_FABRIC_PORT['xmlrpc'], + connect_attempts=_CNX_ATTEMPT_MAX, + connect_delay=_CNX_ATTEMPT_DELAY): + """Initialize""" + super(FabricXMLRPCConnection, self).__init__( + fabric, host, port, connect_attempts, connect_delay + ) + self._proxy = None + + @property + def proxy(self): + """Returns the XMLRPC Proxy of current Fabric connection""" + return self._proxy + + @property + def uri(self): + """Returns the XMLRPC URI for current Fabric connection""" + return _fabric_xmlrpc_uri(self._host, self._port) + + def _xmlrpc_get_proxy(self): + """Return the XMLRPC server proxy instance to MySQL Fabric + + This method tries to get a valid connection to a MySQL Fabric + server. + + Returns a XMLRPC ServerProxy instance. + """ + if self.is_connected: + return self._proxy + + attempts = self._connect_attempts + delay = self._connect_delay + + proxy = None + counter = 0 + while counter != attempts: + counter += 1 + try: + if self._fabric.ssl_config: + if not HAVE_SSL: + raise InterfaceError("Python does not support SSL") + https_handler = FabricHTTPSHandler(self._fabric.ssl_config) + else: + https_handler = None + + transport = FabricTransport(self._fabric.username, + self._fabric.password, + verbose=0, + https_handler=https_handler) + proxy = ServerProxy(self.uri, transport=transport, verbose=0) + proxy._some_nonexisting_method() # pylint: disable=W0212 + except Fault: + # We are actually connected + return proxy + except socket.error as exc: + if counter == attempts: + raise InterfaceError( + "Connection to MySQL Fabric failed ({0})".format(exc)) + _LOGGER.debug( + "Retrying {host}:{port}, attempts {counter}".format( + host=self.host, port=self.port, counter=counter)) + if delay > 0: + time.sleep(delay) + + def connect(self): + """Connect with MySQL Fabric""" + self._proxy = self._xmlrpc_get_proxy() + + @property + def is_connected(self): + """Check whether connection with Fabric is valid + + Return True if we can still interact with the Fabric server; False + if Not. + + Returns True or False. + """ + try: + self._proxy._some_nonexisting_method() # pylint: disable=W0212 + except Fault: + return True + except (TypeError, AttributeError): + return False + else: + return False + + +class FabricMySQLConnection(FabricConnection): + """ + Class holding a connection to a MySQL Fabric server through MySQL protocol + """ + def __init__(self, fabric, host, port=MYSQL_FABRIC_PORT['mysql'], + connect_attempts=_CNX_ATTEMPT_MAX, + connect_delay=_CNX_ATTEMPT_DELAY): + """Initialize""" + super(FabricMySQLConnection, self).__init__( + fabric, host, port=port, + connect_attempts=connect_attempts, connect_delay=connect_delay + ) + self._connection = None + + @property + def connection(self): + """Returns the MySQL RPC Connection to Fabric""" + return self._connection + + def _get_connection(self): + """Return the connection instance to MySQL Fabric through MySQL RPC + + This method tries to get a valid connection to a MySQL Fabric + server. + + Returns a MySQLConnection instance. + """ + if self.is_connected: + return self._connection + + attempts = self._connect_attempts + delay = self._connect_delay + + counter = 0 + + while counter != attempts: + counter += 1 + try: + dbconfig = { + 'host': self._host, + 'port': self._port, + 'user': self._fabric.username, + 'password': self._fabric.password + } + if self._fabric.ssl_config: + if not HAVE_SSL: + raise InterfaceError("Python does not support SSL") + dbconfig['ssl_key'] = self._fabric.ssl_config['key'] + dbconfig['ssl_cert'] = self._fabric.ssl_config['cert'] + + return MySQLConnection(**dbconfig) + + except AttributeError as exc: + if counter == attempts: + raise InterfaceError( + "Connection to MySQL Fabric failed ({0})".format(exc)) + _LOGGER.debug( + "Retrying {host}:{port}, attempts {counter}".format( + host=self.host, port=self.port, counter=counter)) + if delay > 0: + time.sleep(delay) + + def connect(self): + """Connect with MySQL Fabric""" + self._connection = self._get_connection() + + @property + def is_connected(self): + """Check whether connection with Fabric is valid + + Return True if we can still interact with the Fabric server; False + if Not. + + Returns True or False. + """ + try: + return self._connection.is_connected() + except AttributeError: + return False + + +class MySQLFabricConnection(object): + + """Connection to a MySQL server through MySQL Fabric""" + + def __init__(self, **kwargs): + """Initialize""" + self._mysql_cnx = None + self._fabric = None + self._fabric_mysql_server = None + self._mysql_config = None + self._cnx_properties = {} + self.reset_properties() + + # Validity of fabric-argument is checked in config()-method + if 'fabric' not in kwargs: + raise ValueError("Configuration parameters for Fabric missing") + + if kwargs: + self.store_config(**kwargs) + + def __getattr__(self, attr): + """Return the return value of the MySQLConnection instance""" + if attr.startswith('cmd_'): + raise NotSupportedError( + "Calling {attr} is not supported for connections managed by " + "MySQL Fabric.".format(attr=attr)) + return getattr(self._mysql_cnx, attr) + + @property + def fabric_uuid(self): + """Returns the Fabric UUID of the MySQL server""" + if self._fabric_mysql_server: + return self._fabric_mysql_server.uuid + return None + + @property + def properties(self): + """Returns connection properties""" + return self._cnx_properties + + def reset_cache(self, group=None): + """Reset cache for this connection's group""" + if not group and self._fabric_mysql_server: + group = self._fabric_mysql_server.group + self._fabric.reset_cache(group=group) + + def is_connected(self): + """Check whether we are connected with the MySQL server + + Returns True or False + """ + return self._mysql_cnx is not None + + def reset_properties(self): + """Resets the connection properties + + This method can be called to reset the connection properties to + their default values. + """ + self._cnx_properties = {} + for key, attr in _CNX_PROPERTIES.items(): + self._cnx_properties[key] = attr[2] + + def set_property(self, **properties): + """Set one or more connection properties + + Arguments to the set_property() method will be used as properties. + They are validated against the _CNX_PROPERTIES constant. + + Raise ValueError in case an invalid property is being set. TypeError + is raised when the type of the value is not correct. + + To unset a property, set it to None. + """ + try: + self.close() + except Error: + # We tried, but it's OK when we fail. + pass + + props = self._cnx_properties + + for name, value in properties.items(): + if name not in _CNX_PROPERTIES: + raise ValueError( + "Invalid property connection {0}".format(name)) + elif value and not isinstance(value, _CNX_PROPERTIES[name][0]): + valid_types_str = ' or '.join( + [atype.__name__ for atype in _CNX_PROPERTIES[name][0]]) + raise TypeError( + "{name} is not valid, excepted {typename}".format( + name=name, typename=valid_types_str)) + + if (name == 'group' and value and + (props['key'] or props['tables'])): + raise ValueError( + "'group' property can not be set when 'key' or " + "'tables' are set") + elif name in ('key', 'tables') and value and props['group']: + raise ValueError( + "'key' and 'tables' property can not be " + "set together with 'group'") + elif name == 'scope' and value not in (SCOPE_LOCAL, SCOPE_GLOBAL): + raise ValueError("Invalid value for 'scope'") + elif name == 'mode' and value not in ( + MODE_READWRITE, MODE_READONLY): + raise ValueError("Invalid value for 'mode'") + + if value is None: + # Set the default + props[name] = _CNX_PROPERTIES[name][2] + else: + props[name] = value + + def _configure_fabric(self, config): + """Configure the Fabric connection + + The config argument can be either a dictionary containing the + necessary information to setup the connection. Or config can + be an instance of Fabric. + """ + if isinstance(config, Fabric): + self._fabric = config + else: + required_keys = ['host'] + for required_key in required_keys: + if required_key not in config: + raise ValueError( + "Missing configuration parameter '{parameter}' " + "for fabric".format(parameter=required_key)) + host = config['host'] + protocol = config.get('protocol', DEFAULT_FABRIC_PROTOCOL) + try: + port = config.get('port', MYSQL_FABRIC_PORT[protocol]) + except KeyError: + raise InterfaceError( + "{0} protocol is not available".format(protocol)) + server_uuid = _fabric_server_uuid(host, port) + try: + self._fabric = FABRICS[server_uuid] + except KeyError: + _LOGGER.debug("New Fabric connection") + self._fabric = Fabric(**config) + self._fabric.seed() + # Cache the new connection + FABRICS[server_uuid] = self._fabric + + def store_config(self, **kwargs): + """Store configuration of MySQL connections to use with Fabric + + The configuration found in the dictionary kwargs is used + when instanciating a MySQLConnection object. The host and port + entries are used to connect to MySQL Fabric. + + Raises ValueError when the Fabric configuration parameter + is not correct or missing; AttributeError is raised when + when a paramater is not valid. + """ + config = kwargs.copy() + + # Configure the Fabric connection + if 'fabric' in config: + self._configure_fabric(config['fabric']) + del config['fabric'] + + if 'unix_socket' in config: + _LOGGER.warning("MySQL Fabric does not use UNIX sockets.") + config['unix_socket'] = None + + # Try to use the configuration + test_config = config.copy() + if 'pool_name' in test_config: + del test_config['pool_name'] + if 'pool_size' in test_config: + del test_config['pool_size'] + if 'pool_reset_session' in test_config: + del test_config['pool_reset_session'] + try: + pool = MySQLConnectionPool(pool_name=str(uuid.uuid4())) + pool.set_config(**test_config) + except AttributeError as err: + raise AttributeError( + "Connection configuration not valid: {0}".format(err)) + + self._mysql_config = config + + def _connect(self): + """Get a MySQL server based on properties and connect + + This method gets a MySQL server from MySQL Fabric using already + properties set using the set_property() method. You can specify how + many times and the delay between trying using attempts and + attempt_delay. + + Raises ValueError when there are problems with arguments or + properties; InterfaceError on connectivity errors. + """ + if self.is_connected(): + return + props = self._cnx_properties + attempts = props['attempts'] + attempt_delay = props['attempt_delay'] + + dbconfig = self._mysql_config.copy() + counter = 0 + while counter != attempts: + counter += 1 + try: + group = None + if props['tables']: + if props['scope'] == 'LOCAL' and not props['key']: + raise ValueError( + "Scope 'LOCAL' needs key property to be set") + mysqlserver = self._fabric.get_shard_server( + props['tables'], props['key'], + scope=props['scope'], + mode=props['mode']) + elif props['group']: + group = props['group'] + mysqlserver = self._fabric.get_group_server( + group, mode=props['mode']) + else: + raise ValueError( + "Missing group or key and tables properties") + except InterfaceError as exc: + _LOGGER.debug( + "Trying to get MySQL server (attempt {0}; {1})".format( + counter, exc)) + if counter == attempts: + raise InterfaceError("Error getting connection: {0}".format( + exc)) + if attempt_delay > 0: + _LOGGER.debug("Waiting {0}".format(attempt_delay)) + time.sleep(attempt_delay) + continue + + # Make sure we do not change the stored configuration + dbconfig['host'] = mysqlserver.host + dbconfig['port'] = mysqlserver.port + try: + self._mysql_cnx = mysql.connector.connect(**dbconfig) + except Error as exc: + if counter == attempts: + self.reset_cache(mysqlserver.group) + self._fabric.report_failure(mysqlserver.uuid, exc.errno) + raise InterfaceError( + "Reported faulty server to Fabric ({0})".format(exc)) + if attempt_delay > 0: + time.sleep(attempt_delay) + continue + else: + self._fabric_mysql_server = mysqlserver + break + + def disconnect(self): + """Close connection to MySQL server""" + try: + self.rollback() + self._mysql_cnx.close() + except AttributeError: + pass # There was no connection + except Error: + raise + finally: + self._mysql_cnx = None + self._fabric_mysql_server = None + close = disconnect + + def cursor(self, buffered=None, raw=None, prepared=None, cursor_class=None): + """Instantiates and returns a cursor + + This method is similar to MySQLConnection.cursor() except that + it checks whether the connection is available and raises + an InterfaceError when not. + + cursor_class argument is not supported and will raise a + NotSupportedError exception. + + Returns a MySQLCursor or subclass. + """ + self._connect() + if cursor_class: + raise NotSupportedError( + "Custom cursors not supported with MySQL Fabric") + + if prepared: + raise NotSupportedError( + "Prepared Statements are not supported with MySQL Fabric") + + if self._unread_result is True: + raise InternalError("Unread result found.") + + buffered = buffered or self._buffered + raw = raw or self._raw + + cursor_type = 0 + if buffered is True: + cursor_type |= 1 + if raw is True: + cursor_type |= 2 + + types = ( + MySQLCursor, # 0 + MySQLCursorBuffered, + MySQLCursorRaw, + MySQLCursorBufferedRaw, + ) + return (types[cursor_type])(self) + + def handle_mysql_error(self, exc): + """Handles MySQL errors + + This method takes a mysql.connector.errors.Error exception + and checks the error code. Based on the value, it takes + certain actions such as clearing the cache. + """ + if exc.errno in RESET_CACHE_ON_ERROR: + self.reset_cache() + self.disconnect() + raise MySQLFabricError( + "Temporary error ({error}); " + "retry transaction".format(error=str(exc))) + + raise exc + + def commit(self): + """Commit current transaction + + Raises whatever MySQLConnection.commit() raises, but + raises MySQLFabricError when MySQL returns error + ER_OPTION_PREVENTS_STATEMENT. + """ + try: + self._mysql_cnx.commit() + except Error as exc: + self.handle_mysql_error(exc) + + def rollback(self): + """Rollback current transaction + + Raises whatever MySQLConnection.rollback() raises, but + raises MySQLFabricError when MySQL returns error + ER_OPTION_PREVENTS_STATEMENT. + """ + try: + self._mysql_cnx.rollback() + except Error as exc: + self.handle_mysql_error(exc) + + def cmd_query(self, statement): + """Send a statement to the MySQL server + + Raises whatever MySQLConnection.cmd_query() raises, but + raises MySQLFabricError when MySQL returns error + ER_OPTION_PREVENTS_STATEMENT. + + Returns a dictionary. + """ + self._connect() + try: + return self._mysql_cnx.cmd_query(statement) + except Error as exc: + self.handle_mysql_error(exc) + + def cmd_query_iter(self, statements): + """Send one or more statements to the MySQL server + + Raises whatever MySQLConnection.cmd_query_iter() raises, but + raises MySQLFabricError when MySQL returns error + ER_OPTION_PREVENTS_STATEMENT. + + Returns a dictionary. + """ + self._connect() + try: + return self._mysql_cnx.cmd_query_iter(statements) + except Error as exc: + self.handle_mysql_error(exc) diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/locales/__init__.py b/elitebot/lib/python3.11/site-packages/mysql/connector/locales/__init__.py new file mode 100644 index 0000000..ad784e6 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/locales/__init__.py @@ -0,0 +1,71 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Translations +""" + +__all__ = [ + 'get_client_error' +] + +from .. import errorcode + +def get_client_error(error, language='eng'): + """Lookup client error + + This function will lookup the client error message based on the given + error and return the error message. If the error was not found, + None will be returned. + + Error can be either an integer or a string. For example: + error: 2000 + error: CR_UNKNOWN_ERROR + + The language attribute can be used to retrieve a localized message, when + available. + + Returns a string or None. + """ + try: + tmp = __import__('mysql.connector.locales.{0}'.format(language), + globals(), locals(), ['client_error']) + except ImportError: + raise ImportError("No localization support for language '{0}'".format( + language)) + client_error = tmp.client_error + + if isinstance(error, int): + errno = error + for key, value in errorcode.__dict__.items(): + if value == errno: + error = key + break + + if isinstance(error, (str)): + try: + return getattr(client_error, error) + except AttributeError: + return None + + raise ValueError("error argument needs to be either an integer or string") + diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/__init__.py b/elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/__init__.py new file mode 100644 index 0000000..cfddd84 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/__init__.py @@ -0,0 +1,25 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""English Content +""" diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/client_error.py b/elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/client_error.py new file mode 100644 index 0000000..d145a17 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/locales/eng/client_error.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# This file was auto-generated. +_GENERATED_ON = '2015-12-13' +_MYSQL_VERSION = (5, 7, 10) + +# Start MySQL Error messages +CR_UNKNOWN_ERROR = u"Unknown MySQL error" +CR_SOCKET_CREATE_ERROR = u"Can't create UNIX socket (%s)" +CR_CONNECTION_ERROR = u"Can't connect to local MySQL server through socket '%-.100s' (%s)" +CR_CONN_HOST_ERROR = u"Can't connect to MySQL server on '%-.100s' (%s)" +CR_IPSOCK_ERROR = u"Can't create TCP/IP socket (%s)" +CR_UNKNOWN_HOST = u"Unknown MySQL server host '%-.100s' (%s)" +CR_SERVER_GONE_ERROR = u"MySQL server has gone away" +CR_VERSION_ERROR = u"Protocol mismatch; server version = %s, client version = %s" +CR_OUT_OF_MEMORY = u"MySQL client ran out of memory" +CR_WRONG_HOST_INFO = u"Wrong host info" +CR_LOCALHOST_CONNECTION = u"Localhost via UNIX socket" +CR_TCP_CONNECTION = u"%-.100s via TCP/IP" +CR_SERVER_HANDSHAKE_ERR = u"Error in server handshake" +CR_SERVER_LOST = u"Lost connection to MySQL server during query" +CR_COMMANDS_OUT_OF_SYNC = u"Commands out of sync; you can't run this command now" +CR_NAMEDPIPE_CONNECTION = u"Named pipe: %-.32s" +CR_NAMEDPIPEWAIT_ERROR = u"Can't wait for named pipe to host: %-.64s pipe: %-.32s (%s)" +CR_NAMEDPIPEOPEN_ERROR = u"Can't open named pipe to host: %-.64s pipe: %-.32s (%s)" +CR_NAMEDPIPESETSTATE_ERROR = u"Can't set state of named pipe to host: %-.64s pipe: %-.32s (%s)" +CR_CANT_READ_CHARSET = u"Can't initialize character set %-.32s (path: %-.100s)" +CR_NET_PACKET_TOO_LARGE = u"Got packet bigger than 'max_allowed_packet' bytes" +CR_EMBEDDED_CONNECTION = u"Embedded server" +CR_PROBE_SLAVE_STATUS = u"Error on SHOW SLAVE STATUS:" +CR_PROBE_SLAVE_HOSTS = u"Error on SHOW SLAVE HOSTS:" +CR_PROBE_SLAVE_CONNECT = u"Error connecting to slave:" +CR_PROBE_MASTER_CONNECT = u"Error connecting to master:" +CR_SSL_CONNECTION_ERROR = u"SSL connection error: %-.100s" +CR_MALFORMED_PACKET = u"Malformed packet" +CR_WRONG_LICENSE = u"This client library is licensed only for use with MySQL servers having '%s' license" +CR_NULL_POINTER = u"Invalid use of null pointer" +CR_NO_PREPARE_STMT = u"Statement not prepared" +CR_PARAMS_NOT_BOUND = u"No data supplied for parameters in prepared statement" +CR_DATA_TRUNCATED = u"Data truncated" +CR_NO_PARAMETERS_EXISTS = u"No parameters exist in the statement" +CR_INVALID_PARAMETER_NO = u"Invalid parameter number" +CR_INVALID_BUFFER_USE = u"Can't send long data for non-string/non-binary data types (parameter: %s)" +CR_UNSUPPORTED_PARAM_TYPE = u"Using unsupported buffer type: %s (parameter: %s)" +CR_SHARED_MEMORY_CONNECTION = u"Shared memory: %-.100s" +CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR = u"Can't open shared memory; client could not create request event (%s)" +CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR = u"Can't open shared memory; no answer event received from server (%s)" +CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR = u"Can't open shared memory; server could not allocate file mapping (%s)" +CR_SHARED_MEMORY_CONNECT_MAP_ERROR = u"Can't open shared memory; server could not get pointer to file mapping (%s)" +CR_SHARED_MEMORY_FILE_MAP_ERROR = u"Can't open shared memory; client could not allocate file mapping (%s)" +CR_SHARED_MEMORY_MAP_ERROR = u"Can't open shared memory; client could not get pointer to file mapping (%s)" +CR_SHARED_MEMORY_EVENT_ERROR = u"Can't open shared memory; client could not create %s event (%s)" +CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR = u"Can't open shared memory; no answer from server (%s)" +CR_SHARED_MEMORY_CONNECT_SET_ERROR = u"Can't open shared memory; cannot send request event to server (%s)" +CR_CONN_UNKNOW_PROTOCOL = u"Wrong or unknown protocol" +CR_INVALID_CONN_HANDLE = u"Invalid connection handle" +CR_UNUSED_1 = u"Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)" +CR_FETCH_CANCELED = u"Row retrieval was canceled by mysql_stmt_close() call" +CR_NO_DATA = u"Attempt to read column without prior row fetch" +CR_NO_STMT_METADATA = u"Prepared statement contains no metadata" +CR_NO_RESULT_SET = u"Attempt to read a row while there is no result set associated with the statement" +CR_NOT_IMPLEMENTED = u"This feature is not implemented yet" +CR_SERVER_LOST_EXTENDED = u"Lost connection to MySQL server at '%s', system error: %s" +CR_STMT_CLOSED = u"Statement closed indirectly because of a preceding %s() call" +CR_NEW_STMT_METADATA = u"The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again" +CR_ALREADY_CONNECTED = u"This handle is already connected. Use a separate handle for each connection." +CR_AUTH_PLUGIN_CANNOT_LOAD = u"Authentication plugin '%s' cannot be loaded: %s" +CR_DUPLICATE_CONNECTION_ATTR = u"There is an attribute with the same name already" +CR_AUTH_PLUGIN_ERR = u"Authentication plugin '%s' reported error: %s" +CR_INSECURE_API_ERR = u"Insecure API function call: '%s' Use instead: '%s'" +# End MySQL Error messages + diff --git a/elitebot/lib/python3.11/site-packages/mysql/connector/network.py b/elitebot/lib/python3.11/site-packages/mysql/connector/network.py new file mode 100644 index 0000000..1ef55a3 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/mysql/connector/network.py @@ -0,0 +1,514 @@ +# MySQL Connector/Python - MySQL driver written in Python. +# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + +# MySQL Connector/Python is licensed under the terms of the GPLv2 +# , like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Module implementing low-level socket communication with MySQL servers. +""" + +from collections import deque +import socket +import struct +import sys +import zlib + +try: + import ssl +except: + # If import fails, we don't have SSL support. + pass + +from . import constants, errors +from .catch23 import PY2, init_bytearray, struct_unpack + + +def _strioerror(err): + """Reformat the IOError error message + + This function reformats the IOError error message. + """ + if not err.errno: + return str(err) + return '{errno} {strerr}'.format(errno=err.errno, strerr=err.strerror) + + +def _prepare_packets(buf, pktnr): + """Prepare a packet for sending to the MySQL server""" + pkts = [] + pllen = len(buf) + maxpktlen = constants.MAX_PACKET_LENGTH + while pllen > maxpktlen: + pkts.append(b'\xff\xff\xff' + struct.pack(' 255: + self._packet_number = 0 + return self._packet_number + + @property + def next_compressed_packet_number(self): + """Increments the compressed packet number""" + self._compressed_packet_number = self._compressed_packet_number + 1 + if self._compressed_packet_number > 255: + self._compressed_packet_number = 0 + return self._compressed_packet_number + + def open_connection(self): + """Open the socket""" + raise NotImplementedError + + def get_address(self): + """Get the location of the socket""" + raise NotImplementedError + + def shutdown(self): + """Shut down the socket before closing it""" + try: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + del self._packet_queue + except (socket.error, AttributeError): + pass + + def close_connection(self): + """Close the socket""" + try: + self.sock.close() + del self._packet_queue + except (socket.error, AttributeError): + pass + + def send_plain(self, buf, packet_number=None, + compressed_packet_number=None): + """Send packets to the MySQL server""" + if packet_number is None: + self.next_packet_number # pylint: disable=W0104 + else: + self._packet_number = packet_number + packets = _prepare_packets(buf, self._packet_number) + for packet in packets: + try: + if PY2: + self.sock.sendall(buffer(packet)) # pylint: disable=E0602 + else: + self.sock.sendall(packet) + except IOError as err: + raise errors.OperationalError( + errno=2055, values=(self.get_address(), _strioerror(err))) + except AttributeError: + raise errors.OperationalError(errno=2006) + + send = send_plain + + def send_compressed(self, buf, packet_number=None, + compressed_packet_number=None): + """Send compressed packets to the MySQL server""" + if packet_number is None: + self.next_packet_number # pylint: disable=W0104 + else: + self._packet_number = packet_number + if compressed_packet_number is None: + self.next_compressed_packet_number # pylint: disable=W0104 + else: + self._compressed_packet_number = compressed_packet_number + + pktnr = self._packet_number + pllen = len(buf) + zpkts = [] + maxpktlen = constants.MAX_PACKET_LENGTH + if pllen > maxpktlen: + pkts = _prepare_packets(buf, pktnr) + if PY2: + tmpbuf = bytearray() + for pkt in pkts: + tmpbuf += pkt + tmpbuf = buffer(tmpbuf) # pylint: disable=E0602 + else: + tmpbuf = b''.join(pkts) + del pkts + zbuf = zlib.compress(tmpbuf[:16384]) + header = (struct.pack(' maxpktlen: + zbuf = zlib.compress(tmpbuf[:maxpktlen]) + header = (struct.pack(' 50: + zbuf = zlib.compress(pkt) + zpkts.append(struct.pack(' 0: + raise errors.InterfaceError(errno=2013) + packet_view = packet_view[read:] + rest -= read + return packet + except IOError as err: + raise errors.OperationalError( + errno=2055, values=(self.get_address(), _strioerror(err))) + + def recv_py26_plain(self): + """Receive packets from the MySQL server""" + try: + # Read the header of the MySQL packet, 4 bytes + header = bytearray(b'') + header_len = 0 + while header_len < 4: + chunk = self.sock.recv(4 - header_len) + if not chunk: + raise errors.InterfaceError(errno=2013) + header += chunk + header_len = len(header) + + # Save the packet number and payload length + self._packet_number = header[3] + payload_len = struct_unpack(" 0: + chunk = self.sock.recv(rest) + if not chunk: + raise errors.InterfaceError(errno=2013) + payload += chunk + rest = payload_len - len(payload) + return header + payload + except IOError as err: + raise errors.OperationalError( + errno=2055, values=(self.get_address(), _strioerror(err))) + + if sys.version_info[0:2] == (2, 6): + recv = recv_py26_plain + recv_plain = recv_py26_plain + else: + recv = recv_plain + + def _split_zipped_payload(self, packet_bunch): + """Split compressed payload""" + while packet_bunch: + if PY2: + payload_length = struct.unpack_from( + ", like most +# MySQL Connectors. There are special exceptions to the terms and +# conditions of the GPLv2 as it is applied to this software, see the +# FOSS License Exception +# . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +"""Implements parser to parse MySQL option files. +""" + +import codecs +import io +import os +import re + +from .catch23 import PY2 +from .constants import DEFAULT_CONFIGURATION, CNX_POOL_ARGS, CNX_FABRIC_ARGS + +# pylint: disable=F0401 +if PY2: + from ConfigParser import SafeConfigParser, MissingSectionHeaderError +else: + from configparser import (ConfigParser as SafeConfigParser, + MissingSectionHeaderError) +# pylint: enable=F0401 + +DEFAULT_EXTENSIONS = { + 'nt': ('ini', 'cnf'), + 'posix': ('cnf',) +} + + +def read_option_files(**config): + """ + Read option files for connection parameters. + + Checks if connection arguments contain option file arguments, and then + reads option files accordingly. + """ + if 'option_files' in config: + try: + if isinstance(config['option_groups'], str): + config['option_groups'] = [config['option_groups']] + groups = config['option_groups'] + del config['option_groups'] + except KeyError: + groups = ['client', 'connector_python'] + + if isinstance(config['option_files'], str): + config['option_files'] = [config['option_files']] + option_parser = MySQLOptionsParser(list(config['option_files']), + keep_dashes=False) + del config['option_files'] + + config_from_file = option_parser.get_groups_as_dict_with_priority( + *groups) + config_options = {} + fabric_options = {} + for group in groups: + try: + for option, value in config_from_file[group].items(): + try: + if option == 'socket': + option = 'unix_socket' + + if option in CNX_FABRIC_ARGS: + if (option not in fabric_options or + fabric_options[option][1] <= value[1]): + fabric_options[option] = value + continue + + if (option not in CNX_POOL_ARGS and + option not in ['fabric', 'failover']): + # pylint: disable=W0104 + DEFAULT_CONFIGURATION[option] + # pylint: enable=W0104 + + if (option not in config_options or + config_options[option][1] <= value[1]): + config_options[option] = value + except KeyError: + if group is 'connector_python': + raise AttributeError("Unsupported argument " + "'{0}'".format(option)) + except KeyError: + continue + + not_evaluate = ('password', 'passwd') + for option, value in config_options.items(): + if option not in config: + try: + if option in not_evaluate: + config[option] = value[0] + else: + config[option] = eval(value[0]) # pylint: disable=W0123 + except (NameError, SyntaxError): + config[option] = value[0] + + if fabric_options: + config['fabric'] = {} + for option, value in fabric_options.items(): + try: + # pylint: disable=W0123 + config['fabric'][option.split('_', 1)[1]] = eval(value[0]) + # pylint: enable=W0123 + except (NameError, SyntaxError): + config['fabric'][option.split('_', 1)[1]] = value[0] + return config + + +class MySQLOptionsParser(SafeConfigParser): # pylint: disable=R0901 + """This class implements methods to parse MySQL option files""" + + def __init__(self, files=None, keep_dashes=True): # pylint: disable=W0231 + """Initialize + + If defaults is True, default option files are read first + + Raises ValueError if defaults is set to True but defaults files + cannot be found. + """ + + # Regular expression to allow options with no value(For Python v2.6) + self.OPTCRE = re.compile( # pylint: disable=C0103 + r'(?P
`` which has one row and two + cells: one containing the line numbers and one containing the code. + Example: + + .. sourcecode:: html + +
+
+ + +
+
1
+            2
+
+
def foo(bar):
+              pass
+            
+
+ + (whitespace added to improve clarity). + + A list of lines can be specified using the `hl_lines` option to make these + lines highlighted (as of Pygments 0.11). + + With the `full` option, a complete HTML 4 document is output, including + the style definitions inside a `` + {% else %} + {{ head | safe }} + {% endif %} +{% if not embed %} + + +{% endif %} +{{ body | safe }} +{% for diagram in diagrams %} +

+{% endfor %} +{% if not embed %} + + +{% endif %} +""" + +template = Template(jinja2_template_source) + +# Note: ideally this would be a dataclass, but we're supporting Python 3.5+ so we can't do this yet +NamedDiagram = NamedTuple( + "NamedDiagram", + [("name", str), ("diagram", typing.Optional[railroad.DiagramItem]), ("index", int)], +) +""" +A simple structure for associating a name with a railroad diagram +""" + +T = TypeVar("T") + + +class EachItem(railroad.Group): + """ + Custom railroad item to compose a: + - Group containing a + - OneOrMore containing a + - Choice of the elements in the Each + with the group label indicating that all must be matched + """ + + all_label = "[ALL]" + + def __init__(self, *items): + choice_item = railroad.Choice(len(items) - 1, *items) + one_or_more_item = railroad.OneOrMore(item=choice_item) + super().__init__(one_or_more_item, label=self.all_label) + + +class AnnotatedItem(railroad.Group): + """ + Simple subclass of Group that creates an annotation label + """ + + def __init__(self, label: str, item): + super().__init__(item=item, label="[{}]".format(label) if label else label) + + +class EditablePartial(Generic[T]): + """ + Acts like a functools.partial, but can be edited. In other words, it represents a type that hasn't yet been + constructed. + """ + + # We need this here because the railroad constructors actually transform the data, so can't be called until the + # entire tree is assembled + + def __init__(self, func: Callable[..., T], args: list, kwargs: dict): + self.func = func + self.args = args + self.kwargs = kwargs + + @classmethod + def from_call(cls, func: Callable[..., T], *args, **kwargs) -> "EditablePartial[T]": + """ + If you call this function in the same way that you would call the constructor, it will store the arguments + as you expect. For example EditablePartial.from_call(Fraction, 1, 3)() == Fraction(1, 3) + """ + return EditablePartial(func=func, args=list(args), kwargs=kwargs) + + @property + def name(self): + return self.kwargs["name"] + + def __call__(self) -> T: + """ + Evaluate the partial and return the result + """ + args = self.args.copy() + kwargs = self.kwargs.copy() + + # This is a helpful hack to allow you to specify varargs parameters (e.g. *args) as keyword args (e.g. + # args=['list', 'of', 'things']) + arg_spec = inspect.getfullargspec(self.func) + if arg_spec.varargs in self.kwargs: + args += kwargs.pop(arg_spec.varargs) + + return self.func(*args, **kwargs) + + +def railroad_to_html(diagrams: List[NamedDiagram], embed=False, **kwargs) -> str: + """ + Given a list of NamedDiagram, produce a single HTML string that visualises those diagrams + :params kwargs: kwargs to be passed in to the template + """ + data = [] + for diagram in diagrams: + if diagram.diagram is None: + continue + io = StringIO() + try: + css = kwargs.get('css') + diagram.diagram.writeStandalone(io.write, css=css) + except AttributeError: + diagram.diagram.writeSvg(io.write) + title = diagram.name + if diagram.index == 0: + title += " (root)" + data.append({"title": title, "text": "", "svg": io.getvalue()}) + + return template.render(diagrams=data, embed=embed, **kwargs) + + +def resolve_partial(partial: "EditablePartial[T]") -> T: + """ + Recursively resolves a collection of Partials into whatever type they are + """ + if isinstance(partial, EditablePartial): + partial.args = resolve_partial(partial.args) + partial.kwargs = resolve_partial(partial.kwargs) + return partial() + elif isinstance(partial, list): + return [resolve_partial(x) for x in partial] + elif isinstance(partial, dict): + return {key: resolve_partial(x) for key, x in partial.items()} + else: + return partial + + +def to_railroad( + element: pyparsing.ParserElement, + diagram_kwargs: typing.Optional[dict] = None, + vertical: int = 3, + show_results_names: bool = False, + show_groups: bool = False, +) -> List[NamedDiagram]: + """ + Convert a pyparsing element tree into a list of diagrams. This is the recommended entrypoint to diagram + creation if you want to access the Railroad tree before it is converted to HTML + :param element: base element of the parser being diagrammed + :param diagram_kwargs: kwargs to pass to the Diagram() constructor + :param vertical: (optional) - int - limit at which number of alternatives should be + shown vertically instead of horizontally + :param show_results_names - bool to indicate whether results name annotations should be + included in the diagram + :param show_groups - bool to indicate whether groups should be highlighted with an unlabeled + surrounding box + """ + # Convert the whole tree underneath the root + lookup = ConverterState(diagram_kwargs=diagram_kwargs or {}) + _to_diagram_element( + element, + lookup=lookup, + parent=None, + vertical=vertical, + show_results_names=show_results_names, + show_groups=show_groups, + ) + + root_id = id(element) + # Convert the root if it hasn't been already + if root_id in lookup: + if not element.customName: + lookup[root_id].name = "" + lookup[root_id].mark_for_extraction(root_id, lookup, force=True) + + # Now that we're finished, we can convert from intermediate structures into Railroad elements + diags = list(lookup.diagrams.values()) + if len(diags) > 1: + # collapse out duplicate diags with the same name + seen = set() + deduped_diags = [] + for d in diags: + # don't extract SkipTo elements, they are uninformative as subdiagrams + if d.name == "...": + continue + if d.name is not None and d.name not in seen: + seen.add(d.name) + deduped_diags.append(d) + resolved = [resolve_partial(partial) for partial in deduped_diags] + else: + # special case - if just one diagram, always display it, even if + # it has no name + resolved = [resolve_partial(partial) for partial in diags] + return sorted(resolved, key=lambda diag: diag.index) + + +def _should_vertical( + specification: int, exprs: Iterable[pyparsing.ParserElement] +) -> bool: + """ + Returns true if we should return a vertical list of elements + """ + if specification is None: + return False + else: + return len(_visible_exprs(exprs)) >= specification + + +class ElementState: + """ + State recorded for an individual pyparsing Element + """ + + # Note: this should be a dataclass, but we have to support Python 3.5 + def __init__( + self, + element: pyparsing.ParserElement, + converted: EditablePartial, + parent: EditablePartial, + number: int, + name: str = None, + parent_index: typing.Optional[int] = None, + ): + #: The pyparsing element that this represents + self.element: pyparsing.ParserElement = element + #: The name of the element + self.name: typing.Optional[str] = name + #: The output Railroad element in an unconverted state + self.converted: EditablePartial = converted + #: The parent Railroad element, which we store so that we can extract this if it's duplicated + self.parent: EditablePartial = parent + #: The order in which we found this element, used for sorting diagrams if this is extracted into a diagram + self.number: int = number + #: The index of this inside its parent + self.parent_index: typing.Optional[int] = parent_index + #: If true, we should extract this out into a subdiagram + self.extract: bool = False + #: If true, all of this element's children have been filled out + self.complete: bool = False + + def mark_for_extraction( + self, el_id: int, state: "ConverterState", name: str = None, force: bool = False + ): + """ + Called when this instance has been seen twice, and thus should eventually be extracted into a sub-diagram + :param el_id: id of the element + :param state: element/diagram state tracker + :param name: name to use for this element's text + :param force: If true, force extraction now, regardless of the state of this. Only useful for extracting the + root element when we know we're finished + """ + self.extract = True + + # Set the name + if not self.name: + if name: + # Allow forcing a custom name + self.name = name + elif self.element.customName: + self.name = self.element.customName + else: + self.name = "" + + # Just because this is marked for extraction doesn't mean we can do it yet. We may have to wait for children + # to be added + # Also, if this is just a string literal etc, don't bother extracting it + if force or (self.complete and _worth_extracting(self.element)): + state.extract_into_diagram(el_id) + + +class ConverterState: + """ + Stores some state that persists between recursions into the element tree + """ + + def __init__(self, diagram_kwargs: typing.Optional[dict] = None): + #: A dictionary mapping ParserElements to state relating to them + self._element_diagram_states: Dict[int, ElementState] = {} + #: A dictionary mapping ParserElement IDs to subdiagrams generated from them + self.diagrams: Dict[int, EditablePartial[NamedDiagram]] = {} + #: The index of the next unnamed element + self.unnamed_index: int = 1 + #: The index of the next element. This is used for sorting + self.index: int = 0 + #: Shared kwargs that are used to customize the construction of diagrams + self.diagram_kwargs: dict = diagram_kwargs or {} + self.extracted_diagram_names: Set[str] = set() + + def __setitem__(self, key: int, value: ElementState): + self._element_diagram_states[key] = value + + def __getitem__(self, key: int) -> ElementState: + return self._element_diagram_states[key] + + def __delitem__(self, key: int): + del self._element_diagram_states[key] + + def __contains__(self, key: int): + return key in self._element_diagram_states + + def generate_unnamed(self) -> int: + """ + Generate a number used in the name of an otherwise unnamed diagram + """ + self.unnamed_index += 1 + return self.unnamed_index + + def generate_index(self) -> int: + """ + Generate a number used to index a diagram + """ + self.index += 1 + return self.index + + def extract_into_diagram(self, el_id: int): + """ + Used when we encounter the same token twice in the same tree. When this + happens, we replace all instances of that token with a terminal, and + create a new subdiagram for the token + """ + position = self[el_id] + + # Replace the original definition of this element with a regular block + if position.parent: + ret = EditablePartial.from_call(railroad.NonTerminal, text=position.name) + if "item" in position.parent.kwargs: + position.parent.kwargs["item"] = ret + elif "items" in position.parent.kwargs: + position.parent.kwargs["items"][position.parent_index] = ret + + # If the element we're extracting is a group, skip to its content but keep the title + if position.converted.func == railroad.Group: + content = position.converted.kwargs["item"] + else: + content = position.converted + + self.diagrams[el_id] = EditablePartial.from_call( + NamedDiagram, + name=position.name, + diagram=EditablePartial.from_call( + railroad.Diagram, content, **self.diagram_kwargs + ), + index=position.number, + ) + + del self[el_id] + + +def _worth_extracting(element: pyparsing.ParserElement) -> bool: + """ + Returns true if this element is worth having its own sub-diagram. Simply, if any of its children + themselves have children, then its complex enough to extract + """ + children = element.recurse() + return any(child.recurse() for child in children) + + +def _apply_diagram_item_enhancements(fn): + """ + decorator to ensure enhancements to a diagram item (such as results name annotations) + get applied on return from _to_diagram_element (we do this since there are several + returns in _to_diagram_element) + """ + + def _inner( + element: pyparsing.ParserElement, + parent: typing.Optional[EditablePartial], + lookup: ConverterState = None, + vertical: int = None, + index: int = 0, + name_hint: str = None, + show_results_names: bool = False, + show_groups: bool = False, + ) -> typing.Optional[EditablePartial]: + ret = fn( + element, + parent, + lookup, + vertical, + index, + name_hint, + show_results_names, + show_groups, + ) + + # apply annotation for results name, if present + if show_results_names and ret is not None: + element_results_name = element.resultsName + if element_results_name: + # add "*" to indicate if this is a "list all results" name + element_results_name += "" if element.modalResults else "*" + ret = EditablePartial.from_call( + railroad.Group, item=ret, label=element_results_name + ) + + return ret + + return _inner + + +def _visible_exprs(exprs: Iterable[pyparsing.ParserElement]): + non_diagramming_exprs = ( + pyparsing.ParseElementEnhance, + pyparsing.PositionToken, + pyparsing.And._ErrorStop, + ) + return [ + e + for e in exprs + if not (e.customName or e.resultsName or isinstance(e, non_diagramming_exprs)) + ] + + +@_apply_diagram_item_enhancements +def _to_diagram_element( + element: pyparsing.ParserElement, + parent: typing.Optional[EditablePartial], + lookup: ConverterState = None, + vertical: int = None, + index: int = 0, + name_hint: str = None, + show_results_names: bool = False, + show_groups: bool = False, +) -> typing.Optional[EditablePartial]: + """ + Recursively converts a PyParsing Element to a railroad Element + :param lookup: The shared converter state that keeps track of useful things + :param index: The index of this element within the parent + :param parent: The parent of this element in the output tree + :param vertical: Controls at what point we make a list of elements vertical. If this is an integer (the default), + it sets the threshold of the number of items before we go vertical. If True, always go vertical, if False, never + do so + :param name_hint: If provided, this will override the generated name + :param show_results_names: bool flag indicating whether to add annotations for results names + :returns: The converted version of the input element, but as a Partial that hasn't yet been constructed + :param show_groups: bool flag indicating whether to show groups using bounding box + """ + exprs = element.recurse() + name = name_hint or element.customName or element.__class__.__name__ + + # Python's id() is used to provide a unique identifier for elements + el_id = id(element) + + element_results_name = element.resultsName + + # Here we basically bypass processing certain wrapper elements if they contribute nothing to the diagram + if not element.customName: + if isinstance( + element, + ( + # pyparsing.TokenConverter, + # pyparsing.Forward, + pyparsing.Located, + ), + ): + # However, if this element has a useful custom name, and its child does not, we can pass it on to the child + if exprs: + if not exprs[0].customName: + propagated_name = name + else: + propagated_name = None + + return _to_diagram_element( + element.expr, + parent=parent, + lookup=lookup, + vertical=vertical, + index=index, + name_hint=propagated_name, + show_results_names=show_results_names, + show_groups=show_groups, + ) + + # If the element isn't worth extracting, we always treat it as the first time we say it + if _worth_extracting(element): + if el_id in lookup: + # If we've seen this element exactly once before, we are only just now finding out that it's a duplicate, + # so we have to extract it into a new diagram. + looked_up = lookup[el_id] + looked_up.mark_for_extraction(el_id, lookup, name=name_hint) + ret = EditablePartial.from_call(railroad.NonTerminal, text=looked_up.name) + return ret + + elif el_id in lookup.diagrams: + # If we have seen the element at least twice before, and have already extracted it into a subdiagram, we + # just put in a marker element that refers to the sub-diagram + ret = EditablePartial.from_call( + railroad.NonTerminal, text=lookup.diagrams[el_id].kwargs["name"] + ) + return ret + + # Recursively convert child elements + # Here we find the most relevant Railroad element for matching pyparsing Element + # We use ``items=[]`` here to hold the place for where the child elements will go once created + if isinstance(element, pyparsing.And): + # detect And's created with ``expr*N`` notation - for these use a OneOrMore with a repeat + # (all will have the same name, and resultsName) + if not exprs: + return None + if len(set((e.name, e.resultsName) for e in exprs)) == 1: + ret = EditablePartial.from_call( + railroad.OneOrMore, item="", repeat=str(len(exprs)) + ) + elif _should_vertical(vertical, exprs): + ret = EditablePartial.from_call(railroad.Stack, items=[]) + else: + ret = EditablePartial.from_call(railroad.Sequence, items=[]) + elif isinstance(element, (pyparsing.Or, pyparsing.MatchFirst)): + if not exprs: + return None + if _should_vertical(vertical, exprs): + ret = EditablePartial.from_call(railroad.Choice, 0, items=[]) + else: + ret = EditablePartial.from_call(railroad.HorizontalChoice, items=[]) + elif isinstance(element, pyparsing.Each): + if not exprs: + return None + ret = EditablePartial.from_call(EachItem, items=[]) + elif isinstance(element, pyparsing.NotAny): + ret = EditablePartial.from_call(AnnotatedItem, label="NOT", item="") + elif isinstance(element, pyparsing.FollowedBy): + ret = EditablePartial.from_call(AnnotatedItem, label="LOOKAHEAD", item="") + elif isinstance(element, pyparsing.PrecededBy): + ret = EditablePartial.from_call(AnnotatedItem, label="LOOKBEHIND", item="") + elif isinstance(element, pyparsing.Group): + if show_groups: + ret = EditablePartial.from_call(AnnotatedItem, label="", item="") + else: + ret = EditablePartial.from_call(railroad.Group, label="", item="") + elif isinstance(element, pyparsing.TokenConverter): + label = type(element).__name__.lower() + if label == "tokenconverter": + ret = EditablePartial.from_call(railroad.Sequence, items=[]) + else: + ret = EditablePartial.from_call(AnnotatedItem, label=label, item="") + elif isinstance(element, pyparsing.Opt): + ret = EditablePartial.from_call(railroad.Optional, item="") + elif isinstance(element, pyparsing.OneOrMore): + ret = EditablePartial.from_call(railroad.OneOrMore, item="") + elif isinstance(element, pyparsing.ZeroOrMore): + ret = EditablePartial.from_call(railroad.ZeroOrMore, item="") + elif isinstance(element, pyparsing.Group): + ret = EditablePartial.from_call( + railroad.Group, item=None, label=element_results_name + ) + elif isinstance(element, pyparsing.Empty) and not element.customName: + # Skip unnamed "Empty" elements + ret = None + elif isinstance(element, pyparsing.ParseElementEnhance): + ret = EditablePartial.from_call(railroad.Sequence, items=[]) + elif len(exprs) > 0 and not element_results_name: + ret = EditablePartial.from_call(railroad.Group, item="", label=name) + elif len(exprs) > 0: + ret = EditablePartial.from_call(railroad.Sequence, items=[]) + else: + terminal = EditablePartial.from_call(railroad.Terminal, element.defaultName) + ret = terminal + + if ret is None: + return + + # Indicate this element's position in the tree so we can extract it if necessary + lookup[el_id] = ElementState( + element=element, + converted=ret, + parent=parent, + parent_index=index, + number=lookup.generate_index(), + ) + if element.customName: + lookup[el_id].mark_for_extraction(el_id, lookup, element.customName) + + i = 0 + for expr in exprs: + # Add a placeholder index in case we have to extract the child before we even add it to the parent + if "items" in ret.kwargs: + ret.kwargs["items"].insert(i, None) + + item = _to_diagram_element( + expr, + parent=ret, + lookup=lookup, + vertical=vertical, + index=i, + show_results_names=show_results_names, + show_groups=show_groups, + ) + + # Some elements don't need to be shown in the diagram + if item is not None: + if "item" in ret.kwargs: + ret.kwargs["item"] = item + elif "items" in ret.kwargs: + # If we've already extracted the child, don't touch this index, since it's occupied by a nonterminal + ret.kwargs["items"][i] = item + i += 1 + elif "items" in ret.kwargs: + # If we're supposed to skip this element, remove it from the parent + del ret.kwargs["items"][i] + + # If all this items children are none, skip this item + if ret and ( + ("items" in ret.kwargs and len(ret.kwargs["items"]) == 0) + or ("item" in ret.kwargs and ret.kwargs["item"] is None) + ): + ret = EditablePartial.from_call(railroad.Terminal, name) + + # Mark this element as "complete", ie it has all of its children + if el_id in lookup: + lookup[el_id].complete = True + + if el_id in lookup and lookup[el_id].extract and lookup[el_id].complete: + lookup.extract_into_diagram(el_id) + if ret is not None: + ret = EditablePartial.from_call( + railroad.NonTerminal, text=lookup.diagrams[el_id].kwargs["name"] + ) + + return ret diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/exceptions.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/exceptions.py new file mode 100644 index 0000000..12219f1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/exceptions.py @@ -0,0 +1,299 @@ +# exceptions.py + +import re +import sys +import typing + +from .util import ( + col, + line, + lineno, + _collapse_string_to_ranges, + replaced_by_pep8, +) +from .unicode import pyparsing_unicode as ppu + + +class ExceptionWordUnicode(ppu.Latin1, ppu.LatinA, ppu.LatinB, ppu.Greek, ppu.Cyrillic): + pass + + +_extract_alphanums = _collapse_string_to_ranges(ExceptionWordUnicode.alphanums) +_exception_word_extractor = re.compile("([" + _extract_alphanums + "]{1,16})|.") + + +class ParseBaseException(Exception): + """base exception class for all parsing runtime exceptions""" + + loc: int + msg: str + pstr: str + parser_element: typing.Any # "ParserElement" + args: typing.Tuple[str, int, typing.Optional[str]] + + __slots__ = ( + "loc", + "msg", + "pstr", + "parser_element", + "args", + ) + + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( + self, + pstr: str, + loc: int = 0, + msg: typing.Optional[str] = None, + elem=None, + ): + self.loc = loc + if msg is None: + self.msg = pstr + self.pstr = "" + else: + self.msg = msg + self.pstr = pstr + self.parser_element = elem + self.args = (pstr, loc, msg) + + @staticmethod + def explain_exception(exc, depth=16): + """ + Method to take an exception and translate the Python internal traceback into a list + of the pyparsing expressions that caused the exception to be raised. + + Parameters: + + - exc - exception raised during parsing (need not be a ParseException, in support + of Python exceptions that might be raised in a parse action) + - depth (default=16) - number of levels back in the stack trace to list expression + and function names; if None, the full stack trace names will be listed; if 0, only + the failing input line, marker, and exception string will be shown + + Returns a multi-line string listing the ParserElements and/or function names in the + exception's stack trace. + """ + import inspect + from .core import ParserElement + + if depth is None: + depth = sys.getrecursionlimit() + ret = [] + if isinstance(exc, ParseBaseException): + ret.append(exc.line) + ret.append(" " * (exc.column - 1) + "^") + ret.append(f"{type(exc).__name__}: {exc}") + + if depth > 0: + callers = inspect.getinnerframes(exc.__traceback__, context=depth) + seen = set() + for i, ff in enumerate(callers[-depth:]): + frm = ff[0] + + f_self = frm.f_locals.get("self", None) + if isinstance(f_self, ParserElement): + if not frm.f_code.co_name.startswith( + ("parseImpl", "_parseNoCache") + ): + continue + if id(f_self) in seen: + continue + seen.add(id(f_self)) + + self_type = type(f_self) + ret.append( + f"{self_type.__module__}.{self_type.__name__} - {f_self}" + ) + + elif f_self is not None: + self_type = type(f_self) + ret.append(f"{self_type.__module__}.{self_type.__name__}") + + else: + code = frm.f_code + if code.co_name in ("wrapper", ""): + continue + + ret.append(code.co_name) + + depth -= 1 + if not depth: + break + + return "\n".join(ret) + + @classmethod + def _from_exception(cls, pe): + """ + internal factory method to simplify creating one type of ParseException + from another - avoids having __init__ signature conflicts among subclasses + """ + return cls(pe.pstr, pe.loc, pe.msg, pe.parser_element) + + @property + def line(self) -> str: + """ + Return the line of text where the exception occurred. + """ + return line(self.loc, self.pstr) + + @property + def lineno(self) -> int: + """ + Return the 1-based line number of text where the exception occurred. + """ + return lineno(self.loc, self.pstr) + + @property + def col(self) -> int: + """ + Return the 1-based column on the line of text where the exception occurred. + """ + return col(self.loc, self.pstr) + + @property + def column(self) -> int: + """ + Return the 1-based column on the line of text where the exception occurred. + """ + return col(self.loc, self.pstr) + + # pre-PEP8 compatibility + @property + def parserElement(self): + return self.parser_element + + @parserElement.setter + def parserElement(self, elem): + self.parser_element = elem + + def __str__(self) -> str: + if self.pstr: + if self.loc >= len(self.pstr): + foundstr = ", found end of text" + else: + # pull out next word at error location + found_match = _exception_word_extractor.match(self.pstr, self.loc) + if found_match is not None: + found = found_match.group(0) + else: + found = self.pstr[self.loc : self.loc + 1] + foundstr = (", found %r" % found).replace(r"\\", "\\") + else: + foundstr = "" + return f"{self.msg}{foundstr} (at char {self.loc}), (line:{self.lineno}, col:{self.column})" + + def __repr__(self): + return str(self) + + def mark_input_line( + self, marker_string: typing.Optional[str] = None, *, markerString: str = ">!<" + ) -> str: + """ + Extracts the exception line from the input string, and marks + the location of the exception with a special symbol. + """ + markerString = marker_string if marker_string is not None else markerString + line_str = self.line + line_column = self.column - 1 + if markerString: + line_str = "".join( + (line_str[:line_column], markerString, line_str[line_column:]) + ) + return line_str.strip() + + def explain(self, depth=16) -> str: + """ + Method to translate the Python internal traceback into a list + of the pyparsing expressions that caused the exception to be raised. + + Parameters: + + - depth (default=16) - number of levels back in the stack trace to list expression + and function names; if None, the full stack trace names will be listed; if 0, only + the failing input line, marker, and exception string will be shown + + Returns a multi-line string listing the ParserElements and/or function names in the + exception's stack trace. + + Example:: + + expr = pp.Word(pp.nums) * 3 + try: + expr.parse_string("123 456 A789") + except pp.ParseException as pe: + print(pe.explain(depth=0)) + + prints:: + + 123 456 A789 + ^ + ParseException: Expected W:(0-9), found 'A' (at char 8), (line:1, col:9) + + Note: the diagnostic output will include string representations of the expressions + that failed to parse. These representations will be more helpful if you use `set_name` to + give identifiable names to your expressions. Otherwise they will use the default string + forms, which may be cryptic to read. + + Note: pyparsing's default truncation of exception tracebacks may also truncate the + stack of expressions that are displayed in the ``explain`` output. To get the full listing + of parser expressions, you may have to set ``ParserElement.verbose_stacktrace = True`` + """ + return self.explain_exception(self, depth) + + # fmt: off + @replaced_by_pep8(mark_input_line) + def markInputline(self): ... + # fmt: on + + +class ParseException(ParseBaseException): + """ + Exception thrown when a parse expression doesn't match the input string + + Example:: + + try: + Word(nums).set_name("integer").parse_string("ABC") + except ParseException as pe: + print(pe) + print("column: {}".format(pe.column)) + + prints:: + + Expected integer (at char 0), (line:1, col:1) + column: 1 + + """ + + +class ParseFatalException(ParseBaseException): + """ + User-throwable exception thrown when inconsistent parse content + is found; stops all parsing immediately + """ + + +class ParseSyntaxException(ParseFatalException): + """ + Just like :class:`ParseFatalException`, but thrown internally + when an :class:`ErrorStop` ('-' operator) indicates + that parsing is to stop immediately because an unbacktrackable + syntax error has been found. + """ + + +class RecursiveGrammarException(Exception): + """ + Exception thrown by :class:`ParserElement.validate` if the + grammar could be left-recursive; parser may need to enable + left recursion using :class:`ParserElement.enable_left_recursion` + """ + + def __init__(self, parseElementList): + self.parseElementTrace = parseElementList + + def __str__(self) -> str: + return f"RecursiveGrammarException: {self.parseElementTrace}" diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/helpers.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/helpers.py new file mode 100644 index 0000000..018f0d6 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/helpers.py @@ -0,0 +1,1100 @@ +# helpers.py +import html.entities +import re +import sys +import typing + +from . import __diag__ +from .core import * +from .util import ( + _bslash, + _flatten, + _escape_regex_range_chars, + replaced_by_pep8, +) + + +# +# global helpers +# +def counted_array( + expr: ParserElement, + int_expr: typing.Optional[ParserElement] = None, + *, + intExpr: typing.Optional[ParserElement] = None, +) -> ParserElement: + """Helper to define a counted list of expressions. + + This helper defines a pattern of the form:: + + integer expr expr expr... + + where the leading integer tells how many expr expressions follow. + The matched tokens returns the array of expr tokens as a list - the + leading count token is suppressed. + + If ``int_expr`` is specified, it should be a pyparsing expression + that produces an integer value. + + Example:: + + counted_array(Word(alphas)).parse_string('2 ab cd ef') # -> ['ab', 'cd'] + + # in this parser, the leading integer value is given in binary, + # '10' indicating that 2 values are in the array + binary_constant = Word('01').set_parse_action(lambda t: int(t[0], 2)) + counted_array(Word(alphas), int_expr=binary_constant).parse_string('10 ab cd ef') # -> ['ab', 'cd'] + + # if other fields must be parsed after the count but before the + # list items, give the fields results names and they will + # be preserved in the returned ParseResults: + count_with_metadata = integer + Word(alphas)("type") + typed_array = counted_array(Word(alphanums), int_expr=count_with_metadata)("items") + result = typed_array.parse_string("3 bool True True False") + print(result.dump()) + + # prints + # ['True', 'True', 'False'] + # - items: ['True', 'True', 'False'] + # - type: 'bool' + """ + intExpr = intExpr or int_expr + array_expr = Forward() + + def count_field_parse_action(s, l, t): + nonlocal array_expr + n = t[0] + array_expr <<= (expr * n) if n else Empty() + # clear list contents, but keep any named results + del t[:] + + if intExpr is None: + intExpr = Word(nums).set_parse_action(lambda t: int(t[0])) + else: + intExpr = intExpr.copy() + intExpr.set_name("arrayLen") + intExpr.add_parse_action(count_field_parse_action, call_during_try=True) + return (intExpr + array_expr).set_name("(len) " + str(expr) + "...") + + +def match_previous_literal(expr: ParserElement) -> ParserElement: + """Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks for + a 'repeat' of a previous expression. For example:: + + first = Word(nums) + second = match_previous_literal(first) + match_expr = first + ":" + second + + will match ``"1:1"``, but not ``"1:2"``. Because this + matches a previous literal, will also match the leading + ``"1:1"`` in ``"1:10"``. If this is not desired, use + :class:`match_previous_expr`. Do *not* use with packrat parsing + enabled. + """ + rep = Forward() + + def copy_token_to_repeater(s, l, t): + if t: + if len(t) == 1: + rep << t[0] + else: + # flatten t tokens + tflat = _flatten(t.as_list()) + rep << And(Literal(tt) for tt in tflat) + else: + rep << Empty() + + expr.add_parse_action(copy_token_to_repeater, callDuringTry=True) + rep.set_name("(prev) " + str(expr)) + return rep + + +def match_previous_expr(expr: ParserElement) -> ParserElement: + """Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks for + a 'repeat' of a previous expression. For example:: + + first = Word(nums) + second = match_previous_expr(first) + match_expr = first + ":" + second + + will match ``"1:1"``, but not ``"1:2"``. Because this + matches by expressions, will *not* match the leading ``"1:1"`` + in ``"1:10"``; the expressions are evaluated first, and then + compared, so ``"1"`` is compared with ``"10"``. Do *not* use + with packrat parsing enabled. + """ + rep = Forward() + e2 = expr.copy() + rep <<= e2 + + def copy_token_to_repeater(s, l, t): + matchTokens = _flatten(t.as_list()) + + def must_match_these_tokens(s, l, t): + theseTokens = _flatten(t.as_list()) + if theseTokens != matchTokens: + raise ParseException( + s, l, f"Expected {matchTokens}, found{theseTokens}" + ) + + rep.set_parse_action(must_match_these_tokens, callDuringTry=True) + + expr.add_parse_action(copy_token_to_repeater, callDuringTry=True) + rep.set_name("(prev) " + str(expr)) + return rep + + +def one_of( + strs: Union[typing.Iterable[str], str], + caseless: bool = False, + use_regex: bool = True, + as_keyword: bool = False, + *, + useRegex: bool = True, + asKeyword: bool = False, +) -> ParserElement: + """Helper to quickly define a set of alternative :class:`Literal` s, + and makes sure to do longest-first testing when there is a conflict, + regardless of the input order, but returns + a :class:`MatchFirst` for best performance. + + Parameters: + + - ``strs`` - a string of space-delimited literals, or a collection of + string literals + - ``caseless`` - treat all literals as caseless - (default= ``False``) + - ``use_regex`` - as an optimization, will + generate a :class:`Regex` object; otherwise, will generate + a :class:`MatchFirst` object (if ``caseless=True`` or ``as_keyword=True``, or if + creating a :class:`Regex` raises an exception) - (default= ``True``) + - ``as_keyword`` - enforce :class:`Keyword`-style matching on the + generated expressions - (default= ``False``) + - ``asKeyword`` and ``useRegex`` are retained for pre-PEP8 compatibility, + but will be removed in a future release + + Example:: + + comp_oper = one_of("< = > <= >= !=") + var = Word(alphas) + number = Word(nums) + term = var | number + comparison_expr = term + comp_oper + term + print(comparison_expr.search_string("B = 12 AA=23 B<=AA AA>12")) + + prints:: + + [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] + """ + asKeyword = asKeyword or as_keyword + useRegex = useRegex and use_regex + + if ( + isinstance(caseless, str_type) + and __diag__.warn_on_multiple_string_args_to_oneof + ): + warnings.warn( + "More than one string argument passed to one_of, pass" + " choices as a list or space-delimited string", + stacklevel=2, + ) + + if caseless: + isequal = lambda a, b: a.upper() == b.upper() + masks = lambda a, b: b.upper().startswith(a.upper()) + parseElementClass = CaselessKeyword if asKeyword else CaselessLiteral + else: + isequal = lambda a, b: a == b + masks = lambda a, b: b.startswith(a) + parseElementClass = Keyword if asKeyword else Literal + + symbols: List[str] = [] + if isinstance(strs, str_type): + strs = typing.cast(str, strs) + symbols = strs.split() + elif isinstance(strs, Iterable): + symbols = list(strs) + else: + raise TypeError("Invalid argument to one_of, expected string or iterable") + if not symbols: + return NoMatch() + + # reorder given symbols to take care to avoid masking longer choices with shorter ones + # (but only if the given symbols are not just single characters) + if any(len(sym) > 1 for sym in symbols): + i = 0 + while i < len(symbols) - 1: + cur = symbols[i] + for j, other in enumerate(symbols[i + 1 :]): + if isequal(other, cur): + del symbols[i + j + 1] + break + elif masks(cur, other): + del symbols[i + j + 1] + symbols.insert(i, other) + break + else: + i += 1 + + if useRegex: + re_flags: int = re.IGNORECASE if caseless else 0 + + try: + if all(len(sym) == 1 for sym in symbols): + # symbols are just single characters, create range regex pattern + patt = f"[{''.join(_escape_regex_range_chars(sym) for sym in symbols)}]" + else: + patt = "|".join(re.escape(sym) for sym in symbols) + + # wrap with \b word break markers if defining as keywords + if asKeyword: + patt = rf"\b(?:{patt})\b" + + ret = Regex(patt, flags=re_flags).set_name(" | ".join(symbols)) + + if caseless: + # add parse action to return symbols as specified, not in random + # casing as found in input string + symbol_map = {sym.lower(): sym for sym in symbols} + ret.add_parse_action(lambda s, l, t: symbol_map[t[0].lower()]) + + return ret + + except re.error: + warnings.warn( + "Exception creating Regex for one_of, building MatchFirst", stacklevel=2 + ) + + # last resort, just use MatchFirst + return MatchFirst(parseElementClass(sym) for sym in symbols).set_name( + " | ".join(symbols) + ) + + +def dict_of(key: ParserElement, value: ParserElement) -> ParserElement: + """Helper to easily and clearly define a dictionary by specifying + the respective patterns for the key and value. Takes care of + defining the :class:`Dict`, :class:`ZeroOrMore`, and + :class:`Group` tokens in the proper order. The key pattern + can include delimiting markers or punctuation, as long as they are + suppressed, thereby leaving the significant key text. The value + pattern can include named results, so that the :class:`Dict` results + can include named token fields. + + Example:: + + text = "shape: SQUARE posn: upper left color: light blue texture: burlap" + attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) + print(attr_expr[1, ...].parse_string(text).dump()) + + attr_label = label + attr_value = Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join) + + # similar to Dict, but simpler call format + result = dict_of(attr_label, attr_value).parse_string(text) + print(result.dump()) + print(result['shape']) + print(result.shape) # object attribute access works too + print(result.as_dict()) + + prints:: + + [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] + - color: 'light blue' + - posn: 'upper left' + - shape: 'SQUARE' + - texture: 'burlap' + SQUARE + SQUARE + {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} + """ + return Dict(OneOrMore(Group(key + value))) + + +def original_text_for( + expr: ParserElement, as_string: bool = True, *, asString: bool = True +) -> ParserElement: + """Helper to return the original, untokenized text for a given + expression. Useful to restore the parsed fields of an HTML start + tag into the raw tag text itself, or to revert separate tokens with + intervening whitespace back to the original matching input text. By + default, returns a string containing the original parsed text. + + If the optional ``as_string`` argument is passed as + ``False``, then the return value is + a :class:`ParseResults` containing any results names that + were originally matched, and a single token containing the original + matched text from the input string. So if the expression passed to + :class:`original_text_for` contains expressions with defined + results names, you must set ``as_string`` to ``False`` if you + want to preserve those results name values. + + The ``asString`` pre-PEP8 argument is retained for compatibility, + but will be removed in a future release. + + Example:: + + src = "this is test bold text normal text " + for tag in ("b", "i"): + opener, closer = make_html_tags(tag) + patt = original_text_for(opener + ... + closer) + print(patt.search_string(src)[0]) + + prints:: + + [' bold text '] + ['text'] + """ + asString = asString and as_string + + locMarker = Empty().set_parse_action(lambda s, loc, t: loc) + endlocMarker = locMarker.copy() + endlocMarker.callPreparse = False + matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") + if asString: + extractText = lambda s, l, t: s[t._original_start : t._original_end] + else: + + def extractText(s, l, t): + t[:] = [s[t.pop("_original_start") : t.pop("_original_end")]] + + matchExpr.set_parse_action(extractText) + matchExpr.ignoreExprs = expr.ignoreExprs + matchExpr.suppress_warning(Diagnostics.warn_ungrouped_named_tokens_in_collection) + return matchExpr + + +def ungroup(expr: ParserElement) -> ParserElement: + """Helper to undo pyparsing's default grouping of And expressions, + even if all but one are non-empty. + """ + return TokenConverter(expr).add_parse_action(lambda t: t[0]) + + +def locatedExpr(expr: ParserElement) -> ParserElement: + """ + (DEPRECATED - future code should use the :class:`Located` class) + Helper to decorate a returned token with its starting and ending + locations in the input string. + + This helper adds the following results names: + + - ``locn_start`` - location where matched expression begins + - ``locn_end`` - location where matched expression ends + - ``value`` - the actual parsed results + + Be careful if the input text contains ```` characters, you + may want to call :class:`ParserElement.parse_with_tabs` + + Example:: + + wd = Word(alphas) + for match in locatedExpr(wd).search_string("ljsdf123lksdjjf123lkkjj1222"): + print(match) + + prints:: + + [[0, 'ljsdf', 5]] + [[8, 'lksdjjf', 15]] + [[18, 'lkkjj', 23]] + """ + locator = Empty().set_parse_action(lambda ss, ll, tt: ll) + return Group( + locator("locn_start") + + expr("value") + + locator.copy().leaveWhitespace()("locn_end") + ) + + +def nested_expr( + opener: Union[str, ParserElement] = "(", + closer: Union[str, ParserElement] = ")", + content: typing.Optional[ParserElement] = None, + ignore_expr: ParserElement = quoted_string(), + *, + ignoreExpr: ParserElement = quoted_string(), +) -> ParserElement: + """Helper method for defining nested lists enclosed in opening and + closing delimiters (``"("`` and ``")"`` are the default). + + Parameters: + + - ``opener`` - opening character for a nested list + (default= ``"("``); can also be a pyparsing expression + - ``closer`` - closing character for a nested list + (default= ``")"``); can also be a pyparsing expression + - ``content`` - expression for items within the nested lists + (default= ``None``) + - ``ignore_expr`` - expression for ignoring opening and closing delimiters + (default= :class:`quoted_string`) + - ``ignoreExpr`` - this pre-PEP8 argument is retained for compatibility + but will be removed in a future release + + If an expression is not provided for the content argument, the + nested expression will capture all whitespace-delimited content + between delimiters as a list of separate values. + + Use the ``ignore_expr`` argument to define expressions that may + contain opening or closing characters that should not be treated as + opening or closing characters for nesting, such as quoted_string or + a comment expression. Specify multiple expressions using an + :class:`Or` or :class:`MatchFirst`. The default is + :class:`quoted_string`, but if no expressions are to be ignored, then + pass ``None`` for this argument. + + Example:: + + data_type = one_of("void int short long char float double") + decl_data_type = Combine(data_type + Opt(Word('*'))) + ident = Word(alphas+'_', alphanums+'_') + number = pyparsing_common.number + arg = Group(decl_data_type + ident) + LPAR, RPAR = map(Suppress, "()") + + code_body = nested_expr('{', '}', ignore_expr=(quoted_string | c_style_comment)) + + c_function = (decl_data_type("type") + + ident("name") + + LPAR + Opt(DelimitedList(arg), [])("args") + RPAR + + code_body("body")) + c_function.ignore(c_style_comment) + + source_code = ''' + int is_odd(int x) { + return (x%2); + } + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { + return (10+ord(hchar)-ord('A')); + } + } + ''' + for func in c_function.search_string(source_code): + print("%(name)s (%(type)s) args: %(args)s" % func) + + + prints:: + + is_odd (int) args: [['int', 'x']] + dec_to_hex (int) args: [['char', 'hchar']] + """ + if ignoreExpr != ignore_expr: + ignoreExpr = ignore_expr if ignoreExpr == quoted_string() else ignoreExpr + if opener == closer: + raise ValueError("opening and closing strings cannot be the same") + if content is None: + if isinstance(opener, str_type) and isinstance(closer, str_type): + opener = typing.cast(str, opener) + closer = typing.cast(str, closer) + if len(opener) == 1 and len(closer) == 1: + if ignoreExpr is not None: + content = Combine( + OneOrMore( + ~ignoreExpr + + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS, + exact=1, + ) + ) + ).set_parse_action(lambda t: t[0].strip()) + else: + content = empty.copy() + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS + ).set_parse_action(lambda t: t[0].strip()) + else: + if ignoreExpr is not None: + content = Combine( + OneOrMore( + ~ignoreExpr + + ~Literal(opener) + + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) + ) + ).set_parse_action(lambda t: t[0].strip()) + else: + content = Combine( + OneOrMore( + ~Literal(opener) + + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) + ) + ).set_parse_action(lambda t: t[0].strip()) + else: + raise ValueError( + "opening and closing arguments must be strings if no content expression is given" + ) + ret = Forward() + if ignoreExpr is not None: + ret <<= Group( + Suppress(opener) + ZeroOrMore(ignoreExpr | ret | content) + Suppress(closer) + ) + else: + ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer)) + ret.set_name("nested %s%s expression" % (opener, closer)) + return ret + + +def _makeTags(tagStr, xml, suppress_LT=Suppress("<"), suppress_GT=Suppress(">")): + """Internal helper to construct opening and closing tag expressions, given a tag name""" + if isinstance(tagStr, str_type): + resname = tagStr + tagStr = Keyword(tagStr, caseless=not xml) + else: + resname = tagStr.name + + tagAttrName = Word(alphas, alphanums + "_-:") + if xml: + tagAttrValue = dbl_quoted_string.copy().set_parse_action(remove_quotes) + openTag = ( + suppress_LT + + tagStr("tag") + + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue))) + + Opt("/", default=[False])("empty").set_parse_action( + lambda s, l, t: t[0] == "/" + ) + + suppress_GT + ) + else: + tagAttrValue = quoted_string.copy().set_parse_action(remove_quotes) | Word( + printables, exclude_chars=">" + ) + openTag = ( + suppress_LT + + tagStr("tag") + + Dict( + ZeroOrMore( + Group( + tagAttrName.set_parse_action(lambda t: t[0].lower()) + + Opt(Suppress("=") + tagAttrValue) + ) + ) + ) + + Opt("/", default=[False])("empty").set_parse_action( + lambda s, l, t: t[0] == "/" + ) + + suppress_GT + ) + closeTag = Combine(Literal("", adjacent=False) + + openTag.set_name("<%s>" % resname) + # add start results name in parse action now that ungrouped names are not reported at two levels + openTag.add_parse_action( + lambda t: t.__setitem__( + "start" + "".join(resname.replace(":", " ").title().split()), t.copy() + ) + ) + closeTag = closeTag( + "end" + "".join(resname.replace(":", " ").title().split()) + ).set_name("" % resname) + openTag.tag = resname + closeTag.tag = resname + openTag.tag_body = SkipTo(closeTag()) + return openTag, closeTag + + +def make_html_tags( + tag_str: Union[str, ParserElement] +) -> Tuple[ParserElement, ParserElement]: + """Helper to construct opening and closing tag expressions for HTML, + given a tag name. Matches tags in either upper or lower case, + attributes with namespaces and with quoted or unquoted values. + + Example:: + + text = 'More info at the pyparsing wiki page' + # make_html_tags returns pyparsing expressions for the opening and + # closing tags as a 2-tuple + a, a_end = make_html_tags("A") + link_expr = a + SkipTo(a_end)("link_text") + a_end + + for link in link_expr.search_string(text): + # attributes in the tag (like "href" shown here) are + # also accessible as named results + print(link.link_text, '->', link.href) + + prints:: + + pyparsing -> https://github.com/pyparsing/pyparsing/wiki + """ + return _makeTags(tag_str, False) + + +def make_xml_tags( + tag_str: Union[str, ParserElement] +) -> Tuple[ParserElement, ParserElement]: + """Helper to construct opening and closing tag expressions for XML, + given a tag name. Matches tags only in the given upper/lower case. + + Example: similar to :class:`make_html_tags` + """ + return _makeTags(tag_str, True) + + +any_open_tag: ParserElement +any_close_tag: ParserElement +any_open_tag, any_close_tag = make_html_tags( + Word(alphas, alphanums + "_:").set_name("any tag") +) + +_htmlEntityMap = {k.rstrip(";"): v for k, v in html.entities.html5.items()} +common_html_entity = Regex("&(?P" + "|".join(_htmlEntityMap) + ");").set_name( + "common HTML entity" +) + + +def replace_html_entity(s, l, t): + """Helper parser action to replace common HTML entities with their special characters""" + return _htmlEntityMap.get(t.entity) + + +class OpAssoc(Enum): + """Enumeration of operator associativity + - used in constructing InfixNotationOperatorSpec for :class:`infix_notation`""" + + LEFT = 1 + RIGHT = 2 + + +InfixNotationOperatorArgType = Union[ + ParserElement, str, Tuple[Union[ParserElement, str], Union[ParserElement, str]] +] +InfixNotationOperatorSpec = Union[ + Tuple[ + InfixNotationOperatorArgType, + int, + OpAssoc, + typing.Optional[ParseAction], + ], + Tuple[ + InfixNotationOperatorArgType, + int, + OpAssoc, + ], +] + + +def infix_notation( + base_expr: ParserElement, + op_list: List[InfixNotationOperatorSpec], + lpar: Union[str, ParserElement] = Suppress("("), + rpar: Union[str, ParserElement] = Suppress(")"), +) -> ParserElement: + """Helper method for constructing grammars of expressions made up of + operators working in a precedence hierarchy. Operators may be unary + or binary, left- or right-associative. Parse actions can also be + attached to operator expressions. The generated parser will also + recognize the use of parentheses to override operator precedences + (see example below). + + Note: if you define a deep operator list, you may see performance + issues when using infix_notation. See + :class:`ParserElement.enable_packrat` for a mechanism to potentially + improve your parser performance. + + Parameters: + + - ``base_expr`` - expression representing the most basic operand to + be used in the expression + - ``op_list`` - list of tuples, one for each operator precedence level + in the expression grammar; each tuple is of the form ``(op_expr, + num_operands, right_left_assoc, (optional)parse_action)``, where: + + - ``op_expr`` is the pyparsing expression for the operator; may also + be a string, which will be converted to a Literal; if ``num_operands`` + is 3, ``op_expr`` is a tuple of two expressions, for the two + operators separating the 3 terms + - ``num_operands`` is the number of terms for this operator (must be 1, + 2, or 3) + - ``right_left_assoc`` is the indicator whether the operator is right + or left associative, using the pyparsing-defined constants + ``OpAssoc.RIGHT`` and ``OpAssoc.LEFT``. + - ``parse_action`` is the parse action to be associated with + expressions matching this operator expression (the parse action + tuple member may be omitted); if the parse action is passed + a tuple or list of functions, this is equivalent to calling + ``set_parse_action(*fn)`` + (:class:`ParserElement.set_parse_action`) + - ``lpar`` - expression for matching left-parentheses; if passed as a + str, then will be parsed as ``Suppress(lpar)``. If lpar is passed as + an expression (such as ``Literal('(')``), then it will be kept in + the parsed results, and grouped with them. (default= ``Suppress('(')``) + - ``rpar`` - expression for matching right-parentheses; if passed as a + str, then will be parsed as ``Suppress(rpar)``. If rpar is passed as + an expression (such as ``Literal(')')``), then it will be kept in + the parsed results, and grouped with them. (default= ``Suppress(')')``) + + Example:: + + # simple example of four-function arithmetic with ints and + # variable names + integer = pyparsing_common.signed_integer + varname = pyparsing_common.identifier + + arith_expr = infix_notation(integer | varname, + [ + ('-', 1, OpAssoc.RIGHT), + (one_of('* /'), 2, OpAssoc.LEFT), + (one_of('+ -'), 2, OpAssoc.LEFT), + ]) + + arith_expr.run_tests(''' + 5+3*6 + (5+3)*6 + -2--11 + ''', full_dump=False) + + prints:: + + 5+3*6 + [[5, '+', [3, '*', 6]]] + + (5+3)*6 + [[[5, '+', 3], '*', 6]] + + (5+x)*y + [[[5, '+', 'x'], '*', 'y']] + + -2--11 + [[['-', 2], '-', ['-', 11]]] + """ + + # captive version of FollowedBy that does not do parse actions or capture results names + class _FB(FollowedBy): + def parseImpl(self, instring, loc, doActions=True): + self.expr.try_parse(instring, loc) + return loc, [] + + _FB.__name__ = "FollowedBy>" + + ret = Forward() + if isinstance(lpar, str): + lpar = Suppress(lpar) + if isinstance(rpar, str): + rpar = Suppress(rpar) + + # if lpar and rpar are not suppressed, wrap in group + if not (isinstance(rpar, Suppress) and isinstance(rpar, Suppress)): + lastExpr = base_expr | Group(lpar + ret + rpar) + else: + lastExpr = base_expr | (lpar + ret + rpar) + + arity: int + rightLeftAssoc: opAssoc + pa: typing.Optional[ParseAction] + opExpr1: ParserElement + opExpr2: ParserElement + for i, operDef in enumerate(op_list): + opExpr, arity, rightLeftAssoc, pa = (operDef + (None,))[:4] # type: ignore[assignment] + if isinstance(opExpr, str_type): + opExpr = ParserElement._literalStringClass(opExpr) + opExpr = typing.cast(ParserElement, opExpr) + if arity == 3: + if not isinstance(opExpr, (tuple, list)) or len(opExpr) != 2: + raise ValueError( + "if numterms=3, opExpr must be a tuple or list of two expressions" + ) + opExpr1, opExpr2 = opExpr + term_name = f"{opExpr1}{opExpr2} term" + else: + term_name = f"{opExpr} term" + + if not 1 <= arity <= 3: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + + if rightLeftAssoc not in (OpAssoc.LEFT, OpAssoc.RIGHT): + raise ValueError("operator must indicate right or left associativity") + + thisExpr: ParserElement = Forward().set_name(term_name) + thisExpr = typing.cast(Forward, thisExpr) + if rightLeftAssoc is OpAssoc.LEFT: + if arity == 1: + matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + opExpr[1, ...]) + elif arity == 2: + if opExpr is not None: + matchExpr = _FB(lastExpr + opExpr + lastExpr) + Group( + lastExpr + (opExpr + lastExpr)[1, ...] + ) + else: + matchExpr = _FB(lastExpr + lastExpr) + Group(lastExpr[2, ...]) + elif arity == 3: + matchExpr = _FB( + lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr + ) + Group(lastExpr + OneOrMore(opExpr1 + lastExpr + opExpr2 + lastExpr)) + elif rightLeftAssoc is OpAssoc.RIGHT: + if arity == 1: + # try to avoid LR with this extra test + if not isinstance(opExpr, Opt): + opExpr = Opt(opExpr) + matchExpr = _FB(opExpr.expr + thisExpr) + Group(opExpr + thisExpr) + elif arity == 2: + if opExpr is not None: + matchExpr = _FB(lastExpr + opExpr + thisExpr) + Group( + lastExpr + (opExpr + thisExpr)[1, ...] + ) + else: + matchExpr = _FB(lastExpr + thisExpr) + Group( + lastExpr + thisExpr[1, ...] + ) + elif arity == 3: + matchExpr = _FB( + lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr + ) + Group(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + if pa: + if isinstance(pa, (tuple, list)): + matchExpr.set_parse_action(*pa) + else: + matchExpr.set_parse_action(pa) + thisExpr <<= (matchExpr | lastExpr).setName(term_name) + lastExpr = thisExpr + ret <<= lastExpr + return ret + + +def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]): + """ + (DEPRECATED - use :class:`IndentedBlock` class instead) + Helper method for defining space-delimited indentation blocks, + such as those used to define block statements in Python source code. + + Parameters: + + - ``blockStatementExpr`` - expression defining syntax of statement that + is repeated within the indented block + - ``indentStack`` - list created by caller to manage indentation stack + (multiple ``statementWithIndentedBlock`` expressions within a single + grammar should share a common ``indentStack``) + - ``indent`` - boolean indicating whether block must be indented beyond + the current level; set to ``False`` for block of left-most statements + (default= ``True``) + + A valid block must contain at least one ``blockStatement``. + + (Note that indentedBlock uses internal parse actions which make it + incompatible with packrat parsing.) + + Example:: + + data = ''' + def A(z): + A1 + B = 100 + G = A2 + A2 + A3 + B + def BB(a,b,c): + BB1 + def BBA(): + bba1 + bba2 + bba3 + C + D + def spam(x,y): + def eggs(z): + pass + ''' + + + indentStack = [1] + stmt = Forward() + + identifier = Word(alphas, alphanums) + funcDecl = ("def" + identifier + Group("(" + Opt(delimitedList(identifier)) + ")") + ":") + func_body = indentedBlock(stmt, indentStack) + funcDef = Group(funcDecl + func_body) + + rvalue = Forward() + funcCall = Group(identifier + "(" + Opt(delimitedList(rvalue)) + ")") + rvalue << (funcCall | identifier | Word(nums)) + assignment = Group(identifier + "=" + rvalue) + stmt << (funcDef | assignment | identifier) + + module_body = stmt[1, ...] + + parseTree = module_body.parseString(data) + parseTree.pprint() + + prints:: + + [['def', + 'A', + ['(', 'z', ')'], + ':', + [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], + 'B', + ['def', + 'BB', + ['(', 'a', 'b', 'c', ')'], + ':', + [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], + 'C', + 'D', + ['def', + 'spam', + ['(', 'x', 'y', ')'], + ':', + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + """ + backup_stacks.append(indentStack[:]) + + def reset_stack(): + indentStack[:] = backup_stacks[-1] + + def checkPeerIndent(s, l, t): + if l >= len(s): + return + curCol = col(l, s) + if curCol != indentStack[-1]: + if curCol > indentStack[-1]: + raise ParseException(s, l, "illegal nesting") + raise ParseException(s, l, "not a peer entry") + + def checkSubIndent(s, l, t): + curCol = col(l, s) + if curCol > indentStack[-1]: + indentStack.append(curCol) + else: + raise ParseException(s, l, "not a subentry") + + def checkUnindent(s, l, t): + if l >= len(s): + return + curCol = col(l, s) + if not (indentStack and curCol in indentStack): + raise ParseException(s, l, "not an unindent") + if curCol < indentStack[-1]: + indentStack.pop() + + NL = OneOrMore(LineEnd().set_whitespace_chars("\t ").suppress()) + INDENT = (Empty() + Empty().set_parse_action(checkSubIndent)).set_name("INDENT") + PEER = Empty().set_parse_action(checkPeerIndent).set_name("") + UNDENT = Empty().set_parse_action(checkUnindent).set_name("UNINDENT") + if indent: + smExpr = Group( + Opt(NL) + + INDENT + + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) + + UNDENT + ) + else: + smExpr = Group( + Opt(NL) + + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) + + Opt(UNDENT) + ) + + # add a parse action to remove backup_stack from list of backups + smExpr.add_parse_action( + lambda: backup_stacks.pop(-1) and None if backup_stacks else None + ) + smExpr.set_fail_action(lambda a, b, c, d: reset_stack()) + blockStatementExpr.ignore(_bslash + LineEnd()) + return smExpr.set_name("indented block") + + +# it's easy to get these comment structures wrong - they're very common, so may as well make them available +c_style_comment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + "*/").set_name( + "C style comment" +) +"Comment of the form ``/* ... */``" + +html_comment = Regex(r"").set_name("HTML comment") +"Comment of the form ````" + +rest_of_line = Regex(r".*").leave_whitespace().set_name("rest of line") +dbl_slash_comment = Regex(r"//(?:\\\n|[^\n])*").set_name("// comment") +"Comment of the form ``// ... (to end of line)``" + +cpp_style_comment = Combine( + Regex(r"/\*(?:[^*]|\*(?!/))*") + "*/" | dbl_slash_comment +).set_name("C++ style comment") +"Comment of either form :class:`c_style_comment` or :class:`dbl_slash_comment`" + +java_style_comment = cpp_style_comment +"Same as :class:`cpp_style_comment`" + +python_style_comment = Regex(r"#.*").set_name("Python style comment") +"Comment of the form ``# ... (to end of line)``" + + +# build list of built-in expressions, for future reference if a global default value +# gets updated +_builtin_exprs: List[ParserElement] = [ + v for v in vars().values() if isinstance(v, ParserElement) +] + + +# compatibility function, superseded by DelimitedList class +def delimited_list( + expr: Union[str, ParserElement], + delim: Union[str, ParserElement] = ",", + combine: bool = False, + min: typing.Optional[int] = None, + max: typing.Optional[int] = None, + *, + allow_trailing_delim: bool = False, +) -> ParserElement: + """(DEPRECATED - use :class:`DelimitedList` class)""" + return DelimitedList( + expr, delim, combine, min, max, allow_trailing_delim=allow_trailing_delim + ) + + +# pre-PEP8 compatible names +# fmt: off +opAssoc = OpAssoc +anyOpenTag = any_open_tag +anyCloseTag = any_close_tag +commonHTMLEntity = common_html_entity +cStyleComment = c_style_comment +htmlComment = html_comment +restOfLine = rest_of_line +dblSlashComment = dbl_slash_comment +cppStyleComment = cpp_style_comment +javaStyleComment = java_style_comment +pythonStyleComment = python_style_comment + +@replaced_by_pep8(DelimitedList) +def delimitedList(): ... + +@replaced_by_pep8(DelimitedList) +def delimited_list(): ... + +@replaced_by_pep8(counted_array) +def countedArray(): ... + +@replaced_by_pep8(match_previous_literal) +def matchPreviousLiteral(): ... + +@replaced_by_pep8(match_previous_expr) +def matchPreviousExpr(): ... + +@replaced_by_pep8(one_of) +def oneOf(): ... + +@replaced_by_pep8(dict_of) +def dictOf(): ... + +@replaced_by_pep8(original_text_for) +def originalTextFor(): ... + +@replaced_by_pep8(nested_expr) +def nestedExpr(): ... + +@replaced_by_pep8(make_html_tags) +def makeHTMLTags(): ... + +@replaced_by_pep8(make_xml_tags) +def makeXMLTags(): ... + +@replaced_by_pep8(replace_html_entity) +def replaceHTMLEntity(): ... + +@replaced_by_pep8(infix_notation) +def infixNotation(): ... +# fmt: on diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/results.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/results.py new file mode 100644 index 0000000..0313049 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/results.py @@ -0,0 +1,796 @@ +# results.py +from collections.abc import ( + MutableMapping, + Mapping, + MutableSequence, + Iterator, + Sequence, + Container, +) +import pprint +from typing import Tuple, Any, Dict, Set, List + +str_type: Tuple[type, ...] = (str, bytes) +_generator_type = type((_ for _ in ())) + + +class _ParseResultsWithOffset: + tup: Tuple["ParseResults", int] + __slots__ = ["tup"] + + def __init__(self, p1: "ParseResults", p2: int): + self.tup: Tuple[ParseResults, int] = (p1, p2) + + def __getitem__(self, i): + return self.tup[i] + + def __getstate__(self): + return self.tup + + def __setstate__(self, *args): + self.tup = args[0] + + +class ParseResults: + """Structured parse results, to provide multiple means of access to + the parsed data: + + - as a list (``len(results)``) + - by list index (``results[0], results[1]``, etc.) + - by attribute (``results.`` - see :class:`ParserElement.set_results_name`) + + Example:: + + integer = Word(nums) + date_str = (integer.set_results_name("year") + '/' + + integer.set_results_name("month") + '/' + + integer.set_results_name("day")) + # equivalent form: + # date_str = (integer("year") + '/' + # + integer("month") + '/' + # + integer("day")) + + # parse_string returns a ParseResults object + result = date_str.parse_string("1999/12/31") + + def test(s, fn=repr): + print(f"{s} -> {fn(eval(s))}") + test("list(result)") + test("result[0]") + test("result['month']") + test("result.day") + test("'month' in result") + test("'minutes' in result") + test("result.dump()", str) + + prints:: + + list(result) -> ['1999', '/', '12', '/', '31'] + result[0] -> '1999' + result['month'] -> '12' + result.day -> '31' + 'month' in result -> True + 'minutes' in result -> False + result.dump() -> ['1999', '/', '12', '/', '31'] + - day: '31' + - month: '12' + - year: '1999' + """ + + _null_values: Tuple[Any, ...] = (None, [], ()) + + _name: str + _parent: "ParseResults" + _all_names: Set[str] + _modal: bool + _toklist: List[Any] + _tokdict: Dict[str, Any] + + __slots__ = ( + "_name", + "_parent", + "_all_names", + "_modal", + "_toklist", + "_tokdict", + ) + + class List(list): + """ + Simple wrapper class to distinguish parsed list results that should be preserved + as actual Python lists, instead of being converted to :class:`ParseResults`:: + + LBRACK, RBRACK = map(pp.Suppress, "[]") + element = pp.Forward() + item = ppc.integer + element_list = LBRACK + pp.DelimitedList(element) + RBRACK + + # add parse actions to convert from ParseResults to actual Python collection types + def as_python_list(t): + return pp.ParseResults.List(t.as_list()) + element_list.add_parse_action(as_python_list) + + element <<= item | element_list + + element.run_tests(''' + 100 + [2,3,4] + [[2, 1],3,4] + [(2, 1),3,4] + (2,3,4) + ''', post_parse=lambda s, r: (r[0], type(r[0]))) + + prints:: + + 100 + (100, ) + + [2,3,4] + ([2, 3, 4], ) + + [[2, 1],3,4] + ([[2, 1], 3, 4], ) + + (Used internally by :class:`Group` when `aslist=True`.) + """ + + def __new__(cls, contained=None): + if contained is None: + contained = [] + + if not isinstance(contained, list): + raise TypeError( + f"{cls.__name__} may only be constructed with a list, not {type(contained).__name__}" + ) + + return list.__new__(cls) + + def __new__(cls, toklist=None, name=None, **kwargs): + if isinstance(toklist, ParseResults): + return toklist + self = object.__new__(cls) + self._name = None + self._parent = None + self._all_names = set() + + if toklist is None: + self._toklist = [] + elif isinstance(toklist, (list, _generator_type)): + self._toklist = ( + [toklist[:]] + if isinstance(toklist, ParseResults.List) + else list(toklist) + ) + else: + self._toklist = [toklist] + self._tokdict = dict() + return self + + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( + self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance + ): + self._tokdict: Dict[str, _ParseResultsWithOffset] + self._modal = modal + if name is not None and name != "": + if isinstance(name, int): + name = str(name) + if not modal: + self._all_names = {name} + self._name = name + if toklist not in self._null_values: + if isinstance(toklist, (str_type, type)): + toklist = [toklist] + if asList: + if isinstance(toklist, ParseResults): + self[name] = _ParseResultsWithOffset( + ParseResults(toklist._toklist), 0 + ) + else: + self[name] = _ParseResultsWithOffset( + ParseResults(toklist[0]), 0 + ) + self[name]._name = name + else: + try: + self[name] = toklist[0] + except (KeyError, TypeError, IndexError): + if toklist is not self: + self[name] = toklist + else: + self._name = name + + def __getitem__(self, i): + if isinstance(i, (int, slice)): + return self._toklist[i] + else: + if i not in self._all_names: + return self._tokdict[i][-1][0] + else: + return ParseResults([v[0] for v in self._tokdict[i]]) + + def __setitem__(self, k, v, isinstance=isinstance): + if isinstance(v, _ParseResultsWithOffset): + self._tokdict[k] = self._tokdict.get(k, list()) + [v] + sub = v[0] + elif isinstance(k, (int, slice)): + self._toklist[k] = v + sub = v + else: + self._tokdict[k] = self._tokdict.get(k, list()) + [ + _ParseResultsWithOffset(v, 0) + ] + sub = v + if isinstance(sub, ParseResults): + sub._parent = self + + def __delitem__(self, i): + if isinstance(i, (int, slice)): + mylen = len(self._toklist) + del self._toklist[i] + + # convert int to slice + if isinstance(i, int): + if i < 0: + i += mylen + i = slice(i, i + 1) + # get removed indices + removed = list(range(*i.indices(mylen))) + removed.reverse() + # fixup indices in token dictionary + for name, occurrences in self._tokdict.items(): + for j in removed: + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset( + value, position - (position > j) + ) + else: + del self._tokdict[i] + + def __contains__(self, k) -> bool: + return k in self._tokdict + + def __len__(self) -> int: + return len(self._toklist) + + def __bool__(self) -> bool: + return not not (self._toklist or self._tokdict) + + def __iter__(self) -> Iterator: + return iter(self._toklist) + + def __reversed__(self) -> Iterator: + return iter(self._toklist[::-1]) + + def keys(self): + return iter(self._tokdict) + + def values(self): + return (self[k] for k in self.keys()) + + def items(self): + return ((k, self[k]) for k in self.keys()) + + def haskeys(self) -> bool: + """ + Since ``keys()`` returns an iterator, this method is helpful in bypassing + code that looks for the existence of any defined results names.""" + return not not self._tokdict + + def pop(self, *args, **kwargs): + """ + Removes and returns item at specified index (default= ``last``). + Supports both ``list`` and ``dict`` semantics for ``pop()``. If + passed no argument or an integer argument, it will use ``list`` + semantics and pop tokens from the list of parsed tokens. If passed + a non-integer argument (most likely a string), it will use ``dict`` + semantics and pop the corresponding value from any defined results + names. A second default return value argument is supported, just as in + ``dict.pop()``. + + Example:: + + numlist = Word(nums)[...] + print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] + + def remove_first(tokens): + tokens.pop(0) + numlist.add_parse_action(remove_first) + print(numlist.parse_string("0 123 321")) # -> ['123', '321'] + + label = Word(alphas) + patt = label("LABEL") + Word(nums)[1, ...] + print(patt.parse_string("AAB 123 321").dump()) + + # Use pop() in a parse action to remove named result (note that corresponding value is not + # removed from list form of results) + def remove_LABEL(tokens): + tokens.pop("LABEL") + return tokens + patt.add_parse_action(remove_LABEL) + print(patt.parse_string("AAB 123 321").dump()) + + prints:: + + ['AAB', '123', '321'] + - LABEL: 'AAB' + + ['AAB', '123', '321'] + """ + if not args: + args = [-1] + for k, v in kwargs.items(): + if k == "default": + args = (args[0], v) + else: + raise TypeError(f"pop() got an unexpected keyword argument {k!r}") + if isinstance(args[0], int) or len(args) == 1 or args[0] in self: + index = args[0] + ret = self[index] + del self[index] + return ret + else: + defaultvalue = args[1] + return defaultvalue + + def get(self, key, default_value=None): + """ + Returns named result matching the given key, or if there is no + such name, then returns the given ``default_value`` or ``None`` if no + ``default_value`` is specified. + + Similar to ``dict.get()``. + + Example:: + + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parse_string("1999/12/31") + print(result.get("year")) # -> '1999' + print(result.get("hour", "not specified")) # -> 'not specified' + print(result.get("hour")) # -> None + """ + if key in self: + return self[key] + else: + return default_value + + def insert(self, index, ins_string): + """ + Inserts new element at location index in the list of parsed tokens. + + Similar to ``list.insert()``. + + Example:: + + numlist = Word(nums)[...] + print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to insert the parse location in the front of the parsed results + def insert_locn(locn, tokens): + tokens.insert(0, locn) + numlist.add_parse_action(insert_locn) + print(numlist.parse_string("0 123 321")) # -> [0, '0', '123', '321'] + """ + self._toklist.insert(index, ins_string) + # fixup indices in token dictionary + for name, occurrences in self._tokdict.items(): + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset( + value, position + (position > index) + ) + + def append(self, item): + """ + Add single element to end of ``ParseResults`` list of elements. + + Example:: + + numlist = Word(nums)[...] + print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to compute the sum of the parsed integers, and add it to the end + def append_sum(tokens): + tokens.append(sum(map(int, tokens))) + numlist.add_parse_action(append_sum) + print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321', 444] + """ + self._toklist.append(item) + + def extend(self, itemseq): + """ + Add sequence of elements to end of ``ParseResults`` list of elements. + + Example:: + + patt = Word(alphas)[1, ...] + + # use a parse action to append the reverse of the matched strings, to make a palindrome + def make_palindrome(tokens): + tokens.extend(reversed([t[::-1] for t in tokens])) + return ''.join(tokens) + patt.add_parse_action(make_palindrome) + print(patt.parse_string("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' + """ + if isinstance(itemseq, ParseResults): + self.__iadd__(itemseq) + else: + self._toklist.extend(itemseq) + + def clear(self): + """ + Clear all elements and results names. + """ + del self._toklist[:] + self._tokdict.clear() + + def __getattr__(self, name): + try: + return self[name] + except KeyError: + if name.startswith("__"): + raise AttributeError(name) + return "" + + def __add__(self, other: "ParseResults") -> "ParseResults": + ret = self.copy() + ret += other + return ret + + def __iadd__(self, other: "ParseResults") -> "ParseResults": + if not other: + return self + + if other._tokdict: + offset = len(self._toklist) + addoffset = lambda a: offset if a < 0 else a + offset + otheritems = other._tokdict.items() + otherdictitems = [ + (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) + for k, vlist in otheritems + for v in vlist + ] + for k, v in otherdictitems: + self[k] = v + if isinstance(v[0], ParseResults): + v[0]._parent = self + + self._toklist += other._toklist + self._all_names |= other._all_names + return self + + def __radd__(self, other) -> "ParseResults": + if isinstance(other, int) and other == 0: + # useful for merging many ParseResults using sum() builtin + return self.copy() + else: + # this may raise a TypeError - so be it + return other + self + + def __repr__(self) -> str: + return f"{type(self).__name__}({self._toklist!r}, {self.as_dict()})" + + def __str__(self) -> str: + return ( + "[" + + ", ".join( + [ + str(i) if isinstance(i, ParseResults) else repr(i) + for i in self._toklist + ] + ) + + "]" + ) + + def _asStringList(self, sep=""): + out = [] + for item in self._toklist: + if out and sep: + out.append(sep) + if isinstance(item, ParseResults): + out += item._asStringList() + else: + out.append(str(item)) + return out + + def as_list(self) -> list: + """ + Returns the parse results as a nested list of matching tokens, all converted to strings. + + Example:: + + patt = Word(alphas)[1, ...] + result = patt.parse_string("sldkj lsdkj sldkj") + # even though the result prints in string-like form, it is actually a pyparsing ParseResults + print(type(result), result) # -> ['sldkj', 'lsdkj', 'sldkj'] + + # Use as_list() to create an actual list + result_list = result.as_list() + print(type(result_list), result_list) # -> ['sldkj', 'lsdkj', 'sldkj'] + """ + return [ + res.as_list() if isinstance(res, ParseResults) else res + for res in self._toklist + ] + + def as_dict(self) -> dict: + """ + Returns the named parse results as a nested dictionary. + + Example:: + + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parse_string('12/31/1999') + print(type(result), repr(result)) # -> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) + + result_dict = result.as_dict() + print(type(result_dict), repr(result_dict)) # -> {'day': '1999', 'year': '12', 'month': '31'} + + # even though a ParseResults supports dict-like access, sometime you just need to have a dict + import json + print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable + print(json.dumps(result.as_dict())) # -> {"month": "31", "day": "1999", "year": "12"} + """ + + def to_item(obj): + if isinstance(obj, ParseResults): + return obj.as_dict() if obj.haskeys() else [to_item(v) for v in obj] + else: + return obj + + return dict((k, to_item(v)) for k, v in self.items()) + + def copy(self) -> "ParseResults": + """ + Returns a new shallow copy of a :class:`ParseResults` object. `ParseResults` + items contained within the source are shared with the copy. Use + :class:`ParseResults.deepcopy()` to create a copy with its own separate + content values. + """ + ret = ParseResults(self._toklist) + ret._tokdict = self._tokdict.copy() + ret._parent = self._parent + ret._all_names |= self._all_names + ret._name = self._name + return ret + + def deepcopy(self) -> "ParseResults": + """ + Returns a new deep copy of a :class:`ParseResults` object. + """ + ret = self.copy() + # replace values with copies if they are of known mutable types + for i, obj in enumerate(self._toklist): + if isinstance(obj, ParseResults): + self._toklist[i] = obj.deepcopy() + elif isinstance(obj, (str, bytes)): + pass + elif isinstance(obj, MutableMapping): + self._toklist[i] = dest = type(obj)() + for k, v in obj.items(): + dest[k] = v.deepcopy() if isinstance(v, ParseResults) else v + elif isinstance(obj, Container): + self._toklist[i] = type(obj)( + v.deepcopy() if isinstance(v, ParseResults) else v for v in obj + ) + return ret + + def get_name(self): + r""" + Returns the results name for this token expression. Useful when several + different expressions might match at a particular location. + + Example:: + + integer = Word(nums) + ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") + house_number_expr = Suppress('#') + Word(nums, alphanums) + user_data = (Group(house_number_expr)("house_number") + | Group(ssn_expr)("ssn") + | Group(integer)("age")) + user_info = user_data[1, ...] + + result = user_info.parse_string("22 111-22-3333 #221B") + for item in result: + print(item.get_name(), ':', item[0]) + + prints:: + + age : 22 + ssn : 111-22-3333 + house_number : 221B + """ + if self._name: + return self._name + elif self._parent: + par: "ParseResults" = self._parent + parent_tokdict_items = par._tokdict.items() + return next( + ( + k + for k, vlist in parent_tokdict_items + for v, loc in vlist + if v is self + ), + None, + ) + elif ( + len(self) == 1 + and len(self._tokdict) == 1 + and next(iter(self._tokdict.values()))[0][1] in (0, -1) + ): + return next(iter(self._tokdict.keys())) + else: + return None + + def dump(self, indent="", full=True, include_list=True, _depth=0) -> str: + """ + Diagnostic method for listing out the contents of + a :class:`ParseResults`. Accepts an optional ``indent`` argument so + that this string can be embedded in a nested display of other data. + + Example:: + + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parse_string('1999/12/31') + print(result.dump()) + + prints:: + + ['1999', '/', '12', '/', '31'] + - day: '31' + - month: '12' + - year: '1999' + """ + out = [] + NL = "\n" + out.append(indent + str(self.as_list()) if include_list else "") + + if full: + if self.haskeys(): + items = sorted((str(k), v) for k, v in self.items()) + for k, v in items: + if out: + out.append(NL) + out.append(f"{indent}{(' ' * _depth)}- {k}: ") + if isinstance(v, ParseResults): + if v: + out.append( + v.dump( + indent=indent, + full=full, + include_list=include_list, + _depth=_depth + 1, + ) + ) + else: + out.append(str(v)) + else: + out.append(repr(v)) + if any(isinstance(vv, ParseResults) for vv in self): + v = self + for i, vv in enumerate(v): + if isinstance(vv, ParseResults): + out.append( + "\n{}{}[{}]:\n{}{}{}".format( + indent, + (" " * (_depth)), + i, + indent, + (" " * (_depth + 1)), + vv.dump( + indent=indent, + full=full, + include_list=include_list, + _depth=_depth + 1, + ), + ) + ) + else: + out.append( + "\n%s%s[%d]:\n%s%s%s" + % ( + indent, + (" " * (_depth)), + i, + indent, + (" " * (_depth + 1)), + str(vv), + ) + ) + + return "".join(out) + + def pprint(self, *args, **kwargs): + """ + Pretty-printer for parsed results as a list, using the + `pprint `_ module. + Accepts additional positional or keyword args as defined for + `pprint.pprint `_ . + + Example:: + + ident = Word(alphas, alphanums) + num = Word(nums) + func = Forward() + term = ident | num | Group('(' + func + ')') + func <<= ident + Group(Optional(DelimitedList(term))) + result = func.parse_string("fna a,b,(fnb c,d,200),100") + result.pprint(width=40) + + prints:: + + ['fna', + ['a', + 'b', + ['(', 'fnb', ['c', 'd', '200'], ')'], + '100']] + """ + pprint.pprint(self.as_list(), *args, **kwargs) + + # add support for pickle protocol + def __getstate__(self): + return ( + self._toklist, + ( + self._tokdict.copy(), + None, + self._all_names, + self._name, + ), + ) + + def __setstate__(self, state): + self._toklist, (self._tokdict, par, inAccumNames, self._name) = state + self._all_names = set(inAccumNames) + self._parent = None + + def __getnewargs__(self): + return self._toklist, self._name + + def __dir__(self): + return dir(type(self)) + list(self.keys()) + + @classmethod + def from_dict(cls, other, name=None) -> "ParseResults": + """ + Helper classmethod to construct a ``ParseResults`` from a ``dict``, preserving the + name-value relations as results names. If an optional ``name`` argument is + given, a nested ``ParseResults`` will be returned. + """ + + def is_iterable(obj): + try: + iter(obj) + except Exception: + return False + # str's are iterable, but in pyparsing, we don't want to iterate over them + else: + return not isinstance(obj, str_type) + + ret = cls([]) + for k, v in other.items(): + if isinstance(v, Mapping): + ret += cls.from_dict(v, name=k) + else: + ret += cls([v], name=k, asList=is_iterable(v)) + if name is not None: + ret = cls([ret], name=name) + return ret + + asList = as_list + """Deprecated - use :class:`as_list`""" + asDict = as_dict + """Deprecated - use :class:`as_dict`""" + getName = get_name + """Deprecated - use :class:`get_name`""" + + +MutableMapping.register(ParseResults) +MutableSequence.register(ParseResults) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/testing.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/testing.py new file mode 100644 index 0000000..6a254c1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/testing.py @@ -0,0 +1,331 @@ +# testing.py + +from contextlib import contextmanager +import typing + +from .core import ( + ParserElement, + ParseException, + Keyword, + __diag__, + __compat__, +) + + +class pyparsing_test: + """ + namespace class for classes useful in writing unit tests + """ + + class reset_pyparsing_context: + """ + Context manager to be used when writing unit tests that modify pyparsing config values: + - packrat parsing + - bounded recursion parsing + - default whitespace characters. + - default keyword characters + - literal string auto-conversion class + - __diag__ settings + + Example:: + + with reset_pyparsing_context(): + # test that literals used to construct a grammar are automatically suppressed + ParserElement.inlineLiteralsUsing(Suppress) + + term = Word(alphas) | Word(nums) + group = Group('(' + term[...] + ')') + + # assert that the '()' characters are not included in the parsed tokens + self.assertParseAndCheckList(group, "(abc 123 def)", ['abc', '123', 'def']) + + # after exiting context manager, literals are converted to Literal expressions again + """ + + def __init__(self): + self._save_context = {} + + def save(self): + self._save_context["default_whitespace"] = ParserElement.DEFAULT_WHITE_CHARS + self._save_context["default_keyword_chars"] = Keyword.DEFAULT_KEYWORD_CHARS + + self._save_context[ + "literal_string_class" + ] = ParserElement._literalStringClass + + self._save_context["verbose_stacktrace"] = ParserElement.verbose_stacktrace + + self._save_context["packrat_enabled"] = ParserElement._packratEnabled + if ParserElement._packratEnabled: + self._save_context[ + "packrat_cache_size" + ] = ParserElement.packrat_cache.size + else: + self._save_context["packrat_cache_size"] = None + self._save_context["packrat_parse"] = ParserElement._parse + self._save_context[ + "recursion_enabled" + ] = ParserElement._left_recursion_enabled + + self._save_context["__diag__"] = { + name: getattr(__diag__, name) for name in __diag__._all_names + } + + self._save_context["__compat__"] = { + "collect_all_And_tokens": __compat__.collect_all_And_tokens + } + + return self + + def restore(self): + # reset pyparsing global state + if ( + ParserElement.DEFAULT_WHITE_CHARS + != self._save_context["default_whitespace"] + ): + ParserElement.set_default_whitespace_chars( + self._save_context["default_whitespace"] + ) + + ParserElement.verbose_stacktrace = self._save_context["verbose_stacktrace"] + + Keyword.DEFAULT_KEYWORD_CHARS = self._save_context["default_keyword_chars"] + ParserElement.inlineLiteralsUsing( + self._save_context["literal_string_class"] + ) + + for name, value in self._save_context["__diag__"].items(): + (__diag__.enable if value else __diag__.disable)(name) + + ParserElement._packratEnabled = False + if self._save_context["packrat_enabled"]: + ParserElement.enable_packrat(self._save_context["packrat_cache_size"]) + else: + ParserElement._parse = self._save_context["packrat_parse"] + ParserElement._left_recursion_enabled = self._save_context[ + "recursion_enabled" + ] + + __compat__.collect_all_And_tokens = self._save_context["__compat__"] + + return self + + def copy(self): + ret = type(self)() + ret._save_context.update(self._save_context) + return ret + + def __enter__(self): + return self.save() + + def __exit__(self, *args): + self.restore() + + class TestParseResultsAsserts: + """ + A mixin class to add parse results assertion methods to normal unittest.TestCase classes. + """ + + def assertParseResultsEquals( + self, result, expected_list=None, expected_dict=None, msg=None + ): + """ + Unit test assertion to compare a :class:`ParseResults` object with an optional ``expected_list``, + and compare any defined results names with an optional ``expected_dict``. + """ + if expected_list is not None: + self.assertEqual(expected_list, result.as_list(), msg=msg) + if expected_dict is not None: + self.assertEqual(expected_dict, result.as_dict(), msg=msg) + + def assertParseAndCheckList( + self, expr, test_string, expected_list, msg=None, verbose=True + ): + """ + Convenience wrapper assert to test a parser element and input string, and assert that + the resulting ``ParseResults.asList()`` is equal to the ``expected_list``. + """ + result = expr.parse_string(test_string, parse_all=True) + if verbose: + print(result.dump()) + else: + print(result.as_list()) + self.assertParseResultsEquals(result, expected_list=expected_list, msg=msg) + + def assertParseAndCheckDict( + self, expr, test_string, expected_dict, msg=None, verbose=True + ): + """ + Convenience wrapper assert to test a parser element and input string, and assert that + the resulting ``ParseResults.asDict()`` is equal to the ``expected_dict``. + """ + result = expr.parse_string(test_string, parseAll=True) + if verbose: + print(result.dump()) + else: + print(result.as_list()) + self.assertParseResultsEquals(result, expected_dict=expected_dict, msg=msg) + + def assertRunTestResults( + self, run_tests_report, expected_parse_results=None, msg=None + ): + """ + Unit test assertion to evaluate output of ``ParserElement.runTests()``. If a list of + list-dict tuples is given as the ``expected_parse_results`` argument, then these are zipped + with the report tuples returned by ``runTests`` and evaluated using ``assertParseResultsEquals``. + Finally, asserts that the overall ``runTests()`` success value is ``True``. + + :param run_tests_report: tuple(bool, [tuple(str, ParseResults or Exception)]) returned from runTests + :param expected_parse_results (optional): [tuple(str, list, dict, Exception)] + """ + run_test_success, run_test_results = run_tests_report + + if expected_parse_results is not None: + merged = [ + (*rpt, expected) + for rpt, expected in zip(run_test_results, expected_parse_results) + ] + for test_string, result, expected in merged: + # expected should be a tuple containing a list and/or a dict or an exception, + # and optional failure message string + # an empty tuple will skip any result validation + fail_msg = next( + (exp for exp in expected if isinstance(exp, str)), None + ) + expected_exception = next( + ( + exp + for exp in expected + if isinstance(exp, type) and issubclass(exp, Exception) + ), + None, + ) + if expected_exception is not None: + with self.assertRaises( + expected_exception=expected_exception, msg=fail_msg or msg + ): + if isinstance(result, Exception): + raise result + else: + expected_list = next( + (exp for exp in expected if isinstance(exp, list)), None + ) + expected_dict = next( + (exp for exp in expected if isinstance(exp, dict)), None + ) + if (expected_list, expected_dict) != (None, None): + self.assertParseResultsEquals( + result, + expected_list=expected_list, + expected_dict=expected_dict, + msg=fail_msg or msg, + ) + else: + # warning here maybe? + print(f"no validation for {test_string!r}") + + # do this last, in case some specific test results can be reported instead + self.assertTrue( + run_test_success, msg=msg if msg is not None else "failed runTests" + ) + + @contextmanager + def assertRaisesParseException(self, exc_type=ParseException, msg=None): + with self.assertRaises(exc_type, msg=msg): + yield + + @staticmethod + def with_line_numbers( + s: str, + start_line: typing.Optional[int] = None, + end_line: typing.Optional[int] = None, + expand_tabs: bool = True, + eol_mark: str = "|", + mark_spaces: typing.Optional[str] = None, + mark_control: typing.Optional[str] = None, + ) -> str: + """ + Helpful method for debugging a parser - prints a string with line and column numbers. + (Line and column numbers are 1-based.) + + :param s: tuple(bool, str - string to be printed with line and column numbers + :param start_line: int - (optional) starting line number in s to print (default=1) + :param end_line: int - (optional) ending line number in s to print (default=len(s)) + :param expand_tabs: bool - (optional) expand tabs to spaces, to match the pyparsing default + :param eol_mark: str - (optional) string to mark the end of lines, helps visualize trailing spaces (default="|") + :param mark_spaces: str - (optional) special character to display in place of spaces + :param mark_control: str - (optional) convert non-printing control characters to a placeholding + character; valid values: + - "unicode" - replaces control chars with Unicode symbols, such as "␍" and "␊" + - any single character string - replace control characters with given string + - None (default) - string is displayed as-is + + :return: str - input string with leading line numbers and column number headers + """ + if expand_tabs: + s = s.expandtabs() + if mark_control is not None: + mark_control = typing.cast(str, mark_control) + if mark_control == "unicode": + transtable_map = { + c: u for c, u in zip(range(0, 33), range(0x2400, 0x2433)) + } + transtable_map[127] = 0x2421 + tbl = str.maketrans(transtable_map) + eol_mark = "" + else: + ord_mark_control = ord(mark_control) + tbl = str.maketrans( + {c: ord_mark_control for c in list(range(0, 32)) + [127]} + ) + s = s.translate(tbl) + if mark_spaces is not None and mark_spaces != " ": + if mark_spaces == "unicode": + tbl = str.maketrans({9: 0x2409, 32: 0x2423}) + s = s.translate(tbl) + else: + s = s.replace(" ", mark_spaces) + if start_line is None: + start_line = 1 + if end_line is None: + end_line = len(s) + end_line = min(end_line, len(s)) + start_line = min(max(1, start_line), end_line) + + if mark_control != "unicode": + s_lines = s.splitlines()[start_line - 1 : end_line] + else: + s_lines = [line + "␊" for line in s.split("␊")[start_line - 1 : end_line]] + if not s_lines: + return "" + + lineno_width = len(str(end_line)) + max_line_len = max(len(line) for line in s_lines) + lead = " " * (lineno_width + 1) + if max_line_len >= 99: + header0 = ( + lead + + "".join( + f"{' ' * 99}{(i + 1) % 100}" + for i in range(max(max_line_len // 100, 1)) + ) + + "\n" + ) + else: + header0 = "" + header1 = ( + header0 + + lead + + "".join(f" {(i + 1) % 10}" for i in range(-(-max_line_len // 10))) + + "\n" + ) + header2 = lead + "1234567890" * (-(-max_line_len // 10)) + "\n" + return ( + header1 + + header2 + + "\n".join( + f"{i:{lineno_width}d}:{line}{eol_mark}" + for i, line in enumerate(s_lines, start=start_line) + ) + + "\n" + ) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/unicode.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/unicode.py new file mode 100644 index 0000000..ec0b3a4 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/unicode.py @@ -0,0 +1,361 @@ +# unicode.py + +import sys +from itertools import filterfalse +from typing import List, Tuple, Union + + +class _lazyclassproperty: + def __init__(self, fn): + self.fn = fn + self.__doc__ = fn.__doc__ + self.__name__ = fn.__name__ + + def __get__(self, obj, cls): + if cls is None: + cls = type(obj) + if not hasattr(cls, "_intern") or any( + cls._intern is getattr(superclass, "_intern", []) + for superclass in cls.__mro__[1:] + ): + cls._intern = {} + attrname = self.fn.__name__ + if attrname not in cls._intern: + cls._intern[attrname] = self.fn(cls) + return cls._intern[attrname] + + +UnicodeRangeList = List[Union[Tuple[int, int], Tuple[int]]] + + +class unicode_set: + """ + A set of Unicode characters, for language-specific strings for + ``alphas``, ``nums``, ``alphanums``, and ``printables``. + A unicode_set is defined by a list of ranges in the Unicode character + set, in a class attribute ``_ranges``. Ranges can be specified using + 2-tuples or a 1-tuple, such as:: + + _ranges = [ + (0x0020, 0x007e), + (0x00a0, 0x00ff), + (0x0100,), + ] + + Ranges are left- and right-inclusive. A 1-tuple of (x,) is treated as (x, x). + + A unicode set can also be defined using multiple inheritance of other unicode sets:: + + class CJK(Chinese, Japanese, Korean): + pass + """ + + _ranges: UnicodeRangeList = [] + + @_lazyclassproperty + def _chars_for_ranges(cls): + ret = [] + for cc in cls.__mro__: + if cc is unicode_set: + break + for rr in getattr(cc, "_ranges", ()): + ret.extend(range(rr[0], rr[-1] + 1)) + return [chr(c) for c in sorted(set(ret))] + + @_lazyclassproperty + def printables(cls): + """all non-whitespace characters in this range""" + return "".join(filterfalse(str.isspace, cls._chars_for_ranges)) + + @_lazyclassproperty + def alphas(cls): + """all alphabetic characters in this range""" + return "".join(filter(str.isalpha, cls._chars_for_ranges)) + + @_lazyclassproperty + def nums(cls): + """all numeric digit characters in this range""" + return "".join(filter(str.isdigit, cls._chars_for_ranges)) + + @_lazyclassproperty + def alphanums(cls): + """all alphanumeric characters in this range""" + return cls.alphas + cls.nums + + @_lazyclassproperty + def identchars(cls): + """all characters in this range that are valid identifier characters, plus underscore '_'""" + return "".join( + sorted( + set( + "".join(filter(str.isidentifier, cls._chars_for_ranges)) + + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµº" + + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" + + "_" + ) + ) + ) + + @_lazyclassproperty + def identbodychars(cls): + """ + all characters in this range that are valid identifier body characters, + plus the digits 0-9, and · (Unicode MIDDLE DOT) + """ + return "".join( + sorted( + set( + cls.identchars + + "0123456789·" + + "".join( + [c for c in cls._chars_for_ranges if ("_" + c).isidentifier()] + ) + ) + ) + ) + + @_lazyclassproperty + def identifier(cls): + """ + a pyparsing Word expression for an identifier using this range's definitions for + identchars and identbodychars + """ + from pip._vendor.pyparsing import Word + + return Word(cls.identchars, cls.identbodychars) + + +class pyparsing_unicode(unicode_set): + """ + A namespace class for defining common language unicode_sets. + """ + + # fmt: off + + # define ranges in language character sets + _ranges: UnicodeRangeList = [ + (0x0020, sys.maxunicode), + ] + + class BasicMultilingualPlane(unicode_set): + """Unicode set for the Basic Multilingual Plane""" + _ranges: UnicodeRangeList = [ + (0x0020, 0xFFFF), + ] + + class Latin1(unicode_set): + """Unicode set for Latin-1 Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0020, 0x007E), + (0x00A0, 0x00FF), + ] + + class LatinA(unicode_set): + """Unicode set for Latin-A Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0100, 0x017F), + ] + + class LatinB(unicode_set): + """Unicode set for Latin-B Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0180, 0x024F), + ] + + class Greek(unicode_set): + """Unicode set for Greek Unicode Character Ranges""" + _ranges: UnicodeRangeList = [ + (0x0342, 0x0345), + (0x0370, 0x0377), + (0x037A, 0x037F), + (0x0384, 0x038A), + (0x038C,), + (0x038E, 0x03A1), + (0x03A3, 0x03E1), + (0x03F0, 0x03FF), + (0x1D26, 0x1D2A), + (0x1D5E,), + (0x1D60,), + (0x1D66, 0x1D6A), + (0x1F00, 0x1F15), + (0x1F18, 0x1F1D), + (0x1F20, 0x1F45), + (0x1F48, 0x1F4D), + (0x1F50, 0x1F57), + (0x1F59,), + (0x1F5B,), + (0x1F5D,), + (0x1F5F, 0x1F7D), + (0x1F80, 0x1FB4), + (0x1FB6, 0x1FC4), + (0x1FC6, 0x1FD3), + (0x1FD6, 0x1FDB), + (0x1FDD, 0x1FEF), + (0x1FF2, 0x1FF4), + (0x1FF6, 0x1FFE), + (0x2129,), + (0x2719, 0x271A), + (0xAB65,), + (0x10140, 0x1018D), + (0x101A0,), + (0x1D200, 0x1D245), + (0x1F7A1, 0x1F7A7), + ] + + class Cyrillic(unicode_set): + """Unicode set for Cyrillic Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0400, 0x052F), + (0x1C80, 0x1C88), + (0x1D2B,), + (0x1D78,), + (0x2DE0, 0x2DFF), + (0xA640, 0xA672), + (0xA674, 0xA69F), + (0xFE2E, 0xFE2F), + ] + + class Chinese(unicode_set): + """Unicode set for Chinese Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x2E80, 0x2E99), + (0x2E9B, 0x2EF3), + (0x31C0, 0x31E3), + (0x3400, 0x4DB5), + (0x4E00, 0x9FEF), + (0xA700, 0xA707), + (0xF900, 0xFA6D), + (0xFA70, 0xFAD9), + (0x16FE2, 0x16FE3), + (0x1F210, 0x1F212), + (0x1F214, 0x1F23B), + (0x1F240, 0x1F248), + (0x20000, 0x2A6D6), + (0x2A700, 0x2B734), + (0x2B740, 0x2B81D), + (0x2B820, 0x2CEA1), + (0x2CEB0, 0x2EBE0), + (0x2F800, 0x2FA1D), + ] + + class Japanese(unicode_set): + """Unicode set for Japanese Unicode Character Range, combining Kanji, Hiragana, and Katakana ranges""" + + class Kanji(unicode_set): + "Unicode set for Kanji Unicode Character Range" + _ranges: UnicodeRangeList = [ + (0x4E00, 0x9FBF), + (0x3000, 0x303F), + ] + + class Hiragana(unicode_set): + """Unicode set for Hiragana Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x3041, 0x3096), + (0x3099, 0x30A0), + (0x30FC,), + (0xFF70,), + (0x1B001,), + (0x1B150, 0x1B152), + (0x1F200,), + ] + + class Katakana(unicode_set): + """Unicode set for Katakana Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x3099, 0x309C), + (0x30A0, 0x30FF), + (0x31F0, 0x31FF), + (0x32D0, 0x32FE), + (0xFF65, 0xFF9F), + (0x1B000,), + (0x1B164, 0x1B167), + (0x1F201, 0x1F202), + (0x1F213,), + ] + + 漢字 = Kanji + カタカナ = Katakana + ひらがな = Hiragana + + _ranges = ( + Kanji._ranges + + Hiragana._ranges + + Katakana._ranges + ) + + class Hangul(unicode_set): + """Unicode set for Hangul (Korean) Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x1100, 0x11FF), + (0x302E, 0x302F), + (0x3131, 0x318E), + (0x3200, 0x321C), + (0x3260, 0x327B), + (0x327E,), + (0xA960, 0xA97C), + (0xAC00, 0xD7A3), + (0xD7B0, 0xD7C6), + (0xD7CB, 0xD7FB), + (0xFFA0, 0xFFBE), + (0xFFC2, 0xFFC7), + (0xFFCA, 0xFFCF), + (0xFFD2, 0xFFD7), + (0xFFDA, 0xFFDC), + ] + + Korean = Hangul + + class CJK(Chinese, Japanese, Hangul): + """Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range""" + + class Thai(unicode_set): + """Unicode set for Thai Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0E01, 0x0E3A), + (0x0E3F, 0x0E5B) + ] + + class Arabic(unicode_set): + """Unicode set for Arabic Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0600, 0x061B), + (0x061E, 0x06FF), + (0x0700, 0x077F), + ] + + class Hebrew(unicode_set): + """Unicode set for Hebrew Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0591, 0x05C7), + (0x05D0, 0x05EA), + (0x05EF, 0x05F4), + (0xFB1D, 0xFB36), + (0xFB38, 0xFB3C), + (0xFB3E,), + (0xFB40, 0xFB41), + (0xFB43, 0xFB44), + (0xFB46, 0xFB4F), + ] + + class Devanagari(unicode_set): + """Unicode set for Devanagari Unicode Character Range""" + _ranges: UnicodeRangeList = [ + (0x0900, 0x097F), + (0xA8E0, 0xA8FF) + ] + + BMP = BasicMultilingualPlane + + # add language identifiers using language Unicode + العربية = Arabic + 中文 = Chinese + кириллица = Cyrillic + Ελληνικά = Greek + עִברִית = Hebrew + 日本語 = Japanese + 한국어 = Korean + ไทย = Thai + देवनागरी = Devanagari + + # fmt: on diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/util.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/util.py new file mode 100644 index 0000000..d8d3f41 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyparsing/util.py @@ -0,0 +1,284 @@ +# util.py +import inspect +import warnings +import types +import collections +import itertools +from functools import lru_cache, wraps +from typing import Callable, List, Union, Iterable, TypeVar, cast + +_bslash = chr(92) +C = TypeVar("C", bound=Callable) + + +class __config_flags: + """Internal class for defining compatibility and debugging flags""" + + _all_names: List[str] = [] + _fixed_names: List[str] = [] + _type_desc = "configuration" + + @classmethod + def _set(cls, dname, value): + if dname in cls._fixed_names: + warnings.warn( + f"{cls.__name__}.{dname} {cls._type_desc} is {str(getattr(cls, dname)).upper()}" + f" and cannot be overridden", + stacklevel=3, + ) + return + if dname in cls._all_names: + setattr(cls, dname, value) + else: + raise ValueError(f"no such {cls._type_desc} {dname!r}") + + enable = classmethod(lambda cls, name: cls._set(name, True)) + disable = classmethod(lambda cls, name: cls._set(name, False)) + + +@lru_cache(maxsize=128) +def col(loc: int, strg: str) -> int: + """ + Returns current column within a string, counting newlines as line separators. + The first column is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See + :class:`ParserElement.parse_string` for more + information on parsing strings containing ```` s, and suggested + methods to maintain a consistent view of the parsed string, the parse + location, and line and column positions within the parsed string. + """ + s = strg + return 1 if 0 < loc < len(s) and s[loc - 1] == "\n" else loc - s.rfind("\n", 0, loc) + + +@lru_cache(maxsize=128) +def lineno(loc: int, strg: str) -> int: + """Returns current line number within a string, counting newlines as line separators. + The first line is number 1. + + Note - the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See :class:`ParserElement.parse_string` + for more information on parsing strings containing ```` s, and + suggested methods to maintain a consistent view of the parsed string, the + parse location, and line and column positions within the parsed string. + """ + return strg.count("\n", 0, loc) + 1 + + +@lru_cache(maxsize=128) +def line(loc: int, strg: str) -> str: + """ + Returns the line of text containing loc within a string, counting newlines as line separators. + """ + last_cr = strg.rfind("\n", 0, loc) + next_cr = strg.find("\n", loc) + return strg[last_cr + 1 : next_cr] if next_cr >= 0 else strg[last_cr + 1 :] + + +class _UnboundedCache: + def __init__(self): + cache = {} + cache_get = cache.get + self.not_in_cache = not_in_cache = object() + + def get(_, key): + return cache_get(key, not_in_cache) + + def set_(_, key, value): + cache[key] = value + + def clear(_): + cache.clear() + + self.size = None + self.get = types.MethodType(get, self) + self.set = types.MethodType(set_, self) + self.clear = types.MethodType(clear, self) + + +class _FifoCache: + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + cache = {} + keyring = [object()] * size + cache_get = cache.get + cache_pop = cache.pop + keyiter = itertools.cycle(range(size)) + + def get(_, key): + return cache_get(key, not_in_cache) + + def set_(_, key, value): + cache[key] = value + i = next(keyiter) + cache_pop(keyring[i], None) + keyring[i] = key + + def clear(_): + cache.clear() + keyring[:] = [object()] * size + + self.size = size + self.get = types.MethodType(get, self) + self.set = types.MethodType(set_, self) + self.clear = types.MethodType(clear, self) + + +class LRUMemo: + """ + A memoizing mapping that retains `capacity` deleted items + + The memo tracks retained items by their access order; once `capacity` items + are retained, the least recently used item is discarded. + """ + + def __init__(self, capacity): + self._capacity = capacity + self._active = {} + self._memory = collections.OrderedDict() + + def __getitem__(self, key): + try: + return self._active[key] + except KeyError: + self._memory.move_to_end(key) + return self._memory[key] + + def __setitem__(self, key, value): + self._memory.pop(key, None) + self._active[key] = value + + def __delitem__(self, key): + try: + value = self._active.pop(key) + except KeyError: + pass + else: + while len(self._memory) >= self._capacity: + self._memory.popitem(last=False) + self._memory[key] = value + + def clear(self): + self._active.clear() + self._memory.clear() + + +class UnboundedMemo(dict): + """ + A memoizing mapping that retains all deleted items + """ + + def __delitem__(self, key): + pass + + +def _escape_regex_range_chars(s: str) -> str: + # escape these chars: ^-[] + for c in r"\^-[]": + s = s.replace(c, _bslash + c) + s = s.replace("\n", r"\n") + s = s.replace("\t", r"\t") + return str(s) + + +def _collapse_string_to_ranges( + s: Union[str, Iterable[str]], re_escape: bool = True +) -> str: + def is_consecutive(c): + c_int = ord(c) + is_consecutive.prev, prev = c_int, is_consecutive.prev + if c_int - prev > 1: + is_consecutive.value = next(is_consecutive.counter) + return is_consecutive.value + + is_consecutive.prev = 0 # type: ignore [attr-defined] + is_consecutive.counter = itertools.count() # type: ignore [attr-defined] + is_consecutive.value = -1 # type: ignore [attr-defined] + + def escape_re_range_char(c): + return "\\" + c if c in r"\^-][" else c + + def no_escape_re_range_char(c): + return c + + if not re_escape: + escape_re_range_char = no_escape_re_range_char + + ret = [] + s = "".join(sorted(set(s))) + if len(s) > 3: + for _, chars in itertools.groupby(s, key=is_consecutive): + first = last = next(chars) + last = collections.deque( + itertools.chain(iter([last]), chars), maxlen=1 + ).pop() + if first == last: + ret.append(escape_re_range_char(first)) + else: + sep = "" if ord(last) == ord(first) + 1 else "-" + ret.append( + f"{escape_re_range_char(first)}{sep}{escape_re_range_char(last)}" + ) + else: + ret = [escape_re_range_char(c) for c in s] + + return "".join(ret) + + +def _flatten(ll: list) -> list: + ret = [] + for i in ll: + if isinstance(i, list): + ret.extend(_flatten(i)) + else: + ret.append(i) + return ret + + +def _make_synonym_function(compat_name: str, fn: C) -> C: + # In a future version, uncomment the code in the internal _inner() functions + # to begin emitting DeprecationWarnings. + + # Unwrap staticmethod/classmethod + fn = getattr(fn, "__func__", fn) + + # (Presence of 'self' arg in signature is used by explain_exception() methods, so we take + # some extra steps to add it if present in decorated function.) + if "self" == list(inspect.signature(fn).parameters)[0]: + + @wraps(fn) + def _inner(self, *args, **kwargs): + # warnings.warn( + # f"Deprecated - use {fn.__name__}", DeprecationWarning, stacklevel=3 + # ) + return fn(self, *args, **kwargs) + + else: + + @wraps(fn) + def _inner(*args, **kwargs): + # warnings.warn( + # f"Deprecated - use {fn.__name__}", DeprecationWarning, stacklevel=3 + # ) + return fn(*args, **kwargs) + + _inner.__doc__ = f"""Deprecated - use :class:`{fn.__name__}`""" + _inner.__name__ = compat_name + _inner.__annotations__ = fn.__annotations__ + if isinstance(fn, types.FunctionType): + _inner.__kwdefaults__ = fn.__kwdefaults__ + elif isinstance(fn, type) and hasattr(fn, "__init__"): + _inner.__kwdefaults__ = fn.__init__.__kwdefaults__ + else: + _inner.__kwdefaults__ = None + _inner.__qualname__ = fn.__qualname__ + return cast(C, _inner) + + +def replaced_by_pep8(fn: C) -> Callable[[Callable], C]: + """ + Decorator for pre-PEP8 compatibility synonyms, to link them to the new function. + """ + return lambda other: _make_synonym_function(other.__name__, fn) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/__init__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/__init__.py new file mode 100644 index 0000000..ddfcf7f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/__init__.py @@ -0,0 +1,23 @@ +"""Wrappers to call pyproject.toml-based build backend hooks. +""" + +from ._impl import ( + BackendInvalid, + BackendUnavailable, + BuildBackendHookCaller, + HookMissing, + UnsupportedOperation, + default_subprocess_runner, + quiet_subprocess_runner, +) + +__version__ = '1.0.0' +__all__ = [ + 'BackendUnavailable', + 'BackendInvalid', + 'HookMissing', + 'UnsupportedOperation', + 'default_subprocess_runner', + 'quiet_subprocess_runner', + 'BuildBackendHookCaller', +] diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_compat.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_compat.py new file mode 100644 index 0000000..95e509c --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_compat.py @@ -0,0 +1,8 @@ +__all__ = ("tomllib",) + +import sys + +if sys.version_info >= (3, 11): + import tomllib +else: + from pip._vendor import tomli as tomllib diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_impl.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_impl.py new file mode 100644 index 0000000..37b0e65 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_impl.py @@ -0,0 +1,330 @@ +import json +import os +import sys +import tempfile +from contextlib import contextmanager +from os.path import abspath +from os.path import join as pjoin +from subprocess import STDOUT, check_call, check_output + +from ._in_process import _in_proc_script_path + + +def write_json(obj, path, **kwargs): + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, **kwargs) + + +def read_json(path): + with open(path, encoding='utf-8') as f: + return json.load(f) + + +class BackendUnavailable(Exception): + """Will be raised if the backend cannot be imported in the hook process.""" + def __init__(self, traceback): + self.traceback = traceback + + +class BackendInvalid(Exception): + """Will be raised if the backend is invalid.""" + def __init__(self, backend_name, backend_path, message): + super().__init__(message) + self.backend_name = backend_name + self.backend_path = backend_path + + +class HookMissing(Exception): + """Will be raised on missing hooks (if a fallback can't be used).""" + def __init__(self, hook_name): + super().__init__(hook_name) + self.hook_name = hook_name + + +class UnsupportedOperation(Exception): + """May be raised by build_sdist if the backend indicates that it can't.""" + def __init__(self, traceback): + self.traceback = traceback + + +def default_subprocess_runner(cmd, cwd=None, extra_environ=None): + """The default method of calling the wrapper subprocess. + + This uses :func:`subprocess.check_call` under the hood. + """ + env = os.environ.copy() + if extra_environ: + env.update(extra_environ) + + check_call(cmd, cwd=cwd, env=env) + + +def quiet_subprocess_runner(cmd, cwd=None, extra_environ=None): + """Call the subprocess while suppressing output. + + This uses :func:`subprocess.check_output` under the hood. + """ + env = os.environ.copy() + if extra_environ: + env.update(extra_environ) + + check_output(cmd, cwd=cwd, env=env, stderr=STDOUT) + + +def norm_and_check(source_tree, requested): + """Normalise and check a backend path. + + Ensure that the requested backend path is specified as a relative path, + and resolves to a location under the given source tree. + + Return an absolute version of the requested path. + """ + if os.path.isabs(requested): + raise ValueError("paths must be relative") + + abs_source = os.path.abspath(source_tree) + abs_requested = os.path.normpath(os.path.join(abs_source, requested)) + # We have to use commonprefix for Python 2.7 compatibility. So we + # normalise case to avoid problems because commonprefix is a character + # based comparison :-( + norm_source = os.path.normcase(abs_source) + norm_requested = os.path.normcase(abs_requested) + if os.path.commonprefix([norm_source, norm_requested]) != norm_source: + raise ValueError("paths must be inside source tree") + + return abs_requested + + +class BuildBackendHookCaller: + """A wrapper to call the build backend hooks for a source directory. + """ + + def __init__( + self, + source_dir, + build_backend, + backend_path=None, + runner=None, + python_executable=None, + ): + """ + :param source_dir: The source directory to invoke the build backend for + :param build_backend: The build backend spec + :param backend_path: Additional path entries for the build backend spec + :param runner: The :ref:`subprocess runner ` to use + :param python_executable: + The Python executable used to invoke the build backend + """ + if runner is None: + runner = default_subprocess_runner + + self.source_dir = abspath(source_dir) + self.build_backend = build_backend + if backend_path: + backend_path = [ + norm_and_check(self.source_dir, p) for p in backend_path + ] + self.backend_path = backend_path + self._subprocess_runner = runner + if not python_executable: + python_executable = sys.executable + self.python_executable = python_executable + + @contextmanager + def subprocess_runner(self, runner): + """A context manager for temporarily overriding the default + :ref:`subprocess runner `. + + .. code-block:: python + + hook_caller = BuildBackendHookCaller(...) + with hook_caller.subprocess_runner(quiet_subprocess_runner): + ... + """ + prev = self._subprocess_runner + self._subprocess_runner = runner + try: + yield + finally: + self._subprocess_runner = prev + + def _supported_features(self): + """Return the list of optional features supported by the backend.""" + return self._call_hook('_supported_features', {}) + + def get_requires_for_build_wheel(self, config_settings=None): + """Get additional dependencies required for building a wheel. + + :returns: A list of :pep:`dependency specifiers <508>`. + :rtype: list[str] + + .. admonition:: Fallback + + If the build backend does not defined a hook with this name, an + empty list will be returned. + """ + return self._call_hook('get_requires_for_build_wheel', { + 'config_settings': config_settings + }) + + def prepare_metadata_for_build_wheel( + self, metadata_directory, config_settings=None, + _allow_fallback=True): + """Prepare a ``*.dist-info`` folder with metadata for this project. + + :returns: Name of the newly created subfolder within + ``metadata_directory``, containing the metadata. + :rtype: str + + .. admonition:: Fallback + + If the build backend does not define a hook with this name and + ``_allow_fallback`` is truthy, the backend will be asked to build a + wheel via the ``build_wheel`` hook and the dist-info extracted from + that will be returned. + """ + return self._call_hook('prepare_metadata_for_build_wheel', { + 'metadata_directory': abspath(metadata_directory), + 'config_settings': config_settings, + '_allow_fallback': _allow_fallback, + }) + + def build_wheel( + self, wheel_directory, config_settings=None, + metadata_directory=None): + """Build a wheel from this project. + + :returns: + The name of the newly created wheel within ``wheel_directory``. + + .. admonition:: Interaction with fallback + + If the ``build_wheel`` hook was called in the fallback for + :meth:`prepare_metadata_for_build_wheel`, the build backend would + not be invoked. Instead, the previously built wheel will be copied + to ``wheel_directory`` and the name of that file will be returned. + """ + if metadata_directory is not None: + metadata_directory = abspath(metadata_directory) + return self._call_hook('build_wheel', { + 'wheel_directory': abspath(wheel_directory), + 'config_settings': config_settings, + 'metadata_directory': metadata_directory, + }) + + def get_requires_for_build_editable(self, config_settings=None): + """Get additional dependencies required for building an editable wheel. + + :returns: A list of :pep:`dependency specifiers <508>`. + :rtype: list[str] + + .. admonition:: Fallback + + If the build backend does not defined a hook with this name, an + empty list will be returned. + """ + return self._call_hook('get_requires_for_build_editable', { + 'config_settings': config_settings + }) + + def prepare_metadata_for_build_editable( + self, metadata_directory, config_settings=None, + _allow_fallback=True): + """Prepare a ``*.dist-info`` folder with metadata for this project. + + :returns: Name of the newly created subfolder within + ``metadata_directory``, containing the metadata. + :rtype: str + + .. admonition:: Fallback + + If the build backend does not define a hook with this name and + ``_allow_fallback`` is truthy, the backend will be asked to build a + wheel via the ``build_editable`` hook and the dist-info + extracted from that will be returned. + """ + return self._call_hook('prepare_metadata_for_build_editable', { + 'metadata_directory': abspath(metadata_directory), + 'config_settings': config_settings, + '_allow_fallback': _allow_fallback, + }) + + def build_editable( + self, wheel_directory, config_settings=None, + metadata_directory=None): + """Build an editable wheel from this project. + + :returns: + The name of the newly created wheel within ``wheel_directory``. + + .. admonition:: Interaction with fallback + + If the ``build_editable`` hook was called in the fallback for + :meth:`prepare_metadata_for_build_editable`, the build backend + would not be invoked. Instead, the previously built wheel will be + copied to ``wheel_directory`` and the name of that file will be + returned. + """ + if metadata_directory is not None: + metadata_directory = abspath(metadata_directory) + return self._call_hook('build_editable', { + 'wheel_directory': abspath(wheel_directory), + 'config_settings': config_settings, + 'metadata_directory': metadata_directory, + }) + + def get_requires_for_build_sdist(self, config_settings=None): + """Get additional dependencies required for building an sdist. + + :returns: A list of :pep:`dependency specifiers <508>`. + :rtype: list[str] + """ + return self._call_hook('get_requires_for_build_sdist', { + 'config_settings': config_settings + }) + + def build_sdist(self, sdist_directory, config_settings=None): + """Build an sdist from this project. + + :returns: + The name of the newly created sdist within ``wheel_directory``. + """ + return self._call_hook('build_sdist', { + 'sdist_directory': abspath(sdist_directory), + 'config_settings': config_settings, + }) + + def _call_hook(self, hook_name, kwargs): + extra_environ = {'PEP517_BUILD_BACKEND': self.build_backend} + + if self.backend_path: + backend_path = os.pathsep.join(self.backend_path) + extra_environ['PEP517_BACKEND_PATH'] = backend_path + + with tempfile.TemporaryDirectory() as td: + hook_input = {'kwargs': kwargs} + write_json(hook_input, pjoin(td, 'input.json'), indent=2) + + # Run the hook in a subprocess + with _in_proc_script_path() as script: + python = self.python_executable + self._subprocess_runner( + [python, abspath(str(script)), hook_name, td], + cwd=self.source_dir, + extra_environ=extra_environ + ) + + data = read_json(pjoin(td, 'output.json')) + if data.get('unsupported'): + raise UnsupportedOperation(data.get('traceback', '')) + if data.get('no_backend'): + raise BackendUnavailable(data.get('traceback', '')) + if data.get('backend_invalid'): + raise BackendInvalid( + backend_name=self.build_backend, + backend_path=self.backend_path, + message=data.get('backend_error', '') + ) + if data.get('hook_missing'): + raise HookMissing(data.get('missing_hook_name') or hook_name) + return data['return_val'] diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py new file mode 100644 index 0000000..917fa06 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py @@ -0,0 +1,18 @@ +"""This is a subpackage because the directory is on sys.path for _in_process.py + +The subpackage should stay as empty as possible to avoid shadowing modules that +the backend might import. +""" + +import importlib.resources as resources + +try: + resources.files +except AttributeError: + # Python 3.8 compatibility + def _in_proc_script_path(): + return resources.path(__package__, '_in_process.py') +else: + def _in_proc_script_path(): + return resources.as_file( + resources.files(__package__).joinpath('_in_process.py')) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py new file mode 100644 index 0000000..ee511ff --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py @@ -0,0 +1,353 @@ +"""This is invoked in a subprocess to call the build backend hooks. + +It expects: +- Command line args: hook_name, control_dir +- Environment variables: + PEP517_BUILD_BACKEND=entry.point:spec + PEP517_BACKEND_PATH=paths (separated with os.pathsep) +- control_dir/input.json: + - {"kwargs": {...}} + +Results: +- control_dir/output.json + - {"return_val": ...} +""" +import json +import os +import os.path +import re +import shutil +import sys +import traceback +from glob import glob +from importlib import import_module +from os.path import join as pjoin + +# This file is run as a script, and `import wrappers` is not zip-safe, so we +# include write_json() and read_json() from wrappers.py. + + +def write_json(obj, path, **kwargs): + with open(path, 'w', encoding='utf-8') as f: + json.dump(obj, f, **kwargs) + + +def read_json(path): + with open(path, encoding='utf-8') as f: + return json.load(f) + + +class BackendUnavailable(Exception): + """Raised if we cannot import the backend""" + def __init__(self, traceback): + self.traceback = traceback + + +class BackendInvalid(Exception): + """Raised if the backend is invalid""" + def __init__(self, message): + self.message = message + + +class HookMissing(Exception): + """Raised if a hook is missing and we are not executing the fallback""" + def __init__(self, hook_name=None): + super().__init__(hook_name) + self.hook_name = hook_name + + +def contained_in(filename, directory): + """Test if a file is located within the given directory.""" + filename = os.path.normcase(os.path.abspath(filename)) + directory = os.path.normcase(os.path.abspath(directory)) + return os.path.commonprefix([filename, directory]) == directory + + +def _build_backend(): + """Find and load the build backend""" + # Add in-tree backend directories to the front of sys.path. + backend_path = os.environ.get('PEP517_BACKEND_PATH') + if backend_path: + extra_pathitems = backend_path.split(os.pathsep) + sys.path[:0] = extra_pathitems + + ep = os.environ['PEP517_BUILD_BACKEND'] + mod_path, _, obj_path = ep.partition(':') + try: + obj = import_module(mod_path) + except ImportError: + raise BackendUnavailable(traceback.format_exc()) + + if backend_path: + if not any( + contained_in(obj.__file__, path) + for path in extra_pathitems + ): + raise BackendInvalid("Backend was not loaded from backend-path") + + if obj_path: + for path_part in obj_path.split('.'): + obj = getattr(obj, path_part) + return obj + + +def _supported_features(): + """Return the list of options features supported by the backend. + + Returns a list of strings. + The only possible value is 'build_editable'. + """ + backend = _build_backend() + features = [] + if hasattr(backend, "build_editable"): + features.append("build_editable") + return features + + +def get_requires_for_build_wheel(config_settings): + """Invoke the optional get_requires_for_build_wheel hook + + Returns [] if the hook is not defined. + """ + backend = _build_backend() + try: + hook = backend.get_requires_for_build_wheel + except AttributeError: + return [] + else: + return hook(config_settings) + + +def get_requires_for_build_editable(config_settings): + """Invoke the optional get_requires_for_build_editable hook + + Returns [] if the hook is not defined. + """ + backend = _build_backend() + try: + hook = backend.get_requires_for_build_editable + except AttributeError: + return [] + else: + return hook(config_settings) + + +def prepare_metadata_for_build_wheel( + metadata_directory, config_settings, _allow_fallback): + """Invoke optional prepare_metadata_for_build_wheel + + Implements a fallback by building a wheel if the hook isn't defined, + unless _allow_fallback is False in which case HookMissing is raised. + """ + backend = _build_backend() + try: + hook = backend.prepare_metadata_for_build_wheel + except AttributeError: + if not _allow_fallback: + raise HookMissing() + else: + return hook(metadata_directory, config_settings) + # fallback to build_wheel outside the try block to avoid exception chaining + # which can be confusing to users and is not relevant + whl_basename = backend.build_wheel(metadata_directory, config_settings) + return _get_wheel_metadata_from_wheel(whl_basename, metadata_directory, + config_settings) + + +def prepare_metadata_for_build_editable( + metadata_directory, config_settings, _allow_fallback): + """Invoke optional prepare_metadata_for_build_editable + + Implements a fallback by building an editable wheel if the hook isn't + defined, unless _allow_fallback is False in which case HookMissing is + raised. + """ + backend = _build_backend() + try: + hook = backend.prepare_metadata_for_build_editable + except AttributeError: + if not _allow_fallback: + raise HookMissing() + try: + build_hook = backend.build_editable + except AttributeError: + raise HookMissing(hook_name='build_editable') + else: + whl_basename = build_hook(metadata_directory, config_settings) + return _get_wheel_metadata_from_wheel(whl_basename, + metadata_directory, + config_settings) + else: + return hook(metadata_directory, config_settings) + + +WHEEL_BUILT_MARKER = 'PEP517_ALREADY_BUILT_WHEEL' + + +def _dist_info_files(whl_zip): + """Identify the .dist-info folder inside a wheel ZipFile.""" + res = [] + for path in whl_zip.namelist(): + m = re.match(r'[^/\\]+-[^/\\]+\.dist-info/', path) + if m: + res.append(path) + if res: + return res + raise Exception("No .dist-info folder found in wheel") + + +def _get_wheel_metadata_from_wheel( + whl_basename, metadata_directory, config_settings): + """Extract the metadata from a wheel. + + Fallback for when the build backend does not + define the 'get_wheel_metadata' hook. + """ + from zipfile import ZipFile + with open(os.path.join(metadata_directory, WHEEL_BUILT_MARKER), 'wb'): + pass # Touch marker file + + whl_file = os.path.join(metadata_directory, whl_basename) + with ZipFile(whl_file) as zipf: + dist_info = _dist_info_files(zipf) + zipf.extractall(path=metadata_directory, members=dist_info) + return dist_info[0].split('/')[0] + + +def _find_already_built_wheel(metadata_directory): + """Check for a wheel already built during the get_wheel_metadata hook. + """ + if not metadata_directory: + return None + metadata_parent = os.path.dirname(metadata_directory) + if not os.path.isfile(pjoin(metadata_parent, WHEEL_BUILT_MARKER)): + return None + + whl_files = glob(os.path.join(metadata_parent, '*.whl')) + if not whl_files: + print('Found wheel built marker, but no .whl files') + return None + if len(whl_files) > 1: + print('Found multiple .whl files; unspecified behaviour. ' + 'Will call build_wheel.') + return None + + # Exactly one .whl file + return whl_files[0] + + +def build_wheel(wheel_directory, config_settings, metadata_directory=None): + """Invoke the mandatory build_wheel hook. + + If a wheel was already built in the + prepare_metadata_for_build_wheel fallback, this + will copy it rather than rebuilding the wheel. + """ + prebuilt_whl = _find_already_built_wheel(metadata_directory) + if prebuilt_whl: + shutil.copy2(prebuilt_whl, wheel_directory) + return os.path.basename(prebuilt_whl) + + return _build_backend().build_wheel(wheel_directory, config_settings, + metadata_directory) + + +def build_editable(wheel_directory, config_settings, metadata_directory=None): + """Invoke the optional build_editable hook. + + If a wheel was already built in the + prepare_metadata_for_build_editable fallback, this + will copy it rather than rebuilding the wheel. + """ + backend = _build_backend() + try: + hook = backend.build_editable + except AttributeError: + raise HookMissing() + else: + prebuilt_whl = _find_already_built_wheel(metadata_directory) + if prebuilt_whl: + shutil.copy2(prebuilt_whl, wheel_directory) + return os.path.basename(prebuilt_whl) + + return hook(wheel_directory, config_settings, metadata_directory) + + +def get_requires_for_build_sdist(config_settings): + """Invoke the optional get_requires_for_build_wheel hook + + Returns [] if the hook is not defined. + """ + backend = _build_backend() + try: + hook = backend.get_requires_for_build_sdist + except AttributeError: + return [] + else: + return hook(config_settings) + + +class _DummyException(Exception): + """Nothing should ever raise this exception""" + + +class GotUnsupportedOperation(Exception): + """For internal use when backend raises UnsupportedOperation""" + def __init__(self, traceback): + self.traceback = traceback + + +def build_sdist(sdist_directory, config_settings): + """Invoke the mandatory build_sdist hook.""" + backend = _build_backend() + try: + return backend.build_sdist(sdist_directory, config_settings) + except getattr(backend, 'UnsupportedOperation', _DummyException): + raise GotUnsupportedOperation(traceback.format_exc()) + + +HOOK_NAMES = { + 'get_requires_for_build_wheel', + 'prepare_metadata_for_build_wheel', + 'build_wheel', + 'get_requires_for_build_editable', + 'prepare_metadata_for_build_editable', + 'build_editable', + 'get_requires_for_build_sdist', + 'build_sdist', + '_supported_features', +} + + +def main(): + if len(sys.argv) < 3: + sys.exit("Needs args: hook_name, control_dir") + hook_name = sys.argv[1] + control_dir = sys.argv[2] + if hook_name not in HOOK_NAMES: + sys.exit("Unknown hook: %s" % hook_name) + hook = globals()[hook_name] + + hook_input = read_json(pjoin(control_dir, 'input.json')) + + json_out = {'unsupported': False, 'return_val': None} + try: + json_out['return_val'] = hook(**hook_input['kwargs']) + except BackendUnavailable as e: + json_out['no_backend'] = True + json_out['traceback'] = e.traceback + except BackendInvalid as e: + json_out['backend_invalid'] = True + json_out['backend_error'] = e.message + except GotUnsupportedOperation as e: + json_out['unsupported'] = True + json_out['traceback'] = e.traceback + except HookMissing as e: + json_out['hook_missing'] = True + json_out['missing_hook_name'] = e.hook_name or hook_name + + write_json(json_out, pjoin(control_dir, 'output.json'), indent=2) + + +if __name__ == '__main__': + main() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__init__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__init__.py new file mode 100644 index 0000000..10ff67f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__init__.py @@ -0,0 +1,182 @@ +# __ +# /__) _ _ _ _ _/ _ +# / ( (- (/ (/ (- _) / _) +# / + +""" +Requests HTTP Library +~~~~~~~~~~~~~~~~~~~~~ + +Requests is an HTTP library, written in Python, for human beings. +Basic GET usage: + + >>> import requests + >>> r = requests.get('https://www.python.org') + >>> r.status_code + 200 + >>> b'Python is a programming language' in r.content + True + +... or POST: + + >>> payload = dict(key1='value1', key2='value2') + >>> r = requests.post('https://httpbin.org/post', data=payload) + >>> print(r.text) + { + ... + "form": { + "key1": "value1", + "key2": "value2" + }, + ... + } + +The other HTTP methods are supported - see `requests.api`. Full documentation +is at . + +:copyright: (c) 2017 by Kenneth Reitz. +:license: Apache 2.0, see LICENSE for more details. +""" + +import warnings + +from pip._vendor import urllib3 + +from .exceptions import RequestsDependencyWarning + +charset_normalizer_version = None + +try: + from pip._vendor.chardet import __version__ as chardet_version +except ImportError: + chardet_version = None + + +def check_compatibility(urllib3_version, chardet_version, charset_normalizer_version): + urllib3_version = urllib3_version.split(".") + assert urllib3_version != ["dev"] # Verify urllib3 isn't installed from git. + + # Sometimes, urllib3 only reports its version as 16.1. + if len(urllib3_version) == 2: + urllib3_version.append("0") + + # Check urllib3 for compatibility. + major, minor, patch = urllib3_version # noqa: F811 + major, minor, patch = int(major), int(minor), int(patch) + # urllib3 >= 1.21.1 + assert major >= 1 + if major == 1: + assert minor >= 21 + + # Check charset_normalizer for compatibility. + if chardet_version: + major, minor, patch = chardet_version.split(".")[:3] + major, minor, patch = int(major), int(minor), int(patch) + # chardet_version >= 3.0.2, < 6.0.0 + assert (3, 0, 2) <= (major, minor, patch) < (6, 0, 0) + elif charset_normalizer_version: + major, minor, patch = charset_normalizer_version.split(".")[:3] + major, minor, patch = int(major), int(minor), int(patch) + # charset_normalizer >= 2.0.0 < 4.0.0 + assert (2, 0, 0) <= (major, minor, patch) < (4, 0, 0) + else: + raise Exception("You need either charset_normalizer or chardet installed") + + +def _check_cryptography(cryptography_version): + # cryptography < 1.3.4 + try: + cryptography_version = list(map(int, cryptography_version.split("."))) + except ValueError: + return + + if cryptography_version < [1, 3, 4]: + warning = "Old version of cryptography ({}) may cause slowdown.".format( + cryptography_version + ) + warnings.warn(warning, RequestsDependencyWarning) + + +# Check imported dependencies for compatibility. +try: + check_compatibility( + urllib3.__version__, chardet_version, charset_normalizer_version + ) +except (AssertionError, ValueError): + warnings.warn( + "urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported " + "version!".format( + urllib3.__version__, chardet_version, charset_normalizer_version + ), + RequestsDependencyWarning, + ) + +# Attempt to enable urllib3's fallback for SNI support +# if the standard library doesn't support SNI or the +# 'ssl' library isn't available. +try: + # Note: This logic prevents upgrading cryptography on Windows, if imported + # as part of pip. + from pip._internal.utils.compat import WINDOWS + if not WINDOWS: + raise ImportError("pip internals: don't import cryptography on Windows") + try: + import ssl + except ImportError: + ssl = None + + if not getattr(ssl, "HAS_SNI", False): + from pip._vendor.urllib3.contrib import pyopenssl + + pyopenssl.inject_into_urllib3() + + # Check cryptography version + from cryptography import __version__ as cryptography_version + + _check_cryptography(cryptography_version) +except ImportError: + pass + +# urllib3's DependencyWarnings should be silenced. +from pip._vendor.urllib3.exceptions import DependencyWarning + +warnings.simplefilter("ignore", DependencyWarning) + +# Set default logging handler to avoid "No handler found" warnings. +import logging +from logging import NullHandler + +from . import packages, utils +from .__version__ import ( + __author__, + __author_email__, + __build__, + __cake__, + __copyright__, + __description__, + __license__, + __title__, + __url__, + __version__, +) +from .api import delete, get, head, options, patch, post, put, request +from .exceptions import ( + ConnectionError, + ConnectTimeout, + FileModeWarning, + HTTPError, + JSONDecodeError, + ReadTimeout, + RequestException, + Timeout, + TooManyRedirects, + URLRequired, +) +from .models import PreparedRequest, Request, Response +from .sessions import Session, session +from .status_codes import codes + +logging.getLogger(__name__).addHandler(NullHandler()) + +# FileModeWarnings go off per the default. +warnings.simplefilter("default", FileModeWarning, append=True) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__version__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__version__.py new file mode 100644 index 0000000..5063c3f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/__version__.py @@ -0,0 +1,14 @@ +# .-. .-. .-. . . .-. .-. .-. .-. +# |( |- |.| | | |- `-. | `-. +# ' ' `-' `-`.`-' `-' `-' ' `-' + +__title__ = "requests" +__description__ = "Python HTTP for Humans." +__url__ = "https://requests.readthedocs.io" +__version__ = "2.31.0" +__build__ = 0x023100 +__author__ = "Kenneth Reitz" +__author_email__ = "me@kennethreitz.org" +__license__ = "Apache 2.0" +__copyright__ = "Copyright Kenneth Reitz" +__cake__ = "\u2728 \U0001f370 \u2728" diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/_internal_utils.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/_internal_utils.py new file mode 100644 index 0000000..f2cf635 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/_internal_utils.py @@ -0,0 +1,50 @@ +""" +requests._internal_utils +~~~~~~~~~~~~~~ + +Provides utility functions that are consumed internally by Requests +which depend on extremely few external helpers (such as compat) +""" +import re + +from .compat import builtin_str + +_VALID_HEADER_NAME_RE_BYTE = re.compile(rb"^[^:\s][^:\r\n]*$") +_VALID_HEADER_NAME_RE_STR = re.compile(r"^[^:\s][^:\r\n]*$") +_VALID_HEADER_VALUE_RE_BYTE = re.compile(rb"^\S[^\r\n]*$|^$") +_VALID_HEADER_VALUE_RE_STR = re.compile(r"^\S[^\r\n]*$|^$") + +_HEADER_VALIDATORS_STR = (_VALID_HEADER_NAME_RE_STR, _VALID_HEADER_VALUE_RE_STR) +_HEADER_VALIDATORS_BYTE = (_VALID_HEADER_NAME_RE_BYTE, _VALID_HEADER_VALUE_RE_BYTE) +HEADER_VALIDATORS = { + bytes: _HEADER_VALIDATORS_BYTE, + str: _HEADER_VALIDATORS_STR, +} + + +def to_native_string(string, encoding="ascii"): + """Given a string object, regardless of type, returns a representation of + that string in the native string type, encoding and decoding where + necessary. This assumes ASCII unless told otherwise. + """ + if isinstance(string, builtin_str): + out = string + else: + out = string.decode(encoding) + + return out + + +def unicode_is_ascii(u_string): + """Determine if unicode string only contains ASCII characters. + + :param str u_string: unicode string to check. Must be unicode + and not Python 2 `str`. + :rtype: bool + """ + assert isinstance(u_string, str) + try: + u_string.encode("ascii") + return True + except UnicodeEncodeError: + return False diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/adapters.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/adapters.py new file mode 100644 index 0000000..10c1767 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/adapters.py @@ -0,0 +1,538 @@ +""" +requests.adapters +~~~~~~~~~~~~~~~~~ + +This module contains the transport adapters that Requests uses to define +and maintain connections. +""" + +import os.path +import socket # noqa: F401 + +from pip._vendor.urllib3.exceptions import ClosedPoolError, ConnectTimeoutError +from pip._vendor.urllib3.exceptions import HTTPError as _HTTPError +from pip._vendor.urllib3.exceptions import InvalidHeader as _InvalidHeader +from pip._vendor.urllib3.exceptions import ( + LocationValueError, + MaxRetryError, + NewConnectionError, + ProtocolError, +) +from pip._vendor.urllib3.exceptions import ProxyError as _ProxyError +from pip._vendor.urllib3.exceptions import ReadTimeoutError, ResponseError +from pip._vendor.urllib3.exceptions import SSLError as _SSLError +from pip._vendor.urllib3.poolmanager import PoolManager, proxy_from_url +from pip._vendor.urllib3.util import Timeout as TimeoutSauce +from pip._vendor.urllib3.util import parse_url +from pip._vendor.urllib3.util.retry import Retry + +from .auth import _basic_auth_str +from .compat import basestring, urlparse +from .cookies import extract_cookies_to_jar +from .exceptions import ( + ConnectionError, + ConnectTimeout, + InvalidHeader, + InvalidProxyURL, + InvalidSchema, + InvalidURL, + ProxyError, + ReadTimeout, + RetryError, + SSLError, +) +from .models import Response +from .structures import CaseInsensitiveDict +from .utils import ( + DEFAULT_CA_BUNDLE_PATH, + extract_zipped_paths, + get_auth_from_url, + get_encoding_from_headers, + prepend_scheme_if_needed, + select_proxy, + urldefragauth, +) + +try: + from pip._vendor.urllib3.contrib.socks import SOCKSProxyManager +except ImportError: + + def SOCKSProxyManager(*args, **kwargs): + raise InvalidSchema("Missing dependencies for SOCKS support.") + + +DEFAULT_POOLBLOCK = False +DEFAULT_POOLSIZE = 10 +DEFAULT_RETRIES = 0 +DEFAULT_POOL_TIMEOUT = None + + +class BaseAdapter: + """The Base Transport Adapter""" + + def __init__(self): + super().__init__() + + def send( + self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None + ): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest ` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + """ + raise NotImplementedError + + def close(self): + """Cleans up adapter specific items.""" + raise NotImplementedError + + +class HTTPAdapter(BaseAdapter): + """The built-in HTTP Adapter for urllib3. + + Provides a general-case interface for Requests sessions to contact HTTP and + HTTPS urls by implementing the Transport Adapter interface. This class will + usually be created by the :class:`Session ` class under the + covers. + + :param pool_connections: The number of urllib3 connection pools to cache. + :param pool_maxsize: The maximum number of connections to save in the pool. + :param max_retries: The maximum number of retries each connection + should attempt. Note, this applies only to failed DNS lookups, socket + connections and connection timeouts, never to requests where data has + made it to the server. By default, Requests does not retry failed + connections. If you need granular control over the conditions under + which we retry a request, import urllib3's ``Retry`` class and pass + that instead. + :param pool_block: Whether the connection pool should block for connections. + + Usage:: + + >>> import requests + >>> s = requests.Session() + >>> a = requests.adapters.HTTPAdapter(max_retries=3) + >>> s.mount('http://', a) + """ + + __attrs__ = [ + "max_retries", + "config", + "_pool_connections", + "_pool_maxsize", + "_pool_block", + ] + + def __init__( + self, + pool_connections=DEFAULT_POOLSIZE, + pool_maxsize=DEFAULT_POOLSIZE, + max_retries=DEFAULT_RETRIES, + pool_block=DEFAULT_POOLBLOCK, + ): + if max_retries == DEFAULT_RETRIES: + self.max_retries = Retry(0, read=False) + else: + self.max_retries = Retry.from_int(max_retries) + self.config = {} + self.proxy_manager = {} + + super().__init__() + + self._pool_connections = pool_connections + self._pool_maxsize = pool_maxsize + self._pool_block = pool_block + + self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) + + def __getstate__(self): + return {attr: getattr(self, attr, None) for attr in self.__attrs__} + + def __setstate__(self, state): + # Can't handle by adding 'proxy_manager' to self.__attrs__ because + # self.poolmanager uses a lambda function, which isn't pickleable. + self.proxy_manager = {} + self.config = {} + + for attr, value in state.items(): + setattr(self, attr, value) + + self.init_poolmanager( + self._pool_connections, self._pool_maxsize, block=self._pool_block + ) + + def init_poolmanager( + self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs + ): + """Initializes a urllib3 PoolManager. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param connections: The number of urllib3 connection pools to cache. + :param maxsize: The maximum number of connections to save in the pool. + :param block: Block when no free connections are available. + :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager. + """ + # save these values for pickling + self._pool_connections = connections + self._pool_maxsize = maxsize + self._pool_block = block + + self.poolmanager = PoolManager( + num_pools=connections, + maxsize=maxsize, + block=block, + **pool_kwargs, + ) + + def proxy_manager_for(self, proxy, **proxy_kwargs): + """Return urllib3 ProxyManager for the given proxy. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param proxy: The proxy to return a urllib3 ProxyManager for. + :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager. + :returns: ProxyManager + :rtype: urllib3.ProxyManager + """ + if proxy in self.proxy_manager: + manager = self.proxy_manager[proxy] + elif proxy.lower().startswith("socks"): + username, password = get_auth_from_url(proxy) + manager = self.proxy_manager[proxy] = SOCKSProxyManager( + proxy, + username=username, + password=password, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs, + ) + else: + proxy_headers = self.proxy_headers(proxy) + manager = self.proxy_manager[proxy] = proxy_from_url( + proxy, + proxy_headers=proxy_headers, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs, + ) + + return manager + + def cert_verify(self, conn, url, verify, cert): + """Verify a SSL certificate. This method should not be called from user + code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param conn: The urllib3 connection object associated with the cert. + :param url: The requested URL. + :param verify: Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use + :param cert: The SSL certificate to verify. + """ + if url.lower().startswith("https") and verify: + + cert_loc = None + + # Allow self-specified cert location. + if verify is not True: + cert_loc = verify + + if not cert_loc: + cert_loc = extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH) + + if not cert_loc or not os.path.exists(cert_loc): + raise OSError( + f"Could not find a suitable TLS CA certificate bundle, " + f"invalid path: {cert_loc}" + ) + + conn.cert_reqs = "CERT_REQUIRED" + + if not os.path.isdir(cert_loc): + conn.ca_certs = cert_loc + else: + conn.ca_cert_dir = cert_loc + else: + conn.cert_reqs = "CERT_NONE" + conn.ca_certs = None + conn.ca_cert_dir = None + + if cert: + if not isinstance(cert, basestring): + conn.cert_file = cert[0] + conn.key_file = cert[1] + else: + conn.cert_file = cert + conn.key_file = None + if conn.cert_file and not os.path.exists(conn.cert_file): + raise OSError( + f"Could not find the TLS certificate file, " + f"invalid path: {conn.cert_file}" + ) + if conn.key_file and not os.path.exists(conn.key_file): + raise OSError( + f"Could not find the TLS key file, invalid path: {conn.key_file}" + ) + + def build_response(self, req, resp): + """Builds a :class:`Response ` object from a urllib3 + response. This should not be called from user code, and is only exposed + for use when subclassing the + :class:`HTTPAdapter ` + + :param req: The :class:`PreparedRequest ` used to generate the response. + :param resp: The urllib3 response object. + :rtype: requests.Response + """ + response = Response() + + # Fallback to None if there's no status_code, for whatever reason. + response.status_code = getattr(resp, "status", None) + + # Make headers case-insensitive. + response.headers = CaseInsensitiveDict(getattr(resp, "headers", {})) + + # Set encoding. + response.encoding = get_encoding_from_headers(response.headers) + response.raw = resp + response.reason = response.raw.reason + + if isinstance(req.url, bytes): + response.url = req.url.decode("utf-8") + else: + response.url = req.url + + # Add new cookies from the server. + extract_cookies_to_jar(response.cookies, req, resp) + + # Give the Response some context. + response.request = req + response.connection = self + + return response + + def get_connection(self, url, proxies=None): + """Returns a urllib3 connection for the given URL. This should not be + called from user code, and is only exposed for use when subclassing the + :class:`HTTPAdapter `. + + :param url: The URL to connect to. + :param proxies: (optional) A Requests-style dictionary of proxies used on this request. + :rtype: urllib3.ConnectionPool + """ + proxy = select_proxy(url, proxies) + + if proxy: + proxy = prepend_scheme_if_needed(proxy, "http") + proxy_url = parse_url(proxy) + if not proxy_url.host: + raise InvalidProxyURL( + "Please check proxy URL. It is malformed " + "and could be missing the host." + ) + proxy_manager = self.proxy_manager_for(proxy) + conn = proxy_manager.connection_from_url(url) + else: + # Only scheme should be lower case + parsed = urlparse(url) + url = parsed.geturl() + conn = self.poolmanager.connection_from_url(url) + + return conn + + def close(self): + """Disposes of any internal state. + + Currently, this closes the PoolManager and any active ProxyManager, + which closes any pooled connections. + """ + self.poolmanager.clear() + for proxy in self.proxy_manager.values(): + proxy.clear() + + def request_url(self, request, proxies): + """Obtain the url to use when making the final request. + + If the message is being sent through a HTTP proxy, the full URL has to + be used. Otherwise, we should only use the path portion of the URL. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param request: The :class:`PreparedRequest ` being sent. + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs. + :rtype: str + """ + proxy = select_proxy(request.url, proxies) + scheme = urlparse(request.url).scheme + + is_proxied_http_request = proxy and scheme != "https" + using_socks_proxy = False + if proxy: + proxy_scheme = urlparse(proxy).scheme.lower() + using_socks_proxy = proxy_scheme.startswith("socks") + + url = request.path_url + if is_proxied_http_request and not using_socks_proxy: + url = urldefragauth(request.url) + + return url + + def add_headers(self, request, **kwargs): + """Add any headers needed by the connection. As of v2.0 this does + nothing by default, but is left for overriding by users that subclass + the :class:`HTTPAdapter `. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param request: The :class:`PreparedRequest ` to add headers to. + :param kwargs: The keyword arguments from the call to send(). + """ + pass + + def proxy_headers(self, proxy): + """Returns a dictionary of the headers to add to any request sent + through a proxy. This works with urllib3 magic to ensure that they are + correctly sent to the proxy, rather than in a tunnelled request if + CONNECT is being used. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter `. + + :param proxy: The url of the proxy being used for this request. + :rtype: dict + """ + headers = {} + username, password = get_auth_from_url(proxy) + + if username: + headers["Proxy-Authorization"] = _basic_auth_str(username, password) + + return headers + + def send( + self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None + ): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest ` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple or urllib3 Timeout object + :param verify: (optional) Either a boolean, in which case it controls whether + we verify the server's TLS certificate, or a string, in which case it + must be a path to a CA bundle to use + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + :rtype: requests.Response + """ + + try: + conn = self.get_connection(request.url, proxies) + except LocationValueError as e: + raise InvalidURL(e, request=request) + + self.cert_verify(conn, request.url, verify, cert) + url = self.request_url(request, proxies) + self.add_headers( + request, + stream=stream, + timeout=timeout, + verify=verify, + cert=cert, + proxies=proxies, + ) + + chunked = not (request.body is None or "Content-Length" in request.headers) + + if isinstance(timeout, tuple): + try: + connect, read = timeout + timeout = TimeoutSauce(connect=connect, read=read) + except ValueError: + raise ValueError( + f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, " + f"or a single float to set both timeouts to the same value." + ) + elif isinstance(timeout, TimeoutSauce): + pass + else: + timeout = TimeoutSauce(connect=timeout, read=timeout) + + try: + resp = conn.urlopen( + method=request.method, + url=url, + body=request.body, + headers=request.headers, + redirect=False, + assert_same_host=False, + preload_content=False, + decode_content=False, + retries=self.max_retries, + timeout=timeout, + chunked=chunked, + ) + + except (ProtocolError, OSError) as err: + raise ConnectionError(err, request=request) + + except MaxRetryError as e: + if isinstance(e.reason, ConnectTimeoutError): + # TODO: Remove this in 3.0.0: see #2811 + if not isinstance(e.reason, NewConnectionError): + raise ConnectTimeout(e, request=request) + + if isinstance(e.reason, ResponseError): + raise RetryError(e, request=request) + + if isinstance(e.reason, _ProxyError): + raise ProxyError(e, request=request) + + if isinstance(e.reason, _SSLError): + # This branch is for urllib3 v1.22 and later. + raise SSLError(e, request=request) + + raise ConnectionError(e, request=request) + + except ClosedPoolError as e: + raise ConnectionError(e, request=request) + + except _ProxyError as e: + raise ProxyError(e) + + except (_SSLError, _HTTPError) as e: + if isinstance(e, _SSLError): + # This branch is for urllib3 versions earlier than v1.22 + raise SSLError(e, request=request) + elif isinstance(e, ReadTimeoutError): + raise ReadTimeout(e, request=request) + elif isinstance(e, _InvalidHeader): + raise InvalidHeader(e, request=request) + else: + raise + + return self.build_response(request, resp) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/api.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/api.py new file mode 100644 index 0000000..cd0b3ee --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/api.py @@ -0,0 +1,157 @@ +""" +requests.api +~~~~~~~~~~~~ + +This module implements the Requests API. + +:copyright: (c) 2012 by Kenneth Reitz. +:license: Apache2, see LICENSE for more details. +""" + +from . import sessions + + +def request(method, url, **kwargs): + """Constructs and sends a :class:`Request `. + + :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary, list of tuples or bytes to send + in the query string for the :class:`Request`. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. + :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload. + ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` + or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string + defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers + to add for the file. + :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How many seconds to wait for the server to send data + before giving up, as a float, or a :ref:`(connect timeout, read + timeout) ` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use. Defaults to ``True``. + :param stream: (optional) if ``False``, the response content will be immediately downloaded. + :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. + :return: :class:`Response ` object + :rtype: requests.Response + + Usage:: + + >>> import requests + >>> req = requests.request('GET', 'https://httpbin.org/get') + >>> req + + """ + + # By using the 'with' statement we are sure the session is closed, thus we + # avoid leaving sockets open which can trigger a ResourceWarning in some + # cases, and look like a memory leak in others. + with sessions.Session() as session: + return session.request(method=method, url=url, **kwargs) + + +def get(url, params=None, **kwargs): + r"""Sends a GET request. + + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary, list of tuples or bytes to send + in the query string for the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request("get", url, params=params, **kwargs) + + +def options(url, **kwargs): + r"""Sends an OPTIONS request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request("options", url, **kwargs) + + +def head(url, **kwargs): + r"""Sends a HEAD request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. If + `allow_redirects` is not provided, it will be set to `False` (as + opposed to the default :meth:`request` behavior). + :return: :class:`Response ` object + :rtype: requests.Response + """ + + kwargs.setdefault("allow_redirects", False) + return request("head", url, **kwargs) + + +def post(url, data=None, json=None, **kwargs): + r"""Sends a POST request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request("post", url, data=data, json=json, **kwargs) + + +def put(url, data=None, **kwargs): + r"""Sends a PUT request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request("put", url, data=data, **kwargs) + + +def patch(url, data=None, **kwargs): + r"""Sends a PATCH request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request("patch", url, data=data, **kwargs) + + +def delete(url, **kwargs): + r"""Sends a DELETE request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response ` object + :rtype: requests.Response + """ + + return request("delete", url, **kwargs) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/auth.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/auth.py new file mode 100644 index 0000000..9733686 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/auth.py @@ -0,0 +1,315 @@ +""" +requests.auth +~~~~~~~~~~~~~ + +This module contains the authentication handlers for Requests. +""" + +import hashlib +import os +import re +import threading +import time +import warnings +from base64 import b64encode + +from ._internal_utils import to_native_string +from .compat import basestring, str, urlparse +from .cookies import extract_cookies_to_jar +from .utils import parse_dict_header + +CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded" +CONTENT_TYPE_MULTI_PART = "multipart/form-data" + + +def _basic_auth_str(username, password): + """Returns a Basic Auth string.""" + + # "I want us to put a big-ol' comment on top of it that + # says that this behaviour is dumb but we need to preserve + # it because people are relying on it." + # - Lukasa + # + # These are here solely to maintain backwards compatibility + # for things like ints. This will be removed in 3.0.0. + if not isinstance(username, basestring): + warnings.warn( + "Non-string usernames will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(username), + category=DeprecationWarning, + ) + username = str(username) + + if not isinstance(password, basestring): + warnings.warn( + "Non-string passwords will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(type(password)), + category=DeprecationWarning, + ) + password = str(password) + # -- End Removal -- + + if isinstance(username, str): + username = username.encode("latin1") + + if isinstance(password, str): + password = password.encode("latin1") + + authstr = "Basic " + to_native_string( + b64encode(b":".join((username, password))).strip() + ) + + return authstr + + +class AuthBase: + """Base class that all auth implementations derive from""" + + def __call__(self, r): + raise NotImplementedError("Auth hooks must be callable.") + + +class HTTPBasicAuth(AuthBase): + """Attaches HTTP Basic Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + + def __eq__(self, other): + return all( + [ + self.username == getattr(other, "username", None), + self.password == getattr(other, "password", None), + ] + ) + + def __ne__(self, other): + return not self == other + + def __call__(self, r): + r.headers["Authorization"] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPProxyAuth(HTTPBasicAuth): + """Attaches HTTP Proxy Authentication to a given Request object.""" + + def __call__(self, r): + r.headers["Proxy-Authorization"] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPDigestAuth(AuthBase): + """Attaches HTTP Digest Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + # Keep state in per-thread local storage + self._thread_local = threading.local() + + def init_per_thread_state(self): + # Ensure state is initialized just once per-thread + if not hasattr(self._thread_local, "init"): + self._thread_local.init = True + self._thread_local.last_nonce = "" + self._thread_local.nonce_count = 0 + self._thread_local.chal = {} + self._thread_local.pos = None + self._thread_local.num_401_calls = None + + def build_digest_header(self, method, url): + """ + :rtype: str + """ + + realm = self._thread_local.chal["realm"] + nonce = self._thread_local.chal["nonce"] + qop = self._thread_local.chal.get("qop") + algorithm = self._thread_local.chal.get("algorithm") + opaque = self._thread_local.chal.get("opaque") + hash_utf8 = None + + if algorithm is None: + _algorithm = "MD5" + else: + _algorithm = algorithm.upper() + # lambdas assume digest modules are imported at the top level + if _algorithm == "MD5" or _algorithm == "MD5-SESS": + + def md5_utf8(x): + if isinstance(x, str): + x = x.encode("utf-8") + return hashlib.md5(x).hexdigest() + + hash_utf8 = md5_utf8 + elif _algorithm == "SHA": + + def sha_utf8(x): + if isinstance(x, str): + x = x.encode("utf-8") + return hashlib.sha1(x).hexdigest() + + hash_utf8 = sha_utf8 + elif _algorithm == "SHA-256": + + def sha256_utf8(x): + if isinstance(x, str): + x = x.encode("utf-8") + return hashlib.sha256(x).hexdigest() + + hash_utf8 = sha256_utf8 + elif _algorithm == "SHA-512": + + def sha512_utf8(x): + if isinstance(x, str): + x = x.encode("utf-8") + return hashlib.sha512(x).hexdigest() + + hash_utf8 = sha512_utf8 + + KD = lambda s, d: hash_utf8(f"{s}:{d}") # noqa:E731 + + if hash_utf8 is None: + return None + + # XXX not implemented yet + entdig = None + p_parsed = urlparse(url) + #: path is request-uri defined in RFC 2616 which should not be empty + path = p_parsed.path or "/" + if p_parsed.query: + path += f"?{p_parsed.query}" + + A1 = f"{self.username}:{realm}:{self.password}" + A2 = f"{method}:{path}" + + HA1 = hash_utf8(A1) + HA2 = hash_utf8(A2) + + if nonce == self._thread_local.last_nonce: + self._thread_local.nonce_count += 1 + else: + self._thread_local.nonce_count = 1 + ncvalue = f"{self._thread_local.nonce_count:08x}" + s = str(self._thread_local.nonce_count).encode("utf-8") + s += nonce.encode("utf-8") + s += time.ctime().encode("utf-8") + s += os.urandom(8) + + cnonce = hashlib.sha1(s).hexdigest()[:16] + if _algorithm == "MD5-SESS": + HA1 = hash_utf8(f"{HA1}:{nonce}:{cnonce}") + + if not qop: + respdig = KD(HA1, f"{nonce}:{HA2}") + elif qop == "auth" or "auth" in qop.split(","): + noncebit = f"{nonce}:{ncvalue}:{cnonce}:auth:{HA2}" + respdig = KD(HA1, noncebit) + else: + # XXX handle auth-int. + return None + + self._thread_local.last_nonce = nonce + + # XXX should the partial digests be encoded too? + base = ( + f'username="{self.username}", realm="{realm}", nonce="{nonce}", ' + f'uri="{path}", response="{respdig}"' + ) + if opaque: + base += f', opaque="{opaque}"' + if algorithm: + base += f', algorithm="{algorithm}"' + if entdig: + base += f', digest="{entdig}"' + if qop: + base += f', qop="auth", nc={ncvalue}, cnonce="{cnonce}"' + + return f"Digest {base}" + + def handle_redirect(self, r, **kwargs): + """Reset num_401_calls counter on redirects.""" + if r.is_redirect: + self._thread_local.num_401_calls = 1 + + def handle_401(self, r, **kwargs): + """ + Takes the given response and tries digest-auth, if needed. + + :rtype: requests.Response + """ + + # If response is not 4xx, do not auth + # See https://github.com/psf/requests/issues/3772 + if not 400 <= r.status_code < 500: + self._thread_local.num_401_calls = 1 + return r + + if self._thread_local.pos is not None: + # Rewind the file position indicator of the body to where + # it was to resend the request. + r.request.body.seek(self._thread_local.pos) + s_auth = r.headers.get("www-authenticate", "") + + if "digest" in s_auth.lower() and self._thread_local.num_401_calls < 2: + + self._thread_local.num_401_calls += 1 + pat = re.compile(r"digest ", flags=re.IGNORECASE) + self._thread_local.chal = parse_dict_header(pat.sub("", s_auth, count=1)) + + # Consume content and release the original connection + # to allow our new request to reuse the same one. + r.content + r.close() + prep = r.request.copy() + extract_cookies_to_jar(prep._cookies, r.request, r.raw) + prep.prepare_cookies(prep._cookies) + + prep.headers["Authorization"] = self.build_digest_header( + prep.method, prep.url + ) + _r = r.connection.send(prep, **kwargs) + _r.history.append(r) + _r.request = prep + + return _r + + self._thread_local.num_401_calls = 1 + return r + + def __call__(self, r): + # Initialize per-thread state, if needed + self.init_per_thread_state() + # If we have a saved nonce, skip the 401 + if self._thread_local.last_nonce: + r.headers["Authorization"] = self.build_digest_header(r.method, r.url) + try: + self._thread_local.pos = r.body.tell() + except AttributeError: + # In the case of HTTPDigestAuth being reused and the body of + # the previous request was a file-like object, pos has the + # file position of the previous body. Ensure it's set to + # None. + self._thread_local.pos = None + r.register_hook("response", self.handle_401) + r.register_hook("response", self.handle_redirect) + self._thread_local.num_401_calls = 1 + + return r + + def __eq__(self, other): + return all( + [ + self.username == getattr(other, "username", None), + self.password == getattr(other, "password", None), + ] + ) + + def __ne__(self, other): + return not self == other diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/certs.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/certs.py new file mode 100644 index 0000000..38696a1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/certs.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +""" +requests.certs +~~~~~~~~~~~~~~ + +This module returns the preferred default CA certificate bundle. There is +only one — the one from the certifi package. + +If you are packaging Requests, e.g., for a Linux distribution or a managed +environment, you can change the definition of where() to return a separately +packaged CA bundle. +""" + +import os + +if "_PIP_STANDALONE_CERT" not in os.environ: + from pip._vendor.certifi import where +else: + def where(): + return os.environ["_PIP_STANDALONE_CERT"] + +if __name__ == "__main__": + print(where()) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/compat.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/compat.py new file mode 100644 index 0000000..9ab2bb4 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/compat.py @@ -0,0 +1,67 @@ +""" +requests.compat +~~~~~~~~~~~~~~~ + +This module previously handled import compatibility issues +between Python 2 and Python 3. It remains for backwards +compatibility until the next major version. +""" + +from pip._vendor import chardet + +import sys + +# ------- +# Pythons +# ------- + +# Syntax sugar. +_ver = sys.version_info + +#: Python 2.x? +is_py2 = _ver[0] == 2 + +#: Python 3.x? +is_py3 = _ver[0] == 3 + +# Note: We've patched out simplejson support in pip because it prevents +# upgrading simplejson on Windows. +import json +from json import JSONDecodeError + +# Keep OrderedDict for backwards compatibility. +from collections import OrderedDict +from collections.abc import Callable, Mapping, MutableMapping +from http import cookiejar as cookielib +from http.cookies import Morsel +from io import StringIO + +# -------------- +# Legacy Imports +# -------------- +from urllib.parse import ( + quote, + quote_plus, + unquote, + unquote_plus, + urldefrag, + urlencode, + urljoin, + urlparse, + urlsplit, + urlunparse, +) +from urllib.request import ( + getproxies, + getproxies_environment, + parse_http_list, + proxy_bypass, + proxy_bypass_environment, +) + +builtin_str = str +str = str +bytes = bytes +basestring = (str, bytes) +numeric_types = (int, float) +integer_types = (int,) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/cookies.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/cookies.py new file mode 100644 index 0000000..bf54ab2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/cookies.py @@ -0,0 +1,561 @@ +""" +requests.cookies +~~~~~~~~~~~~~~~~ + +Compatibility code to be able to use `cookielib.CookieJar` with requests. + +requests.utils imports from here, so be careful with imports. +""" + +import calendar +import copy +import time + +from ._internal_utils import to_native_string +from .compat import Morsel, MutableMapping, cookielib, urlparse, urlunparse + +try: + import threading +except ImportError: + import dummy_threading as threading + + +class MockRequest: + """Wraps a `requests.Request` to mimic a `urllib2.Request`. + + The code in `cookielib.CookieJar` expects this interface in order to correctly + manage cookie policies, i.e., determine whether a cookie can be set, given the + domains of the request and the cookie. + + The original request object is read-only. The client is responsible for collecting + the new headers via `get_new_headers()` and interpreting them appropriately. You + probably want `get_cookie_header`, defined below. + """ + + def __init__(self, request): + self._r = request + self._new_headers = {} + self.type = urlparse(self._r.url).scheme + + def get_type(self): + return self.type + + def get_host(self): + return urlparse(self._r.url).netloc + + def get_origin_req_host(self): + return self.get_host() + + def get_full_url(self): + # Only return the response's URL if the user hadn't set the Host + # header + if not self._r.headers.get("Host"): + return self._r.url + # If they did set it, retrieve it and reconstruct the expected domain + host = to_native_string(self._r.headers["Host"], encoding="utf-8") + parsed = urlparse(self._r.url) + # Reconstruct the URL as we expect it + return urlunparse( + [ + parsed.scheme, + host, + parsed.path, + parsed.params, + parsed.query, + parsed.fragment, + ] + ) + + def is_unverifiable(self): + return True + + def has_header(self, name): + return name in self._r.headers or name in self._new_headers + + def get_header(self, name, default=None): + return self._r.headers.get(name, self._new_headers.get(name, default)) + + def add_header(self, key, val): + """cookielib has no legitimate use for this method; add it back if you find one.""" + raise NotImplementedError( + "Cookie headers should be added with add_unredirected_header()" + ) + + def add_unredirected_header(self, name, value): + self._new_headers[name] = value + + def get_new_headers(self): + return self._new_headers + + @property + def unverifiable(self): + return self.is_unverifiable() + + @property + def origin_req_host(self): + return self.get_origin_req_host() + + @property + def host(self): + return self.get_host() + + +class MockResponse: + """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. + + ...what? Basically, expose the parsed HTTP headers from the server response + the way `cookielib` expects to see them. + """ + + def __init__(self, headers): + """Make a MockResponse for `cookielib` to read. + + :param headers: a httplib.HTTPMessage or analogous carrying the headers + """ + self._headers = headers + + def info(self): + return self._headers + + def getheaders(self, name): + self._headers.getheaders(name) + + +def extract_cookies_to_jar(jar, request, response): + """Extract the cookies from the response into a CookieJar. + + :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar) + :param request: our own requests.Request object + :param response: urllib3.HTTPResponse object + """ + if not (hasattr(response, "_original_response") and response._original_response): + return + # the _original_response field is the wrapped httplib.HTTPResponse object, + req = MockRequest(request) + # pull out the HTTPMessage with the headers and put it in the mock: + res = MockResponse(response._original_response.msg) + jar.extract_cookies(res, req) + + +def get_cookie_header(jar, request): + """ + Produce an appropriate Cookie header string to be sent with `request`, or None. + + :rtype: str + """ + r = MockRequest(request) + jar.add_cookie_header(r) + return r.get_new_headers().get("Cookie") + + +def remove_cookie_by_name(cookiejar, name, domain=None, path=None): + """Unsets a cookie by name, by default over all domains and paths. + + Wraps CookieJar.clear(), is O(n). + """ + clearables = [] + for cookie in cookiejar: + if cookie.name != name: + continue + if domain is not None and domain != cookie.domain: + continue + if path is not None and path != cookie.path: + continue + clearables.append((cookie.domain, cookie.path, cookie.name)) + + for domain, path, name in clearables: + cookiejar.clear(domain, path, name) + + +class CookieConflictError(RuntimeError): + """There are two cookies that meet the criteria specified in the cookie jar. + Use .get and .set and include domain and path args in order to be more specific. + """ + + +class RequestsCookieJar(cookielib.CookieJar, MutableMapping): + """Compatibility class; is a cookielib.CookieJar, but exposes a dict + interface. + + This is the CookieJar we create by default for requests and sessions that + don't specify one, since some clients may expect response.cookies and + session.cookies to support dict operations. + + Requests does not use the dict interface internally; it's just for + compatibility with external client code. All requests code should work + out of the box with externally provided instances of ``CookieJar``, e.g. + ``LWPCookieJar`` and ``FileCookieJar``. + + Unlike a regular CookieJar, this class is pickleable. + + .. warning:: dictionary operations that are normally O(1) may be O(n). + """ + + def get(self, name, default=None, domain=None, path=None): + """Dict-like get() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + + .. warning:: operation is O(n), not O(1). + """ + try: + return self._find_no_duplicates(name, domain, path) + except KeyError: + return default + + def set(self, name, value, **kwargs): + """Dict-like set() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + """ + # support client code that unsets cookies by assignment of a None value: + if value is None: + remove_cookie_by_name( + self, name, domain=kwargs.get("domain"), path=kwargs.get("path") + ) + return + + if isinstance(value, Morsel): + c = morsel_to_cookie(value) + else: + c = create_cookie(name, value, **kwargs) + self.set_cookie(c) + return c + + def iterkeys(self): + """Dict-like iterkeys() that returns an iterator of names of cookies + from the jar. + + .. seealso:: itervalues() and iteritems(). + """ + for cookie in iter(self): + yield cookie.name + + def keys(self): + """Dict-like keys() that returns a list of names of cookies from the + jar. + + .. seealso:: values() and items(). + """ + return list(self.iterkeys()) + + def itervalues(self): + """Dict-like itervalues() that returns an iterator of values of cookies + from the jar. + + .. seealso:: iterkeys() and iteritems(). + """ + for cookie in iter(self): + yield cookie.value + + def values(self): + """Dict-like values() that returns a list of values of cookies from the + jar. + + .. seealso:: keys() and items(). + """ + return list(self.itervalues()) + + def iteritems(self): + """Dict-like iteritems() that returns an iterator of name-value tuples + from the jar. + + .. seealso:: iterkeys() and itervalues(). + """ + for cookie in iter(self): + yield cookie.name, cookie.value + + def items(self): + """Dict-like items() that returns a list of name-value tuples from the + jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a + vanilla python dict of key value pairs. + + .. seealso:: keys() and values(). + """ + return list(self.iteritems()) + + def list_domains(self): + """Utility method to list all the domains in the jar.""" + domains = [] + for cookie in iter(self): + if cookie.domain not in domains: + domains.append(cookie.domain) + return domains + + def list_paths(self): + """Utility method to list all the paths in the jar.""" + paths = [] + for cookie in iter(self): + if cookie.path not in paths: + paths.append(cookie.path) + return paths + + def multiple_domains(self): + """Returns True if there are multiple domains in the jar. + Returns False otherwise. + + :rtype: bool + """ + domains = [] + for cookie in iter(self): + if cookie.domain is not None and cookie.domain in domains: + return True + domains.append(cookie.domain) + return False # there is only one domain in jar + + def get_dict(self, domain=None, path=None): + """Takes as an argument an optional domain and path and returns a plain + old Python dict of name-value pairs of cookies that meet the + requirements. + + :rtype: dict + """ + dictionary = {} + for cookie in iter(self): + if (domain is None or cookie.domain == domain) and ( + path is None or cookie.path == path + ): + dictionary[cookie.name] = cookie.value + return dictionary + + def __contains__(self, name): + try: + return super().__contains__(name) + except CookieConflictError: + return True + + def __getitem__(self, name): + """Dict-like __getitem__() for compatibility with client code. Throws + exception if there are more than one cookie with name. In that case, + use the more explicit get() method instead. + + .. warning:: operation is O(n), not O(1). + """ + return self._find_no_duplicates(name) + + def __setitem__(self, name, value): + """Dict-like __setitem__ for compatibility with client code. Throws + exception if there is already a cookie of that name in the jar. In that + case, use the more explicit set() method instead. + """ + self.set(name, value) + + def __delitem__(self, name): + """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s + ``remove_cookie_by_name()``. + """ + remove_cookie_by_name(self, name) + + def set_cookie(self, cookie, *args, **kwargs): + if ( + hasattr(cookie.value, "startswith") + and cookie.value.startswith('"') + and cookie.value.endswith('"') + ): + cookie.value = cookie.value.replace('\\"', "") + return super().set_cookie(cookie, *args, **kwargs) + + def update(self, other): + """Updates this jar with cookies from another CookieJar or dict-like""" + if isinstance(other, cookielib.CookieJar): + for cookie in other: + self.set_cookie(copy.copy(cookie)) + else: + super().update(other) + + def _find(self, name, domain=None, path=None): + """Requests uses this method internally to get cookie values. + + If there are conflicting cookies, _find arbitrarily chooses one. + See _find_no_duplicates if you want an exception thrown if there are + conflicting cookies. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :return: cookie.value + """ + for cookie in iter(self): + if cookie.name == name: + if domain is None or cookie.domain == domain: + if path is None or cookie.path == path: + return cookie.value + + raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}") + + def _find_no_duplicates(self, name, domain=None, path=None): + """Both ``__get_item__`` and ``get`` call this function: it's never + used elsewhere in Requests. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :raises KeyError: if cookie is not found + :raises CookieConflictError: if there are multiple cookies + that match name and optionally domain and path + :return: cookie.value + """ + toReturn = None + for cookie in iter(self): + if cookie.name == name: + if domain is None or cookie.domain == domain: + if path is None or cookie.path == path: + if toReturn is not None: + # if there are multiple cookies that meet passed in criteria + raise CookieConflictError( + f"There are multiple cookies with name, {name!r}" + ) + # we will eventually return this as long as no cookie conflict + toReturn = cookie.value + + if toReturn: + return toReturn + raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}") + + def __getstate__(self): + """Unlike a normal CookieJar, this class is pickleable.""" + state = self.__dict__.copy() + # remove the unpickleable RLock object + state.pop("_cookies_lock") + return state + + def __setstate__(self, state): + """Unlike a normal CookieJar, this class is pickleable.""" + self.__dict__.update(state) + if "_cookies_lock" not in self.__dict__: + self._cookies_lock = threading.RLock() + + def copy(self): + """Return a copy of this RequestsCookieJar.""" + new_cj = RequestsCookieJar() + new_cj.set_policy(self.get_policy()) + new_cj.update(self) + return new_cj + + def get_policy(self): + """Return the CookiePolicy instance used.""" + return self._policy + + +def _copy_cookie_jar(jar): + if jar is None: + return None + + if hasattr(jar, "copy"): + # We're dealing with an instance of RequestsCookieJar + return jar.copy() + # We're dealing with a generic CookieJar instance + new_jar = copy.copy(jar) + new_jar.clear() + for cookie in jar: + new_jar.set_cookie(copy.copy(cookie)) + return new_jar + + +def create_cookie(name, value, **kwargs): + """Make a cookie from underspecified parameters. + + By default, the pair of `name` and `value` will be set for the domain '' + and sent on every request (this is sometimes called a "supercookie"). + """ + result = { + "version": 0, + "name": name, + "value": value, + "port": None, + "domain": "", + "path": "/", + "secure": False, + "expires": None, + "discard": True, + "comment": None, + "comment_url": None, + "rest": {"HttpOnly": None}, + "rfc2109": False, + } + + badargs = set(kwargs) - set(result) + if badargs: + raise TypeError( + f"create_cookie() got unexpected keyword arguments: {list(badargs)}" + ) + + result.update(kwargs) + result["port_specified"] = bool(result["port"]) + result["domain_specified"] = bool(result["domain"]) + result["domain_initial_dot"] = result["domain"].startswith(".") + result["path_specified"] = bool(result["path"]) + + return cookielib.Cookie(**result) + + +def morsel_to_cookie(morsel): + """Convert a Morsel object into a Cookie containing the one k/v pair.""" + + expires = None + if morsel["max-age"]: + try: + expires = int(time.time() + int(morsel["max-age"])) + except ValueError: + raise TypeError(f"max-age: {morsel['max-age']} must be integer") + elif morsel["expires"]: + time_template = "%a, %d-%b-%Y %H:%M:%S GMT" + expires = calendar.timegm(time.strptime(morsel["expires"], time_template)) + return create_cookie( + comment=morsel["comment"], + comment_url=bool(morsel["comment"]), + discard=False, + domain=morsel["domain"], + expires=expires, + name=morsel.key, + path=morsel["path"], + port=None, + rest={"HttpOnly": morsel["httponly"]}, + rfc2109=False, + secure=bool(morsel["secure"]), + value=morsel.value, + version=morsel["version"] or 0, + ) + + +def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True): + """Returns a CookieJar from a key/value dictionary. + + :param cookie_dict: Dict of key/values to insert into CookieJar. + :param cookiejar: (optional) A cookiejar to add the cookies to. + :param overwrite: (optional) If False, will not replace cookies + already in the jar with new ones. + :rtype: CookieJar + """ + if cookiejar is None: + cookiejar = RequestsCookieJar() + + if cookie_dict is not None: + names_from_jar = [cookie.name for cookie in cookiejar] + for name in cookie_dict: + if overwrite or (name not in names_from_jar): + cookiejar.set_cookie(create_cookie(name, cookie_dict[name])) + + return cookiejar + + +def merge_cookies(cookiejar, cookies): + """Add cookies to cookiejar and returns a merged CookieJar. + + :param cookiejar: CookieJar object to add the cookies to. + :param cookies: Dictionary or CookieJar object to be added. + :rtype: CookieJar + """ + if not isinstance(cookiejar, cookielib.CookieJar): + raise ValueError("You can only merge into CookieJar") + + if isinstance(cookies, dict): + cookiejar = cookiejar_from_dict(cookies, cookiejar=cookiejar, overwrite=False) + elif isinstance(cookies, cookielib.CookieJar): + try: + cookiejar.update(cookies) + except AttributeError: + for cookie_in_jar in cookies: + cookiejar.set_cookie(cookie_in_jar) + + return cookiejar diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/exceptions.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/exceptions.py new file mode 100644 index 0000000..168d073 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/exceptions.py @@ -0,0 +1,141 @@ +""" +requests.exceptions +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of Requests' exceptions. +""" +from pip._vendor.urllib3.exceptions import HTTPError as BaseHTTPError + +from .compat import JSONDecodeError as CompatJSONDecodeError + + +class RequestException(IOError): + """There was an ambiguous exception that occurred while handling your + request. + """ + + def __init__(self, *args, **kwargs): + """Initialize RequestException with `request` and `response` objects.""" + response = kwargs.pop("response", None) + self.response = response + self.request = kwargs.pop("request", None) + if response is not None and not self.request and hasattr(response, "request"): + self.request = self.response.request + super().__init__(*args, **kwargs) + + +class InvalidJSONError(RequestException): + """A JSON error occurred.""" + + +class JSONDecodeError(InvalidJSONError, CompatJSONDecodeError): + """Couldn't decode the text into json""" + + def __init__(self, *args, **kwargs): + """ + Construct the JSONDecodeError instance first with all + args. Then use it's args to construct the IOError so that + the json specific args aren't used as IOError specific args + and the error message from JSONDecodeError is preserved. + """ + CompatJSONDecodeError.__init__(self, *args) + InvalidJSONError.__init__(self, *self.args, **kwargs) + + +class HTTPError(RequestException): + """An HTTP error occurred.""" + + +class ConnectionError(RequestException): + """A Connection error occurred.""" + + +class ProxyError(ConnectionError): + """A proxy error occurred.""" + + +class SSLError(ConnectionError): + """An SSL error occurred.""" + + +class Timeout(RequestException): + """The request timed out. + + Catching this error will catch both + :exc:`~requests.exceptions.ConnectTimeout` and + :exc:`~requests.exceptions.ReadTimeout` errors. + """ + + +class ConnectTimeout(ConnectionError, Timeout): + """The request timed out while trying to connect to the remote server. + + Requests that produced this error are safe to retry. + """ + + +class ReadTimeout(Timeout): + """The server did not send any data in the allotted amount of time.""" + + +class URLRequired(RequestException): + """A valid URL is required to make a request.""" + + +class TooManyRedirects(RequestException): + """Too many redirects.""" + + +class MissingSchema(RequestException, ValueError): + """The URL scheme (e.g. http or https) is missing.""" + + +class InvalidSchema(RequestException, ValueError): + """The URL scheme provided is either invalid or unsupported.""" + + +class InvalidURL(RequestException, ValueError): + """The URL provided was somehow invalid.""" + + +class InvalidHeader(RequestException, ValueError): + """The header value provided was somehow invalid.""" + + +class InvalidProxyURL(InvalidURL): + """The proxy URL provided is invalid.""" + + +class ChunkedEncodingError(RequestException): + """The server declared chunked encoding but sent an invalid chunk.""" + + +class ContentDecodingError(RequestException, BaseHTTPError): + """Failed to decode response content.""" + + +class StreamConsumedError(RequestException, TypeError): + """The content for this response was already consumed.""" + + +class RetryError(RequestException): + """Custom retries logic failed""" + + +class UnrewindableBodyError(RequestException): + """Requests encountered an error when trying to rewind a body.""" + + +# Warnings + + +class RequestsWarning(Warning): + """Base warning for Requests.""" + + +class FileModeWarning(RequestsWarning, DeprecationWarning): + """A file was opened in text mode, but Requests determined its binary length.""" + + +class RequestsDependencyWarning(RequestsWarning): + """An imported dependency doesn't match the expected version range.""" diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/help.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/help.py new file mode 100644 index 0000000..2d292c2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/help.py @@ -0,0 +1,131 @@ +"""Module containing bug report helper(s).""" + +import json +import platform +import ssl +import sys + +from pip._vendor import idna +from pip._vendor import urllib3 + +from . import __version__ as requests_version + +charset_normalizer = None + +try: + from pip._vendor import chardet +except ImportError: + chardet = None + +try: + from pip._vendor.urllib3.contrib import pyopenssl +except ImportError: + pyopenssl = None + OpenSSL = None + cryptography = None +else: + import cryptography + import OpenSSL + + +def _implementation(): + """Return a dict with the Python implementation and version. + + Provide both the name and the version of the Python implementation + currently running. For example, on CPython 3.10.3 it will return + {'name': 'CPython', 'version': '3.10.3'}. + + This function works best on CPython and PyPy: in particular, it probably + doesn't work for Jython or IronPython. Future investigation should be done + to work out the correct shape of the code for those platforms. + """ + implementation = platform.python_implementation() + + if implementation == "CPython": + implementation_version = platform.python_version() + elif implementation == "PyPy": + implementation_version = "{}.{}.{}".format( + sys.pypy_version_info.major, + sys.pypy_version_info.minor, + sys.pypy_version_info.micro, + ) + if sys.pypy_version_info.releaselevel != "final": + implementation_version = "".join( + [implementation_version, sys.pypy_version_info.releaselevel] + ) + elif implementation == "Jython": + implementation_version = platform.python_version() # Complete Guess + elif implementation == "IronPython": + implementation_version = platform.python_version() # Complete Guess + else: + implementation_version = "Unknown" + + return {"name": implementation, "version": implementation_version} + + +def info(): + """Generate information for a bug report.""" + try: + platform_info = { + "system": platform.system(), + "release": platform.release(), + } + except OSError: + platform_info = { + "system": "Unknown", + "release": "Unknown", + } + + implementation_info = _implementation() + urllib3_info = {"version": urllib3.__version__} + charset_normalizer_info = {"version": None} + chardet_info = {"version": None} + if charset_normalizer: + charset_normalizer_info = {"version": charset_normalizer.__version__} + if chardet: + chardet_info = {"version": chardet.__version__} + + pyopenssl_info = { + "version": None, + "openssl_version": "", + } + if OpenSSL: + pyopenssl_info = { + "version": OpenSSL.__version__, + "openssl_version": f"{OpenSSL.SSL.OPENSSL_VERSION_NUMBER:x}", + } + cryptography_info = { + "version": getattr(cryptography, "__version__", ""), + } + idna_info = { + "version": getattr(idna, "__version__", ""), + } + + system_ssl = ssl.OPENSSL_VERSION_NUMBER + system_ssl_info = {"version": f"{system_ssl:x}" if system_ssl is not None else ""} + + return { + "platform": platform_info, + "implementation": implementation_info, + "system_ssl": system_ssl_info, + "using_pyopenssl": pyopenssl is not None, + "using_charset_normalizer": chardet is None, + "pyOpenSSL": pyopenssl_info, + "urllib3": urllib3_info, + "chardet": chardet_info, + "charset_normalizer": charset_normalizer_info, + "cryptography": cryptography_info, + "idna": idna_info, + "requests": { + "version": requests_version, + }, + } + + +def main(): + """Pretty-print the bug information as JSON.""" + print(json.dumps(info(), sort_keys=True, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/hooks.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/hooks.py new file mode 100644 index 0000000..d181ba2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/hooks.py @@ -0,0 +1,33 @@ +""" +requests.hooks +~~~~~~~~~~~~~~ + +This module provides the capabilities for the Requests hooks system. + +Available hooks: + +``response``: + The response generated from a Request. +""" +HOOKS = ["response"] + + +def default_hooks(): + return {event: [] for event in HOOKS} + + +# TODO: response is the only one + + +def dispatch_hook(key, hooks, hook_data, **kwargs): + """Dispatches a hook dictionary on a given piece of data.""" + hooks = hooks or {} + hooks = hooks.get(key) + if hooks: + if hasattr(hooks, "__call__"): + hooks = [hooks] + for hook in hooks: + _hook_data = hook(hook_data, **kwargs) + if _hook_data is not None: + hook_data = _hook_data + return hook_data diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/models.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/models.py new file mode 100644 index 0000000..76e6f19 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/models.py @@ -0,0 +1,1034 @@ +""" +requests.models +~~~~~~~~~~~~~~~ + +This module contains the primary objects that power Requests. +""" + +import datetime + +# Import encoding now, to avoid implicit import later. +# Implicit import within threads may cause LookupError when standard library is in a ZIP, +# such as in Embedded Python. See https://github.com/psf/requests/issues/3578. +import encodings.idna # noqa: F401 +from io import UnsupportedOperation + +from pip._vendor.urllib3.exceptions import ( + DecodeError, + LocationParseError, + ProtocolError, + ReadTimeoutError, + SSLError, +) +from pip._vendor.urllib3.fields import RequestField +from pip._vendor.urllib3.filepost import encode_multipart_formdata +from pip._vendor.urllib3.util import parse_url + +from ._internal_utils import to_native_string, unicode_is_ascii +from .auth import HTTPBasicAuth +from .compat import ( + Callable, + JSONDecodeError, + Mapping, + basestring, + builtin_str, + chardet, + cookielib, +) +from .compat import json as complexjson +from .compat import urlencode, urlsplit, urlunparse +from .cookies import _copy_cookie_jar, cookiejar_from_dict, get_cookie_header +from .exceptions import ( + ChunkedEncodingError, + ConnectionError, + ContentDecodingError, + HTTPError, + InvalidJSONError, + InvalidURL, +) +from .exceptions import JSONDecodeError as RequestsJSONDecodeError +from .exceptions import MissingSchema +from .exceptions import SSLError as RequestsSSLError +from .exceptions import StreamConsumedError +from .hooks import default_hooks +from .status_codes import codes +from .structures import CaseInsensitiveDict +from .utils import ( + check_header_validity, + get_auth_from_url, + guess_filename, + guess_json_utf, + iter_slices, + parse_header_links, + requote_uri, + stream_decode_response_unicode, + super_len, + to_key_val_list, +) + +#: The set of HTTP status codes that indicate an automatically +#: processable redirect. +REDIRECT_STATI = ( + codes.moved, # 301 + codes.found, # 302 + codes.other, # 303 + codes.temporary_redirect, # 307 + codes.permanent_redirect, # 308 +) + +DEFAULT_REDIRECT_LIMIT = 30 +CONTENT_CHUNK_SIZE = 10 * 1024 +ITER_CHUNK_SIZE = 512 + + +class RequestEncodingMixin: + @property + def path_url(self): + """Build the path URL to use.""" + + url = [] + + p = urlsplit(self.url) + + path = p.path + if not path: + path = "/" + + url.append(path) + + query = p.query + if query: + url.append("?") + url.append(query) + + return "".join(url) + + @staticmethod + def _encode_params(data): + """Encode parameters in a piece of data. + + Will successfully encode parameters when passed as a dict or a list of + 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary + if parameters are supplied as a dict. + """ + + if isinstance(data, (str, bytes)): + return data + elif hasattr(data, "read"): + return data + elif hasattr(data, "__iter__"): + result = [] + for k, vs in to_key_val_list(data): + if isinstance(vs, basestring) or not hasattr(vs, "__iter__"): + vs = [vs] + for v in vs: + if v is not None: + result.append( + ( + k.encode("utf-8") if isinstance(k, str) else k, + v.encode("utf-8") if isinstance(v, str) else v, + ) + ) + return urlencode(result, doseq=True) + else: + return data + + @staticmethod + def _encode_files(files, data): + """Build the body for a multipart/form-data request. + + Will successfully encode files when passed as a dict or a list of + tuples. Order is retained if data is a list of tuples but arbitrary + if parameters are supplied as a dict. + The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype) + or 4-tuples (filename, fileobj, contentype, custom_headers). + """ + if not files: + raise ValueError("Files must be provided.") + elif isinstance(data, basestring): + raise ValueError("Data must not be a string.") + + new_fields = [] + fields = to_key_val_list(data or {}) + files = to_key_val_list(files or {}) + + for field, val in fields: + if isinstance(val, basestring) or not hasattr(val, "__iter__"): + val = [val] + for v in val: + if v is not None: + # Don't call str() on bytestrings: in Py3 it all goes wrong. + if not isinstance(v, bytes): + v = str(v) + + new_fields.append( + ( + field.decode("utf-8") + if isinstance(field, bytes) + else field, + v.encode("utf-8") if isinstance(v, str) else v, + ) + ) + + for (k, v) in files: + # support for explicit filename + ft = None + fh = None + if isinstance(v, (tuple, list)): + if len(v) == 2: + fn, fp = v + elif len(v) == 3: + fn, fp, ft = v + else: + fn, fp, ft, fh = v + else: + fn = guess_filename(v) or k + fp = v + + if isinstance(fp, (str, bytes, bytearray)): + fdata = fp + elif hasattr(fp, "read"): + fdata = fp.read() + elif fp is None: + continue + else: + fdata = fp + + rf = RequestField(name=k, data=fdata, filename=fn, headers=fh) + rf.make_multipart(content_type=ft) + new_fields.append(rf) + + body, content_type = encode_multipart_formdata(new_fields) + + return body, content_type + + +class RequestHooksMixin: + def register_hook(self, event, hook): + """Properly register a hook.""" + + if event not in self.hooks: + raise ValueError(f'Unsupported event specified, with event name "{event}"') + + if isinstance(hook, Callable): + self.hooks[event].append(hook) + elif hasattr(hook, "__iter__"): + self.hooks[event].extend(h for h in hook if isinstance(h, Callable)) + + def deregister_hook(self, event, hook): + """Deregister a previously registered hook. + Returns True if the hook existed, False if not. + """ + + try: + self.hooks[event].remove(hook) + return True + except ValueError: + return False + + +class Request(RequestHooksMixin): + """A user-created :class:`Request ` object. + + Used to prepare a :class:`PreparedRequest `, which is sent to the server. + + :param method: HTTP method to use. + :param url: URL to send. + :param headers: dictionary of headers to send. + :param files: dictionary of {filename: fileobject} files to multipart upload. + :param data: the body to attach to the request. If a dictionary or + list of tuples ``[(key, value)]`` is provided, form-encoding will + take place. + :param json: json for the body to attach to the request (if files or data is not specified). + :param params: URL parameters to append to the URL. If a dictionary or + list of tuples ``[(key, value)]`` is provided, form-encoding will + take place. + :param auth: Auth handler or (user, pass) tuple. + :param cookies: dictionary or CookieJar of cookies to attach to this request. + :param hooks: dictionary of callback hooks, for internal usage. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'https://httpbin.org/get') + >>> req.prepare() + + """ + + def __init__( + self, + method=None, + url=None, + headers=None, + files=None, + data=None, + params=None, + auth=None, + cookies=None, + hooks=None, + json=None, + ): + + # Default empty dicts for dict params. + data = [] if data is None else data + files = [] if files is None else files + headers = {} if headers is None else headers + params = {} if params is None else params + hooks = {} if hooks is None else hooks + + self.hooks = default_hooks() + for (k, v) in list(hooks.items()): + self.register_hook(event=k, hook=v) + + self.method = method + self.url = url + self.headers = headers + self.files = files + self.data = data + self.json = json + self.params = params + self.auth = auth + self.cookies = cookies + + def __repr__(self): + return f"" + + def prepare(self): + """Constructs a :class:`PreparedRequest ` for transmission and returns it.""" + p = PreparedRequest() + p.prepare( + method=self.method, + url=self.url, + headers=self.headers, + files=self.files, + data=self.data, + json=self.json, + params=self.params, + auth=self.auth, + cookies=self.cookies, + hooks=self.hooks, + ) + return p + + +class PreparedRequest(RequestEncodingMixin, RequestHooksMixin): + """The fully mutable :class:`PreparedRequest ` object, + containing the exact bytes that will be sent to the server. + + Instances are generated from a :class:`Request ` object, and + should not be instantiated manually; doing so may produce undesirable + effects. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'https://httpbin.org/get') + >>> r = req.prepare() + >>> r + + + >>> s = requests.Session() + >>> s.send(r) + + """ + + def __init__(self): + #: HTTP verb to send to the server. + self.method = None + #: HTTP URL to send the request to. + self.url = None + #: dictionary of HTTP headers. + self.headers = None + # The `CookieJar` used to create the Cookie header will be stored here + # after prepare_cookies is called + self._cookies = None + #: request body to send to the server. + self.body = None + #: dictionary of callback hooks, for internal usage. + self.hooks = default_hooks() + #: integer denoting starting position of a readable file-like body. + self._body_position = None + + def prepare( + self, + method=None, + url=None, + headers=None, + files=None, + data=None, + params=None, + auth=None, + cookies=None, + hooks=None, + json=None, + ): + """Prepares the entire request with the given parameters.""" + + self.prepare_method(method) + self.prepare_url(url, params) + self.prepare_headers(headers) + self.prepare_cookies(cookies) + self.prepare_body(data, files, json) + self.prepare_auth(auth, url) + + # Note that prepare_auth must be last to enable authentication schemes + # such as OAuth to work on a fully prepared request. + + # This MUST go after prepare_auth. Authenticators could add a hook + self.prepare_hooks(hooks) + + def __repr__(self): + return f"" + + def copy(self): + p = PreparedRequest() + p.method = self.method + p.url = self.url + p.headers = self.headers.copy() if self.headers is not None else None + p._cookies = _copy_cookie_jar(self._cookies) + p.body = self.body + p.hooks = self.hooks + p._body_position = self._body_position + return p + + def prepare_method(self, method): + """Prepares the given HTTP method.""" + self.method = method + if self.method is not None: + self.method = to_native_string(self.method.upper()) + + @staticmethod + def _get_idna_encoded_host(host): + from pip._vendor import idna + + try: + host = idna.encode(host, uts46=True).decode("utf-8") + except idna.IDNAError: + raise UnicodeError + return host + + def prepare_url(self, url, params): + """Prepares the given HTTP URL.""" + #: Accept objects that have string representations. + #: We're unable to blindly call unicode/str functions + #: as this will include the bytestring indicator (b'') + #: on python 3.x. + #: https://github.com/psf/requests/pull/2238 + if isinstance(url, bytes): + url = url.decode("utf8") + else: + url = str(url) + + # Remove leading whitespaces from url + url = url.lstrip() + + # Don't do any URL preparation for non-HTTP schemes like `mailto`, + # `data` etc to work around exceptions from `url_parse`, which + # handles RFC 3986 only. + if ":" in url and not url.lower().startswith("http"): + self.url = url + return + + # Support for unicode domain names and paths. + try: + scheme, auth, host, port, path, query, fragment = parse_url(url) + except LocationParseError as e: + raise InvalidURL(*e.args) + + if not scheme: + raise MissingSchema( + f"Invalid URL {url!r}: No scheme supplied. " + f"Perhaps you meant https://{url}?" + ) + + if not host: + raise InvalidURL(f"Invalid URL {url!r}: No host supplied") + + # In general, we want to try IDNA encoding the hostname if the string contains + # non-ASCII characters. This allows users to automatically get the correct IDNA + # behaviour. For strings containing only ASCII characters, we need to also verify + # it doesn't start with a wildcard (*), before allowing the unencoded hostname. + if not unicode_is_ascii(host): + try: + host = self._get_idna_encoded_host(host) + except UnicodeError: + raise InvalidURL("URL has an invalid label.") + elif host.startswith(("*", ".")): + raise InvalidURL("URL has an invalid label.") + + # Carefully reconstruct the network location + netloc = auth or "" + if netloc: + netloc += "@" + netloc += host + if port: + netloc += f":{port}" + + # Bare domains aren't valid URLs. + if not path: + path = "/" + + if isinstance(params, (str, bytes)): + params = to_native_string(params) + + enc_params = self._encode_params(params) + if enc_params: + if query: + query = f"{query}&{enc_params}" + else: + query = enc_params + + url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment])) + self.url = url + + def prepare_headers(self, headers): + """Prepares the given HTTP headers.""" + + self.headers = CaseInsensitiveDict() + if headers: + for header in headers.items(): + # Raise exception on invalid header value. + check_header_validity(header) + name, value = header + self.headers[to_native_string(name)] = value + + def prepare_body(self, data, files, json=None): + """Prepares the given HTTP body data.""" + + # Check if file, fo, generator, iterator. + # If not, run through normal process. + + # Nottin' on you. + body = None + content_type = None + + if not data and json is not None: + # urllib3 requires a bytes-like body. Python 2's json.dumps + # provides this natively, but Python 3 gives a Unicode string. + content_type = "application/json" + + try: + body = complexjson.dumps(json, allow_nan=False) + except ValueError as ve: + raise InvalidJSONError(ve, request=self) + + if not isinstance(body, bytes): + body = body.encode("utf-8") + + is_stream = all( + [ + hasattr(data, "__iter__"), + not isinstance(data, (basestring, list, tuple, Mapping)), + ] + ) + + if is_stream: + try: + length = super_len(data) + except (TypeError, AttributeError, UnsupportedOperation): + length = None + + body = data + + if getattr(body, "tell", None) is not None: + # Record the current file position before reading. + # This will allow us to rewind a file in the event + # of a redirect. + try: + self._body_position = body.tell() + except OSError: + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body + self._body_position = object() + + if files: + raise NotImplementedError( + "Streamed bodies and files are mutually exclusive." + ) + + if length: + self.headers["Content-Length"] = builtin_str(length) + else: + self.headers["Transfer-Encoding"] = "chunked" + else: + # Multi-part file uploads. + if files: + (body, content_type) = self._encode_files(files, data) + else: + if data: + body = self._encode_params(data) + if isinstance(data, basestring) or hasattr(data, "read"): + content_type = None + else: + content_type = "application/x-www-form-urlencoded" + + self.prepare_content_length(body) + + # Add content-type if it wasn't explicitly provided. + if content_type and ("content-type" not in self.headers): + self.headers["Content-Type"] = content_type + + self.body = body + + def prepare_content_length(self, body): + """Prepare Content-Length header based on request method and body""" + if body is not None: + length = super_len(body) + if length: + # If length exists, set it. Otherwise, we fallback + # to Transfer-Encoding: chunked. + self.headers["Content-Length"] = builtin_str(length) + elif ( + self.method not in ("GET", "HEAD") + and self.headers.get("Content-Length") is None + ): + # Set Content-Length to 0 for methods that can have a body + # but don't provide one. (i.e. not GET or HEAD) + self.headers["Content-Length"] = "0" + + def prepare_auth(self, auth, url=""): + """Prepares the given HTTP auth data.""" + + # If no Auth is explicitly provided, extract it from the URL first. + if auth is None: + url_auth = get_auth_from_url(self.url) + auth = url_auth if any(url_auth) else None + + if auth: + if isinstance(auth, tuple) and len(auth) == 2: + # special-case basic HTTP auth + auth = HTTPBasicAuth(*auth) + + # Allow auth to make its changes. + r = auth(self) + + # Update self to reflect the auth changes. + self.__dict__.update(r.__dict__) + + # Recompute Content-Length + self.prepare_content_length(self.body) + + def prepare_cookies(self, cookies): + """Prepares the given HTTP cookie data. + + This function eventually generates a ``Cookie`` header from the + given cookies using cookielib. Due to cookielib's design, the header + will not be regenerated if it already exists, meaning this function + can only be called once for the life of the + :class:`PreparedRequest ` object. Any subsequent calls + to ``prepare_cookies`` will have no actual effect, unless the "Cookie" + header is removed beforehand. + """ + if isinstance(cookies, cookielib.CookieJar): + self._cookies = cookies + else: + self._cookies = cookiejar_from_dict(cookies) + + cookie_header = get_cookie_header(self._cookies, self) + if cookie_header is not None: + self.headers["Cookie"] = cookie_header + + def prepare_hooks(self, hooks): + """Prepares the given hooks.""" + # hooks can be passed as None to the prepare method and to this + # method. To prevent iterating over None, simply use an empty list + # if hooks is False-y + hooks = hooks or [] + for event in hooks: + self.register_hook(event, hooks[event]) + + +class Response: + """The :class:`Response ` object, which contains a + server's response to an HTTP request. + """ + + __attrs__ = [ + "_content", + "status_code", + "headers", + "url", + "history", + "encoding", + "reason", + "cookies", + "elapsed", + "request", + ] + + def __init__(self): + self._content = False + self._content_consumed = False + self._next = None + + #: Integer Code of responded HTTP Status, e.g. 404 or 200. + self.status_code = None + + #: Case-insensitive Dictionary of Response Headers. + #: For example, ``headers['content-encoding']`` will return the + #: value of a ``'Content-Encoding'`` response header. + self.headers = CaseInsensitiveDict() + + #: File-like object representation of response (for advanced usage). + #: Use of ``raw`` requires that ``stream=True`` be set on the request. + #: This requirement does not apply for use internally to Requests. + self.raw = None + + #: Final URL location of Response. + self.url = None + + #: Encoding to decode with when accessing r.text. + self.encoding = None + + #: A list of :class:`Response ` objects from + #: the history of the Request. Any redirect responses will end + #: up here. The list is sorted from the oldest to the most recent request. + self.history = [] + + #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK". + self.reason = None + + #: A CookieJar of Cookies the server sent back. + self.cookies = cookiejar_from_dict({}) + + #: The amount of time elapsed between sending the request + #: and the arrival of the response (as a timedelta). + #: This property specifically measures the time taken between sending + #: the first byte of the request and finishing parsing the headers. It + #: is therefore unaffected by consuming the response content or the + #: value of the ``stream`` keyword argument. + self.elapsed = datetime.timedelta(0) + + #: The :class:`PreparedRequest ` object to which this + #: is a response. + self.request = None + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def __getstate__(self): + # Consume everything; accessing the content attribute makes + # sure the content has been fully read. + if not self._content_consumed: + self.content + + return {attr: getattr(self, attr, None) for attr in self.__attrs__} + + def __setstate__(self, state): + for name, value in state.items(): + setattr(self, name, value) + + # pickled objects do not have .raw + setattr(self, "_content_consumed", True) + setattr(self, "raw", None) + + def __repr__(self): + return f"" + + def __bool__(self): + """Returns True if :attr:`status_code` is less than 400. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code, is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + return self.ok + + def __nonzero__(self): + """Returns True if :attr:`status_code` is less than 400. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code, is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + return self.ok + + def __iter__(self): + """Allows you to use a response as an iterator.""" + return self.iter_content(128) + + @property + def ok(self): + """Returns True if :attr:`status_code` is less than 400, False if not. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + try: + self.raise_for_status() + except HTTPError: + return False + return True + + @property + def is_redirect(self): + """True if this Response is a well-formed HTTP redirect that could have + been processed automatically (by :meth:`Session.resolve_redirects`). + """ + return "location" in self.headers and self.status_code in REDIRECT_STATI + + @property + def is_permanent_redirect(self): + """True if this Response one of the permanent versions of redirect.""" + return "location" in self.headers and self.status_code in ( + codes.moved_permanently, + codes.permanent_redirect, + ) + + @property + def next(self): + """Returns a PreparedRequest for the next request in a redirect chain, if there is one.""" + return self._next + + @property + def apparent_encoding(self): + """The apparent encoding, provided by the charset_normalizer or chardet libraries.""" + return chardet.detect(self.content)["encoding"] + + def iter_content(self, chunk_size=1, decode_unicode=False): + """Iterates over the response data. When stream=True is set on the + request, this avoids reading the content at once into memory for + large responses. The chunk size is the number of bytes it should + read into memory. This is not necessarily the length of each item + returned as decoding can take place. + + chunk_size must be of type int or None. A value of None will + function differently depending on the value of `stream`. + stream=True will read data as it arrives in whatever size the + chunks are received. If stream=False, data is returned as + a single chunk. + + If decode_unicode is True, content will be decoded using the best + available encoding based on the response. + """ + + def generate(): + # Special case for urllib3. + if hasattr(self.raw, "stream"): + try: + yield from self.raw.stream(chunk_size, decode_content=True) + except ProtocolError as e: + raise ChunkedEncodingError(e) + except DecodeError as e: + raise ContentDecodingError(e) + except ReadTimeoutError as e: + raise ConnectionError(e) + except SSLError as e: + raise RequestsSSLError(e) + else: + # Standard file-like object. + while True: + chunk = self.raw.read(chunk_size) + if not chunk: + break + yield chunk + + self._content_consumed = True + + if self._content_consumed and isinstance(self._content, bool): + raise StreamConsumedError() + elif chunk_size is not None and not isinstance(chunk_size, int): + raise TypeError( + f"chunk_size must be an int, it is instead a {type(chunk_size)}." + ) + # simulate reading small chunks of the content + reused_chunks = iter_slices(self._content, chunk_size) + + stream_chunks = generate() + + chunks = reused_chunks if self._content_consumed else stream_chunks + + if decode_unicode: + chunks = stream_decode_response_unicode(chunks, self) + + return chunks + + def iter_lines( + self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None + ): + """Iterates over the response data, one line at a time. When + stream=True is set on the request, this avoids reading the + content at once into memory for large responses. + + .. note:: This method is not reentrant safe. + """ + + pending = None + + for chunk in self.iter_content( + chunk_size=chunk_size, decode_unicode=decode_unicode + ): + + if pending is not None: + chunk = pending + chunk + + if delimiter: + lines = chunk.split(delimiter) + else: + lines = chunk.splitlines() + + if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]: + pending = lines.pop() + else: + pending = None + + yield from lines + + if pending is not None: + yield pending + + @property + def content(self): + """Content of the response, in bytes.""" + + if self._content is False: + # Read the contents. + if self._content_consumed: + raise RuntimeError("The content for this response was already consumed") + + if self.status_code == 0 or self.raw is None: + self._content = None + else: + self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b"" + + self._content_consumed = True + # don't need to release the connection; that's been handled by urllib3 + # since we exhausted the data. + return self._content + + @property + def text(self): + """Content of the response, in unicode. + + If Response.encoding is None, encoding will be guessed using + ``charset_normalizer`` or ``chardet``. + + The encoding of the response content is determined based solely on HTTP + headers, following RFC 2616 to the letter. If you can take advantage of + non-HTTP knowledge to make a better guess at the encoding, you should + set ``r.encoding`` appropriately before accessing this property. + """ + + # Try charset from content-type + content = None + encoding = self.encoding + + if not self.content: + return "" + + # Fallback to auto-detected encoding. + if self.encoding is None: + encoding = self.apparent_encoding + + # Decode unicode from given encoding. + try: + content = str(self.content, encoding, errors="replace") + except (LookupError, TypeError): + # A LookupError is raised if the encoding was not found which could + # indicate a misspelling or similar mistake. + # + # A TypeError can be raised if encoding is None + # + # So we try blindly encoding. + content = str(self.content, errors="replace") + + return content + + def json(self, **kwargs): + r"""Returns the json-encoded content of a response, if any. + + :param \*\*kwargs: Optional arguments that ``json.loads`` takes. + :raises requests.exceptions.JSONDecodeError: If the response body does not + contain valid json. + """ + + if not self.encoding and self.content and len(self.content) > 3: + # No encoding set. JSON RFC 4627 section 3 states we should expect + # UTF-8, -16 or -32. Detect which one to use; If the detection or + # decoding fails, fall back to `self.text` (using charset_normalizer to make + # a best guess). + encoding = guess_json_utf(self.content) + if encoding is not None: + try: + return complexjson.loads(self.content.decode(encoding), **kwargs) + except UnicodeDecodeError: + # Wrong UTF codec detected; usually because it's not UTF-8 + # but some other 8-bit codec. This is an RFC violation, + # and the server didn't bother to tell us what codec *was* + # used. + pass + except JSONDecodeError as e: + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) + + try: + return complexjson.loads(self.text, **kwargs) + except JSONDecodeError as e: + # Catch JSON-related errors and raise as requests.JSONDecodeError + # This aliases json.JSONDecodeError and simplejson.JSONDecodeError + raise RequestsJSONDecodeError(e.msg, e.doc, e.pos) + + @property + def links(self): + """Returns the parsed header links of the response, if any.""" + + header = self.headers.get("link") + + resolved_links = {} + + if header: + links = parse_header_links(header) + + for link in links: + key = link.get("rel") or link.get("url") + resolved_links[key] = link + + return resolved_links + + def raise_for_status(self): + """Raises :class:`HTTPError`, if one occurred.""" + + http_error_msg = "" + if isinstance(self.reason, bytes): + # We attempt to decode utf-8 first because some servers + # choose to localize their reason strings. If the string + # isn't utf-8, we fall back to iso-8859-1 for all other + # encodings. (See PR #3538) + try: + reason = self.reason.decode("utf-8") + except UnicodeDecodeError: + reason = self.reason.decode("iso-8859-1") + else: + reason = self.reason + + if 400 <= self.status_code < 500: + http_error_msg = ( + f"{self.status_code} Client Error: {reason} for url: {self.url}" + ) + + elif 500 <= self.status_code < 600: + http_error_msg = ( + f"{self.status_code} Server Error: {reason} for url: {self.url}" + ) + + if http_error_msg: + raise HTTPError(http_error_msg, response=self) + + def close(self): + """Releases the connection back to the pool. Once this method has been + called the underlying ``raw`` object must not be accessed again. + + *Note: Should not normally need to be called explicitly.* + """ + if not self._content_consumed: + self.raw.close() + + release_conn = getattr(self.raw, "release_conn", None) + if release_conn is not None: + release_conn() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/packages.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/packages.py new file mode 100644 index 0000000..9582fa7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/packages.py @@ -0,0 +1,16 @@ +import sys + +# This code exists for backwards compatibility reasons. +# I don't like it either. Just look the other way. :) + +for package in ('urllib3', 'idna', 'chardet'): + vendored_package = "pip._vendor." + package + locals()[package] = __import__(vendored_package) + # This traversal is apparently necessary such that the identities are + # preserved (requests.packages.urllib3.* is urllib3.*) + for mod in list(sys.modules): + if mod == vendored_package or mod.startswith(vendored_package + '.'): + unprefixed_mod = mod[len("pip._vendor."):] + sys.modules['pip._vendor.requests.packages.' + unprefixed_mod] = sys.modules[mod] + +# Kinda cool, though, right? diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/sessions.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/sessions.py new file mode 100644 index 0000000..dbcf2a7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/sessions.py @@ -0,0 +1,833 @@ +""" +requests.sessions +~~~~~~~~~~~~~~~~~ + +This module provides a Session object to manage and persist settings across +requests (cookies, auth, proxies). +""" +import os +import sys +import time +from collections import OrderedDict +from datetime import timedelta + +from ._internal_utils import to_native_string +from .adapters import HTTPAdapter +from .auth import _basic_auth_str +from .compat import Mapping, cookielib, urljoin, urlparse +from .cookies import ( + RequestsCookieJar, + cookiejar_from_dict, + extract_cookies_to_jar, + merge_cookies, +) +from .exceptions import ( + ChunkedEncodingError, + ContentDecodingError, + InvalidSchema, + TooManyRedirects, +) +from .hooks import default_hooks, dispatch_hook + +# formerly defined here, reexposed here for backward compatibility +from .models import ( # noqa: F401 + DEFAULT_REDIRECT_LIMIT, + REDIRECT_STATI, + PreparedRequest, + Request, +) +from .status_codes import codes +from .structures import CaseInsensitiveDict +from .utils import ( # noqa: F401 + DEFAULT_PORTS, + default_headers, + get_auth_from_url, + get_environ_proxies, + get_netrc_auth, + requote_uri, + resolve_proxies, + rewind_body, + should_bypass_proxies, + to_key_val_list, +) + +# Preferred clock, based on which one is more accurate on a given system. +if sys.platform == "win32": + preferred_clock = time.perf_counter +else: + preferred_clock = time.time + + +def merge_setting(request_setting, session_setting, dict_class=OrderedDict): + """Determines appropriate setting for a given request, taking into account + the explicit setting on that request, and the setting in the session. If a + setting is a dictionary, they will be merged together using `dict_class` + """ + + if session_setting is None: + return request_setting + + if request_setting is None: + return session_setting + + # Bypass if not a dictionary (e.g. verify) + if not ( + isinstance(session_setting, Mapping) and isinstance(request_setting, Mapping) + ): + return request_setting + + merged_setting = dict_class(to_key_val_list(session_setting)) + merged_setting.update(to_key_val_list(request_setting)) + + # Remove keys that are set to None. Extract keys first to avoid altering + # the dictionary during iteration. + none_keys = [k for (k, v) in merged_setting.items() if v is None] + for key in none_keys: + del merged_setting[key] + + return merged_setting + + +def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict): + """Properly merges both requests and session hooks. + + This is necessary because when request_hooks == {'response': []}, the + merge breaks Session hooks entirely. + """ + if session_hooks is None or session_hooks.get("response") == []: + return request_hooks + + if request_hooks is None or request_hooks.get("response") == []: + return session_hooks + + return merge_setting(request_hooks, session_hooks, dict_class) + + +class SessionRedirectMixin: + def get_redirect_target(self, resp): + """Receives a Response. Returns a redirect URI or ``None``""" + # Due to the nature of how requests processes redirects this method will + # be called at least once upon the original response and at least twice + # on each subsequent redirect response (if any). + # If a custom mixin is used to handle this logic, it may be advantageous + # to cache the redirect location onto the response object as a private + # attribute. + if resp.is_redirect: + location = resp.headers["location"] + # Currently the underlying http module on py3 decode headers + # in latin1, but empirical evidence suggests that latin1 is very + # rarely used with non-ASCII characters in HTTP headers. + # It is more likely to get UTF8 header rather than latin1. + # This causes incorrect handling of UTF8 encoded location headers. + # To solve this, we re-encode the location in latin1. + location = location.encode("latin1") + return to_native_string(location, "utf8") + return None + + def should_strip_auth(self, old_url, new_url): + """Decide whether Authorization header should be removed when redirecting""" + old_parsed = urlparse(old_url) + new_parsed = urlparse(new_url) + if old_parsed.hostname != new_parsed.hostname: + return True + # Special case: allow http -> https redirect when using the standard + # ports. This isn't specified by RFC 7235, but is kept to avoid + # breaking backwards compatibility with older versions of requests + # that allowed any redirects on the same host. + if ( + old_parsed.scheme == "http" + and old_parsed.port in (80, None) + and new_parsed.scheme == "https" + and new_parsed.port in (443, None) + ): + return False + + # Handle default port usage corresponding to scheme. + changed_port = old_parsed.port != new_parsed.port + changed_scheme = old_parsed.scheme != new_parsed.scheme + default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None) + if ( + not changed_scheme + and old_parsed.port in default_port + and new_parsed.port in default_port + ): + return False + + # Standard case: root URI must match + return changed_port or changed_scheme + + def resolve_redirects( + self, + resp, + req, + stream=False, + timeout=None, + verify=True, + cert=None, + proxies=None, + yield_requests=False, + **adapter_kwargs, + ): + """Receives a Response. Returns a generator of Responses or Requests.""" + + hist = [] # keep track of history + + url = self.get_redirect_target(resp) + previous_fragment = urlparse(req.url).fragment + while url: + prepared_request = req.copy() + + # Update history and keep track of redirects. + # resp.history must ignore the original request in this loop + hist.append(resp) + resp.history = hist[1:] + + try: + resp.content # Consume socket so it can be released + except (ChunkedEncodingError, ContentDecodingError, RuntimeError): + resp.raw.read(decode_content=False) + + if len(resp.history) >= self.max_redirects: + raise TooManyRedirects( + f"Exceeded {self.max_redirects} redirects.", response=resp + ) + + # Release the connection back into the pool. + resp.close() + + # Handle redirection without scheme (see: RFC 1808 Section 4) + if url.startswith("//"): + parsed_rurl = urlparse(resp.url) + url = ":".join([to_native_string(parsed_rurl.scheme), url]) + + # Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2) + parsed = urlparse(url) + if parsed.fragment == "" and previous_fragment: + parsed = parsed._replace(fragment=previous_fragment) + elif parsed.fragment: + previous_fragment = parsed.fragment + url = parsed.geturl() + + # Facilitate relative 'location' headers, as allowed by RFC 7231. + # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') + # Compliant with RFC3986, we percent encode the url. + if not parsed.netloc: + url = urljoin(resp.url, requote_uri(url)) + else: + url = requote_uri(url) + + prepared_request.url = to_native_string(url) + + self.rebuild_method(prepared_request, resp) + + # https://github.com/psf/requests/issues/1084 + if resp.status_code not in ( + codes.temporary_redirect, + codes.permanent_redirect, + ): + # https://github.com/psf/requests/issues/3490 + purged_headers = ("Content-Length", "Content-Type", "Transfer-Encoding") + for header in purged_headers: + prepared_request.headers.pop(header, None) + prepared_request.body = None + + headers = prepared_request.headers + headers.pop("Cookie", None) + + # Extract any cookies sent on the response to the cookiejar + # in the new request. Because we've mutated our copied prepared + # request, use the old one that we haven't yet touched. + extract_cookies_to_jar(prepared_request._cookies, req, resp.raw) + merge_cookies(prepared_request._cookies, self.cookies) + prepared_request.prepare_cookies(prepared_request._cookies) + + # Rebuild auth and proxy information. + proxies = self.rebuild_proxies(prepared_request, proxies) + self.rebuild_auth(prepared_request, resp) + + # A failed tell() sets `_body_position` to `object()`. This non-None + # value ensures `rewindable` will be True, allowing us to raise an + # UnrewindableBodyError, instead of hanging the connection. + rewindable = prepared_request._body_position is not None and ( + "Content-Length" in headers or "Transfer-Encoding" in headers + ) + + # Attempt to rewind consumed file-like object. + if rewindable: + rewind_body(prepared_request) + + # Override the original request. + req = prepared_request + + if yield_requests: + yield req + else: + + resp = self.send( + req, + stream=stream, + timeout=timeout, + verify=verify, + cert=cert, + proxies=proxies, + allow_redirects=False, + **adapter_kwargs, + ) + + extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) + + # extract redirect url, if any, for the next loop + url = self.get_redirect_target(resp) + yield resp + + def rebuild_auth(self, prepared_request, response): + """When being redirected we may want to strip authentication from the + request to avoid leaking credentials. This method intelligently removes + and reapplies authentication where possible to avoid credential loss. + """ + headers = prepared_request.headers + url = prepared_request.url + + if "Authorization" in headers and self.should_strip_auth( + response.request.url, url + ): + # If we get redirected to a new host, we should strip out any + # authentication headers. + del headers["Authorization"] + + # .netrc might have more auth for us on our new host. + new_auth = get_netrc_auth(url) if self.trust_env else None + if new_auth is not None: + prepared_request.prepare_auth(new_auth) + + def rebuild_proxies(self, prepared_request, proxies): + """This method re-evaluates the proxy configuration by considering the + environment variables. If we are redirected to a URL covered by + NO_PROXY, we strip the proxy configuration. Otherwise, we set missing + proxy keys for this URL (in case they were stripped by a previous + redirect). + + This method also replaces the Proxy-Authorization header where + necessary. + + :rtype: dict + """ + headers = prepared_request.headers + scheme = urlparse(prepared_request.url).scheme + new_proxies = resolve_proxies(prepared_request, proxies, self.trust_env) + + if "Proxy-Authorization" in headers: + del headers["Proxy-Authorization"] + + try: + username, password = get_auth_from_url(new_proxies[scheme]) + except KeyError: + username, password = None, None + + # urllib3 handles proxy authorization for us in the standard adapter. + # Avoid appending this to TLS tunneled requests where it may be leaked. + if not scheme.startswith('https') and username and password: + headers["Proxy-Authorization"] = _basic_auth_str(username, password) + + return new_proxies + + def rebuild_method(self, prepared_request, response): + """When being redirected we may want to change the method of the request + based on certain specs or browser behavior. + """ + method = prepared_request.method + + # https://tools.ietf.org/html/rfc7231#section-6.4.4 + if response.status_code == codes.see_other and method != "HEAD": + method = "GET" + + # Do what the browsers do, despite standards... + # First, turn 302s into GETs. + if response.status_code == codes.found and method != "HEAD": + method = "GET" + + # Second, if a POST is responded to with a 301, turn it into a GET. + # This bizarre behaviour is explained in Issue 1704. + if response.status_code == codes.moved and method == "POST": + method = "GET" + + prepared_request.method = method + + +class Session(SessionRedirectMixin): + """A Requests session. + + Provides cookie persistence, connection-pooling, and configuration. + + Basic Usage:: + + >>> import requests + >>> s = requests.Session() + >>> s.get('https://httpbin.org/get') + + + Or as a context manager:: + + >>> with requests.Session() as s: + ... s.get('https://httpbin.org/get') + + """ + + __attrs__ = [ + "headers", + "cookies", + "auth", + "proxies", + "hooks", + "params", + "verify", + "cert", + "adapters", + "stream", + "trust_env", + "max_redirects", + ] + + def __init__(self): + + #: A case-insensitive dictionary of headers to be sent on each + #: :class:`Request ` sent from this + #: :class:`Session `. + self.headers = default_headers() + + #: Default Authentication tuple or object to attach to + #: :class:`Request `. + self.auth = None + + #: Dictionary mapping protocol or protocol and host to the URL of the proxy + #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to + #: be used on each :class:`Request `. + self.proxies = {} + + #: Event-handling hooks. + self.hooks = default_hooks() + + #: Dictionary of querystring data to attach to each + #: :class:`Request `. The dictionary values may be lists for + #: representing multivalued query parameters. + self.params = {} + + #: Stream response content default. + self.stream = False + + #: SSL Verification default. + #: Defaults to `True`, requiring requests to verify the TLS certificate at the + #: remote end. + #: If verify is set to `False`, requests will accept any TLS certificate + #: presented by the server, and will ignore hostname mismatches and/or + #: expired certificates, which will make your application vulnerable to + #: man-in-the-middle (MitM) attacks. + #: Only set this to `False` for testing. + self.verify = True + + #: SSL client certificate default, if String, path to ssl client + #: cert file (.pem). If Tuple, ('cert', 'key') pair. + self.cert = None + + #: Maximum number of redirects allowed. If the request exceeds this + #: limit, a :class:`TooManyRedirects` exception is raised. + #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is + #: 30. + self.max_redirects = DEFAULT_REDIRECT_LIMIT + + #: Trust environment settings for proxy configuration, default + #: authentication and similar. + self.trust_env = True + + #: A CookieJar containing all currently outstanding cookies set on this + #: session. By default it is a + #: :class:`RequestsCookieJar `, but + #: may be any other ``cookielib.CookieJar`` compatible object. + self.cookies = cookiejar_from_dict({}) + + # Default connection adapters. + self.adapters = OrderedDict() + self.mount("https://", HTTPAdapter()) + self.mount("http://", HTTPAdapter()) + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def prepare_request(self, request): + """Constructs a :class:`PreparedRequest ` for + transmission and returns it. The :class:`PreparedRequest` has settings + merged from the :class:`Request ` instance and those of the + :class:`Session`. + + :param request: :class:`Request` instance to prepare with this + session's settings. + :rtype: requests.PreparedRequest + """ + cookies = request.cookies or {} + + # Bootstrap CookieJar. + if not isinstance(cookies, cookielib.CookieJar): + cookies = cookiejar_from_dict(cookies) + + # Merge with session cookies + merged_cookies = merge_cookies( + merge_cookies(RequestsCookieJar(), self.cookies), cookies + ) + + # Set environment's basic authentication if not explicitly set. + auth = request.auth + if self.trust_env and not auth and not self.auth: + auth = get_netrc_auth(request.url) + + p = PreparedRequest() + p.prepare( + method=request.method.upper(), + url=request.url, + files=request.files, + data=request.data, + json=request.json, + headers=merge_setting( + request.headers, self.headers, dict_class=CaseInsensitiveDict + ), + params=merge_setting(request.params, self.params), + auth=merge_setting(auth, self.auth), + cookies=merged_cookies, + hooks=merge_hooks(request.hooks, self.hooks), + ) + return p + + def request( + self, + method, + url, + params=None, + data=None, + headers=None, + cookies=None, + files=None, + auth=None, + timeout=None, + allow_redirects=True, + proxies=None, + hooks=None, + stream=None, + verify=None, + cert=None, + json=None, + ): + """Constructs a :class:`Request `, prepares it and sends it. + Returns :class:`Response ` object. + + :param method: method for the new :class:`Request` object. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary or bytes to be sent in the query + string for the :class:`Request`. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the + :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the + :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the + :class:`Request`. + :param files: (optional) Dictionary of ``'filename': file-like-objects`` + for multipart encoding upload. + :param auth: (optional) Auth tuple or callable to enable + Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) ` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Set to True by default. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol or protocol and + hostname to the URL of the proxy. + :param stream: (optional) whether to immediately download the response + content. Defaults to ``False``. + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use. Defaults to ``True``. When set to + ``False``, requests will accept any TLS certificate presented by + the server, and will ignore hostname mismatches and/or expired + certificates, which will make your application vulnerable to + man-in-the-middle (MitM) attacks. Setting verify to ``False`` + may be useful during local development or testing. + :param cert: (optional) if String, path to ssl client cert file (.pem). + If Tuple, ('cert', 'key') pair. + :rtype: requests.Response + """ + # Create the Request. + req = Request( + method=method.upper(), + url=url, + headers=headers, + files=files, + data=data or {}, + json=json, + params=params or {}, + auth=auth, + cookies=cookies, + hooks=hooks, + ) + prep = self.prepare_request(req) + + proxies = proxies or {} + + settings = self.merge_environment_settings( + prep.url, proxies, stream, verify, cert + ) + + # Send the request. + send_kwargs = { + "timeout": timeout, + "allow_redirects": allow_redirects, + } + send_kwargs.update(settings) + resp = self.send(prep, **send_kwargs) + + return resp + + def get(self, url, **kwargs): + r"""Sends a GET request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault("allow_redirects", True) + return self.request("GET", url, **kwargs) + + def options(self, url, **kwargs): + r"""Sends a OPTIONS request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault("allow_redirects", True) + return self.request("OPTIONS", url, **kwargs) + + def head(self, url, **kwargs): + r"""Sends a HEAD request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault("allow_redirects", False) + return self.request("HEAD", url, **kwargs) + + def post(self, url, data=None, json=None, **kwargs): + r"""Sends a POST request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request("POST", url, data=data, json=json, **kwargs) + + def put(self, url, data=None, **kwargs): + r"""Sends a PUT request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request("PUT", url, data=data, **kwargs) + + def patch(self, url, data=None, **kwargs): + r"""Sends a PATCH request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request("PATCH", url, data=data, **kwargs) + + def delete(self, url, **kwargs): + r"""Sends a DELETE request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request("DELETE", url, **kwargs) + + def send(self, request, **kwargs): + """Send a given PreparedRequest. + + :rtype: requests.Response + """ + # Set defaults that the hooks can utilize to ensure they always have + # the correct parameters to reproduce the previous request. + kwargs.setdefault("stream", self.stream) + kwargs.setdefault("verify", self.verify) + kwargs.setdefault("cert", self.cert) + if "proxies" not in kwargs: + kwargs["proxies"] = resolve_proxies(request, self.proxies, self.trust_env) + + # It's possible that users might accidentally send a Request object. + # Guard against that specific failure case. + if isinstance(request, Request): + raise ValueError("You can only send PreparedRequests.") + + # Set up variables needed for resolve_redirects and dispatching of hooks + allow_redirects = kwargs.pop("allow_redirects", True) + stream = kwargs.get("stream") + hooks = request.hooks + + # Get the appropriate adapter to use + adapter = self.get_adapter(url=request.url) + + # Start time (approximately) of the request + start = preferred_clock() + + # Send the request + r = adapter.send(request, **kwargs) + + # Total elapsed time of the request (approximately) + elapsed = preferred_clock() - start + r.elapsed = timedelta(seconds=elapsed) + + # Response manipulation hooks + r = dispatch_hook("response", hooks, r, **kwargs) + + # Persist cookies + if r.history: + + # If the hooks create history then we want those cookies too + for resp in r.history: + extract_cookies_to_jar(self.cookies, resp.request, resp.raw) + + extract_cookies_to_jar(self.cookies, request, r.raw) + + # Resolve redirects if allowed. + if allow_redirects: + # Redirect resolving generator. + gen = self.resolve_redirects(r, request, **kwargs) + history = [resp for resp in gen] + else: + history = [] + + # Shuffle things around if there's history. + if history: + # Insert the first (original) request at the start + history.insert(0, r) + # Get the last request made + r = history.pop() + r.history = history + + # If redirects aren't being followed, store the response on the Request for Response.next(). + if not allow_redirects: + try: + r._next = next( + self.resolve_redirects(r, request, yield_requests=True, **kwargs) + ) + except StopIteration: + pass + + if not stream: + r.content + + return r + + def merge_environment_settings(self, url, proxies, stream, verify, cert): + """ + Check the environment and merge it with some settings. + + :rtype: dict + """ + # Gather clues from the surrounding environment. + if self.trust_env: + # Set environment's proxies. + no_proxy = proxies.get("no_proxy") if proxies is not None else None + env_proxies = get_environ_proxies(url, no_proxy=no_proxy) + for (k, v) in env_proxies.items(): + proxies.setdefault(k, v) + + # Look for requests environment configuration + # and be compatible with cURL. + if verify is True or verify is None: + verify = ( + os.environ.get("REQUESTS_CA_BUNDLE") + or os.environ.get("CURL_CA_BUNDLE") + or verify + ) + + # Merge all the kwargs. + proxies = merge_setting(proxies, self.proxies) + stream = merge_setting(stream, self.stream) + verify = merge_setting(verify, self.verify) + cert = merge_setting(cert, self.cert) + + return {"proxies": proxies, "stream": stream, "verify": verify, "cert": cert} + + def get_adapter(self, url): + """ + Returns the appropriate connection adapter for the given URL. + + :rtype: requests.adapters.BaseAdapter + """ + for (prefix, adapter) in self.adapters.items(): + + if url.lower().startswith(prefix.lower()): + return adapter + + # Nothing matches :-/ + raise InvalidSchema(f"No connection adapters were found for {url!r}") + + def close(self): + """Closes all adapters and as such the session""" + for v in self.adapters.values(): + v.close() + + def mount(self, prefix, adapter): + """Registers a connection adapter to a prefix. + + Adapters are sorted in descending order by prefix length. + """ + self.adapters[prefix] = adapter + keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] + + for key in keys_to_move: + self.adapters[key] = self.adapters.pop(key) + + def __getstate__(self): + state = {attr: getattr(self, attr, None) for attr in self.__attrs__} + return state + + def __setstate__(self, state): + for attr, value in state.items(): + setattr(self, attr, value) + + +def session(): + """ + Returns a :class:`Session` for context-management. + + .. deprecated:: 1.0.0 + + This method has been deprecated since version 1.0.0 and is only kept for + backwards compatibility. New code should use :class:`~requests.sessions.Session` + to create a session. This may be removed at a future date. + + :rtype: Session + """ + return Session() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/status_codes.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/status_codes.py new file mode 100644 index 0000000..4bd072b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/status_codes.py @@ -0,0 +1,128 @@ +r""" +The ``codes`` object defines a mapping from common names for HTTP statuses +to their numerical codes, accessible either as attributes or as dictionary +items. + +Example:: + + >>> import requests + >>> requests.codes['temporary_redirect'] + 307 + >>> requests.codes.teapot + 418 + >>> requests.codes['\o/'] + 200 + +Some codes have multiple names, and both upper- and lower-case versions of +the names are allowed. For example, ``codes.ok``, ``codes.OK``, and +``codes.okay`` all correspond to the HTTP status code 200. +""" + +from .structures import LookupDict + +_codes = { + # Informational. + 100: ("continue",), + 101: ("switching_protocols",), + 102: ("processing",), + 103: ("checkpoint",), + 122: ("uri_too_long", "request_uri_too_long"), + 200: ("ok", "okay", "all_ok", "all_okay", "all_good", "\\o/", "✓"), + 201: ("created",), + 202: ("accepted",), + 203: ("non_authoritative_info", "non_authoritative_information"), + 204: ("no_content",), + 205: ("reset_content", "reset"), + 206: ("partial_content", "partial"), + 207: ("multi_status", "multiple_status", "multi_stati", "multiple_stati"), + 208: ("already_reported",), + 226: ("im_used",), + # Redirection. + 300: ("multiple_choices",), + 301: ("moved_permanently", "moved", "\\o-"), + 302: ("found",), + 303: ("see_other", "other"), + 304: ("not_modified",), + 305: ("use_proxy",), + 306: ("switch_proxy",), + 307: ("temporary_redirect", "temporary_moved", "temporary"), + 308: ( + "permanent_redirect", + "resume_incomplete", + "resume", + ), # "resume" and "resume_incomplete" to be removed in 3.0 + # Client Error. + 400: ("bad_request", "bad"), + 401: ("unauthorized",), + 402: ("payment_required", "payment"), + 403: ("forbidden",), + 404: ("not_found", "-o-"), + 405: ("method_not_allowed", "not_allowed"), + 406: ("not_acceptable",), + 407: ("proxy_authentication_required", "proxy_auth", "proxy_authentication"), + 408: ("request_timeout", "timeout"), + 409: ("conflict",), + 410: ("gone",), + 411: ("length_required",), + 412: ("precondition_failed", "precondition"), + 413: ("request_entity_too_large",), + 414: ("request_uri_too_large",), + 415: ("unsupported_media_type", "unsupported_media", "media_type"), + 416: ( + "requested_range_not_satisfiable", + "requested_range", + "range_not_satisfiable", + ), + 417: ("expectation_failed",), + 418: ("im_a_teapot", "teapot", "i_am_a_teapot"), + 421: ("misdirected_request",), + 422: ("unprocessable_entity", "unprocessable"), + 423: ("locked",), + 424: ("failed_dependency", "dependency"), + 425: ("unordered_collection", "unordered"), + 426: ("upgrade_required", "upgrade"), + 428: ("precondition_required", "precondition"), + 429: ("too_many_requests", "too_many"), + 431: ("header_fields_too_large", "fields_too_large"), + 444: ("no_response", "none"), + 449: ("retry_with", "retry"), + 450: ("blocked_by_windows_parental_controls", "parental_controls"), + 451: ("unavailable_for_legal_reasons", "legal_reasons"), + 499: ("client_closed_request",), + # Server Error. + 500: ("internal_server_error", "server_error", "/o\\", "✗"), + 501: ("not_implemented",), + 502: ("bad_gateway",), + 503: ("service_unavailable", "unavailable"), + 504: ("gateway_timeout",), + 505: ("http_version_not_supported", "http_version"), + 506: ("variant_also_negotiates",), + 507: ("insufficient_storage",), + 509: ("bandwidth_limit_exceeded", "bandwidth"), + 510: ("not_extended",), + 511: ("network_authentication_required", "network_auth", "network_authentication"), +} + +codes = LookupDict(name="status_codes") + + +def _init(): + for code, titles in _codes.items(): + for title in titles: + setattr(codes, title, code) + if not title.startswith(("\\", "/")): + setattr(codes, title.upper(), code) + + def doc(code): + names = ", ".join(f"``{n}``" for n in _codes[code]) + return "* %d: %s" % (code, names) + + global __doc__ + __doc__ = ( + __doc__ + "\n" + "\n".join(doc(code) for code in sorted(_codes)) + if __doc__ is not None + else None + ) + + +_init() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/structures.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/structures.py new file mode 100644 index 0000000..188e13e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/structures.py @@ -0,0 +1,99 @@ +""" +requests.structures +~~~~~~~~~~~~~~~~~~~ + +Data structures that power Requests. +""" + +from collections import OrderedDict + +from .compat import Mapping, MutableMapping + + +class CaseInsensitiveDict(MutableMapping): + """A case-insensitive ``dict``-like object. + + Implements all methods and operations of + ``MutableMapping`` as well as dict's ``copy``. Also + provides ``lower_items``. + + All keys are expected to be strings. The structure remembers the + case of the last key to be set, and ``iter(instance)``, + ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` + will contain case-sensitive keys. However, querying and contains + testing is case insensitive:: + + cid = CaseInsensitiveDict() + cid['Accept'] = 'application/json' + cid['aCCEPT'] == 'application/json' # True + list(cid) == ['Accept'] # True + + For example, ``headers['content-encoding']`` will return the + value of a ``'Content-Encoding'`` response header, regardless + of how the header name was originally stored. + + If the constructor, ``.update``, or equality comparison + operations are given keys that have equal ``.lower()``s, the + behavior is undefined. + """ + + def __init__(self, data=None, **kwargs): + self._store = OrderedDict() + if data is None: + data = {} + self.update(data, **kwargs) + + def __setitem__(self, key, value): + # Use the lowercased key for lookups, but store the actual + # key alongside the value. + self._store[key.lower()] = (key, value) + + def __getitem__(self, key): + return self._store[key.lower()][1] + + def __delitem__(self, key): + del self._store[key.lower()] + + def __iter__(self): + return (casedkey for casedkey, mappedvalue in self._store.values()) + + def __len__(self): + return len(self._store) + + def lower_items(self): + """Like iteritems(), but with all lowercase keys.""" + return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()) + + def __eq__(self, other): + if isinstance(other, Mapping): + other = CaseInsensitiveDict(other) + else: + return NotImplemented + # Compare insensitively + return dict(self.lower_items()) == dict(other.lower_items()) + + # Copy is required + def copy(self): + return CaseInsensitiveDict(self._store.values()) + + def __repr__(self): + return str(dict(self.items())) + + +class LookupDict(dict): + """Dictionary lookup object.""" + + def __init__(self, name=None): + self.name = name + super().__init__() + + def __repr__(self): + return f"" + + def __getitem__(self, key): + # We allow fall-through here, so values default to None + + return self.__dict__.get(key, None) + + def get(self, key, default=None): + return self.__dict__.get(key, default) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/utils.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/utils.py new file mode 100644 index 0000000..36607ed --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/requests/utils.py @@ -0,0 +1,1094 @@ +""" +requests.utils +~~~~~~~~~~~~~~ + +This module provides utility functions that are used within Requests +that are also useful for external consumption. +""" + +import codecs +import contextlib +import io +import os +import re +import socket +import struct +import sys +import tempfile +import warnings +import zipfile +from collections import OrderedDict + +from pip._vendor.urllib3.util import make_headers, parse_url + +from . import certs +from .__version__ import __version__ + +# to_native_string is unused here, but imported here for backwards compatibility +from ._internal_utils import ( # noqa: F401 + _HEADER_VALIDATORS_BYTE, + _HEADER_VALIDATORS_STR, + HEADER_VALIDATORS, + to_native_string, +) +from .compat import ( + Mapping, + basestring, + bytes, + getproxies, + getproxies_environment, + integer_types, +) +from .compat import parse_http_list as _parse_list_header +from .compat import ( + proxy_bypass, + proxy_bypass_environment, + quote, + str, + unquote, + urlparse, + urlunparse, +) +from .cookies import cookiejar_from_dict +from .exceptions import ( + FileModeWarning, + InvalidHeader, + InvalidURL, + UnrewindableBodyError, +) +from .structures import CaseInsensitiveDict + +NETRC_FILES = (".netrc", "_netrc") + +DEFAULT_CA_BUNDLE_PATH = certs.where() + +DEFAULT_PORTS = {"http": 80, "https": 443} + +# Ensure that ', ' is used to preserve previous delimiter behavior. +DEFAULT_ACCEPT_ENCODING = ", ".join( + re.split(r",\s*", make_headers(accept_encoding=True)["accept-encoding"]) +) + + +if sys.platform == "win32": + # provide a proxy_bypass version on Windows without DNS lookups + + def proxy_bypass_registry(host): + try: + import winreg + except ImportError: + return False + + try: + internetSettings = winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", + ) + # ProxyEnable could be REG_SZ or REG_DWORD, normalizing it + proxyEnable = int(winreg.QueryValueEx(internetSettings, "ProxyEnable")[0]) + # ProxyOverride is almost always a string + proxyOverride = winreg.QueryValueEx(internetSettings, "ProxyOverride")[0] + except (OSError, ValueError): + return False + if not proxyEnable or not proxyOverride: + return False + + # make a check value list from the registry entry: replace the + # '' string by the localhost entry and the corresponding + # canonical entry. + proxyOverride = proxyOverride.split(";") + # now check if we match one of the registry values. + for test in proxyOverride: + if test == "": + if "." not in host: + return True + test = test.replace(".", r"\.") # mask dots + test = test.replace("*", r".*") # change glob sequence + test = test.replace("?", r".") # change glob char + if re.match(test, host, re.I): + return True + return False + + def proxy_bypass(host): # noqa + """Return True, if the host should be bypassed. + + Checks proxy settings gathered from the environment, if specified, + or the registry. + """ + if getproxies_environment(): + return proxy_bypass_environment(host) + else: + return proxy_bypass_registry(host) + + +def dict_to_sequence(d): + """Returns an internal sequence dictionary update.""" + + if hasattr(d, "items"): + d = d.items() + + return d + + +def super_len(o): + total_length = None + current_position = 0 + + if hasattr(o, "__len__"): + total_length = len(o) + + elif hasattr(o, "len"): + total_length = o.len + + elif hasattr(o, "fileno"): + try: + fileno = o.fileno() + except (io.UnsupportedOperation, AttributeError): + # AttributeError is a surprising exception, seeing as how we've just checked + # that `hasattr(o, 'fileno')`. It happens for objects obtained via + # `Tarfile.extractfile()`, per issue 5229. + pass + else: + total_length = os.fstat(fileno).st_size + + # Having used fstat to determine the file length, we need to + # confirm that this file was opened up in binary mode. + if "b" not in o.mode: + warnings.warn( + ( + "Requests has determined the content-length for this " + "request using the binary size of the file: however, the " + "file has been opened in text mode (i.e. without the 'b' " + "flag in the mode). This may lead to an incorrect " + "content-length. In Requests 3.0, support will be removed " + "for files in text mode." + ), + FileModeWarning, + ) + + if hasattr(o, "tell"): + try: + current_position = o.tell() + except OSError: + # This can happen in some weird situations, such as when the file + # is actually a special file descriptor like stdin. In this + # instance, we don't know what the length is, so set it to zero and + # let requests chunk it instead. + if total_length is not None: + current_position = total_length + else: + if hasattr(o, "seek") and total_length is None: + # StringIO and BytesIO have seek but no usable fileno + try: + # seek to end of file + o.seek(0, 2) + total_length = o.tell() + + # seek back to current position to support + # partially read file-like objects + o.seek(current_position or 0) + except OSError: + total_length = 0 + + if total_length is None: + total_length = 0 + + return max(0, total_length - current_position) + + +def get_netrc_auth(url, raise_errors=False): + """Returns the Requests tuple auth for a given url from netrc.""" + + netrc_file = os.environ.get("NETRC") + if netrc_file is not None: + netrc_locations = (netrc_file,) + else: + netrc_locations = (f"~/{f}" for f in NETRC_FILES) + + try: + from netrc import NetrcParseError, netrc + + netrc_path = None + + for f in netrc_locations: + try: + loc = os.path.expanduser(f) + except KeyError: + # os.path.expanduser can fail when $HOME is undefined and + # getpwuid fails. See https://bugs.python.org/issue20164 & + # https://github.com/psf/requests/issues/1846 + return + + if os.path.exists(loc): + netrc_path = loc + break + + # Abort early if there isn't one. + if netrc_path is None: + return + + ri = urlparse(url) + + # Strip port numbers from netloc. This weird `if...encode`` dance is + # used for Python 3.2, which doesn't support unicode literals. + splitstr = b":" + if isinstance(url, str): + splitstr = splitstr.decode("ascii") + host = ri.netloc.split(splitstr)[0] + + try: + _netrc = netrc(netrc_path).authenticators(host) + if _netrc: + # Return with login / password + login_i = 0 if _netrc[0] else 1 + return (_netrc[login_i], _netrc[2]) + except (NetrcParseError, OSError): + # If there was a parsing error or a permissions issue reading the file, + # we'll just skip netrc auth unless explicitly asked to raise errors. + if raise_errors: + raise + + # App Engine hackiness. + except (ImportError, AttributeError): + pass + + +def guess_filename(obj): + """Tries to guess the filename of the given object.""" + name = getattr(obj, "name", None) + if name and isinstance(name, basestring) and name[0] != "<" and name[-1] != ">": + return os.path.basename(name) + + +def extract_zipped_paths(path): + """Replace nonexistent paths that look like they refer to a member of a zip + archive with the location of an extracted copy of the target, or else + just return the provided path unchanged. + """ + if os.path.exists(path): + # this is already a valid path, no need to do anything further + return path + + # find the first valid part of the provided path and treat that as a zip archive + # assume the rest of the path is the name of a member in the archive + archive, member = os.path.split(path) + while archive and not os.path.exists(archive): + archive, prefix = os.path.split(archive) + if not prefix: + # If we don't check for an empty prefix after the split (in other words, archive remains unchanged after the split), + # we _can_ end up in an infinite loop on a rare corner case affecting a small number of users + break + member = "/".join([prefix, member]) + + if not zipfile.is_zipfile(archive): + return path + + zip_file = zipfile.ZipFile(archive) + if member not in zip_file.namelist(): + return path + + # we have a valid zip archive and a valid member of that archive + tmp = tempfile.gettempdir() + extracted_path = os.path.join(tmp, member.split("/")[-1]) + if not os.path.exists(extracted_path): + # use read + write to avoid the creating nested folders, we only want the file, avoids mkdir racing condition + with atomic_open(extracted_path) as file_handler: + file_handler.write(zip_file.read(member)) + return extracted_path + + +@contextlib.contextmanager +def atomic_open(filename): + """Write a file to the disk in an atomic fashion""" + tmp_descriptor, tmp_name = tempfile.mkstemp(dir=os.path.dirname(filename)) + try: + with os.fdopen(tmp_descriptor, "wb") as tmp_handler: + yield tmp_handler + os.replace(tmp_name, filename) + except BaseException: + os.remove(tmp_name) + raise + + +def from_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. Unless it can not be represented as such, return an + OrderedDict, e.g., + + :: + + >>> from_key_val_list([('key', 'val')]) + OrderedDict([('key', 'val')]) + >>> from_key_val_list('string') + Traceback (most recent call last): + ... + ValueError: cannot encode objects that are not 2-tuples + >>> from_key_val_list({'key': 'val'}) + OrderedDict([('key', 'val')]) + + :rtype: OrderedDict + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError("cannot encode objects that are not 2-tuples") + + return OrderedDict(value) + + +def to_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. If it can be, return a list of tuples, e.g., + + :: + + >>> to_key_val_list([('key', 'val')]) + [('key', 'val')] + >>> to_key_val_list({'key': 'val'}) + [('key', 'val')] + >>> to_key_val_list('string') + Traceback (most recent call last): + ... + ValueError: cannot encode objects that are not 2-tuples + + :rtype: list + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError("cannot encode objects that are not 2-tuples") + + if isinstance(value, Mapping): + value = value.items() + + return list(value) + + +# From mitsuhiko/werkzeug (used with permission). +def parse_list_header(value): + """Parse lists as described by RFC 2068 Section 2. + + In particular, parse comma-separated lists where the elements of + the list may include quoted-strings. A quoted-string could + contain a comma. A non-quoted string could have quotes in the + middle. Quotes are removed automatically after parsing. + + It basically works like :func:`parse_set_header` just that items + may appear multiple times and case sensitivity is preserved. + + The return value is a standard :class:`list`: + + >>> parse_list_header('token, "quoted value"') + ['token', 'quoted value'] + + To create a header from the :class:`list` again, use the + :func:`dump_header` function. + + :param value: a string with a list header. + :return: :class:`list` + :rtype: list + """ + result = [] + for item in _parse_list_header(value): + if item[:1] == item[-1:] == '"': + item = unquote_header_value(item[1:-1]) + result.append(item) + return result + + +# From mitsuhiko/werkzeug (used with permission). +def parse_dict_header(value): + """Parse lists of key, value pairs as described by RFC 2068 Section 2 and + convert them into a python dict: + + >>> d = parse_dict_header('foo="is a fish", bar="as well"') + >>> type(d) is dict + True + >>> sorted(d.items()) + [('bar', 'as well'), ('foo', 'is a fish')] + + If there is no value for a key it will be `None`: + + >>> parse_dict_header('key_without_value') + {'key_without_value': None} + + To create a header from the :class:`dict` again, use the + :func:`dump_header` function. + + :param value: a string with a dict header. + :return: :class:`dict` + :rtype: dict + """ + result = {} + for item in _parse_list_header(value): + if "=" not in item: + result[item] = None + continue + name, value = item.split("=", 1) + if value[:1] == value[-1:] == '"': + value = unquote_header_value(value[1:-1]) + result[name] = value + return result + + +# From mitsuhiko/werkzeug (used with permission). +def unquote_header_value(value, is_filename=False): + r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). + This does not use the real unquoting but what browsers are actually + using for quoting. + + :param value: the header value to unquote. + :rtype: str + """ + if value and value[0] == value[-1] == '"': + # this is not the real unquoting, but fixing this so that the + # RFC is met will result in bugs with internet explorer and + # probably some other browsers as well. IE for example is + # uploading files with "C:\foo\bar.txt" as filename + value = value[1:-1] + + # if this is a filename and the starting characters look like + # a UNC path, then just return the value without quotes. Using the + # replace sequence below on a UNC path has the effect of turning + # the leading double slash into a single slash and then + # _fix_ie_filename() doesn't work correctly. See #458. + if not is_filename or value[:2] != "\\\\": + return value.replace("\\\\", "\\").replace('\\"', '"') + return value + + +def dict_from_cookiejar(cj): + """Returns a key/value dictionary from a CookieJar. + + :param cj: CookieJar object to extract cookies from. + :rtype: dict + """ + + cookie_dict = {} + + for cookie in cj: + cookie_dict[cookie.name] = cookie.value + + return cookie_dict + + +def add_dict_to_cookiejar(cj, cookie_dict): + """Returns a CookieJar from a key/value dictionary. + + :param cj: CookieJar to insert cookies into. + :param cookie_dict: Dict of key/values to insert into CookieJar. + :rtype: CookieJar + """ + + return cookiejar_from_dict(cookie_dict, cj) + + +def get_encodings_from_content(content): + """Returns encodings from given content string. + + :param content: bytestring to extract encodings from. + """ + warnings.warn( + ( + "In requests 3.0, get_encodings_from_content will be removed. For " + "more information, please see the discussion on issue #2266. (This" + " warning should only appear once.)" + ), + DeprecationWarning, + ) + + charset_re = re.compile(r']', flags=re.I) + pragma_re = re.compile(r']', flags=re.I) + xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') + + return ( + charset_re.findall(content) + + pragma_re.findall(content) + + xml_re.findall(content) + ) + + +def _parse_content_type_header(header): + """Returns content type and parameters from given header + + :param header: string + :return: tuple containing content type and dictionary of + parameters + """ + + tokens = header.split(";") + content_type, params = tokens[0].strip(), tokens[1:] + params_dict = {} + items_to_strip = "\"' " + + for param in params: + param = param.strip() + if param: + key, value = param, True + index_of_equals = param.find("=") + if index_of_equals != -1: + key = param[:index_of_equals].strip(items_to_strip) + value = param[index_of_equals + 1 :].strip(items_to_strip) + params_dict[key.lower()] = value + return content_type, params_dict + + +def get_encoding_from_headers(headers): + """Returns encodings from given HTTP Header Dict. + + :param headers: dictionary to extract encoding from. + :rtype: str + """ + + content_type = headers.get("content-type") + + if not content_type: + return None + + content_type, params = _parse_content_type_header(content_type) + + if "charset" in params: + return params["charset"].strip("'\"") + + if "text" in content_type: + return "ISO-8859-1" + + if "application/json" in content_type: + # Assume UTF-8 based on RFC 4627: https://www.ietf.org/rfc/rfc4627.txt since the charset was unset + return "utf-8" + + +def stream_decode_response_unicode(iterator, r): + """Stream decodes an iterator.""" + + if r.encoding is None: + yield from iterator + return + + decoder = codecs.getincrementaldecoder(r.encoding)(errors="replace") + for chunk in iterator: + rv = decoder.decode(chunk) + if rv: + yield rv + rv = decoder.decode(b"", final=True) + if rv: + yield rv + + +def iter_slices(string, slice_length): + """Iterate over slices of a string.""" + pos = 0 + if slice_length is None or slice_length <= 0: + slice_length = len(string) + while pos < len(string): + yield string[pos : pos + slice_length] + pos += slice_length + + +def get_unicode_from_response(r): + """Returns the requested content back in unicode. + + :param r: Response object to get unicode content from. + + Tried: + + 1. charset from content-type + 2. fall back and replace all unicode characters + + :rtype: str + """ + warnings.warn( + ( + "In requests 3.0, get_unicode_from_response will be removed. For " + "more information, please see the discussion on issue #2266. (This" + " warning should only appear once.)" + ), + DeprecationWarning, + ) + + tried_encodings = [] + + # Try charset from content-type + encoding = get_encoding_from_headers(r.headers) + + if encoding: + try: + return str(r.content, encoding) + except UnicodeError: + tried_encodings.append(encoding) + + # Fall back: + try: + return str(r.content, encoding, errors="replace") + except TypeError: + return r.content + + +# The unreserved URI characters (RFC 3986) +UNRESERVED_SET = frozenset( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~" +) + + +def unquote_unreserved(uri): + """Un-escape any percent-escape sequences in a URI that are unreserved + characters. This leaves all reserved, illegal and non-ASCII bytes encoded. + + :rtype: str + """ + parts = uri.split("%") + for i in range(1, len(parts)): + h = parts[i][0:2] + if len(h) == 2 and h.isalnum(): + try: + c = chr(int(h, 16)) + except ValueError: + raise InvalidURL(f"Invalid percent-escape sequence: '{h}'") + + if c in UNRESERVED_SET: + parts[i] = c + parts[i][2:] + else: + parts[i] = f"%{parts[i]}" + else: + parts[i] = f"%{parts[i]}" + return "".join(parts) + + +def requote_uri(uri): + """Re-quote the given URI. + + This function passes the given URI through an unquote/quote cycle to + ensure that it is fully and consistently quoted. + + :rtype: str + """ + safe_with_percent = "!#$%&'()*+,/:;=?@[]~" + safe_without_percent = "!#$&'()*+,/:;=?@[]~" + try: + # Unquote only the unreserved characters + # Then quote only illegal characters (do not quote reserved, + # unreserved, or '%') + return quote(unquote_unreserved(uri), safe=safe_with_percent) + except InvalidURL: + # We couldn't unquote the given URI, so let's try quoting it, but + # there may be unquoted '%'s in the URI. We need to make sure they're + # properly quoted so they do not cause issues elsewhere. + return quote(uri, safe=safe_without_percent) + + +def address_in_network(ip, net): + """This function allows you to check if an IP belongs to a network subnet + + Example: returns True if ip = 192.168.1.1 and net = 192.168.1.0/24 + returns False if ip = 192.168.1.1 and net = 192.168.100.0/24 + + :rtype: bool + """ + ipaddr = struct.unpack("=L", socket.inet_aton(ip))[0] + netaddr, bits = net.split("/") + netmask = struct.unpack("=L", socket.inet_aton(dotted_netmask(int(bits))))[0] + network = struct.unpack("=L", socket.inet_aton(netaddr))[0] & netmask + return (ipaddr & netmask) == (network & netmask) + + +def dotted_netmask(mask): + """Converts mask from /xx format to xxx.xxx.xxx.xxx + + Example: if mask is 24 function returns 255.255.255.0 + + :rtype: str + """ + bits = 0xFFFFFFFF ^ (1 << 32 - mask) - 1 + return socket.inet_ntoa(struct.pack(">I", bits)) + + +def is_ipv4_address(string_ip): + """ + :rtype: bool + """ + try: + socket.inet_aton(string_ip) + except OSError: + return False + return True + + +def is_valid_cidr(string_network): + """ + Very simple check of the cidr format in no_proxy variable. + + :rtype: bool + """ + if string_network.count("/") == 1: + try: + mask = int(string_network.split("/")[1]) + except ValueError: + return False + + if mask < 1 or mask > 32: + return False + + try: + socket.inet_aton(string_network.split("/")[0]) + except OSError: + return False + else: + return False + return True + + +@contextlib.contextmanager +def set_environ(env_name, value): + """Set the environment variable 'env_name' to 'value' + + Save previous value, yield, and then restore the previous value stored in + the environment variable 'env_name'. + + If 'value' is None, do nothing""" + value_changed = value is not None + if value_changed: + old_value = os.environ.get(env_name) + os.environ[env_name] = value + try: + yield + finally: + if value_changed: + if old_value is None: + del os.environ[env_name] + else: + os.environ[env_name] = old_value + + +def should_bypass_proxies(url, no_proxy): + """ + Returns whether we should bypass proxies or not. + + :rtype: bool + """ + # Prioritize lowercase environment variables over uppercase + # to keep a consistent behaviour with other http projects (curl, wget). + def get_proxy(key): + return os.environ.get(key) or os.environ.get(key.upper()) + + # First check whether no_proxy is defined. If it is, check that the URL + # we're getting isn't in the no_proxy list. + no_proxy_arg = no_proxy + if no_proxy is None: + no_proxy = get_proxy("no_proxy") + parsed = urlparse(url) + + if parsed.hostname is None: + # URLs don't always have hostnames, e.g. file:/// urls. + return True + + if no_proxy: + # We need to check whether we match here. We need to see if we match + # the end of the hostname, both with and without the port. + no_proxy = (host for host in no_proxy.replace(" ", "").split(",") if host) + + if is_ipv4_address(parsed.hostname): + for proxy_ip in no_proxy: + if is_valid_cidr(proxy_ip): + if address_in_network(parsed.hostname, proxy_ip): + return True + elif parsed.hostname == proxy_ip: + # If no_proxy ip was defined in plain IP notation instead of cidr notation & + # matches the IP of the index + return True + else: + host_with_port = parsed.hostname + if parsed.port: + host_with_port += f":{parsed.port}" + + for host in no_proxy: + if parsed.hostname.endswith(host) or host_with_port.endswith(host): + # The URL does match something in no_proxy, so we don't want + # to apply the proxies on this URL. + return True + + with set_environ("no_proxy", no_proxy_arg): + # parsed.hostname can be `None` in cases such as a file URI. + try: + bypass = proxy_bypass(parsed.hostname) + except (TypeError, socket.gaierror): + bypass = False + + if bypass: + return True + + return False + + +def get_environ_proxies(url, no_proxy=None): + """ + Return a dict of environment proxies. + + :rtype: dict + """ + if should_bypass_proxies(url, no_proxy=no_proxy): + return {} + else: + return getproxies() + + +def select_proxy(url, proxies): + """Select a proxy for the url, if applicable. + + :param url: The url being for the request + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs + """ + proxies = proxies or {} + urlparts = urlparse(url) + if urlparts.hostname is None: + return proxies.get(urlparts.scheme, proxies.get("all")) + + proxy_keys = [ + urlparts.scheme + "://" + urlparts.hostname, + urlparts.scheme, + "all://" + urlparts.hostname, + "all", + ] + proxy = None + for proxy_key in proxy_keys: + if proxy_key in proxies: + proxy = proxies[proxy_key] + break + + return proxy + + +def resolve_proxies(request, proxies, trust_env=True): + """This method takes proxy information from a request and configuration + input to resolve a mapping of target proxies. This will consider settings + such a NO_PROXY to strip proxy configurations. + + :param request: Request or PreparedRequest + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs + :param trust_env: Boolean declaring whether to trust environment configs + + :rtype: dict + """ + proxies = proxies if proxies is not None else {} + url = request.url + scheme = urlparse(url).scheme + no_proxy = proxies.get("no_proxy") + new_proxies = proxies.copy() + + if trust_env and not should_bypass_proxies(url, no_proxy=no_proxy): + environ_proxies = get_environ_proxies(url, no_proxy=no_proxy) + + proxy = environ_proxies.get(scheme, environ_proxies.get("all")) + + if proxy: + new_proxies.setdefault(scheme, proxy) + return new_proxies + + +def default_user_agent(name="python-requests"): + """ + Return a string representing the default user agent. + + :rtype: str + """ + return f"{name}/{__version__}" + + +def default_headers(): + """ + :rtype: requests.structures.CaseInsensitiveDict + """ + return CaseInsensitiveDict( + { + "User-Agent": default_user_agent(), + "Accept-Encoding": DEFAULT_ACCEPT_ENCODING, + "Accept": "*/*", + "Connection": "keep-alive", + } + ) + + +def parse_header_links(value): + """Return a list of parsed link headers proxies. + + i.e. Link: ; rel=front; type="image/jpeg",; rel=back;type="image/jpeg" + + :rtype: list + """ + + links = [] + + replace_chars = " '\"" + + value = value.strip(replace_chars) + if not value: + return links + + for val in re.split(", *<", value): + try: + url, params = val.split(";", 1) + except ValueError: + url, params = val, "" + + link = {"url": url.strip("<> '\"")} + + for param in params.split(";"): + try: + key, value = param.split("=") + except ValueError: + break + + link[key.strip(replace_chars)] = value.strip(replace_chars) + + links.append(link) + + return links + + +# Null bytes; no need to recreate these on each call to guess_json_utf +_null = "\x00".encode("ascii") # encoding to ASCII for Python 3 +_null2 = _null * 2 +_null3 = _null * 3 + + +def guess_json_utf(data): + """ + :rtype: str + """ + # JSON always starts with two ASCII characters, so detection is as + # easy as counting the nulls and from their location and count + # determine the encoding. Also detect a BOM, if present. + sample = data[:4] + if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE): + return "utf-32" # BOM included + if sample[:3] == codecs.BOM_UTF8: + return "utf-8-sig" # BOM included, MS style (discouraged) + if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): + return "utf-16" # BOM included + nullcount = sample.count(_null) + if nullcount == 0: + return "utf-8" + if nullcount == 2: + if sample[::2] == _null2: # 1st and 3rd are null + return "utf-16-be" + if sample[1::2] == _null2: # 2nd and 4th are null + return "utf-16-le" + # Did not detect 2 valid UTF-16 ascii-range characters + if nullcount == 3: + if sample[:3] == _null3: + return "utf-32-be" + if sample[1:] == _null3: + return "utf-32-le" + # Did not detect a valid UTF-32 ascii-range character + return None + + +def prepend_scheme_if_needed(url, new_scheme): + """Given a URL that may or may not have a scheme, prepend the given scheme. + Does not replace a present scheme with the one provided as an argument. + + :rtype: str + """ + parsed = parse_url(url) + scheme, auth, host, port, path, query, fragment = parsed + + # A defect in urlparse determines that there isn't a netloc present in some + # urls. We previously assumed parsing was overly cautious, and swapped the + # netloc and path. Due to a lack of tests on the original defect, this is + # maintained with parse_url for backwards compatibility. + netloc = parsed.netloc + if not netloc: + netloc, path = path, netloc + + if auth: + # parse_url doesn't provide the netloc with auth + # so we'll add it ourselves. + netloc = "@".join([auth, netloc]) + if scheme is None: + scheme = new_scheme + if path is None: + path = "" + + return urlunparse((scheme, netloc, path, "", query, fragment)) + + +def get_auth_from_url(url): + """Given a url with authentication components, extract them into a tuple of + username,password. + + :rtype: (str,str) + """ + parsed = urlparse(url) + + try: + auth = (unquote(parsed.username), unquote(parsed.password)) + except (AttributeError, TypeError): + auth = ("", "") + + return auth + + +def check_header_validity(header): + """Verifies that header parts don't contain leading whitespace + reserved characters, or return characters. + + :param header: tuple, in the format (name, value). + """ + name, value = header + _validate_header_part(header, name, 0) + _validate_header_part(header, value, 1) + + +def _validate_header_part(header, header_part, header_validator_index): + if isinstance(header_part, str): + validator = _HEADER_VALIDATORS_STR[header_validator_index] + elif isinstance(header_part, bytes): + validator = _HEADER_VALIDATORS_BYTE[header_validator_index] + else: + raise InvalidHeader( + f"Header part ({header_part!r}) from {header} " + f"must be of type str or bytes, not {type(header_part)}" + ) + + if not validator.match(header_part): + header_kind = "name" if header_validator_index == 0 else "value" + raise InvalidHeader( + f"Invalid leading whitespace, reserved character(s), or return" + f"character(s) in header {header_kind}: {header_part!r}" + ) + + +def urldefragauth(url): + """ + Given a url remove the fragment and the authentication part. + + :rtype: str + """ + scheme, netloc, path, params, query, fragment = urlparse(url) + + # see func:`prepend_scheme_if_needed` + if not netloc: + netloc, path = path, netloc + + netloc = netloc.rsplit("@", 1)[-1] + + return urlunparse((scheme, netloc, path, params, query, "")) + + +def rewind_body(prepared_request): + """Move file pointer back to its recorded starting position + so it can be read again on redirect. + """ + body_seek = getattr(prepared_request.body, "seek", None) + if body_seek is not None and isinstance( + prepared_request._body_position, integer_types + ): + try: + body_seek(prepared_request._body_position) + except OSError: + raise UnrewindableBodyError( + "An error occurred when rewinding request body for redirect." + ) + else: + raise UnrewindableBodyError("Unable to rewind request body for redirect.") diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/__init__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/__init__.py new file mode 100644 index 0000000..d92acc7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/__init__.py @@ -0,0 +1,26 @@ +__all__ = [ + "__version__", + "AbstractProvider", + "AbstractResolver", + "BaseReporter", + "InconsistentCandidate", + "Resolver", + "RequirementsConflicted", + "ResolutionError", + "ResolutionImpossible", + "ResolutionTooDeep", +] + +__version__ = "1.0.1" + + +from .providers import AbstractProvider, AbstractResolver +from .reporters import BaseReporter +from .resolvers import ( + InconsistentCandidate, + RequirementsConflicted, + ResolutionError, + ResolutionImpossible, + ResolutionTooDeep, + Resolver, +) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/__init__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py new file mode 100644 index 0000000..1becc50 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py @@ -0,0 +1,6 @@ +__all__ = ["Mapping", "Sequence"] + +try: + from collections.abc import Mapping, Sequence +except ImportError: + from collections import Mapping, Sequence diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/providers.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/providers.py new file mode 100644 index 0000000..e99d87e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/providers.py @@ -0,0 +1,133 @@ +class AbstractProvider(object): + """Delegate class to provide the required interface for the resolver.""" + + def identify(self, requirement_or_candidate): + """Given a requirement, return an identifier for it. + + This is used to identify a requirement, e.g. whether two requirements + should have their specifier parts merged. + """ + raise NotImplementedError + + def get_preference( + self, + identifier, + resolutions, + candidates, + information, + backtrack_causes, + ): + """Produce a sort key for given requirement based on preference. + + The preference is defined as "I think this requirement should be + resolved first". The lower the return value is, the more preferred + this group of arguments is. + + :param identifier: An identifier as returned by ``identify()``. This + identifies the dependency matches which should be returned. + :param resolutions: Mapping of candidates currently pinned by the + resolver. Each key is an identifier, and the value is a candidate. + The candidate may conflict with requirements from ``information``. + :param candidates: Mapping of each dependency's possible candidates. + Each value is an iterator of candidates. + :param information: Mapping of requirement information of each package. + Each value is an iterator of *requirement information*. + :param backtrack_causes: Sequence of requirement information that were + the requirements that caused the resolver to most recently backtrack. + + A *requirement information* instance is a named tuple with two members: + + * ``requirement`` specifies a requirement contributing to the current + list of candidates. + * ``parent`` specifies the candidate that provides (depended on) the + requirement, or ``None`` to indicate a root requirement. + + The preference could depend on various issues, including (not + necessarily in this order): + + * Is this package pinned in the current resolution result? + * How relaxed is the requirement? Stricter ones should probably be + worked on first? (I don't know, actually.) + * How many possibilities are there to satisfy this requirement? Those + with few left should likely be worked on first, I guess? + * Are there any known conflicts for this requirement? We should + probably work on those with the most known conflicts. + + A sortable value should be returned (this will be used as the ``key`` + parameter of the built-in sorting function). The smaller the value is, + the more preferred this requirement is (i.e. the sorting function + is called with ``reverse=False``). + """ + raise NotImplementedError + + def find_matches(self, identifier, requirements, incompatibilities): + """Find all possible candidates that satisfy the given constraints. + + :param identifier: An identifier as returned by ``identify()``. This + identifies the dependency matches of which should be returned. + :param requirements: A mapping of requirements that all returned + candidates must satisfy. Each key is an identifier, and the value + an iterator of requirements for that dependency. + :param incompatibilities: A mapping of known incompatibilities of + each dependency. Each key is an identifier, and the value an + iterator of incompatibilities known to the resolver. All + incompatibilities *must* be excluded from the return value. + + This should try to get candidates based on the requirements' types. + For VCS, local, and archive requirements, the one-and-only match is + returned, and for a "named" requirement, the index(es) should be + consulted to find concrete candidates for this requirement. + + The return value should produce candidates ordered by preference; the + most preferred candidate should come first. The return type may be one + of the following: + + * A callable that returns an iterator that yields candidates. + * An collection of candidates. + * An iterable of candidates. This will be consumed immediately into a + list of candidates. + """ + raise NotImplementedError + + def is_satisfied_by(self, requirement, candidate): + """Whether the given requirement can be satisfied by a candidate. + + The candidate is guaranteed to have been generated from the + requirement. + + A boolean should be returned to indicate whether ``candidate`` is a + viable solution to the requirement. + """ + raise NotImplementedError + + def get_dependencies(self, candidate): + """Get dependencies of a candidate. + + This should return a collection of requirements that `candidate` + specifies as its dependencies. + """ + raise NotImplementedError + + +class AbstractResolver(object): + """The thing that performs the actual resolution work.""" + + base_exception = Exception + + def __init__(self, provider, reporter): + self.provider = provider + self.reporter = reporter + + def resolve(self, requirements, **kwargs): + """Take a collection of constraints, spit out the resolution result. + + This returns a representation of the final resolution state, with one + guarenteed attribute ``mapping`` that contains resolved candidates as + values. The keys are their respective identifiers. + + :param requirements: A collection of constraints. + :param kwargs: Additional keyword arguments that subclasses may accept. + + :raises: ``self.base_exception`` or its subclass. + """ + raise NotImplementedError diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/reporters.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/reporters.py new file mode 100644 index 0000000..688b5e1 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/reporters.py @@ -0,0 +1,43 @@ +class BaseReporter(object): + """Delegate class to provider progress reporting for the resolver.""" + + def starting(self): + """Called before the resolution actually starts.""" + + def starting_round(self, index): + """Called before each round of resolution starts. + + The index is zero-based. + """ + + def ending_round(self, index, state): + """Called before each round of resolution ends. + + This is NOT called if the resolution ends at this round. Use `ending` + if you want to report finalization. The index is zero-based. + """ + + def ending(self, state): + """Called before the resolution ends successfully.""" + + def adding_requirement(self, requirement, parent): + """Called when adding a new requirement into the resolve criteria. + + :param requirement: The additional requirement to be applied to filter + the available candidaites. + :param parent: The candidate that requires ``requirement`` as a + dependency, or None if ``requirement`` is one of the root + requirements passed in from ``Resolver.resolve()``. + """ + + def resolving_conflicts(self, causes): + """Called when starting to attempt requirement conflict resolution. + + :param causes: The information on the collision that caused the backtracking. + """ + + def rejecting_candidate(self, criterion, candidate): + """Called when rejecting a candidate during backtracking.""" + + def pinning(self, candidate): + """Called when adding a candidate to the potential solution.""" diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/resolvers.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/resolvers.py new file mode 100644 index 0000000..2c3d0e3 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/resolvers.py @@ -0,0 +1,547 @@ +import collections +import itertools +import operator + +from .providers import AbstractResolver +from .structs import DirectedGraph, IteratorMapping, build_iter_view + +RequirementInformation = collections.namedtuple( + "RequirementInformation", ["requirement", "parent"] +) + + +class ResolverException(Exception): + """A base class for all exceptions raised by this module. + + Exceptions derived by this class should all be handled in this module. Any + bubbling pass the resolver should be treated as a bug. + """ + + +class RequirementsConflicted(ResolverException): + def __init__(self, criterion): + super(RequirementsConflicted, self).__init__(criterion) + self.criterion = criterion + + def __str__(self): + return "Requirements conflict: {}".format( + ", ".join(repr(r) for r in self.criterion.iter_requirement()), + ) + + +class InconsistentCandidate(ResolverException): + def __init__(self, candidate, criterion): + super(InconsistentCandidate, self).__init__(candidate, criterion) + self.candidate = candidate + self.criterion = criterion + + def __str__(self): + return "Provided candidate {!r} does not satisfy {}".format( + self.candidate, + ", ".join(repr(r) for r in self.criterion.iter_requirement()), + ) + + +class Criterion(object): + """Representation of possible resolution results of a package. + + This holds three attributes: + + * `information` is a collection of `RequirementInformation` pairs. + Each pair is a requirement contributing to this criterion, and the + candidate that provides the requirement. + * `incompatibilities` is a collection of all known not-to-work candidates + to exclude from consideration. + * `candidates` is a collection containing all possible candidates deducted + from the union of contributing requirements and known incompatibilities. + It should never be empty, except when the criterion is an attribute of a + raised `RequirementsConflicted` (in which case it is always empty). + + .. note:: + This class is intended to be externally immutable. **Do not** mutate + any of its attribute containers. + """ + + def __init__(self, candidates, information, incompatibilities): + self.candidates = candidates + self.information = information + self.incompatibilities = incompatibilities + + def __repr__(self): + requirements = ", ".join( + "({!r}, via={!r})".format(req, parent) + for req, parent in self.information + ) + return "Criterion({})".format(requirements) + + def iter_requirement(self): + return (i.requirement for i in self.information) + + def iter_parent(self): + return (i.parent for i in self.information) + + +class ResolutionError(ResolverException): + pass + + +class ResolutionImpossible(ResolutionError): + def __init__(self, causes): + super(ResolutionImpossible, self).__init__(causes) + # causes is a list of RequirementInformation objects + self.causes = causes + + +class ResolutionTooDeep(ResolutionError): + def __init__(self, round_count): + super(ResolutionTooDeep, self).__init__(round_count) + self.round_count = round_count + + +# Resolution state in a round. +State = collections.namedtuple("State", "mapping criteria backtrack_causes") + + +class Resolution(object): + """Stateful resolution object. + + This is designed as a one-off object that holds information to kick start + the resolution process, and holds the results afterwards. + """ + + def __init__(self, provider, reporter): + self._p = provider + self._r = reporter + self._states = [] + + @property + def state(self): + try: + return self._states[-1] + except IndexError: + raise AttributeError("state") + + def _push_new_state(self): + """Push a new state into history. + + This new state will be used to hold resolution results of the next + coming round. + """ + base = self._states[-1] + state = State( + mapping=base.mapping.copy(), + criteria=base.criteria.copy(), + backtrack_causes=base.backtrack_causes[:], + ) + self._states.append(state) + + def _add_to_criteria(self, criteria, requirement, parent): + self._r.adding_requirement(requirement=requirement, parent=parent) + + identifier = self._p.identify(requirement_or_candidate=requirement) + criterion = criteria.get(identifier) + if criterion: + incompatibilities = list(criterion.incompatibilities) + else: + incompatibilities = [] + + matches = self._p.find_matches( + identifier=identifier, + requirements=IteratorMapping( + criteria, + operator.methodcaller("iter_requirement"), + {identifier: [requirement]}, + ), + incompatibilities=IteratorMapping( + criteria, + operator.attrgetter("incompatibilities"), + {identifier: incompatibilities}, + ), + ) + + if criterion: + information = list(criterion.information) + information.append(RequirementInformation(requirement, parent)) + else: + information = [RequirementInformation(requirement, parent)] + + criterion = Criterion( + candidates=build_iter_view(matches), + information=information, + incompatibilities=incompatibilities, + ) + if not criterion.candidates: + raise RequirementsConflicted(criterion) + criteria[identifier] = criterion + + def _remove_information_from_criteria(self, criteria, parents): + """Remove information from parents of criteria. + + Concretely, removes all values from each criterion's ``information`` + field that have one of ``parents`` as provider of the requirement. + + :param criteria: The criteria to update. + :param parents: Identifiers for which to remove information from all criteria. + """ + if not parents: + return + for key, criterion in criteria.items(): + criteria[key] = Criterion( + criterion.candidates, + [ + information + for information in criterion.information + if ( + information.parent is None + or self._p.identify(information.parent) not in parents + ) + ], + criterion.incompatibilities, + ) + + def _get_preference(self, name): + return self._p.get_preference( + identifier=name, + resolutions=self.state.mapping, + candidates=IteratorMapping( + self.state.criteria, + operator.attrgetter("candidates"), + ), + information=IteratorMapping( + self.state.criteria, + operator.attrgetter("information"), + ), + backtrack_causes=self.state.backtrack_causes, + ) + + def _is_current_pin_satisfying(self, name, criterion): + try: + current_pin = self.state.mapping[name] + except KeyError: + return False + return all( + self._p.is_satisfied_by(requirement=r, candidate=current_pin) + for r in criterion.iter_requirement() + ) + + def _get_updated_criteria(self, candidate): + criteria = self.state.criteria.copy() + for requirement in self._p.get_dependencies(candidate=candidate): + self._add_to_criteria(criteria, requirement, parent=candidate) + return criteria + + def _attempt_to_pin_criterion(self, name): + criterion = self.state.criteria[name] + + causes = [] + for candidate in criterion.candidates: + try: + criteria = self._get_updated_criteria(candidate) + except RequirementsConflicted as e: + self._r.rejecting_candidate(e.criterion, candidate) + causes.append(e.criterion) + continue + + # Check the newly-pinned candidate actually works. This should + # always pass under normal circumstances, but in the case of a + # faulty provider, we will raise an error to notify the implementer + # to fix find_matches() and/or is_satisfied_by(). + satisfied = all( + self._p.is_satisfied_by(requirement=r, candidate=candidate) + for r in criterion.iter_requirement() + ) + if not satisfied: + raise InconsistentCandidate(candidate, criterion) + + self._r.pinning(candidate=candidate) + self.state.criteria.update(criteria) + + # Put newly-pinned candidate at the end. This is essential because + # backtracking looks at this mapping to get the last pin. + self.state.mapping.pop(name, None) + self.state.mapping[name] = candidate + + return [] + + # All candidates tried, nothing works. This criterion is a dead + # end, signal for backtracking. + return causes + + def _backjump(self, causes): + """Perform backjumping. + + When we enter here, the stack is like this:: + + [ state Z ] + [ state Y ] + [ state X ] + .... earlier states are irrelevant. + + 1. No pins worked for Z, so it does not have a pin. + 2. We want to reset state Y to unpinned, and pin another candidate. + 3. State X holds what state Y was before the pin, but does not + have the incompatibility information gathered in state Y. + + Each iteration of the loop will: + + 1. Identify Z. The incompatibility is not always caused by the latest + state. For example, given three requirements A, B and C, with + dependencies A1, B1 and C1, where A1 and B1 are incompatible: the + last state might be related to C, so we want to discard the + previous state. + 2. Discard Z. + 3. Discard Y but remember its incompatibility information gathered + previously, and the failure we're dealing with right now. + 4. Push a new state Y' based on X, and apply the incompatibility + information from Y to Y'. + 5a. If this causes Y' to conflict, we need to backtrack again. Make Y' + the new Z and go back to step 2. + 5b. If the incompatibilities apply cleanly, end backtracking. + """ + incompatible_reqs = itertools.chain( + (c.parent for c in causes if c.parent is not None), + (c.requirement for c in causes), + ) + incompatible_deps = {self._p.identify(r) for r in incompatible_reqs} + while len(self._states) >= 3: + # Remove the state that triggered backtracking. + del self._states[-1] + + # Ensure to backtrack to a state that caused the incompatibility + incompatible_state = False + while not incompatible_state: + # Retrieve the last candidate pin and known incompatibilities. + try: + broken_state = self._states.pop() + name, candidate = broken_state.mapping.popitem() + except (IndexError, KeyError): + raise ResolutionImpossible(causes) + current_dependencies = { + self._p.identify(d) + for d in self._p.get_dependencies(candidate) + } + incompatible_state = not current_dependencies.isdisjoint( + incompatible_deps + ) + + incompatibilities_from_broken = [ + (k, list(v.incompatibilities)) + for k, v in broken_state.criteria.items() + ] + + # Also mark the newly known incompatibility. + incompatibilities_from_broken.append((name, [candidate])) + + # Create a new state from the last known-to-work one, and apply + # the previously gathered incompatibility information. + def _patch_criteria(): + for k, incompatibilities in incompatibilities_from_broken: + if not incompatibilities: + continue + try: + criterion = self.state.criteria[k] + except KeyError: + continue + matches = self._p.find_matches( + identifier=k, + requirements=IteratorMapping( + self.state.criteria, + operator.methodcaller("iter_requirement"), + ), + incompatibilities=IteratorMapping( + self.state.criteria, + operator.attrgetter("incompatibilities"), + {k: incompatibilities}, + ), + ) + candidates = build_iter_view(matches) + if not candidates: + return False + incompatibilities.extend(criterion.incompatibilities) + self.state.criteria[k] = Criterion( + candidates=candidates, + information=list(criterion.information), + incompatibilities=incompatibilities, + ) + return True + + self._push_new_state() + success = _patch_criteria() + + # It works! Let's work on this new state. + if success: + return True + + # State does not work after applying known incompatibilities. + # Try the still previous state. + + # No way to backtrack anymore. + return False + + def resolve(self, requirements, max_rounds): + if self._states: + raise RuntimeError("already resolved") + + self._r.starting() + + # Initialize the root state. + self._states = [ + State( + mapping=collections.OrderedDict(), + criteria={}, + backtrack_causes=[], + ) + ] + for r in requirements: + try: + self._add_to_criteria(self.state.criteria, r, parent=None) + except RequirementsConflicted as e: + raise ResolutionImpossible(e.criterion.information) + + # The root state is saved as a sentinel so the first ever pin can have + # something to backtrack to if it fails. The root state is basically + # pinning the virtual "root" package in the graph. + self._push_new_state() + + for round_index in range(max_rounds): + self._r.starting_round(index=round_index) + + unsatisfied_names = [ + key + for key, criterion in self.state.criteria.items() + if not self._is_current_pin_satisfying(key, criterion) + ] + + # All criteria are accounted for. Nothing more to pin, we are done! + if not unsatisfied_names: + self._r.ending(state=self.state) + return self.state + + # keep track of satisfied names to calculate diff after pinning + satisfied_names = set(self.state.criteria.keys()) - set( + unsatisfied_names + ) + + # Choose the most preferred unpinned criterion to try. + name = min(unsatisfied_names, key=self._get_preference) + failure_causes = self._attempt_to_pin_criterion(name) + + if failure_causes: + causes = [i for c in failure_causes for i in c.information] + # Backjump if pinning fails. The backjump process puts us in + # an unpinned state, so we can work on it in the next round. + self._r.resolving_conflicts(causes=causes) + success = self._backjump(causes) + self.state.backtrack_causes[:] = causes + + # Dead ends everywhere. Give up. + if not success: + raise ResolutionImpossible(self.state.backtrack_causes) + else: + # discard as information sources any invalidated names + # (unsatisfied names that were previously satisfied) + newly_unsatisfied_names = { + key + for key, criterion in self.state.criteria.items() + if key in satisfied_names + and not self._is_current_pin_satisfying(key, criterion) + } + self._remove_information_from_criteria( + self.state.criteria, newly_unsatisfied_names + ) + # Pinning was successful. Push a new state to do another pin. + self._push_new_state() + + self._r.ending_round(index=round_index, state=self.state) + + raise ResolutionTooDeep(max_rounds) + + +def _has_route_to_root(criteria, key, all_keys, connected): + if key in connected: + return True + if key not in criteria: + return False + for p in criteria[key].iter_parent(): + try: + pkey = all_keys[id(p)] + except KeyError: + continue + if pkey in connected: + connected.add(key) + return True + if _has_route_to_root(criteria, pkey, all_keys, connected): + connected.add(key) + return True + return False + + +Result = collections.namedtuple("Result", "mapping graph criteria") + + +def _build_result(state): + mapping = state.mapping + all_keys = {id(v): k for k, v in mapping.items()} + all_keys[id(None)] = None + + graph = DirectedGraph() + graph.add(None) # Sentinel as root dependencies' parent. + + connected = {None} + for key, criterion in state.criteria.items(): + if not _has_route_to_root(state.criteria, key, all_keys, connected): + continue + if key not in graph: + graph.add(key) + for p in criterion.iter_parent(): + try: + pkey = all_keys[id(p)] + except KeyError: + continue + if pkey not in graph: + graph.add(pkey) + graph.connect(pkey, key) + + return Result( + mapping={k: v for k, v in mapping.items() if k in connected}, + graph=graph, + criteria=state.criteria, + ) + + +class Resolver(AbstractResolver): + """The thing that performs the actual resolution work.""" + + base_exception = ResolverException + + def resolve(self, requirements, max_rounds=100): + """Take a collection of constraints, spit out the resolution result. + + The return value is a representation to the final resolution result. It + is a tuple subclass with three public members: + + * `mapping`: A dict of resolved candidates. Each key is an identifier + of a requirement (as returned by the provider's `identify` method), + and the value is the resolved candidate. + * `graph`: A `DirectedGraph` instance representing the dependency tree. + The vertices are keys of `mapping`, and each edge represents *why* + a particular package is included. A special vertex `None` is + included to represent parents of user-supplied requirements. + * `criteria`: A dict of "criteria" that hold detailed information on + how edges in the graph are derived. Each key is an identifier of a + requirement, and the value is a `Criterion` instance. + + The following exceptions may be raised if a resolution cannot be found: + + * `ResolutionImpossible`: A resolution cannot be found for the given + combination of requirements. The `causes` attribute of the + exception is a list of (requirement, parent), giving the + requirements that could not be satisfied. + * `ResolutionTooDeep`: The dependency tree is too deeply nested and + the resolver gave up. This is usually caused by a circular + dependency, but you can try to resolve this by increasing the + `max_rounds` argument. + """ + resolution = Resolution(self.provider, self.reporter) + state = resolution.resolve(requirements, max_rounds=max_rounds) + return _build_result(state) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/structs.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/structs.py new file mode 100644 index 0000000..359a34f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/resolvelib/structs.py @@ -0,0 +1,170 @@ +import itertools + +from .compat import collections_abc + + +class DirectedGraph(object): + """A graph structure with directed edges.""" + + def __init__(self): + self._vertices = set() + self._forwards = {} # -> Set[] + self._backwards = {} # -> Set[] + + def __iter__(self): + return iter(self._vertices) + + def __len__(self): + return len(self._vertices) + + def __contains__(self, key): + return key in self._vertices + + def copy(self): + """Return a shallow copy of this graph.""" + other = DirectedGraph() + other._vertices = set(self._vertices) + other._forwards = {k: set(v) for k, v in self._forwards.items()} + other._backwards = {k: set(v) for k, v in self._backwards.items()} + return other + + def add(self, key): + """Add a new vertex to the graph.""" + if key in self._vertices: + raise ValueError("vertex exists") + self._vertices.add(key) + self._forwards[key] = set() + self._backwards[key] = set() + + def remove(self, key): + """Remove a vertex from the graph, disconnecting all edges from/to it.""" + self._vertices.remove(key) + for f in self._forwards.pop(key): + self._backwards[f].remove(key) + for t in self._backwards.pop(key): + self._forwards[t].remove(key) + + def connected(self, f, t): + return f in self._backwards[t] and t in self._forwards[f] + + def connect(self, f, t): + """Connect two existing vertices. + + Nothing happens if the vertices are already connected. + """ + if t not in self._vertices: + raise KeyError(t) + self._forwards[f].add(t) + self._backwards[t].add(f) + + def iter_edges(self): + for f, children in self._forwards.items(): + for t in children: + yield f, t + + def iter_children(self, key): + return iter(self._forwards[key]) + + def iter_parents(self, key): + return iter(self._backwards[key]) + + +class IteratorMapping(collections_abc.Mapping): + def __init__(self, mapping, accessor, appends=None): + self._mapping = mapping + self._accessor = accessor + self._appends = appends or {} + + def __repr__(self): + return "IteratorMapping({!r}, {!r}, {!r})".format( + self._mapping, + self._accessor, + self._appends, + ) + + def __bool__(self): + return bool(self._mapping or self._appends) + + __nonzero__ = __bool__ # XXX: Python 2. + + def __contains__(self, key): + return key in self._mapping or key in self._appends + + def __getitem__(self, k): + try: + v = self._mapping[k] + except KeyError: + return iter(self._appends[k]) + return itertools.chain(self._accessor(v), self._appends.get(k, ())) + + def __iter__(self): + more = (k for k in self._appends if k not in self._mapping) + return itertools.chain(self._mapping, more) + + def __len__(self): + more = sum(1 for k in self._appends if k not in self._mapping) + return len(self._mapping) + more + + +class _FactoryIterableView(object): + """Wrap an iterator factory returned by `find_matches()`. + + Calling `iter()` on this class would invoke the underlying iterator + factory, making it a "collection with ordering" that can be iterated + through multiple times, but lacks random access methods presented in + built-in Python sequence types. + """ + + def __init__(self, factory): + self._factory = factory + self._iterable = None + + def __repr__(self): + return "{}({})".format(type(self).__name__, list(self)) + + def __bool__(self): + try: + next(iter(self)) + except StopIteration: + return False + return True + + __nonzero__ = __bool__ # XXX: Python 2. + + def __iter__(self): + iterable = ( + self._factory() if self._iterable is None else self._iterable + ) + self._iterable, current = itertools.tee(iterable) + return current + + +class _SequenceIterableView(object): + """Wrap an iterable returned by find_matches(). + + This is essentially just a proxy to the underlying sequence that provides + the same interface as `_FactoryIterableView`. + """ + + def __init__(self, sequence): + self._sequence = sequence + + def __repr__(self): + return "{}({})".format(type(self).__name__, self._sequence) + + def __bool__(self): + return bool(self._sequence) + + __nonzero__ = __bool__ # XXX: Python 2. + + def __iter__(self): + return iter(self._sequence) + + +def build_iter_view(matches): + """Build an iterable view from the value returned by `find_matches()`.""" + if callable(matches): + return _FactoryIterableView(matches) + if not isinstance(matches, collections_abc.Sequence): + matches = list(matches) + return _SequenceIterableView(matches) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__init__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__init__.py new file mode 100644 index 0000000..73f58d7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__init__.py @@ -0,0 +1,177 @@ +"""Rich text and beautiful formatting in the terminal.""" + +import os +from typing import IO, TYPE_CHECKING, Any, Callable, Optional, Union + +from ._extension import load_ipython_extension # noqa: F401 + +__all__ = ["get_console", "reconfigure", "print", "inspect", "print_json"] + +if TYPE_CHECKING: + from .console import Console + +# Global console used by alternative print +_console: Optional["Console"] = None + +try: + _IMPORT_CWD = os.path.abspath(os.getcwd()) +except FileNotFoundError: + # Can happen if the cwd has been deleted + _IMPORT_CWD = "" + + +def get_console() -> "Console": + """Get a global :class:`~rich.console.Console` instance. This function is used when Rich requires a Console, + and hasn't been explicitly given one. + + Returns: + Console: A console instance. + """ + global _console + if _console is None: + from .console import Console + + _console = Console() + + return _console + + +def reconfigure(*args: Any, **kwargs: Any) -> None: + """Reconfigures the global console by replacing it with another. + + Args: + *args (Any): Positional arguments for the replacement :class:`~rich.console.Console`. + **kwargs (Any): Keyword arguments for the replacement :class:`~rich.console.Console`. + """ + from pip._vendor.rich.console import Console + + new_console = Console(*args, **kwargs) + _console = get_console() + _console.__dict__ = new_console.__dict__ + + +def print( + *objects: Any, + sep: str = " ", + end: str = "\n", + file: Optional[IO[str]] = None, + flush: bool = False, +) -> None: + r"""Print object(s) supplied via positional arguments. + This function has an identical signature to the built-in print. + For more advanced features, see the :class:`~rich.console.Console` class. + + Args: + sep (str, optional): Separator between printed objects. Defaults to " ". + end (str, optional): Character to write at end of output. Defaults to "\\n". + file (IO[str], optional): File to write to, or None for stdout. Defaults to None. + flush (bool, optional): Has no effect as Rich always flushes output. Defaults to False. + + """ + from .console import Console + + write_console = get_console() if file is None else Console(file=file) + return write_console.print(*objects, sep=sep, end=end) + + +def print_json( + json: Optional[str] = None, + *, + data: Any = None, + indent: Union[None, int, str] = 2, + highlight: bool = True, + skip_keys: bool = False, + ensure_ascii: bool = False, + check_circular: bool = True, + allow_nan: bool = True, + default: Optional[Callable[[Any], Any]] = None, + sort_keys: bool = False, +) -> None: + """Pretty prints JSON. Output will be valid JSON. + + Args: + json (str): A string containing JSON. + data (Any): If json is not supplied, then encode this data. + indent (int, optional): Number of spaces to indent. Defaults to 2. + highlight (bool, optional): Enable highlighting of output: Defaults to True. + skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False. + ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False. + check_circular (bool, optional): Check for circular references. Defaults to True. + allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True. + default (Callable, optional): A callable that converts values that can not be encoded + in to something that can be JSON encoded. Defaults to None. + sort_keys (bool, optional): Sort dictionary keys. Defaults to False. + """ + + get_console().print_json( + json, + data=data, + indent=indent, + highlight=highlight, + skip_keys=skip_keys, + ensure_ascii=ensure_ascii, + check_circular=check_circular, + allow_nan=allow_nan, + default=default, + sort_keys=sort_keys, + ) + + +def inspect( + obj: Any, + *, + console: Optional["Console"] = None, + title: Optional[str] = None, + help: bool = False, + methods: bool = False, + docs: bool = True, + private: bool = False, + dunder: bool = False, + sort: bool = True, + all: bool = False, + value: bool = True, +) -> None: + """Inspect any Python object. + + * inspect() to see summarized info. + * inspect(, methods=True) to see methods. + * inspect(, help=True) to see full (non-abbreviated) help. + * inspect(, private=True) to see private attributes (single underscore). + * inspect(, dunder=True) to see attributes beginning with double underscore. + * inspect(, all=True) to see all attributes. + + Args: + obj (Any): An object to inspect. + title (str, optional): Title to display over inspect result, or None use type. Defaults to None. + help (bool, optional): Show full help text rather than just first paragraph. Defaults to False. + methods (bool, optional): Enable inspection of callables. Defaults to False. + docs (bool, optional): Also render doc strings. Defaults to True. + private (bool, optional): Show private attributes (beginning with underscore). Defaults to False. + dunder (bool, optional): Show attributes starting with double underscore. Defaults to False. + sort (bool, optional): Sort attributes alphabetically. Defaults to True. + all (bool, optional): Show all attributes. Defaults to False. + value (bool, optional): Pretty print value. Defaults to True. + """ + _console = console or get_console() + from pip._vendor.rich._inspect import Inspect + + # Special case for inspect(inspect) + is_inspect = obj is inspect + + _inspect = Inspect( + obj, + title=title, + help=is_inspect or help, + methods=is_inspect or methods, + docs=is_inspect or docs, + private=private, + dunder=dunder, + sort=sort, + all=all, + value=value, + ) + _console.print(_inspect) + + +if __name__ == "__main__": # pragma: no cover + print("Hello, **World**") diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__main__.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__main__.py new file mode 100644 index 0000000..270629f --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/__main__.py @@ -0,0 +1,274 @@ +import colorsys +import io +from time import process_time + +from pip._vendor.rich import box +from pip._vendor.rich.color import Color +from pip._vendor.rich.console import Console, ConsoleOptions, Group, RenderableType, RenderResult +from pip._vendor.rich.markdown import Markdown +from pip._vendor.rich.measure import Measurement +from pip._vendor.rich.pretty import Pretty +from pip._vendor.rich.segment import Segment +from pip._vendor.rich.style import Style +from pip._vendor.rich.syntax import Syntax +from pip._vendor.rich.table import Table +from pip._vendor.rich.text import Text + + +class ColorBox: + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + for y in range(0, 5): + for x in range(options.max_width): + h = x / options.max_width + l = 0.1 + ((y / 5) * 0.7) + r1, g1, b1 = colorsys.hls_to_rgb(h, l, 1.0) + r2, g2, b2 = colorsys.hls_to_rgb(h, l + 0.7 / 10, 1.0) + bgcolor = Color.from_rgb(r1 * 255, g1 * 255, b1 * 255) + color = Color.from_rgb(r2 * 255, g2 * 255, b2 * 255) + yield Segment("▄", Style(color=color, bgcolor=bgcolor)) + yield Segment.line() + + def __rich_measure__( + self, console: "Console", options: ConsoleOptions + ) -> Measurement: + return Measurement(1, options.max_width) + + +def make_test_card() -> Table: + """Get a renderable that demonstrates a number of features.""" + table = Table.grid(padding=1, pad_edge=True) + table.title = "Rich features" + table.add_column("Feature", no_wrap=True, justify="center", style="bold red") + table.add_column("Demonstration") + + color_table = Table( + box=None, + expand=False, + show_header=False, + show_edge=False, + pad_edge=False, + ) + color_table.add_row( + ( + "✓ [bold green]4-bit color[/]\n" + "✓ [bold blue]8-bit color[/]\n" + "✓ [bold magenta]Truecolor (16.7 million)[/]\n" + "✓ [bold yellow]Dumb terminals[/]\n" + "✓ [bold cyan]Automatic color conversion" + ), + ColorBox(), + ) + + table.add_row("Colors", color_table) + + table.add_row( + "Styles", + "All ansi styles: [bold]bold[/], [dim]dim[/], [italic]italic[/italic], [underline]underline[/], [strike]strikethrough[/], [reverse]reverse[/], and even [blink]blink[/].", + ) + + lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque in metus sed sapien ultricies pretium a at justo. Maecenas luctus velit et auctor maximus." + lorem_table = Table.grid(padding=1, collapse_padding=True) + lorem_table.pad_edge = False + lorem_table.add_row( + Text(lorem, justify="left", style="green"), + Text(lorem, justify="center", style="yellow"), + Text(lorem, justify="right", style="blue"), + Text(lorem, justify="full", style="red"), + ) + table.add_row( + "Text", + Group( + Text.from_markup( + """Word wrap text. Justify [green]left[/], [yellow]center[/], [blue]right[/] or [red]full[/].\n""" + ), + lorem_table, + ), + ) + + def comparison(renderable1: RenderableType, renderable2: RenderableType) -> Table: + table = Table(show_header=False, pad_edge=False, box=None, expand=True) + table.add_column("1", ratio=1) + table.add_column("2", ratio=1) + table.add_row(renderable1, renderable2) + return table + + table.add_row( + "Asian\nlanguage\nsupport", + ":flag_for_china: 该库支持中文,日文和韩文文本!\n:flag_for_japan: ライブラリは中国語、日本語、韓国語のテキストをサポートしています\n:flag_for_south_korea: 이 라이브러리는 중국어, 일본어 및 한국어 텍스트를 지원합니다", + ) + + markup_example = ( + "[bold magenta]Rich[/] supports a simple [i]bbcode[/i]-like [b]markup[/b] for [yellow]color[/], [underline]style[/], and emoji! " + ":+1: :apple: :ant: :bear: :baguette_bread: :bus: " + ) + table.add_row("Markup", markup_example) + + example_table = Table( + show_edge=False, + show_header=True, + expand=False, + row_styles=["none", "dim"], + box=box.SIMPLE, + ) + example_table.add_column("[green]Date", style="green", no_wrap=True) + example_table.add_column("[blue]Title", style="blue") + example_table.add_column( + "[cyan]Production Budget", + style="cyan", + justify="right", + no_wrap=True, + ) + example_table.add_column( + "[magenta]Box Office", + style="magenta", + justify="right", + no_wrap=True, + ) + example_table.add_row( + "Dec 20, 2019", + "Star Wars: The Rise of Skywalker", + "$275,000,000", + "$375,126,118", + ) + example_table.add_row( + "May 25, 2018", + "[b]Solo[/]: A Star Wars Story", + "$275,000,000", + "$393,151,347", + ) + example_table.add_row( + "Dec 15, 2017", + "Star Wars Ep. VIII: The Last Jedi", + "$262,000,000", + "[bold]$1,332,539,889[/bold]", + ) + example_table.add_row( + "May 19, 1999", + "Star Wars Ep. [b]I[/b]: [i]The phantom Menace", + "$115,000,000", + "$1,027,044,677", + ) + + table.add_row("Tables", example_table) + + code = '''\ +def iter_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: + """Iterate and generate a tuple with a flag for last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + for value in iter_values: + yield False, previous_value + previous_value = value + yield True, previous_value''' + + pretty_data = { + "foo": [ + 3.1427, + ( + "Paul Atreides", + "Vladimir Harkonnen", + "Thufir Hawat", + ), + ], + "atomic": (False, True, None), + } + table.add_row( + "Syntax\nhighlighting\n&\npretty\nprinting", + comparison( + Syntax(code, "python3", line_numbers=True, indent_guides=True), + Pretty(pretty_data, indent_guides=True), + ), + ) + + markdown_example = """\ +# Markdown + +Supports much of the *markdown* __syntax__! + +- Headers +- Basic formatting: **bold**, *italic*, `code` +- Block quotes +- Lists, and more... + """ + table.add_row( + "Markdown", comparison("[cyan]" + markdown_example, Markdown(markdown_example)) + ) + + table.add_row( + "+more!", + """Progress bars, columns, styled logging handler, tracebacks, etc...""", + ) + return table + + +if __name__ == "__main__": # pragma: no cover + + console = Console( + file=io.StringIO(), + force_terminal=True, + ) + test_card = make_test_card() + + # Print once to warm cache + start = process_time() + console.print(test_card) + pre_cache_taken = round((process_time() - start) * 1000.0, 1) + + console.file = io.StringIO() + + start = process_time() + console.print(test_card) + taken = round((process_time() - start) * 1000.0, 1) + + c = Console(record=True) + c.print(test_card) + + print(f"rendered in {pre_cache_taken}ms (cold cache)") + print(f"rendered in {taken}ms (warm cache)") + + from pip._vendor.rich.panel import Panel + + console = Console() + + sponsor_message = Table.grid(padding=1) + sponsor_message.add_column(style="green", justify="right") + sponsor_message.add_column(no_wrap=True) + + sponsor_message.add_row( + "Textualize", + "[u blue link=https://github.com/textualize]https://github.com/textualize", + ) + sponsor_message.add_row( + "Twitter", + "[u blue link=https://twitter.com/willmcgugan]https://twitter.com/willmcgugan", + ) + + intro_message = Text.from_markup( + """\ +We hope you enjoy using Rich! + +Rich is maintained with [red]:heart:[/] by [link=https://www.textualize.io]Textualize.io[/] + +- Will McGugan""" + ) + + message = Table.grid(padding=2) + message.add_column() + message.add_column(no_wrap=True) + message.add_row(intro_message, sponsor_message) + + console.print( + Panel.fit( + message, + box=box.ROUNDED, + padding=(1, 2), + title="[b red]Thanks for trying out Rich!", + border_style="bright_blue", + ), + justify="center", + ) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_cell_widths.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_cell_widths.py new file mode 100644 index 0000000..36286df --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_cell_widths.py @@ -0,0 +1,451 @@ +# Auto generated by make_terminal_widths.py + +CELL_WIDTHS = [ + (0, 0, 0), + (1, 31, -1), + (127, 159, -1), + (768, 879, 0), + (1155, 1161, 0), + (1425, 1469, 0), + (1471, 1471, 0), + (1473, 1474, 0), + (1476, 1477, 0), + (1479, 1479, 0), + (1552, 1562, 0), + (1611, 1631, 0), + (1648, 1648, 0), + (1750, 1756, 0), + (1759, 1764, 0), + (1767, 1768, 0), + (1770, 1773, 0), + (1809, 1809, 0), + (1840, 1866, 0), + (1958, 1968, 0), + (2027, 2035, 0), + (2045, 2045, 0), + (2070, 2073, 0), + (2075, 2083, 0), + (2085, 2087, 0), + (2089, 2093, 0), + (2137, 2139, 0), + (2259, 2273, 0), + (2275, 2306, 0), + (2362, 2362, 0), + (2364, 2364, 0), + (2369, 2376, 0), + (2381, 2381, 0), + (2385, 2391, 0), + (2402, 2403, 0), + (2433, 2433, 0), + (2492, 2492, 0), + (2497, 2500, 0), + (2509, 2509, 0), + (2530, 2531, 0), + (2558, 2558, 0), + (2561, 2562, 0), + (2620, 2620, 0), + (2625, 2626, 0), + (2631, 2632, 0), + (2635, 2637, 0), + (2641, 2641, 0), + (2672, 2673, 0), + (2677, 2677, 0), + (2689, 2690, 0), + (2748, 2748, 0), + (2753, 2757, 0), + (2759, 2760, 0), + (2765, 2765, 0), + (2786, 2787, 0), + (2810, 2815, 0), + (2817, 2817, 0), + (2876, 2876, 0), + (2879, 2879, 0), + (2881, 2884, 0), + (2893, 2893, 0), + (2901, 2902, 0), + (2914, 2915, 0), + (2946, 2946, 0), + (3008, 3008, 0), + (3021, 3021, 0), + (3072, 3072, 0), + (3076, 3076, 0), + (3134, 3136, 0), + (3142, 3144, 0), + (3146, 3149, 0), + (3157, 3158, 0), + (3170, 3171, 0), + (3201, 3201, 0), + (3260, 3260, 0), + (3263, 3263, 0), + (3270, 3270, 0), + (3276, 3277, 0), + (3298, 3299, 0), + (3328, 3329, 0), + (3387, 3388, 0), + (3393, 3396, 0), + (3405, 3405, 0), + (3426, 3427, 0), + (3457, 3457, 0), + (3530, 3530, 0), + (3538, 3540, 0), + (3542, 3542, 0), + (3633, 3633, 0), + (3636, 3642, 0), + (3655, 3662, 0), + (3761, 3761, 0), + (3764, 3772, 0), + (3784, 3789, 0), + (3864, 3865, 0), + (3893, 3893, 0), + (3895, 3895, 0), + (3897, 3897, 0), + (3953, 3966, 0), + (3968, 3972, 0), + (3974, 3975, 0), + (3981, 3991, 0), + (3993, 4028, 0), + (4038, 4038, 0), + (4141, 4144, 0), + (4146, 4151, 0), + (4153, 4154, 0), + (4157, 4158, 0), + (4184, 4185, 0), + (4190, 4192, 0), + (4209, 4212, 0), + (4226, 4226, 0), + (4229, 4230, 0), + (4237, 4237, 0), + (4253, 4253, 0), + (4352, 4447, 2), + (4957, 4959, 0), + (5906, 5908, 0), + (5938, 5940, 0), + (5970, 5971, 0), + (6002, 6003, 0), + (6068, 6069, 0), + (6071, 6077, 0), + (6086, 6086, 0), + (6089, 6099, 0), + (6109, 6109, 0), + (6155, 6157, 0), + (6277, 6278, 0), + (6313, 6313, 0), + (6432, 6434, 0), + (6439, 6440, 0), + (6450, 6450, 0), + (6457, 6459, 0), + (6679, 6680, 0), + (6683, 6683, 0), + (6742, 6742, 0), + (6744, 6750, 0), + (6752, 6752, 0), + (6754, 6754, 0), + (6757, 6764, 0), + (6771, 6780, 0), + (6783, 6783, 0), + (6832, 6848, 0), + (6912, 6915, 0), + (6964, 6964, 0), + (6966, 6970, 0), + (6972, 6972, 0), + (6978, 6978, 0), + (7019, 7027, 0), + (7040, 7041, 0), + (7074, 7077, 0), + (7080, 7081, 0), + (7083, 7085, 0), + (7142, 7142, 0), + (7144, 7145, 0), + (7149, 7149, 0), + (7151, 7153, 0), + (7212, 7219, 0), + (7222, 7223, 0), + (7376, 7378, 0), + (7380, 7392, 0), + (7394, 7400, 0), + (7405, 7405, 0), + (7412, 7412, 0), + (7416, 7417, 0), + (7616, 7673, 0), + (7675, 7679, 0), + (8203, 8207, 0), + (8232, 8238, 0), + (8288, 8291, 0), + (8400, 8432, 0), + (8986, 8987, 2), + (9001, 9002, 2), + (9193, 9196, 2), + (9200, 9200, 2), + (9203, 9203, 2), + (9725, 9726, 2), + (9748, 9749, 2), + (9800, 9811, 2), + (9855, 9855, 2), + (9875, 9875, 2), + (9889, 9889, 2), + (9898, 9899, 2), + (9917, 9918, 2), + (9924, 9925, 2), + (9934, 9934, 2), + (9940, 9940, 2), + (9962, 9962, 2), + (9970, 9971, 2), + (9973, 9973, 2), + (9978, 9978, 2), + (9981, 9981, 2), + (9989, 9989, 2), + (9994, 9995, 2), + (10024, 10024, 2), + (10060, 10060, 2), + (10062, 10062, 2), + (10067, 10069, 2), + (10071, 10071, 2), + (10133, 10135, 2), + (10160, 10160, 2), + (10175, 10175, 2), + (11035, 11036, 2), + (11088, 11088, 2), + (11093, 11093, 2), + (11503, 11505, 0), + (11647, 11647, 0), + (11744, 11775, 0), + (11904, 11929, 2), + (11931, 12019, 2), + (12032, 12245, 2), + (12272, 12283, 2), + (12288, 12329, 2), + (12330, 12333, 0), + (12334, 12350, 2), + (12353, 12438, 2), + (12441, 12442, 0), + (12443, 12543, 2), + (12549, 12591, 2), + (12593, 12686, 2), + (12688, 12771, 2), + (12784, 12830, 2), + (12832, 12871, 2), + (12880, 19903, 2), + (19968, 42124, 2), + (42128, 42182, 2), + (42607, 42610, 0), + (42612, 42621, 0), + (42654, 42655, 0), + (42736, 42737, 0), + (43010, 43010, 0), + (43014, 43014, 0), + (43019, 43019, 0), + (43045, 43046, 0), + (43052, 43052, 0), + (43204, 43205, 0), + (43232, 43249, 0), + (43263, 43263, 0), + (43302, 43309, 0), + (43335, 43345, 0), + (43360, 43388, 2), + (43392, 43394, 0), + (43443, 43443, 0), + (43446, 43449, 0), + (43452, 43453, 0), + (43493, 43493, 0), + (43561, 43566, 0), + (43569, 43570, 0), + (43573, 43574, 0), + (43587, 43587, 0), + (43596, 43596, 0), + (43644, 43644, 0), + (43696, 43696, 0), + (43698, 43700, 0), + (43703, 43704, 0), + (43710, 43711, 0), + (43713, 43713, 0), + (43756, 43757, 0), + (43766, 43766, 0), + (44005, 44005, 0), + (44008, 44008, 0), + (44013, 44013, 0), + (44032, 55203, 2), + (63744, 64255, 2), + (64286, 64286, 0), + (65024, 65039, 0), + (65040, 65049, 2), + (65056, 65071, 0), + (65072, 65106, 2), + (65108, 65126, 2), + (65128, 65131, 2), + (65281, 65376, 2), + (65504, 65510, 2), + (66045, 66045, 0), + (66272, 66272, 0), + (66422, 66426, 0), + (68097, 68099, 0), + (68101, 68102, 0), + (68108, 68111, 0), + (68152, 68154, 0), + (68159, 68159, 0), + (68325, 68326, 0), + (68900, 68903, 0), + (69291, 69292, 0), + (69446, 69456, 0), + (69633, 69633, 0), + (69688, 69702, 0), + (69759, 69761, 0), + (69811, 69814, 0), + (69817, 69818, 0), + (69888, 69890, 0), + (69927, 69931, 0), + (69933, 69940, 0), + (70003, 70003, 0), + (70016, 70017, 0), + (70070, 70078, 0), + (70089, 70092, 0), + (70095, 70095, 0), + (70191, 70193, 0), + (70196, 70196, 0), + (70198, 70199, 0), + (70206, 70206, 0), + (70367, 70367, 0), + (70371, 70378, 0), + (70400, 70401, 0), + (70459, 70460, 0), + (70464, 70464, 0), + (70502, 70508, 0), + (70512, 70516, 0), + (70712, 70719, 0), + (70722, 70724, 0), + (70726, 70726, 0), + (70750, 70750, 0), + (70835, 70840, 0), + (70842, 70842, 0), + (70847, 70848, 0), + (70850, 70851, 0), + (71090, 71093, 0), + (71100, 71101, 0), + (71103, 71104, 0), + (71132, 71133, 0), + (71219, 71226, 0), + (71229, 71229, 0), + (71231, 71232, 0), + (71339, 71339, 0), + (71341, 71341, 0), + (71344, 71349, 0), + (71351, 71351, 0), + (71453, 71455, 0), + (71458, 71461, 0), + (71463, 71467, 0), + (71727, 71735, 0), + (71737, 71738, 0), + (71995, 71996, 0), + (71998, 71998, 0), + (72003, 72003, 0), + (72148, 72151, 0), + (72154, 72155, 0), + (72160, 72160, 0), + (72193, 72202, 0), + (72243, 72248, 0), + (72251, 72254, 0), + (72263, 72263, 0), + (72273, 72278, 0), + (72281, 72283, 0), + (72330, 72342, 0), + (72344, 72345, 0), + (72752, 72758, 0), + (72760, 72765, 0), + (72767, 72767, 0), + (72850, 72871, 0), + (72874, 72880, 0), + (72882, 72883, 0), + (72885, 72886, 0), + (73009, 73014, 0), + (73018, 73018, 0), + (73020, 73021, 0), + (73023, 73029, 0), + (73031, 73031, 0), + (73104, 73105, 0), + (73109, 73109, 0), + (73111, 73111, 0), + (73459, 73460, 0), + (92912, 92916, 0), + (92976, 92982, 0), + (94031, 94031, 0), + (94095, 94098, 0), + (94176, 94179, 2), + (94180, 94180, 0), + (94192, 94193, 2), + (94208, 100343, 2), + (100352, 101589, 2), + (101632, 101640, 2), + (110592, 110878, 2), + (110928, 110930, 2), + (110948, 110951, 2), + (110960, 111355, 2), + (113821, 113822, 0), + (119143, 119145, 0), + (119163, 119170, 0), + (119173, 119179, 0), + (119210, 119213, 0), + (119362, 119364, 0), + (121344, 121398, 0), + (121403, 121452, 0), + (121461, 121461, 0), + (121476, 121476, 0), + (121499, 121503, 0), + (121505, 121519, 0), + (122880, 122886, 0), + (122888, 122904, 0), + (122907, 122913, 0), + (122915, 122916, 0), + (122918, 122922, 0), + (123184, 123190, 0), + (123628, 123631, 0), + (125136, 125142, 0), + (125252, 125258, 0), + (126980, 126980, 2), + (127183, 127183, 2), + (127374, 127374, 2), + (127377, 127386, 2), + (127488, 127490, 2), + (127504, 127547, 2), + (127552, 127560, 2), + (127568, 127569, 2), + (127584, 127589, 2), + (127744, 127776, 2), + (127789, 127797, 2), + (127799, 127868, 2), + (127870, 127891, 2), + (127904, 127946, 2), + (127951, 127955, 2), + (127968, 127984, 2), + (127988, 127988, 2), + (127992, 128062, 2), + (128064, 128064, 2), + (128066, 128252, 2), + (128255, 128317, 2), + (128331, 128334, 2), + (128336, 128359, 2), + (128378, 128378, 2), + (128405, 128406, 2), + (128420, 128420, 2), + (128507, 128591, 2), + (128640, 128709, 2), + (128716, 128716, 2), + (128720, 128722, 2), + (128725, 128727, 2), + (128747, 128748, 2), + (128756, 128764, 2), + (128992, 129003, 2), + (129292, 129338, 2), + (129340, 129349, 2), + (129351, 129400, 2), + (129402, 129483, 2), + (129485, 129535, 2), + (129648, 129652, 2), + (129656, 129658, 2), + (129664, 129670, 2), + (129680, 129704, 2), + (129712, 129718, 2), + (129728, 129730, 2), + (129744, 129750, 2), + (131072, 196605, 2), + (196608, 262141, 2), + (917760, 917999, 0), +] diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_codes.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_codes.py new file mode 100644 index 0000000..1f2877b --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_codes.py @@ -0,0 +1,3610 @@ +EMOJI = { + "1st_place_medal": "🥇", + "2nd_place_medal": "🥈", + "3rd_place_medal": "🥉", + "ab_button_(blood_type)": "🆎", + "atm_sign": "🏧", + "a_button_(blood_type)": "🅰", + "afghanistan": "🇦🇫", + "albania": "🇦🇱", + "algeria": "🇩🇿", + "american_samoa": "🇦🇸", + "andorra": "🇦🇩", + "angola": "🇦🇴", + "anguilla": "🇦🇮", + "antarctica": "🇦🇶", + "antigua_&_barbuda": "🇦🇬", + "aquarius": "♒", + "argentina": "🇦🇷", + "aries": "♈", + "armenia": "🇦🇲", + "aruba": "🇦🇼", + "ascension_island": "🇦🇨", + "australia": "🇦🇺", + "austria": "🇦🇹", + "azerbaijan": "🇦🇿", + "back_arrow": "🔙", + "b_button_(blood_type)": "🅱", + "bahamas": "🇧🇸", + "bahrain": "🇧🇭", + "bangladesh": "🇧🇩", + "barbados": "🇧🇧", + "belarus": "🇧🇾", + "belgium": "🇧🇪", + "belize": "🇧🇿", + "benin": "🇧🇯", + "bermuda": "🇧🇲", + "bhutan": "🇧🇹", + "bolivia": "🇧🇴", + "bosnia_&_herzegovina": "🇧🇦", + "botswana": "🇧🇼", + "bouvet_island": "🇧🇻", + "brazil": "🇧🇷", + "british_indian_ocean_territory": "🇮🇴", + "british_virgin_islands": "🇻🇬", + "brunei": "🇧🇳", + "bulgaria": "🇧🇬", + "burkina_faso": "🇧🇫", + "burundi": "🇧🇮", + "cl_button": "🆑", + "cool_button": "🆒", + "cambodia": "🇰🇭", + "cameroon": "🇨🇲", + "canada": "🇨🇦", + "canary_islands": "🇮🇨", + "cancer": "♋", + "cape_verde": "🇨🇻", + "capricorn": "♑", + "caribbean_netherlands": "🇧🇶", + "cayman_islands": "🇰🇾", + "central_african_republic": "🇨🇫", + "ceuta_&_melilla": "🇪🇦", + "chad": "🇹🇩", + "chile": "🇨🇱", + "china": "🇨🇳", + "christmas_island": "🇨🇽", + "christmas_tree": "🎄", + "clipperton_island": "🇨🇵", + "cocos_(keeling)_islands": "🇨🇨", + "colombia": "🇨🇴", + "comoros": "🇰🇲", + "congo_-_brazzaville": "🇨🇬", + "congo_-_kinshasa": "🇨🇩", + "cook_islands": "🇨🇰", + "costa_rica": "🇨🇷", + "croatia": "🇭🇷", + "cuba": "🇨🇺", + "curaçao": "🇨🇼", + "cyprus": "🇨🇾", + "czechia": "🇨🇿", + "côte_d’ivoire": "🇨🇮", + "denmark": "🇩🇰", + "diego_garcia": "🇩🇬", + "djibouti": "🇩🇯", + "dominica": "🇩🇲", + "dominican_republic": "🇩🇴", + "end_arrow": "🔚", + "ecuador": "🇪🇨", + "egypt": "🇪🇬", + "el_salvador": "🇸🇻", + "england": "🏴\U000e0067\U000e0062\U000e0065\U000e006e\U000e0067\U000e007f", + "equatorial_guinea": "🇬🇶", + "eritrea": "🇪🇷", + "estonia": "🇪🇪", + "ethiopia": "🇪🇹", + "european_union": "🇪🇺", + "free_button": "🆓", + "falkland_islands": "🇫🇰", + "faroe_islands": "🇫🇴", + "fiji": "🇫🇯", + "finland": "🇫🇮", + "france": "🇫🇷", + "french_guiana": "🇬🇫", + "french_polynesia": "🇵🇫", + "french_southern_territories": "🇹🇫", + "gabon": "🇬🇦", + "gambia": "🇬🇲", + "gemini": "♊", + "georgia": "🇬🇪", + "germany": "🇩🇪", + "ghana": "🇬🇭", + "gibraltar": "🇬🇮", + "greece": "🇬🇷", + "greenland": "🇬🇱", + "grenada": "🇬🇩", + "guadeloupe": "🇬🇵", + "guam": "🇬🇺", + "guatemala": "🇬🇹", + "guernsey": "🇬🇬", + "guinea": "🇬🇳", + "guinea-bissau": "🇬🇼", + "guyana": "🇬🇾", + "haiti": "🇭🇹", + "heard_&_mcdonald_islands": "🇭🇲", + "honduras": "🇭🇳", + "hong_kong_sar_china": "🇭🇰", + "hungary": "🇭🇺", + "id_button": "🆔", + "iceland": "🇮🇸", + "india": "🇮🇳", + "indonesia": "🇮🇩", + "iran": "🇮🇷", + "iraq": "🇮🇶", + "ireland": "🇮🇪", + "isle_of_man": "🇮🇲", + "israel": "🇮🇱", + "italy": "🇮🇹", + "jamaica": "🇯🇲", + "japan": "🗾", + "japanese_acceptable_button": "🉑", + "japanese_application_button": "🈸", + "japanese_bargain_button": "🉐", + "japanese_castle": "🏯", + "japanese_congratulations_button": "㊗", + "japanese_discount_button": "🈹", + "japanese_dolls": "🎎", + "japanese_free_of_charge_button": "🈚", + "japanese_here_button": "🈁", + "japanese_monthly_amount_button": "🈷", + "japanese_no_vacancy_button": "🈵", + "japanese_not_free_of_charge_button": "🈶", + "japanese_open_for_business_button": "🈺", + "japanese_passing_grade_button": "🈴", + "japanese_post_office": "🏣", + "japanese_prohibited_button": "🈲", + "japanese_reserved_button": "🈯", + "japanese_secret_button": "㊙", + "japanese_service_charge_button": "🈂", + "japanese_symbol_for_beginner": "🔰", + "japanese_vacancy_button": "🈳", + "jersey": "🇯🇪", + "jordan": "🇯🇴", + "kazakhstan": "🇰🇿", + "kenya": "🇰🇪", + "kiribati": "🇰🇮", + "kosovo": "🇽🇰", + "kuwait": "🇰🇼", + "kyrgyzstan": "🇰🇬", + "laos": "🇱🇦", + "latvia": "🇱🇻", + "lebanon": "🇱🇧", + "leo": "♌", + "lesotho": "🇱🇸", + "liberia": "🇱🇷", + "libra": "♎", + "libya": "🇱🇾", + "liechtenstein": "🇱🇮", + "lithuania": "🇱🇹", + "luxembourg": "🇱🇺", + "macau_sar_china": "🇲🇴", + "macedonia": "🇲🇰", + "madagascar": "🇲🇬", + "malawi": "🇲🇼", + "malaysia": "🇲🇾", + "maldives": "🇲🇻", + "mali": "🇲🇱", + "malta": "🇲🇹", + "marshall_islands": "🇲🇭", + "martinique": "🇲🇶", + "mauritania": "🇲🇷", + "mauritius": "🇲🇺", + "mayotte": "🇾🇹", + "mexico": "🇲🇽", + "micronesia": "🇫🇲", + "moldova": "🇲🇩", + "monaco": "🇲🇨", + "mongolia": "🇲🇳", + "montenegro": "🇲🇪", + "montserrat": "🇲🇸", + "morocco": "🇲🇦", + "mozambique": "🇲🇿", + "mrs._claus": "🤶", + "mrs._claus_dark_skin_tone": "🤶🏿", + "mrs._claus_light_skin_tone": "🤶🏻", + "mrs._claus_medium-dark_skin_tone": "🤶🏾", + "mrs._claus_medium-light_skin_tone": "🤶🏼", + "mrs._claus_medium_skin_tone": "🤶🏽", + "myanmar_(burma)": "🇲🇲", + "new_button": "🆕", + "ng_button": "🆖", + "namibia": "🇳🇦", + "nauru": "🇳🇷", + "nepal": "🇳🇵", + "netherlands": "🇳🇱", + "new_caledonia": "🇳🇨", + "new_zealand": "🇳🇿", + "nicaragua": "🇳🇮", + "niger": "🇳🇪", + "nigeria": "🇳🇬", + "niue": "🇳🇺", + "norfolk_island": "🇳🇫", + "north_korea": "🇰🇵", + "northern_mariana_islands": "🇲🇵", + "norway": "🇳🇴", + "ok_button": "🆗", + "ok_hand": "👌", + "ok_hand_dark_skin_tone": "👌🏿", + "ok_hand_light_skin_tone": "👌🏻", + "ok_hand_medium-dark_skin_tone": "👌🏾", + "ok_hand_medium-light_skin_tone": "👌🏼", + "ok_hand_medium_skin_tone": "👌🏽", + "on!_arrow": "🔛", + "o_button_(blood_type)": "🅾", + "oman": "🇴🇲", + "ophiuchus": "⛎", + "p_button": "🅿", + "pakistan": "🇵🇰", + "palau": "🇵🇼", + "palestinian_territories": "🇵🇸", + "panama": "🇵🇦", + "papua_new_guinea": "🇵🇬", + "paraguay": "🇵🇾", + "peru": "🇵🇪", + "philippines": "🇵🇭", + "pisces": "♓", + "pitcairn_islands": "🇵🇳", + "poland": "🇵🇱", + "portugal": "🇵🇹", + "puerto_rico": "🇵🇷", + "qatar": "🇶🇦", + "romania": "🇷🇴", + "russia": "🇷🇺", + "rwanda": "🇷🇼", + "réunion": "🇷🇪", + "soon_arrow": "🔜", + "sos_button": "🆘", + "sagittarius": "♐", + "samoa": "🇼🇸", + "san_marino": "🇸🇲", + "santa_claus": "🎅", + "santa_claus_dark_skin_tone": "🎅🏿", + "santa_claus_light_skin_tone": "🎅🏻", + "santa_claus_medium-dark_skin_tone": "🎅🏾", + "santa_claus_medium-light_skin_tone": "🎅🏼", + "santa_claus_medium_skin_tone": "🎅🏽", + "saudi_arabia": "🇸🇦", + "scorpio": "♏", + "scotland": "🏴\U000e0067\U000e0062\U000e0073\U000e0063\U000e0074\U000e007f", + "senegal": "🇸🇳", + "serbia": "🇷🇸", + "seychelles": "🇸🇨", + "sierra_leone": "🇸🇱", + "singapore": "🇸🇬", + "sint_maarten": "🇸🇽", + "slovakia": "🇸🇰", + "slovenia": "🇸🇮", + "solomon_islands": "🇸🇧", + "somalia": "🇸🇴", + "south_africa": "🇿🇦", + "south_georgia_&_south_sandwich_islands": "🇬🇸", + "south_korea": "🇰🇷", + "south_sudan": "🇸🇸", + "spain": "🇪🇸", + "sri_lanka": "🇱🇰", + "st._barthélemy": "🇧🇱", + "st._helena": "🇸🇭", + "st._kitts_&_nevis": "🇰🇳", + "st._lucia": "🇱🇨", + "st._martin": "🇲🇫", + "st._pierre_&_miquelon": "🇵🇲", + "st._vincent_&_grenadines": "🇻🇨", + "statue_of_liberty": "🗽", + "sudan": "🇸🇩", + "suriname": "🇸🇷", + "svalbard_&_jan_mayen": "🇸🇯", + "swaziland": "🇸🇿", + "sweden": "🇸🇪", + "switzerland": "🇨🇭", + "syria": "🇸🇾", + "são_tomé_&_príncipe": "🇸🇹", + "t-rex": "🦖", + "top_arrow": "🔝", + "taiwan": "🇹🇼", + "tajikistan": "🇹🇯", + "tanzania": "🇹🇿", + "taurus": "♉", + "thailand": "🇹🇭", + "timor-leste": "🇹🇱", + "togo": "🇹🇬", + "tokelau": "🇹🇰", + "tokyo_tower": "🗼", + "tonga": "🇹🇴", + "trinidad_&_tobago": "🇹🇹", + "tristan_da_cunha": "🇹🇦", + "tunisia": "🇹🇳", + "turkey": "🦃", + "turkmenistan": "🇹🇲", + "turks_&_caicos_islands": "🇹🇨", + "tuvalu": "🇹🇻", + "u.s._outlying_islands": "🇺🇲", + "u.s._virgin_islands": "🇻🇮", + "up!_button": "🆙", + "uganda": "🇺🇬", + "ukraine": "🇺🇦", + "united_arab_emirates": "🇦🇪", + "united_kingdom": "🇬🇧", + "united_nations": "🇺🇳", + "united_states": "🇺🇸", + "uruguay": "🇺🇾", + "uzbekistan": "🇺🇿", + "vs_button": "🆚", + "vanuatu": "🇻🇺", + "vatican_city": "🇻🇦", + "venezuela": "🇻🇪", + "vietnam": "🇻🇳", + "virgo": "♍", + "wales": "🏴\U000e0067\U000e0062\U000e0077\U000e006c\U000e0073\U000e007f", + "wallis_&_futuna": "🇼🇫", + "western_sahara": "🇪🇭", + "yemen": "🇾🇪", + "zambia": "🇿🇲", + "zimbabwe": "🇿🇼", + "abacus": "🧮", + "adhesive_bandage": "🩹", + "admission_tickets": "🎟", + "adult": "🧑", + "adult_dark_skin_tone": "🧑🏿", + "adult_light_skin_tone": "🧑🏻", + "adult_medium-dark_skin_tone": "🧑🏾", + "adult_medium-light_skin_tone": "🧑🏼", + "adult_medium_skin_tone": "🧑🏽", + "aerial_tramway": "🚡", + "airplane": "✈", + "airplane_arrival": "🛬", + "airplane_departure": "🛫", + "alarm_clock": "⏰", + "alembic": "⚗", + "alien": "👽", + "alien_monster": "👾", + "ambulance": "🚑", + "american_football": "🏈", + "amphora": "🏺", + "anchor": "⚓", + "anger_symbol": "💢", + "angry_face": "😠", + "angry_face_with_horns": "👿", + "anguished_face": "😧", + "ant": "🐜", + "antenna_bars": "📶", + "anxious_face_with_sweat": "😰", + "articulated_lorry": "🚛", + "artist_palette": "🎨", + "astonished_face": "😲", + "atom_symbol": "⚛", + "auto_rickshaw": "🛺", + "automobile": "🚗", + "avocado": "🥑", + "axe": "🪓", + "baby": "👶", + "baby_angel": "👼", + "baby_angel_dark_skin_tone": "👼🏿", + "baby_angel_light_skin_tone": "👼🏻", + "baby_angel_medium-dark_skin_tone": "👼🏾", + "baby_angel_medium-light_skin_tone": "👼🏼", + "baby_angel_medium_skin_tone": "👼🏽", + "baby_bottle": "🍼", + "baby_chick": "🐤", + "baby_dark_skin_tone": "👶🏿", + "baby_light_skin_tone": "👶🏻", + "baby_medium-dark_skin_tone": "👶🏾", + "baby_medium-light_skin_tone": "👶🏼", + "baby_medium_skin_tone": "👶🏽", + "baby_symbol": "🚼", + "backhand_index_pointing_down": "👇", + "backhand_index_pointing_down_dark_skin_tone": "👇🏿", + "backhand_index_pointing_down_light_skin_tone": "👇🏻", + "backhand_index_pointing_down_medium-dark_skin_tone": "👇🏾", + "backhand_index_pointing_down_medium-light_skin_tone": "👇🏼", + "backhand_index_pointing_down_medium_skin_tone": "👇🏽", + "backhand_index_pointing_left": "👈", + "backhand_index_pointing_left_dark_skin_tone": "👈🏿", + "backhand_index_pointing_left_light_skin_tone": "👈🏻", + "backhand_index_pointing_left_medium-dark_skin_tone": "👈🏾", + "backhand_index_pointing_left_medium-light_skin_tone": "👈🏼", + "backhand_index_pointing_left_medium_skin_tone": "👈🏽", + "backhand_index_pointing_right": "👉", + "backhand_index_pointing_right_dark_skin_tone": "👉🏿", + "backhand_index_pointing_right_light_skin_tone": "👉🏻", + "backhand_index_pointing_right_medium-dark_skin_tone": "👉🏾", + "backhand_index_pointing_right_medium-light_skin_tone": "👉🏼", + "backhand_index_pointing_right_medium_skin_tone": "👉🏽", + "backhand_index_pointing_up": "👆", + "backhand_index_pointing_up_dark_skin_tone": "👆🏿", + "backhand_index_pointing_up_light_skin_tone": "👆🏻", + "backhand_index_pointing_up_medium-dark_skin_tone": "👆🏾", + "backhand_index_pointing_up_medium-light_skin_tone": "👆🏼", + "backhand_index_pointing_up_medium_skin_tone": "👆🏽", + "bacon": "🥓", + "badger": "🦡", + "badminton": "🏸", + "bagel": "🥯", + "baggage_claim": "🛄", + "baguette_bread": "🥖", + "balance_scale": "⚖", + "bald": "🦲", + "bald_man": "👨\u200d🦲", + "bald_woman": "👩\u200d🦲", + "ballet_shoes": "🩰", + "balloon": "🎈", + "ballot_box_with_ballot": "🗳", + "ballot_box_with_check": "☑", + "banana": "🍌", + "banjo": "🪕", + "bank": "🏦", + "bar_chart": "📊", + "barber_pole": "💈", + "baseball": "⚾", + "basket": "🧺", + "basketball": "🏀", + "bat": "🦇", + "bathtub": "🛁", + "battery": "🔋", + "beach_with_umbrella": "🏖", + "beaming_face_with_smiling_eyes": "😁", + "bear_face": "🐻", + "bearded_person": "🧔", + "bearded_person_dark_skin_tone": "🧔🏿", + "bearded_person_light_skin_tone": "🧔🏻", + "bearded_person_medium-dark_skin_tone": "🧔🏾", + "bearded_person_medium-light_skin_tone": "🧔🏼", + "bearded_person_medium_skin_tone": "🧔🏽", + "beating_heart": "💓", + "bed": "🛏", + "beer_mug": "🍺", + "bell": "🔔", + "bell_with_slash": "🔕", + "bellhop_bell": "🛎", + "bento_box": "🍱", + "beverage_box": "🧃", + "bicycle": "🚲", + "bikini": "👙", + "billed_cap": "🧢", + "biohazard": "☣", + "bird": "🐦", + "birthday_cake": "🎂", + "black_circle": "⚫", + "black_flag": "🏴", + "black_heart": "🖤", + "black_large_square": "⬛", + "black_medium-small_square": "◾", + "black_medium_square": "◼", + "black_nib": "✒", + "black_small_square": "▪", + "black_square_button": "🔲", + "blond-haired_man": "👱\u200d♂️", + "blond-haired_man_dark_skin_tone": "👱🏿\u200d♂️", + "blond-haired_man_light_skin_tone": "👱🏻\u200d♂️", + "blond-haired_man_medium-dark_skin_tone": "👱🏾\u200d♂️", + "blond-haired_man_medium-light_skin_tone": "👱🏼\u200d♂️", + "blond-haired_man_medium_skin_tone": "👱🏽\u200d♂️", + "blond-haired_person": "👱", + "blond-haired_person_dark_skin_tone": "👱🏿", + "blond-haired_person_light_skin_tone": "👱🏻", + "blond-haired_person_medium-dark_skin_tone": "👱🏾", + "blond-haired_person_medium-light_skin_tone": "👱🏼", + "blond-haired_person_medium_skin_tone": "👱🏽", + "blond-haired_woman": "👱\u200d♀️", + "blond-haired_woman_dark_skin_tone": "👱🏿\u200d♀️", + "blond-haired_woman_light_skin_tone": "👱🏻\u200d♀️", + "blond-haired_woman_medium-dark_skin_tone": "👱🏾\u200d♀️", + "blond-haired_woman_medium-light_skin_tone": "👱🏼\u200d♀️", + "blond-haired_woman_medium_skin_tone": "👱🏽\u200d♀️", + "blossom": "🌼", + "blowfish": "🐡", + "blue_book": "📘", + "blue_circle": "🔵", + "blue_heart": "💙", + "blue_square": "🟦", + "boar": "🐗", + "bomb": "💣", + "bone": "🦴", + "bookmark": "🔖", + "bookmark_tabs": "📑", + "books": "📚", + "bottle_with_popping_cork": "🍾", + "bouquet": "💐", + "bow_and_arrow": "🏹", + "bowl_with_spoon": "🥣", + "bowling": "🎳", + "boxing_glove": "🥊", + "boy": "👦", + "boy_dark_skin_tone": "👦🏿", + "boy_light_skin_tone": "👦🏻", + "boy_medium-dark_skin_tone": "👦🏾", + "boy_medium-light_skin_tone": "👦🏼", + "boy_medium_skin_tone": "👦🏽", + "brain": "🧠", + "bread": "🍞", + "breast-feeding": "🤱", + "breast-feeding_dark_skin_tone": "🤱🏿", + "breast-feeding_light_skin_tone": "🤱🏻", + "breast-feeding_medium-dark_skin_tone": "🤱🏾", + "breast-feeding_medium-light_skin_tone": "🤱🏼", + "breast-feeding_medium_skin_tone": "🤱🏽", + "brick": "🧱", + "bride_with_veil": "👰", + "bride_with_veil_dark_skin_tone": "👰🏿", + "bride_with_veil_light_skin_tone": "👰🏻", + "bride_with_veil_medium-dark_skin_tone": "👰🏾", + "bride_with_veil_medium-light_skin_tone": "👰🏼", + "bride_with_veil_medium_skin_tone": "👰🏽", + "bridge_at_night": "🌉", + "briefcase": "💼", + "briefs": "🩲", + "bright_button": "🔆", + "broccoli": "🥦", + "broken_heart": "💔", + "broom": "🧹", + "brown_circle": "🟤", + "brown_heart": "🤎", + "brown_square": "🟫", + "bug": "🐛", + "building_construction": "🏗", + "bullet_train": "🚅", + "burrito": "🌯", + "bus": "🚌", + "bus_stop": "🚏", + "bust_in_silhouette": "👤", + "busts_in_silhouette": "👥", + "butter": "🧈", + "butterfly": "🦋", + "cactus": "🌵", + "calendar": "📆", + "call_me_hand": "🤙", + "call_me_hand_dark_skin_tone": "🤙🏿", + "call_me_hand_light_skin_tone": "🤙🏻", + "call_me_hand_medium-dark_skin_tone": "🤙🏾", + "call_me_hand_medium-light_skin_tone": "🤙🏼", + "call_me_hand_medium_skin_tone": "🤙🏽", + "camel": "🐫", + "camera": "📷", + "camera_with_flash": "📸", + "camping": "🏕", + "candle": "🕯", + "candy": "🍬", + "canned_food": "🥫", + "canoe": "🛶", + "card_file_box": "🗃", + "card_index": "📇", + "card_index_dividers": "🗂", + "carousel_horse": "🎠", + "carp_streamer": "🎏", + "carrot": "🥕", + "castle": "🏰", + "cat": "🐱", + "cat_face": "🐱", + "cat_face_with_tears_of_joy": "😹", + "cat_face_with_wry_smile": "😼", + "chains": "⛓", + "chair": "🪑", + "chart_decreasing": "📉", + "chart_increasing": "📈", + "chart_increasing_with_yen": "💹", + "cheese_wedge": "🧀", + "chequered_flag": "🏁", + "cherries": "🍒", + "cherry_blossom": "🌸", + "chess_pawn": "♟", + "chestnut": "🌰", + "chicken": "🐔", + "child": "🧒", + "child_dark_skin_tone": "🧒🏿", + "child_light_skin_tone": "🧒🏻", + "child_medium-dark_skin_tone": "🧒🏾", + "child_medium-light_skin_tone": "🧒🏼", + "child_medium_skin_tone": "🧒🏽", + "children_crossing": "🚸", + "chipmunk": "🐿", + "chocolate_bar": "🍫", + "chopsticks": "🥢", + "church": "⛪", + "cigarette": "🚬", + "cinema": "🎦", + "circled_m": "Ⓜ", + "circus_tent": "🎪", + "cityscape": "🏙", + "cityscape_at_dusk": "🌆", + "clamp": "🗜", + "clapper_board": "🎬", + "clapping_hands": "👏", + "clapping_hands_dark_skin_tone": "👏🏿", + "clapping_hands_light_skin_tone": "👏🏻", + "clapping_hands_medium-dark_skin_tone": "👏🏾", + "clapping_hands_medium-light_skin_tone": "👏🏼", + "clapping_hands_medium_skin_tone": "👏🏽", + "classical_building": "🏛", + "clinking_beer_mugs": "🍻", + "clinking_glasses": "🥂", + "clipboard": "📋", + "clockwise_vertical_arrows": "🔃", + "closed_book": "📕", + "closed_mailbox_with_lowered_flag": "📪", + "closed_mailbox_with_raised_flag": "📫", + "closed_umbrella": "🌂", + "cloud": "☁", + "cloud_with_lightning": "🌩", + "cloud_with_lightning_and_rain": "⛈", + "cloud_with_rain": "🌧", + "cloud_with_snow": "🌨", + "clown_face": "🤡", + "club_suit": "♣", + "clutch_bag": "👝", + "coat": "🧥", + "cocktail_glass": "🍸", + "coconut": "🥥", + "coffin": "⚰", + "cold_face": "🥶", + "collision": "💥", + "comet": "☄", + "compass": "🧭", + "computer_disk": "💽", + "computer_mouse": "🖱", + "confetti_ball": "🎊", + "confounded_face": "😖", + "confused_face": "😕", + "construction": "🚧", + "construction_worker": "👷", + "construction_worker_dark_skin_tone": "👷🏿", + "construction_worker_light_skin_tone": "👷🏻", + "construction_worker_medium-dark_skin_tone": "👷🏾", + "construction_worker_medium-light_skin_tone": "👷🏼", + "construction_worker_medium_skin_tone": "👷🏽", + "control_knobs": "🎛", + "convenience_store": "🏪", + "cooked_rice": "🍚", + "cookie": "🍪", + "cooking": "🍳", + "copyright": "©", + "couch_and_lamp": "🛋", + "counterclockwise_arrows_button": "🔄", + "couple_with_heart": "💑", + "couple_with_heart_man_man": "👨\u200d❤️\u200d👨", + "couple_with_heart_woman_man": "👩\u200d❤️\u200d👨", + "couple_with_heart_woman_woman": "👩\u200d❤️\u200d👩", + "cow": "🐮", + "cow_face": "🐮", + "cowboy_hat_face": "🤠", + "crab": "🦀", + "crayon": "🖍", + "credit_card": "💳", + "crescent_moon": "🌙", + "cricket": "🦗", + "cricket_game": "🏏", + "crocodile": "🐊", + "croissant": "🥐", + "cross_mark": "❌", + "cross_mark_button": "❎", + "crossed_fingers": "🤞", + "crossed_fingers_dark_skin_tone": "🤞🏿", + "crossed_fingers_light_skin_tone": "🤞🏻", + "crossed_fingers_medium-dark_skin_tone": "🤞🏾", + "crossed_fingers_medium-light_skin_tone": "🤞🏼", + "crossed_fingers_medium_skin_tone": "🤞🏽", + "crossed_flags": "🎌", + "crossed_swords": "⚔", + "crown": "👑", + "crying_cat_face": "😿", + "crying_face": "😢", + "crystal_ball": "🔮", + "cucumber": "🥒", + "cupcake": "🧁", + "cup_with_straw": "🥤", + "curling_stone": "🥌", + "curly_hair": "🦱", + "curly-haired_man": "👨\u200d🦱", + "curly-haired_woman": "👩\u200d🦱", + "curly_loop": "➰", + "currency_exchange": "💱", + "curry_rice": "🍛", + "custard": "🍮", + "customs": "🛃", + "cut_of_meat": "🥩", + "cyclone": "🌀", + "dagger": "🗡", + "dango": "🍡", + "dashing_away": "💨", + "deaf_person": "🧏", + "deciduous_tree": "🌳", + "deer": "🦌", + "delivery_truck": "🚚", + "department_store": "🏬", + "derelict_house": "🏚", + "desert": "🏜", + "desert_island": "🏝", + "desktop_computer": "🖥", + "detective": "🕵", + "detective_dark_skin_tone": "🕵🏿", + "detective_light_skin_tone": "🕵🏻", + "detective_medium-dark_skin_tone": "🕵🏾", + "detective_medium-light_skin_tone": "🕵🏼", + "detective_medium_skin_tone": "🕵🏽", + "diamond_suit": "♦", + "diamond_with_a_dot": "💠", + "dim_button": "🔅", + "direct_hit": "🎯", + "disappointed_face": "😞", + "diving_mask": "🤿", + "diya_lamp": "🪔", + "dizzy": "💫", + "dizzy_face": "😵", + "dna": "🧬", + "dog": "🐶", + "dog_face": "🐶", + "dollar_banknote": "💵", + "dolphin": "🐬", + "door": "🚪", + "dotted_six-pointed_star": "🔯", + "double_curly_loop": "➿", + "double_exclamation_mark": "‼", + "doughnut": "🍩", + "dove": "🕊", + "down-left_arrow": "↙", + "down-right_arrow": "↘", + "down_arrow": "⬇", + "downcast_face_with_sweat": "😓", + "downwards_button": "🔽", + "dragon": "🐉", + "dragon_face": "🐲", + "dress": "👗", + "drooling_face": "🤤", + "drop_of_blood": "🩸", + "droplet": "💧", + "drum": "🥁", + "duck": "🦆", + "dumpling": "🥟", + "dvd": "📀", + "e-mail": "📧", + "eagle": "🦅", + "ear": "👂", + "ear_dark_skin_tone": "👂🏿", + "ear_light_skin_tone": "👂🏻", + "ear_medium-dark_skin_tone": "👂🏾", + "ear_medium-light_skin_tone": "👂🏼", + "ear_medium_skin_tone": "👂🏽", + "ear_of_corn": "🌽", + "ear_with_hearing_aid": "🦻", + "egg": "🍳", + "eggplant": "🍆", + "eight-pointed_star": "✴", + "eight-spoked_asterisk": "✳", + "eight-thirty": "🕣", + "eight_o’clock": "🕗", + "eject_button": "⏏", + "electric_plug": "🔌", + "elephant": "🐘", + "eleven-thirty": "🕦", + "eleven_o’clock": "🕚", + "elf": "🧝", + "elf_dark_skin_tone": "🧝🏿", + "elf_light_skin_tone": "🧝🏻", + "elf_medium-dark_skin_tone": "🧝🏾", + "elf_medium-light_skin_tone": "🧝🏼", + "elf_medium_skin_tone": "🧝🏽", + "envelope": "✉", + "envelope_with_arrow": "📩", + "euro_banknote": "💶", + "evergreen_tree": "🌲", + "ewe": "🐑", + "exclamation_mark": "❗", + "exclamation_question_mark": "⁉", + "exploding_head": "🤯", + "expressionless_face": "😑", + "eye": "👁", + "eye_in_speech_bubble": "👁️\u200d🗨️", + "eyes": "👀", + "face_blowing_a_kiss": "😘", + "face_savoring_food": "😋", + "face_screaming_in_fear": "😱", + "face_vomiting": "🤮", + "face_with_hand_over_mouth": "🤭", + "face_with_head-bandage": "🤕", + "face_with_medical_mask": "😷", + "face_with_monocle": "🧐", + "face_with_open_mouth": "😮", + "face_with_raised_eyebrow": "🤨", + "face_with_rolling_eyes": "🙄", + "face_with_steam_from_nose": "😤", + "face_with_symbols_on_mouth": "🤬", + "face_with_tears_of_joy": "😂", + "face_with_thermometer": "🤒", + "face_with_tongue": "😛", + "face_without_mouth": "😶", + "factory": "🏭", + "fairy": "🧚", + "fairy_dark_skin_tone": "🧚🏿", + "fairy_light_skin_tone": "🧚🏻", + "fairy_medium-dark_skin_tone": "🧚🏾", + "fairy_medium-light_skin_tone": "🧚🏼", + "fairy_medium_skin_tone": "🧚🏽", + "falafel": "🧆", + "fallen_leaf": "🍂", + "family": "👪", + "family_man_boy": "👨\u200d👦", + "family_man_boy_boy": "👨\u200d👦\u200d👦", + "family_man_girl": "👨\u200d👧", + "family_man_girl_boy": "👨\u200d👧\u200d👦", + "family_man_girl_girl": "👨\u200d👧\u200d👧", + "family_man_man_boy": "👨\u200d👨\u200d👦", + "family_man_man_boy_boy": "👨\u200d👨\u200d👦\u200d👦", + "family_man_man_girl": "👨\u200d👨\u200d👧", + "family_man_man_girl_boy": "👨\u200d👨\u200d👧\u200d👦", + "family_man_man_girl_girl": "👨\u200d👨\u200d👧\u200d👧", + "family_man_woman_boy": "👨\u200d👩\u200d👦", + "family_man_woman_boy_boy": "👨\u200d👩\u200d👦\u200d👦", + "family_man_woman_girl": "👨\u200d👩\u200d👧", + "family_man_woman_girl_boy": "👨\u200d👩\u200d👧\u200d👦", + "family_man_woman_girl_girl": "👨\u200d👩\u200d👧\u200d👧", + "family_woman_boy": "👩\u200d👦", + "family_woman_boy_boy": "👩\u200d👦\u200d👦", + "family_woman_girl": "👩\u200d👧", + "family_woman_girl_boy": "👩\u200d👧\u200d👦", + "family_woman_girl_girl": "👩\u200d👧\u200d👧", + "family_woman_woman_boy": "👩\u200d👩\u200d👦", + "family_woman_woman_boy_boy": "👩\u200d👩\u200d👦\u200d👦", + "family_woman_woman_girl": "👩\u200d👩\u200d👧", + "family_woman_woman_girl_boy": "👩\u200d👩\u200d👧\u200d👦", + "family_woman_woman_girl_girl": "👩\u200d👩\u200d👧\u200d👧", + "fast-forward_button": "⏩", + "fast_down_button": "⏬", + "fast_reverse_button": "⏪", + "fast_up_button": "⏫", + "fax_machine": "📠", + "fearful_face": "😨", + "female_sign": "♀", + "ferris_wheel": "🎡", + "ferry": "⛴", + "field_hockey": "🏑", + "file_cabinet": "🗄", + "file_folder": "📁", + "film_frames": "🎞", + "film_projector": "📽", + "fire": "🔥", + "fire_extinguisher": "🧯", + "firecracker": "🧨", + "fire_engine": "🚒", + "fireworks": "🎆", + "first_quarter_moon": "🌓", + "first_quarter_moon_face": "🌛", + "fish": "🐟", + "fish_cake_with_swirl": "🍥", + "fishing_pole": "🎣", + "five-thirty": "🕠", + "five_o’clock": "🕔", + "flag_in_hole": "⛳", + "flamingo": "🦩", + "flashlight": "🔦", + "flat_shoe": "🥿", + "fleur-de-lis": "⚜", + "flexed_biceps": "💪", + "flexed_biceps_dark_skin_tone": "💪🏿", + "flexed_biceps_light_skin_tone": "💪🏻", + "flexed_biceps_medium-dark_skin_tone": "💪🏾", + "flexed_biceps_medium-light_skin_tone": "💪🏼", + "flexed_biceps_medium_skin_tone": "💪🏽", + "floppy_disk": "💾", + "flower_playing_cards": "🎴", + "flushed_face": "😳", + "flying_disc": "🥏", + "flying_saucer": "🛸", + "fog": "🌫", + "foggy": "🌁", + "folded_hands": "🙏", + "folded_hands_dark_skin_tone": "🙏🏿", + "folded_hands_light_skin_tone": "🙏🏻", + "folded_hands_medium-dark_skin_tone": "🙏🏾", + "folded_hands_medium-light_skin_tone": "🙏🏼", + "folded_hands_medium_skin_tone": "🙏🏽", + "foot": "🦶", + "footprints": "👣", + "fork_and_knife": "🍴", + "fork_and_knife_with_plate": "🍽", + "fortune_cookie": "🥠", + "fountain": "⛲", + "fountain_pen": "🖋", + "four-thirty": "🕟", + "four_leaf_clover": "🍀", + "four_o’clock": "🕓", + "fox_face": "🦊", + "framed_picture": "🖼", + "french_fries": "🍟", + "fried_shrimp": "🍤", + "frog_face": "🐸", + "front-facing_baby_chick": "🐥", + "frowning_face": "☹", + "frowning_face_with_open_mouth": "😦", + "fuel_pump": "⛽", + "full_moon": "🌕", + "full_moon_face": "🌝", + "funeral_urn": "⚱", + "game_die": "🎲", + "garlic": "🧄", + "gear": "⚙", + "gem_stone": "💎", + "genie": "🧞", + "ghost": "👻", + "giraffe": "🦒", + "girl": "👧", + "girl_dark_skin_tone": "👧🏿", + "girl_light_skin_tone": "👧🏻", + "girl_medium-dark_skin_tone": "👧🏾", + "girl_medium-light_skin_tone": "👧🏼", + "girl_medium_skin_tone": "👧🏽", + "glass_of_milk": "🥛", + "glasses": "👓", + "globe_showing_americas": "🌎", + "globe_showing_asia-australia": "🌏", + "globe_showing_europe-africa": "🌍", + "globe_with_meridians": "🌐", + "gloves": "🧤", + "glowing_star": "🌟", + "goal_net": "🥅", + "goat": "🐐", + "goblin": "👺", + "goggles": "🥽", + "gorilla": "🦍", + "graduation_cap": "🎓", + "grapes": "🍇", + "green_apple": "🍏", + "green_book": "📗", + "green_circle": "🟢", + "green_heart": "💚", + "green_salad": "🥗", + "green_square": "🟩", + "grimacing_face": "😬", + "grinning_cat_face": "😺", + "grinning_cat_face_with_smiling_eyes": "😸", + "grinning_face": "😀", + "grinning_face_with_big_eyes": "😃", + "grinning_face_with_smiling_eyes": "😄", + "grinning_face_with_sweat": "😅", + "grinning_squinting_face": "😆", + "growing_heart": "💗", + "guard": "💂", + "guard_dark_skin_tone": "💂🏿", + "guard_light_skin_tone": "💂🏻", + "guard_medium-dark_skin_tone": "💂🏾", + "guard_medium-light_skin_tone": "💂🏼", + "guard_medium_skin_tone": "💂🏽", + "guide_dog": "🦮", + "guitar": "🎸", + "hamburger": "🍔", + "hammer": "🔨", + "hammer_and_pick": "⚒", + "hammer_and_wrench": "🛠", + "hamster_face": "🐹", + "hand_with_fingers_splayed": "🖐", + "hand_with_fingers_splayed_dark_skin_tone": "🖐🏿", + "hand_with_fingers_splayed_light_skin_tone": "🖐🏻", + "hand_with_fingers_splayed_medium-dark_skin_tone": "🖐🏾", + "hand_with_fingers_splayed_medium-light_skin_tone": "🖐🏼", + "hand_with_fingers_splayed_medium_skin_tone": "🖐🏽", + "handbag": "👜", + "handshake": "🤝", + "hatching_chick": "🐣", + "headphone": "🎧", + "hear-no-evil_monkey": "🙉", + "heart_decoration": "💟", + "heart_suit": "♥", + "heart_with_arrow": "💘", + "heart_with_ribbon": "💝", + "heavy_check_mark": "✔", + "heavy_division_sign": "➗", + "heavy_dollar_sign": "💲", + "heavy_heart_exclamation": "❣", + "heavy_large_circle": "⭕", + "heavy_minus_sign": "➖", + "heavy_multiplication_x": "✖", + "heavy_plus_sign": "➕", + "hedgehog": "🦔", + "helicopter": "🚁", + "herb": "🌿", + "hibiscus": "🌺", + "high-heeled_shoe": "👠", + "high-speed_train": "🚄", + "high_voltage": "⚡", + "hiking_boot": "🥾", + "hindu_temple": "🛕", + "hippopotamus": "🦛", + "hole": "🕳", + "honey_pot": "🍯", + "honeybee": "🐝", + "horizontal_traffic_light": "🚥", + "horse": "🐴", + "horse_face": "🐴", + "horse_racing": "🏇", + "horse_racing_dark_skin_tone": "🏇🏿", + "horse_racing_light_skin_tone": "🏇🏻", + "horse_racing_medium-dark_skin_tone": "🏇🏾", + "horse_racing_medium-light_skin_tone": "🏇🏼", + "horse_racing_medium_skin_tone": "🏇🏽", + "hospital": "🏥", + "hot_beverage": "☕", + "hot_dog": "🌭", + "hot_face": "🥵", + "hot_pepper": "🌶", + "hot_springs": "♨", + "hotel": "🏨", + "hourglass_done": "⌛", + "hourglass_not_done": "⏳", + "house": "🏠", + "house_with_garden": "🏡", + "houses": "🏘", + "hugging_face": "🤗", + "hundred_points": "💯", + "hushed_face": "😯", + "ice": "🧊", + "ice_cream": "🍨", + "ice_hockey": "🏒", + "ice_skate": "⛸", + "inbox_tray": "📥", + "incoming_envelope": "📨", + "index_pointing_up": "☝", + "index_pointing_up_dark_skin_tone": "☝🏿", + "index_pointing_up_light_skin_tone": "☝🏻", + "index_pointing_up_medium-dark_skin_tone": "☝🏾", + "index_pointing_up_medium-light_skin_tone": "☝🏼", + "index_pointing_up_medium_skin_tone": "☝🏽", + "infinity": "♾", + "information": "ℹ", + "input_latin_letters": "🔤", + "input_latin_lowercase": "🔡", + "input_latin_uppercase": "🔠", + "input_numbers": "🔢", + "input_symbols": "🔣", + "jack-o-lantern": "🎃", + "jeans": "👖", + "jigsaw": "🧩", + "joker": "🃏", + "joystick": "🕹", + "kaaba": "🕋", + "kangaroo": "🦘", + "key": "🔑", + "keyboard": "⌨", + "keycap_#": "#️⃣", + "keycap_*": "*️⃣", + "keycap_0": "0️⃣", + "keycap_1": "1️⃣", + "keycap_10": "🔟", + "keycap_2": "2️⃣", + "keycap_3": "3️⃣", + "keycap_4": "4️⃣", + "keycap_5": "5️⃣", + "keycap_6": "6️⃣", + "keycap_7": "7️⃣", + "keycap_8": "8️⃣", + "keycap_9": "9️⃣", + "kick_scooter": "🛴", + "kimono": "👘", + "kiss": "💋", + "kiss_man_man": "👨\u200d❤️\u200d💋\u200d👨", + "kiss_mark": "💋", + "kiss_woman_man": "👩\u200d❤️\u200d💋\u200d👨", + "kiss_woman_woman": "👩\u200d❤️\u200d💋\u200d👩", + "kissing_cat_face": "😽", + "kissing_face": "😗", + "kissing_face_with_closed_eyes": "😚", + "kissing_face_with_smiling_eyes": "😙", + "kitchen_knife": "🔪", + "kite": "🪁", + "kiwi_fruit": "🥝", + "koala": "🐨", + "lab_coat": "🥼", + "label": "🏷", + "lacrosse": "🥍", + "lady_beetle": "🐞", + "laptop_computer": "💻", + "large_blue_diamond": "🔷", + "large_orange_diamond": "🔶", + "last_quarter_moon": "🌗", + "last_quarter_moon_face": "🌜", + "last_track_button": "⏮", + "latin_cross": "✝", + "leaf_fluttering_in_wind": "🍃", + "leafy_green": "🥬", + "ledger": "📒", + "left-facing_fist": "🤛", + "left-facing_fist_dark_skin_tone": "🤛🏿", + "left-facing_fist_light_skin_tone": "🤛🏻", + "left-facing_fist_medium-dark_skin_tone": "🤛🏾", + "left-facing_fist_medium-light_skin_tone": "🤛🏼", + "left-facing_fist_medium_skin_tone": "🤛🏽", + "left-right_arrow": "↔", + "left_arrow": "⬅", + "left_arrow_curving_right": "↪", + "left_luggage": "🛅", + "left_speech_bubble": "🗨", + "leg": "🦵", + "lemon": "🍋", + "leopard": "🐆", + "level_slider": "🎚", + "light_bulb": "💡", + "light_rail": "🚈", + "link": "🔗", + "linked_paperclips": "🖇", + "lion_face": "🦁", + "lipstick": "💄", + "litter_in_bin_sign": "🚮", + "lizard": "🦎", + "llama": "🦙", + "lobster": "🦞", + "locked": "🔒", + "locked_with_key": "🔐", + "locked_with_pen": "🔏", + "locomotive": "🚂", + "lollipop": "🍭", + "lotion_bottle": "🧴", + "loudly_crying_face": "😭", + "loudspeaker": "📢", + "love-you_gesture": "🤟", + "love-you_gesture_dark_skin_tone": "🤟🏿", + "love-you_gesture_light_skin_tone": "🤟🏻", + "love-you_gesture_medium-dark_skin_tone": "🤟🏾", + "love-you_gesture_medium-light_skin_tone": "🤟🏼", + "love-you_gesture_medium_skin_tone": "🤟🏽", + "love_hotel": "🏩", + "love_letter": "💌", + "luggage": "🧳", + "lying_face": "🤥", + "mage": "🧙", + "mage_dark_skin_tone": "🧙🏿", + "mage_light_skin_tone": "🧙🏻", + "mage_medium-dark_skin_tone": "🧙🏾", + "mage_medium-light_skin_tone": "🧙🏼", + "mage_medium_skin_tone": "🧙🏽", + "magnet": "🧲", + "magnifying_glass_tilted_left": "🔍", + "magnifying_glass_tilted_right": "🔎", + "mahjong_red_dragon": "🀄", + "male_sign": "♂", + "man": "👨", + "man_and_woman_holding_hands": "👫", + "man_artist": "👨\u200d🎨", + "man_artist_dark_skin_tone": "👨🏿\u200d🎨", + "man_artist_light_skin_tone": "👨🏻\u200d🎨", + "man_artist_medium-dark_skin_tone": "👨🏾\u200d🎨", + "man_artist_medium-light_skin_tone": "👨🏼\u200d🎨", + "man_artist_medium_skin_tone": "👨🏽\u200d🎨", + "man_astronaut": "👨\u200d🚀", + "man_astronaut_dark_skin_tone": "👨🏿\u200d🚀", + "man_astronaut_light_skin_tone": "👨🏻\u200d🚀", + "man_astronaut_medium-dark_skin_tone": "👨🏾\u200d🚀", + "man_astronaut_medium-light_skin_tone": "👨🏼\u200d🚀", + "man_astronaut_medium_skin_tone": "👨🏽\u200d🚀", + "man_biking": "🚴\u200d♂️", + "man_biking_dark_skin_tone": "🚴🏿\u200d♂️", + "man_biking_light_skin_tone": "🚴🏻\u200d♂️", + "man_biking_medium-dark_skin_tone": "🚴🏾\u200d♂️", + "man_biking_medium-light_skin_tone": "🚴🏼\u200d♂️", + "man_biking_medium_skin_tone": "🚴🏽\u200d♂️", + "man_bouncing_ball": "⛹️\u200d♂️", + "man_bouncing_ball_dark_skin_tone": "⛹🏿\u200d♂️", + "man_bouncing_ball_light_skin_tone": "⛹🏻\u200d♂️", + "man_bouncing_ball_medium-dark_skin_tone": "⛹🏾\u200d♂️", + "man_bouncing_ball_medium-light_skin_tone": "⛹🏼\u200d♂️", + "man_bouncing_ball_medium_skin_tone": "⛹🏽\u200d♂️", + "man_bowing": "🙇\u200d♂️", + "man_bowing_dark_skin_tone": "🙇🏿\u200d♂️", + "man_bowing_light_skin_tone": "🙇🏻\u200d♂️", + "man_bowing_medium-dark_skin_tone": "🙇🏾\u200d♂️", + "man_bowing_medium-light_skin_tone": "🙇🏼\u200d♂️", + "man_bowing_medium_skin_tone": "🙇🏽\u200d♂️", + "man_cartwheeling": "🤸\u200d♂️", + "man_cartwheeling_dark_skin_tone": "🤸🏿\u200d♂️", + "man_cartwheeling_light_skin_tone": "🤸🏻\u200d♂️", + "man_cartwheeling_medium-dark_skin_tone": "🤸🏾\u200d♂️", + "man_cartwheeling_medium-light_skin_tone": "🤸🏼\u200d♂️", + "man_cartwheeling_medium_skin_tone": "🤸🏽\u200d♂️", + "man_climbing": "🧗\u200d♂️", + "man_climbing_dark_skin_tone": "🧗🏿\u200d♂️", + "man_climbing_light_skin_tone": "🧗🏻\u200d♂️", + "man_climbing_medium-dark_skin_tone": "🧗🏾\u200d♂️", + "man_climbing_medium-light_skin_tone": "🧗🏼\u200d♂️", + "man_climbing_medium_skin_tone": "🧗🏽\u200d♂️", + "man_construction_worker": "👷\u200d♂️", + "man_construction_worker_dark_skin_tone": "👷🏿\u200d♂️", + "man_construction_worker_light_skin_tone": "👷🏻\u200d♂️", + "man_construction_worker_medium-dark_skin_tone": "👷🏾\u200d♂️", + "man_construction_worker_medium-light_skin_tone": "👷🏼\u200d♂️", + "man_construction_worker_medium_skin_tone": "👷🏽\u200d♂️", + "man_cook": "👨\u200d🍳", + "man_cook_dark_skin_tone": "👨🏿\u200d🍳", + "man_cook_light_skin_tone": "👨🏻\u200d🍳", + "man_cook_medium-dark_skin_tone": "👨🏾\u200d🍳", + "man_cook_medium-light_skin_tone": "👨🏼\u200d🍳", + "man_cook_medium_skin_tone": "👨🏽\u200d🍳", + "man_dancing": "🕺", + "man_dancing_dark_skin_tone": "🕺🏿", + "man_dancing_light_skin_tone": "🕺🏻", + "man_dancing_medium-dark_skin_tone": "🕺🏾", + "man_dancing_medium-light_skin_tone": "🕺🏼", + "man_dancing_medium_skin_tone": "🕺🏽", + "man_dark_skin_tone": "👨🏿", + "man_detective": "🕵️\u200d♂️", + "man_detective_dark_skin_tone": "🕵🏿\u200d♂️", + "man_detective_light_skin_tone": "🕵🏻\u200d♂️", + "man_detective_medium-dark_skin_tone": "🕵🏾\u200d♂️", + "man_detective_medium-light_skin_tone": "🕵🏼\u200d♂️", + "man_detective_medium_skin_tone": "🕵🏽\u200d♂️", + "man_elf": "🧝\u200d♂️", + "man_elf_dark_skin_tone": "🧝🏿\u200d♂️", + "man_elf_light_skin_tone": "🧝🏻\u200d♂️", + "man_elf_medium-dark_skin_tone": "🧝🏾\u200d♂️", + "man_elf_medium-light_skin_tone": "🧝🏼\u200d♂️", + "man_elf_medium_skin_tone": "🧝🏽\u200d♂️", + "man_facepalming": "🤦\u200d♂️", + "man_facepalming_dark_skin_tone": "🤦🏿\u200d♂️", + "man_facepalming_light_skin_tone": "🤦🏻\u200d♂️", + "man_facepalming_medium-dark_skin_tone": "🤦🏾\u200d♂️", + "man_facepalming_medium-light_skin_tone": "🤦🏼\u200d♂️", + "man_facepalming_medium_skin_tone": "🤦🏽\u200d♂️", + "man_factory_worker": "👨\u200d🏭", + "man_factory_worker_dark_skin_tone": "👨🏿\u200d🏭", + "man_factory_worker_light_skin_tone": "👨🏻\u200d🏭", + "man_factory_worker_medium-dark_skin_tone": "👨🏾\u200d🏭", + "man_factory_worker_medium-light_skin_tone": "👨🏼\u200d🏭", + "man_factory_worker_medium_skin_tone": "👨🏽\u200d🏭", + "man_fairy": "🧚\u200d♂️", + "man_fairy_dark_skin_tone": "🧚🏿\u200d♂️", + "man_fairy_light_skin_tone": "🧚🏻\u200d♂️", + "man_fairy_medium-dark_skin_tone": "🧚🏾\u200d♂️", + "man_fairy_medium-light_skin_tone": "🧚🏼\u200d♂️", + "man_fairy_medium_skin_tone": "🧚🏽\u200d♂️", + "man_farmer": "👨\u200d🌾", + "man_farmer_dark_skin_tone": "👨🏿\u200d🌾", + "man_farmer_light_skin_tone": "👨🏻\u200d🌾", + "man_farmer_medium-dark_skin_tone": "👨🏾\u200d🌾", + "man_farmer_medium-light_skin_tone": "👨🏼\u200d🌾", + "man_farmer_medium_skin_tone": "👨🏽\u200d🌾", + "man_firefighter": "👨\u200d🚒", + "man_firefighter_dark_skin_tone": "👨🏿\u200d🚒", + "man_firefighter_light_skin_tone": "👨🏻\u200d🚒", + "man_firefighter_medium-dark_skin_tone": "👨🏾\u200d🚒", + "man_firefighter_medium-light_skin_tone": "👨🏼\u200d🚒", + "man_firefighter_medium_skin_tone": "👨🏽\u200d🚒", + "man_frowning": "🙍\u200d♂️", + "man_frowning_dark_skin_tone": "🙍🏿\u200d♂️", + "man_frowning_light_skin_tone": "🙍🏻\u200d♂️", + "man_frowning_medium-dark_skin_tone": "🙍🏾\u200d♂️", + "man_frowning_medium-light_skin_tone": "🙍🏼\u200d♂️", + "man_frowning_medium_skin_tone": "🙍🏽\u200d♂️", + "man_genie": "🧞\u200d♂️", + "man_gesturing_no": "🙅\u200d♂️", + "man_gesturing_no_dark_skin_tone": "🙅🏿\u200d♂️", + "man_gesturing_no_light_skin_tone": "🙅🏻\u200d♂️", + "man_gesturing_no_medium-dark_skin_tone": "🙅🏾\u200d♂️", + "man_gesturing_no_medium-light_skin_tone": "🙅🏼\u200d♂️", + "man_gesturing_no_medium_skin_tone": "🙅🏽\u200d♂️", + "man_gesturing_ok": "🙆\u200d♂️", + "man_gesturing_ok_dark_skin_tone": "🙆🏿\u200d♂️", + "man_gesturing_ok_light_skin_tone": "🙆🏻\u200d♂️", + "man_gesturing_ok_medium-dark_skin_tone": "🙆🏾\u200d♂️", + "man_gesturing_ok_medium-light_skin_tone": "🙆🏼\u200d♂️", + "man_gesturing_ok_medium_skin_tone": "🙆🏽\u200d♂️", + "man_getting_haircut": "💇\u200d♂️", + "man_getting_haircut_dark_skin_tone": "💇🏿\u200d♂️", + "man_getting_haircut_light_skin_tone": "💇🏻\u200d♂️", + "man_getting_haircut_medium-dark_skin_tone": "💇🏾\u200d♂️", + "man_getting_haircut_medium-light_skin_tone": "💇🏼\u200d♂️", + "man_getting_haircut_medium_skin_tone": "💇🏽\u200d♂️", + "man_getting_massage": "💆\u200d♂️", + "man_getting_massage_dark_skin_tone": "💆🏿\u200d♂️", + "man_getting_massage_light_skin_tone": "💆🏻\u200d♂️", + "man_getting_massage_medium-dark_skin_tone": "💆🏾\u200d♂️", + "man_getting_massage_medium-light_skin_tone": "💆🏼\u200d♂️", + "man_getting_massage_medium_skin_tone": "💆🏽\u200d♂️", + "man_golfing": "🏌️\u200d♂️", + "man_golfing_dark_skin_tone": "🏌🏿\u200d♂️", + "man_golfing_light_skin_tone": "🏌🏻\u200d♂️", + "man_golfing_medium-dark_skin_tone": "🏌🏾\u200d♂️", + "man_golfing_medium-light_skin_tone": "🏌🏼\u200d♂️", + "man_golfing_medium_skin_tone": "🏌🏽\u200d♂️", + "man_guard": "💂\u200d♂️", + "man_guard_dark_skin_tone": "💂🏿\u200d♂️", + "man_guard_light_skin_tone": "💂🏻\u200d♂️", + "man_guard_medium-dark_skin_tone": "💂🏾\u200d♂️", + "man_guard_medium-light_skin_tone": "💂🏼\u200d♂️", + "man_guard_medium_skin_tone": "💂🏽\u200d♂️", + "man_health_worker": "👨\u200d⚕️", + "man_health_worker_dark_skin_tone": "👨🏿\u200d⚕️", + "man_health_worker_light_skin_tone": "👨🏻\u200d⚕️", + "man_health_worker_medium-dark_skin_tone": "👨🏾\u200d⚕️", + "man_health_worker_medium-light_skin_tone": "👨🏼\u200d⚕️", + "man_health_worker_medium_skin_tone": "👨🏽\u200d⚕️", + "man_in_lotus_position": "🧘\u200d♂️", + "man_in_lotus_position_dark_skin_tone": "🧘🏿\u200d♂️", + "man_in_lotus_position_light_skin_tone": "🧘🏻\u200d♂️", + "man_in_lotus_position_medium-dark_skin_tone": "🧘🏾\u200d♂️", + "man_in_lotus_position_medium-light_skin_tone": "🧘🏼\u200d♂️", + "man_in_lotus_position_medium_skin_tone": "🧘🏽\u200d♂️", + "man_in_manual_wheelchair": "👨\u200d🦽", + "man_in_motorized_wheelchair": "👨\u200d🦼", + "man_in_steamy_room": "🧖\u200d♂️", + "man_in_steamy_room_dark_skin_tone": "🧖🏿\u200d♂️", + "man_in_steamy_room_light_skin_tone": "🧖🏻\u200d♂️", + "man_in_steamy_room_medium-dark_skin_tone": "🧖🏾\u200d♂️", + "man_in_steamy_room_medium-light_skin_tone": "🧖🏼\u200d♂️", + "man_in_steamy_room_medium_skin_tone": "🧖🏽\u200d♂️", + "man_in_suit_levitating": "🕴", + "man_in_suit_levitating_dark_skin_tone": "🕴🏿", + "man_in_suit_levitating_light_skin_tone": "🕴🏻", + "man_in_suit_levitating_medium-dark_skin_tone": "🕴🏾", + "man_in_suit_levitating_medium-light_skin_tone": "🕴🏼", + "man_in_suit_levitating_medium_skin_tone": "🕴🏽", + "man_in_tuxedo": "🤵", + "man_in_tuxedo_dark_skin_tone": "🤵🏿", + "man_in_tuxedo_light_skin_tone": "🤵🏻", + "man_in_tuxedo_medium-dark_skin_tone": "🤵🏾", + "man_in_tuxedo_medium-light_skin_tone": "🤵🏼", + "man_in_tuxedo_medium_skin_tone": "🤵🏽", + "man_judge": "👨\u200d⚖️", + "man_judge_dark_skin_tone": "👨🏿\u200d⚖️", + "man_judge_light_skin_tone": "👨🏻\u200d⚖️", + "man_judge_medium-dark_skin_tone": "👨🏾\u200d⚖️", + "man_judge_medium-light_skin_tone": "👨🏼\u200d⚖️", + "man_judge_medium_skin_tone": "👨🏽\u200d⚖️", + "man_juggling": "🤹\u200d♂️", + "man_juggling_dark_skin_tone": "🤹🏿\u200d♂️", + "man_juggling_light_skin_tone": "🤹🏻\u200d♂️", + "man_juggling_medium-dark_skin_tone": "🤹🏾\u200d♂️", + "man_juggling_medium-light_skin_tone": "🤹🏼\u200d♂️", + "man_juggling_medium_skin_tone": "🤹🏽\u200d♂️", + "man_lifting_weights": "🏋️\u200d♂️", + "man_lifting_weights_dark_skin_tone": "🏋🏿\u200d♂️", + "man_lifting_weights_light_skin_tone": "🏋🏻\u200d♂️", + "man_lifting_weights_medium-dark_skin_tone": "🏋🏾\u200d♂️", + "man_lifting_weights_medium-light_skin_tone": "🏋🏼\u200d♂️", + "man_lifting_weights_medium_skin_tone": "🏋🏽\u200d♂️", + "man_light_skin_tone": "👨🏻", + "man_mage": "🧙\u200d♂️", + "man_mage_dark_skin_tone": "🧙🏿\u200d♂️", + "man_mage_light_skin_tone": "🧙🏻\u200d♂️", + "man_mage_medium-dark_skin_tone": "🧙🏾\u200d♂️", + "man_mage_medium-light_skin_tone": "🧙🏼\u200d♂️", + "man_mage_medium_skin_tone": "🧙🏽\u200d♂️", + "man_mechanic": "👨\u200d🔧", + "man_mechanic_dark_skin_tone": "👨🏿\u200d🔧", + "man_mechanic_light_skin_tone": "👨🏻\u200d🔧", + "man_mechanic_medium-dark_skin_tone": "👨🏾\u200d🔧", + "man_mechanic_medium-light_skin_tone": "👨🏼\u200d🔧", + "man_mechanic_medium_skin_tone": "👨🏽\u200d🔧", + "man_medium-dark_skin_tone": "👨🏾", + "man_medium-light_skin_tone": "👨🏼", + "man_medium_skin_tone": "👨🏽", + "man_mountain_biking": "🚵\u200d♂️", + "man_mountain_biking_dark_skin_tone": "🚵🏿\u200d♂️", + "man_mountain_biking_light_skin_tone": "🚵🏻\u200d♂️", + "man_mountain_biking_medium-dark_skin_tone": "🚵🏾\u200d♂️", + "man_mountain_biking_medium-light_skin_tone": "🚵🏼\u200d♂️", + "man_mountain_biking_medium_skin_tone": "🚵🏽\u200d♂️", + "man_office_worker": "👨\u200d💼", + "man_office_worker_dark_skin_tone": "👨🏿\u200d💼", + "man_office_worker_light_skin_tone": "👨🏻\u200d💼", + "man_office_worker_medium-dark_skin_tone": "👨🏾\u200d💼", + "man_office_worker_medium-light_skin_tone": "👨🏼\u200d💼", + "man_office_worker_medium_skin_tone": "👨🏽\u200d💼", + "man_pilot": "👨\u200d✈️", + "man_pilot_dark_skin_tone": "👨🏿\u200d✈️", + "man_pilot_light_skin_tone": "👨🏻\u200d✈️", + "man_pilot_medium-dark_skin_tone": "👨🏾\u200d✈️", + "man_pilot_medium-light_skin_tone": "👨🏼\u200d✈️", + "man_pilot_medium_skin_tone": "👨🏽\u200d✈️", + "man_playing_handball": "🤾\u200d♂️", + "man_playing_handball_dark_skin_tone": "🤾🏿\u200d♂️", + "man_playing_handball_light_skin_tone": "🤾🏻\u200d♂️", + "man_playing_handball_medium-dark_skin_tone": "🤾🏾\u200d♂️", + "man_playing_handball_medium-light_skin_tone": "🤾🏼\u200d♂️", + "man_playing_handball_medium_skin_tone": "🤾🏽\u200d♂️", + "man_playing_water_polo": "🤽\u200d♂️", + "man_playing_water_polo_dark_skin_tone": "🤽🏿\u200d♂️", + "man_playing_water_polo_light_skin_tone": "🤽🏻\u200d♂️", + "man_playing_water_polo_medium-dark_skin_tone": "🤽🏾\u200d♂️", + "man_playing_water_polo_medium-light_skin_tone": "🤽🏼\u200d♂️", + "man_playing_water_polo_medium_skin_tone": "🤽🏽\u200d♂️", + "man_police_officer": "👮\u200d♂️", + "man_police_officer_dark_skin_tone": "👮🏿\u200d♂️", + "man_police_officer_light_skin_tone": "👮🏻\u200d♂️", + "man_police_officer_medium-dark_skin_tone": "👮🏾\u200d♂️", + "man_police_officer_medium-light_skin_tone": "👮🏼\u200d♂️", + "man_police_officer_medium_skin_tone": "👮🏽\u200d♂️", + "man_pouting": "🙎\u200d♂️", + "man_pouting_dark_skin_tone": "🙎🏿\u200d♂️", + "man_pouting_light_skin_tone": "🙎🏻\u200d♂️", + "man_pouting_medium-dark_skin_tone": "🙎🏾\u200d♂️", + "man_pouting_medium-light_skin_tone": "🙎🏼\u200d♂️", + "man_pouting_medium_skin_tone": "🙎🏽\u200d♂️", + "man_raising_hand": "🙋\u200d♂️", + "man_raising_hand_dark_skin_tone": "🙋🏿\u200d♂️", + "man_raising_hand_light_skin_tone": "🙋🏻\u200d♂️", + "man_raising_hand_medium-dark_skin_tone": "🙋🏾\u200d♂️", + "man_raising_hand_medium-light_skin_tone": "🙋🏼\u200d♂️", + "man_raising_hand_medium_skin_tone": "🙋🏽\u200d♂️", + "man_rowing_boat": "🚣\u200d♂️", + "man_rowing_boat_dark_skin_tone": "🚣🏿\u200d♂️", + "man_rowing_boat_light_skin_tone": "🚣🏻\u200d♂️", + "man_rowing_boat_medium-dark_skin_tone": "🚣🏾\u200d♂️", + "man_rowing_boat_medium-light_skin_tone": "🚣🏼\u200d♂️", + "man_rowing_boat_medium_skin_tone": "🚣🏽\u200d♂️", + "man_running": "🏃\u200d♂️", + "man_running_dark_skin_tone": "🏃🏿\u200d♂️", + "man_running_light_skin_tone": "🏃🏻\u200d♂️", + "man_running_medium-dark_skin_tone": "🏃🏾\u200d♂️", + "man_running_medium-light_skin_tone": "🏃🏼\u200d♂️", + "man_running_medium_skin_tone": "🏃🏽\u200d♂️", + "man_scientist": "👨\u200d🔬", + "man_scientist_dark_skin_tone": "👨🏿\u200d🔬", + "man_scientist_light_skin_tone": "👨🏻\u200d🔬", + "man_scientist_medium-dark_skin_tone": "👨🏾\u200d🔬", + "man_scientist_medium-light_skin_tone": "👨🏼\u200d🔬", + "man_scientist_medium_skin_tone": "👨🏽\u200d🔬", + "man_shrugging": "🤷\u200d♂️", + "man_shrugging_dark_skin_tone": "🤷🏿\u200d♂️", + "man_shrugging_light_skin_tone": "🤷🏻\u200d♂️", + "man_shrugging_medium-dark_skin_tone": "🤷🏾\u200d♂️", + "man_shrugging_medium-light_skin_tone": "🤷🏼\u200d♂️", + "man_shrugging_medium_skin_tone": "🤷🏽\u200d♂️", + "man_singer": "👨\u200d🎤", + "man_singer_dark_skin_tone": "👨🏿\u200d🎤", + "man_singer_light_skin_tone": "👨🏻\u200d🎤", + "man_singer_medium-dark_skin_tone": "👨🏾\u200d🎤", + "man_singer_medium-light_skin_tone": "👨🏼\u200d🎤", + "man_singer_medium_skin_tone": "👨🏽\u200d🎤", + "man_student": "👨\u200d🎓", + "man_student_dark_skin_tone": "👨🏿\u200d🎓", + "man_student_light_skin_tone": "👨🏻\u200d🎓", + "man_student_medium-dark_skin_tone": "👨🏾\u200d🎓", + "man_student_medium-light_skin_tone": "👨🏼\u200d🎓", + "man_student_medium_skin_tone": "👨🏽\u200d🎓", + "man_surfing": "🏄\u200d♂️", + "man_surfing_dark_skin_tone": "🏄🏿\u200d♂️", + "man_surfing_light_skin_tone": "🏄🏻\u200d♂️", + "man_surfing_medium-dark_skin_tone": "🏄🏾\u200d♂️", + "man_surfing_medium-light_skin_tone": "🏄🏼\u200d♂️", + "man_surfing_medium_skin_tone": "🏄🏽\u200d♂️", + "man_swimming": "🏊\u200d♂️", + "man_swimming_dark_skin_tone": "🏊🏿\u200d♂️", + "man_swimming_light_skin_tone": "🏊🏻\u200d♂️", + "man_swimming_medium-dark_skin_tone": "🏊🏾\u200d♂️", + "man_swimming_medium-light_skin_tone": "🏊🏼\u200d♂️", + "man_swimming_medium_skin_tone": "🏊🏽\u200d♂️", + "man_teacher": "👨\u200d🏫", + "man_teacher_dark_skin_tone": "👨🏿\u200d🏫", + "man_teacher_light_skin_tone": "👨🏻\u200d🏫", + "man_teacher_medium-dark_skin_tone": "👨🏾\u200d🏫", + "man_teacher_medium-light_skin_tone": "👨🏼\u200d🏫", + "man_teacher_medium_skin_tone": "👨🏽\u200d🏫", + "man_technologist": "👨\u200d💻", + "man_technologist_dark_skin_tone": "👨🏿\u200d💻", + "man_technologist_light_skin_tone": "👨🏻\u200d💻", + "man_technologist_medium-dark_skin_tone": "👨🏾\u200d💻", + "man_technologist_medium-light_skin_tone": "👨🏼\u200d💻", + "man_technologist_medium_skin_tone": "👨🏽\u200d💻", + "man_tipping_hand": "💁\u200d♂️", + "man_tipping_hand_dark_skin_tone": "💁🏿\u200d♂️", + "man_tipping_hand_light_skin_tone": "💁🏻\u200d♂️", + "man_tipping_hand_medium-dark_skin_tone": "💁🏾\u200d♂️", + "man_tipping_hand_medium-light_skin_tone": "💁🏼\u200d♂️", + "man_tipping_hand_medium_skin_tone": "💁🏽\u200d♂️", + "man_vampire": "🧛\u200d♂️", + "man_vampire_dark_skin_tone": "🧛🏿\u200d♂️", + "man_vampire_light_skin_tone": "🧛🏻\u200d♂️", + "man_vampire_medium-dark_skin_tone": "🧛🏾\u200d♂️", + "man_vampire_medium-light_skin_tone": "🧛🏼\u200d♂️", + "man_vampire_medium_skin_tone": "🧛🏽\u200d♂️", + "man_walking": "🚶\u200d♂️", + "man_walking_dark_skin_tone": "🚶🏿\u200d♂️", + "man_walking_light_skin_tone": "🚶🏻\u200d♂️", + "man_walking_medium-dark_skin_tone": "🚶🏾\u200d♂️", + "man_walking_medium-light_skin_tone": "🚶🏼\u200d♂️", + "man_walking_medium_skin_tone": "🚶🏽\u200d♂️", + "man_wearing_turban": "👳\u200d♂️", + "man_wearing_turban_dark_skin_tone": "👳🏿\u200d♂️", + "man_wearing_turban_light_skin_tone": "👳🏻\u200d♂️", + "man_wearing_turban_medium-dark_skin_tone": "👳🏾\u200d♂️", + "man_wearing_turban_medium-light_skin_tone": "👳🏼\u200d♂️", + "man_wearing_turban_medium_skin_tone": "👳🏽\u200d♂️", + "man_with_probing_cane": "👨\u200d🦯", + "man_with_chinese_cap": "👲", + "man_with_chinese_cap_dark_skin_tone": "👲🏿", + "man_with_chinese_cap_light_skin_tone": "👲🏻", + "man_with_chinese_cap_medium-dark_skin_tone": "👲🏾", + "man_with_chinese_cap_medium-light_skin_tone": "👲🏼", + "man_with_chinese_cap_medium_skin_tone": "👲🏽", + "man_zombie": "🧟\u200d♂️", + "mango": "🥭", + "mantelpiece_clock": "🕰", + "manual_wheelchair": "🦽", + "man’s_shoe": "👞", + "map_of_japan": "🗾", + "maple_leaf": "🍁", + "martial_arts_uniform": "🥋", + "mate": "🧉", + "meat_on_bone": "🍖", + "mechanical_arm": "🦾", + "mechanical_leg": "🦿", + "medical_symbol": "⚕", + "megaphone": "📣", + "melon": "🍈", + "memo": "📝", + "men_with_bunny_ears": "👯\u200d♂️", + "men_wrestling": "🤼\u200d♂️", + "menorah": "🕎", + "men’s_room": "🚹", + "mermaid": "🧜\u200d♀️", + "mermaid_dark_skin_tone": "🧜🏿\u200d♀️", + "mermaid_light_skin_tone": "🧜🏻\u200d♀️", + "mermaid_medium-dark_skin_tone": "🧜🏾\u200d♀️", + "mermaid_medium-light_skin_tone": "🧜🏼\u200d♀️", + "mermaid_medium_skin_tone": "🧜🏽\u200d♀️", + "merman": "🧜\u200d♂️", + "merman_dark_skin_tone": "🧜🏿\u200d♂️", + "merman_light_skin_tone": "🧜🏻\u200d♂️", + "merman_medium-dark_skin_tone": "🧜🏾\u200d♂️", + "merman_medium-light_skin_tone": "🧜🏼\u200d♂️", + "merman_medium_skin_tone": "🧜🏽\u200d♂️", + "merperson": "🧜", + "merperson_dark_skin_tone": "🧜🏿", + "merperson_light_skin_tone": "🧜🏻", + "merperson_medium-dark_skin_tone": "🧜🏾", + "merperson_medium-light_skin_tone": "🧜🏼", + "merperson_medium_skin_tone": "🧜🏽", + "metro": "🚇", + "microbe": "🦠", + "microphone": "🎤", + "microscope": "🔬", + "middle_finger": "🖕", + "middle_finger_dark_skin_tone": "🖕🏿", + "middle_finger_light_skin_tone": "🖕🏻", + "middle_finger_medium-dark_skin_tone": "🖕🏾", + "middle_finger_medium-light_skin_tone": "🖕🏼", + "middle_finger_medium_skin_tone": "🖕🏽", + "military_medal": "🎖", + "milky_way": "🌌", + "minibus": "🚐", + "moai": "🗿", + "mobile_phone": "📱", + "mobile_phone_off": "📴", + "mobile_phone_with_arrow": "📲", + "money-mouth_face": "🤑", + "money_bag": "💰", + "money_with_wings": "💸", + "monkey": "🐒", + "monkey_face": "🐵", + "monorail": "🚝", + "moon_cake": "🥮", + "moon_viewing_ceremony": "🎑", + "mosque": "🕌", + "mosquito": "🦟", + "motor_boat": "🛥", + "motor_scooter": "🛵", + "motorcycle": "🏍", + "motorized_wheelchair": "🦼", + "motorway": "🛣", + "mount_fuji": "🗻", + "mountain": "⛰", + "mountain_cableway": "🚠", + "mountain_railway": "🚞", + "mouse": "🐭", + "mouse_face": "🐭", + "mouth": "👄", + "movie_camera": "🎥", + "mushroom": "🍄", + "musical_keyboard": "🎹", + "musical_note": "🎵", + "musical_notes": "🎶", + "musical_score": "🎼", + "muted_speaker": "🔇", + "nail_polish": "💅", + "nail_polish_dark_skin_tone": "💅🏿", + "nail_polish_light_skin_tone": "💅🏻", + "nail_polish_medium-dark_skin_tone": "💅🏾", + "nail_polish_medium-light_skin_tone": "💅🏼", + "nail_polish_medium_skin_tone": "💅🏽", + "name_badge": "📛", + "national_park": "🏞", + "nauseated_face": "🤢", + "nazar_amulet": "🧿", + "necktie": "👔", + "nerd_face": "🤓", + "neutral_face": "😐", + "new_moon": "🌑", + "new_moon_face": "🌚", + "newspaper": "📰", + "next_track_button": "⏭", + "night_with_stars": "🌃", + "nine-thirty": "🕤", + "nine_o’clock": "🕘", + "no_bicycles": "🚳", + "no_entry": "⛔", + "no_littering": "🚯", + "no_mobile_phones": "📵", + "no_one_under_eighteen": "🔞", + "no_pedestrians": "🚷", + "no_smoking": "🚭", + "non-potable_water": "🚱", + "nose": "👃", + "nose_dark_skin_tone": "👃🏿", + "nose_light_skin_tone": "👃🏻", + "nose_medium-dark_skin_tone": "👃🏾", + "nose_medium-light_skin_tone": "👃🏼", + "nose_medium_skin_tone": "👃🏽", + "notebook": "📓", + "notebook_with_decorative_cover": "📔", + "nut_and_bolt": "🔩", + "octopus": "🐙", + "oden": "🍢", + "office_building": "🏢", + "ogre": "👹", + "oil_drum": "🛢", + "old_key": "🗝", + "old_man": "👴", + "old_man_dark_skin_tone": "👴🏿", + "old_man_light_skin_tone": "👴🏻", + "old_man_medium-dark_skin_tone": "👴🏾", + "old_man_medium-light_skin_tone": "👴🏼", + "old_man_medium_skin_tone": "👴🏽", + "old_woman": "👵", + "old_woman_dark_skin_tone": "👵🏿", + "old_woman_light_skin_tone": "👵🏻", + "old_woman_medium-dark_skin_tone": "👵🏾", + "old_woman_medium-light_skin_tone": "👵🏼", + "old_woman_medium_skin_tone": "👵🏽", + "older_adult": "🧓", + "older_adult_dark_skin_tone": "🧓🏿", + "older_adult_light_skin_tone": "🧓🏻", + "older_adult_medium-dark_skin_tone": "🧓🏾", + "older_adult_medium-light_skin_tone": "🧓🏼", + "older_adult_medium_skin_tone": "🧓🏽", + "om": "🕉", + "oncoming_automobile": "🚘", + "oncoming_bus": "🚍", + "oncoming_fist": "👊", + "oncoming_fist_dark_skin_tone": "👊🏿", + "oncoming_fist_light_skin_tone": "👊🏻", + "oncoming_fist_medium-dark_skin_tone": "👊🏾", + "oncoming_fist_medium-light_skin_tone": "👊🏼", + "oncoming_fist_medium_skin_tone": "👊🏽", + "oncoming_police_car": "🚔", + "oncoming_taxi": "🚖", + "one-piece_swimsuit": "🩱", + "one-thirty": "🕜", + "one_o’clock": "🕐", + "onion": "🧅", + "open_book": "📖", + "open_file_folder": "📂", + "open_hands": "👐", + "open_hands_dark_skin_tone": "👐🏿", + "open_hands_light_skin_tone": "👐🏻", + "open_hands_medium-dark_skin_tone": "👐🏾", + "open_hands_medium-light_skin_tone": "👐🏼", + "open_hands_medium_skin_tone": "👐🏽", + "open_mailbox_with_lowered_flag": "📭", + "open_mailbox_with_raised_flag": "📬", + "optical_disk": "💿", + "orange_book": "📙", + "orange_circle": "🟠", + "orange_heart": "🧡", + "orange_square": "🟧", + "orangutan": "🦧", + "orthodox_cross": "☦", + "otter": "🦦", + "outbox_tray": "📤", + "owl": "🦉", + "ox": "🐂", + "oyster": "🦪", + "package": "📦", + "page_facing_up": "📄", + "page_with_curl": "📃", + "pager": "📟", + "paintbrush": "🖌", + "palm_tree": "🌴", + "palms_up_together": "🤲", + "palms_up_together_dark_skin_tone": "🤲🏿", + "palms_up_together_light_skin_tone": "🤲🏻", + "palms_up_together_medium-dark_skin_tone": "🤲🏾", + "palms_up_together_medium-light_skin_tone": "🤲🏼", + "palms_up_together_medium_skin_tone": "🤲🏽", + "pancakes": "🥞", + "panda_face": "🐼", + "paperclip": "📎", + "parrot": "🦜", + "part_alternation_mark": "〽", + "party_popper": "🎉", + "partying_face": "🥳", + "passenger_ship": "🛳", + "passport_control": "🛂", + "pause_button": "⏸", + "paw_prints": "🐾", + "peace_symbol": "☮", + "peach": "🍑", + "peacock": "🦚", + "peanuts": "🥜", + "pear": "🍐", + "pen": "🖊", + "pencil": "📝", + "penguin": "🐧", + "pensive_face": "😔", + "people_holding_hands": "🧑\u200d🤝\u200d🧑", + "people_with_bunny_ears": "👯", + "people_wrestling": "🤼", + "performing_arts": "🎭", + "persevering_face": "😣", + "person_biking": "🚴", + "person_biking_dark_skin_tone": "🚴🏿", + "person_biking_light_skin_tone": "🚴🏻", + "person_biking_medium-dark_skin_tone": "🚴🏾", + "person_biking_medium-light_skin_tone": "🚴🏼", + "person_biking_medium_skin_tone": "🚴🏽", + "person_bouncing_ball": "⛹", + "person_bouncing_ball_dark_skin_tone": "⛹🏿", + "person_bouncing_ball_light_skin_tone": "⛹🏻", + "person_bouncing_ball_medium-dark_skin_tone": "⛹🏾", + "person_bouncing_ball_medium-light_skin_tone": "⛹🏼", + "person_bouncing_ball_medium_skin_tone": "⛹🏽", + "person_bowing": "🙇", + "person_bowing_dark_skin_tone": "🙇🏿", + "person_bowing_light_skin_tone": "🙇🏻", + "person_bowing_medium-dark_skin_tone": "🙇🏾", + "person_bowing_medium-light_skin_tone": "🙇🏼", + "person_bowing_medium_skin_tone": "🙇🏽", + "person_cartwheeling": "🤸", + "person_cartwheeling_dark_skin_tone": "🤸🏿", + "person_cartwheeling_light_skin_tone": "🤸🏻", + "person_cartwheeling_medium-dark_skin_tone": "🤸🏾", + "person_cartwheeling_medium-light_skin_tone": "🤸🏼", + "person_cartwheeling_medium_skin_tone": "🤸🏽", + "person_climbing": "🧗", + "person_climbing_dark_skin_tone": "🧗🏿", + "person_climbing_light_skin_tone": "🧗🏻", + "person_climbing_medium-dark_skin_tone": "🧗🏾", + "person_climbing_medium-light_skin_tone": "🧗🏼", + "person_climbing_medium_skin_tone": "🧗🏽", + "person_facepalming": "🤦", + "person_facepalming_dark_skin_tone": "🤦🏿", + "person_facepalming_light_skin_tone": "🤦🏻", + "person_facepalming_medium-dark_skin_tone": "🤦🏾", + "person_facepalming_medium-light_skin_tone": "🤦🏼", + "person_facepalming_medium_skin_tone": "🤦🏽", + "person_fencing": "🤺", + "person_frowning": "🙍", + "person_frowning_dark_skin_tone": "🙍🏿", + "person_frowning_light_skin_tone": "🙍🏻", + "person_frowning_medium-dark_skin_tone": "🙍🏾", + "person_frowning_medium-light_skin_tone": "🙍🏼", + "person_frowning_medium_skin_tone": "🙍🏽", + "person_gesturing_no": "🙅", + "person_gesturing_no_dark_skin_tone": "🙅🏿", + "person_gesturing_no_light_skin_tone": "🙅🏻", + "person_gesturing_no_medium-dark_skin_tone": "🙅🏾", + "person_gesturing_no_medium-light_skin_tone": "🙅🏼", + "person_gesturing_no_medium_skin_tone": "🙅🏽", + "person_gesturing_ok": "🙆", + "person_gesturing_ok_dark_skin_tone": "🙆🏿", + "person_gesturing_ok_light_skin_tone": "🙆🏻", + "person_gesturing_ok_medium-dark_skin_tone": "🙆🏾", + "person_gesturing_ok_medium-light_skin_tone": "🙆🏼", + "person_gesturing_ok_medium_skin_tone": "🙆🏽", + "person_getting_haircut": "💇", + "person_getting_haircut_dark_skin_tone": "💇🏿", + "person_getting_haircut_light_skin_tone": "💇🏻", + "person_getting_haircut_medium-dark_skin_tone": "💇🏾", + "person_getting_haircut_medium-light_skin_tone": "💇🏼", + "person_getting_haircut_medium_skin_tone": "💇🏽", + "person_getting_massage": "💆", + "person_getting_massage_dark_skin_tone": "💆🏿", + "person_getting_massage_light_skin_tone": "💆🏻", + "person_getting_massage_medium-dark_skin_tone": "💆🏾", + "person_getting_massage_medium-light_skin_tone": "💆🏼", + "person_getting_massage_medium_skin_tone": "💆🏽", + "person_golfing": "🏌", + "person_golfing_dark_skin_tone": "🏌🏿", + "person_golfing_light_skin_tone": "🏌🏻", + "person_golfing_medium-dark_skin_tone": "🏌🏾", + "person_golfing_medium-light_skin_tone": "🏌🏼", + "person_golfing_medium_skin_tone": "🏌🏽", + "person_in_bed": "🛌", + "person_in_bed_dark_skin_tone": "🛌🏿", + "person_in_bed_light_skin_tone": "🛌🏻", + "person_in_bed_medium-dark_skin_tone": "🛌🏾", + "person_in_bed_medium-light_skin_tone": "🛌🏼", + "person_in_bed_medium_skin_tone": "🛌🏽", + "person_in_lotus_position": "🧘", + "person_in_lotus_position_dark_skin_tone": "🧘🏿", + "person_in_lotus_position_light_skin_tone": "🧘🏻", + "person_in_lotus_position_medium-dark_skin_tone": "🧘🏾", + "person_in_lotus_position_medium-light_skin_tone": "🧘🏼", + "person_in_lotus_position_medium_skin_tone": "🧘🏽", + "person_in_steamy_room": "🧖", + "person_in_steamy_room_dark_skin_tone": "🧖🏿", + "person_in_steamy_room_light_skin_tone": "🧖🏻", + "person_in_steamy_room_medium-dark_skin_tone": "🧖🏾", + "person_in_steamy_room_medium-light_skin_tone": "🧖🏼", + "person_in_steamy_room_medium_skin_tone": "🧖🏽", + "person_juggling": "🤹", + "person_juggling_dark_skin_tone": "🤹🏿", + "person_juggling_light_skin_tone": "🤹🏻", + "person_juggling_medium-dark_skin_tone": "🤹🏾", + "person_juggling_medium-light_skin_tone": "🤹🏼", + "person_juggling_medium_skin_tone": "🤹🏽", + "person_kneeling": "🧎", + "person_lifting_weights": "🏋", + "person_lifting_weights_dark_skin_tone": "🏋🏿", + "person_lifting_weights_light_skin_tone": "🏋🏻", + "person_lifting_weights_medium-dark_skin_tone": "🏋🏾", + "person_lifting_weights_medium-light_skin_tone": "🏋🏼", + "person_lifting_weights_medium_skin_tone": "🏋🏽", + "person_mountain_biking": "🚵", + "person_mountain_biking_dark_skin_tone": "🚵🏿", + "person_mountain_biking_light_skin_tone": "🚵🏻", + "person_mountain_biking_medium-dark_skin_tone": "🚵🏾", + "person_mountain_biking_medium-light_skin_tone": "🚵🏼", + "person_mountain_biking_medium_skin_tone": "🚵🏽", + "person_playing_handball": "🤾", + "person_playing_handball_dark_skin_tone": "🤾🏿", + "person_playing_handball_light_skin_tone": "🤾🏻", + "person_playing_handball_medium-dark_skin_tone": "🤾🏾", + "person_playing_handball_medium-light_skin_tone": "🤾🏼", + "person_playing_handball_medium_skin_tone": "🤾🏽", + "person_playing_water_polo": "🤽", + "person_playing_water_polo_dark_skin_tone": "🤽🏿", + "person_playing_water_polo_light_skin_tone": "🤽🏻", + "person_playing_water_polo_medium-dark_skin_tone": "🤽🏾", + "person_playing_water_polo_medium-light_skin_tone": "🤽🏼", + "person_playing_water_polo_medium_skin_tone": "🤽🏽", + "person_pouting": "🙎", + "person_pouting_dark_skin_tone": "🙎🏿", + "person_pouting_light_skin_tone": "🙎🏻", + "person_pouting_medium-dark_skin_tone": "🙎🏾", + "person_pouting_medium-light_skin_tone": "🙎🏼", + "person_pouting_medium_skin_tone": "🙎🏽", + "person_raising_hand": "🙋", + "person_raising_hand_dark_skin_tone": "🙋🏿", + "person_raising_hand_light_skin_tone": "🙋🏻", + "person_raising_hand_medium-dark_skin_tone": "🙋🏾", + "person_raising_hand_medium-light_skin_tone": "🙋🏼", + "person_raising_hand_medium_skin_tone": "🙋🏽", + "person_rowing_boat": "🚣", + "person_rowing_boat_dark_skin_tone": "🚣🏿", + "person_rowing_boat_light_skin_tone": "🚣🏻", + "person_rowing_boat_medium-dark_skin_tone": "🚣🏾", + "person_rowing_boat_medium-light_skin_tone": "🚣🏼", + "person_rowing_boat_medium_skin_tone": "🚣🏽", + "person_running": "🏃", + "person_running_dark_skin_tone": "🏃🏿", + "person_running_light_skin_tone": "🏃🏻", + "person_running_medium-dark_skin_tone": "🏃🏾", + "person_running_medium-light_skin_tone": "🏃🏼", + "person_running_medium_skin_tone": "🏃🏽", + "person_shrugging": "🤷", + "person_shrugging_dark_skin_tone": "🤷🏿", + "person_shrugging_light_skin_tone": "🤷🏻", + "person_shrugging_medium-dark_skin_tone": "🤷🏾", + "person_shrugging_medium-light_skin_tone": "🤷🏼", + "person_shrugging_medium_skin_tone": "🤷🏽", + "person_standing": "🧍", + "person_surfing": "🏄", + "person_surfing_dark_skin_tone": "🏄🏿", + "person_surfing_light_skin_tone": "🏄🏻", + "person_surfing_medium-dark_skin_tone": "🏄🏾", + "person_surfing_medium-light_skin_tone": "🏄🏼", + "person_surfing_medium_skin_tone": "🏄🏽", + "person_swimming": "🏊", + "person_swimming_dark_skin_tone": "🏊🏿", + "person_swimming_light_skin_tone": "🏊🏻", + "person_swimming_medium-dark_skin_tone": "🏊🏾", + "person_swimming_medium-light_skin_tone": "🏊🏼", + "person_swimming_medium_skin_tone": "🏊🏽", + "person_taking_bath": "🛀", + "person_taking_bath_dark_skin_tone": "🛀🏿", + "person_taking_bath_light_skin_tone": "🛀🏻", + "person_taking_bath_medium-dark_skin_tone": "🛀🏾", + "person_taking_bath_medium-light_skin_tone": "🛀🏼", + "person_taking_bath_medium_skin_tone": "🛀🏽", + "person_tipping_hand": "💁", + "person_tipping_hand_dark_skin_tone": "💁🏿", + "person_tipping_hand_light_skin_tone": "💁🏻", + "person_tipping_hand_medium-dark_skin_tone": "💁🏾", + "person_tipping_hand_medium-light_skin_tone": "💁🏼", + "person_tipping_hand_medium_skin_tone": "💁🏽", + "person_walking": "🚶", + "person_walking_dark_skin_tone": "🚶🏿", + "person_walking_light_skin_tone": "🚶🏻", + "person_walking_medium-dark_skin_tone": "🚶🏾", + "person_walking_medium-light_skin_tone": "🚶🏼", + "person_walking_medium_skin_tone": "🚶🏽", + "person_wearing_turban": "👳", + "person_wearing_turban_dark_skin_tone": "👳🏿", + "person_wearing_turban_light_skin_tone": "👳🏻", + "person_wearing_turban_medium-dark_skin_tone": "👳🏾", + "person_wearing_turban_medium-light_skin_tone": "👳🏼", + "person_wearing_turban_medium_skin_tone": "👳🏽", + "petri_dish": "🧫", + "pick": "⛏", + "pie": "🥧", + "pig": "🐷", + "pig_face": "🐷", + "pig_nose": "🐽", + "pile_of_poo": "💩", + "pill": "💊", + "pinching_hand": "🤏", + "pine_decoration": "🎍", + "pineapple": "🍍", + "ping_pong": "🏓", + "pirate_flag": "🏴\u200d☠️", + "pistol": "🔫", + "pizza": "🍕", + "place_of_worship": "🛐", + "play_button": "▶", + "play_or_pause_button": "⏯", + "pleading_face": "🥺", + "police_car": "🚓", + "police_car_light": "🚨", + "police_officer": "👮", + "police_officer_dark_skin_tone": "👮🏿", + "police_officer_light_skin_tone": "👮🏻", + "police_officer_medium-dark_skin_tone": "👮🏾", + "police_officer_medium-light_skin_tone": "👮🏼", + "police_officer_medium_skin_tone": "👮🏽", + "poodle": "🐩", + "pool_8_ball": "🎱", + "popcorn": "🍿", + "post_office": "🏣", + "postal_horn": "📯", + "postbox": "📮", + "pot_of_food": "🍲", + "potable_water": "🚰", + "potato": "🥔", + "poultry_leg": "🍗", + "pound_banknote": "💷", + "pouting_cat_face": "😾", + "pouting_face": "😡", + "prayer_beads": "📿", + "pregnant_woman": "🤰", + "pregnant_woman_dark_skin_tone": "🤰🏿", + "pregnant_woman_light_skin_tone": "🤰🏻", + "pregnant_woman_medium-dark_skin_tone": "🤰🏾", + "pregnant_woman_medium-light_skin_tone": "🤰🏼", + "pregnant_woman_medium_skin_tone": "🤰🏽", + "pretzel": "🥨", + "probing_cane": "🦯", + "prince": "🤴", + "prince_dark_skin_tone": "🤴🏿", + "prince_light_skin_tone": "🤴🏻", + "prince_medium-dark_skin_tone": "🤴🏾", + "prince_medium-light_skin_tone": "🤴🏼", + "prince_medium_skin_tone": "🤴🏽", + "princess": "👸", + "princess_dark_skin_tone": "👸🏿", + "princess_light_skin_tone": "👸🏻", + "princess_medium-dark_skin_tone": "👸🏾", + "princess_medium-light_skin_tone": "👸🏼", + "princess_medium_skin_tone": "👸🏽", + "printer": "🖨", + "prohibited": "🚫", + "purple_circle": "🟣", + "purple_heart": "💜", + "purple_square": "🟪", + "purse": "👛", + "pushpin": "📌", + "question_mark": "❓", + "rabbit": "🐰", + "rabbit_face": "🐰", + "raccoon": "🦝", + "racing_car": "🏎", + "radio": "📻", + "radio_button": "🔘", + "radioactive": "☢", + "railway_car": "🚃", + "railway_track": "🛤", + "rainbow": "🌈", + "rainbow_flag": "🏳️\u200d🌈", + "raised_back_of_hand": "🤚", + "raised_back_of_hand_dark_skin_tone": "🤚🏿", + "raised_back_of_hand_light_skin_tone": "🤚🏻", + "raised_back_of_hand_medium-dark_skin_tone": "🤚🏾", + "raised_back_of_hand_medium-light_skin_tone": "🤚🏼", + "raised_back_of_hand_medium_skin_tone": "🤚🏽", + "raised_fist": "✊", + "raised_fist_dark_skin_tone": "✊🏿", + "raised_fist_light_skin_tone": "✊🏻", + "raised_fist_medium-dark_skin_tone": "✊🏾", + "raised_fist_medium-light_skin_tone": "✊🏼", + "raised_fist_medium_skin_tone": "✊🏽", + "raised_hand": "✋", + "raised_hand_dark_skin_tone": "✋🏿", + "raised_hand_light_skin_tone": "✋🏻", + "raised_hand_medium-dark_skin_tone": "✋🏾", + "raised_hand_medium-light_skin_tone": "✋🏼", + "raised_hand_medium_skin_tone": "✋🏽", + "raising_hands": "🙌", + "raising_hands_dark_skin_tone": "🙌🏿", + "raising_hands_light_skin_tone": "🙌🏻", + "raising_hands_medium-dark_skin_tone": "🙌🏾", + "raising_hands_medium-light_skin_tone": "🙌🏼", + "raising_hands_medium_skin_tone": "🙌🏽", + "ram": "🐏", + "rat": "🐀", + "razor": "🪒", + "ringed_planet": "🪐", + "receipt": "🧾", + "record_button": "⏺", + "recycling_symbol": "♻", + "red_apple": "🍎", + "red_circle": "🔴", + "red_envelope": "🧧", + "red_hair": "🦰", + "red-haired_man": "👨\u200d🦰", + "red-haired_woman": "👩\u200d🦰", + "red_heart": "❤", + "red_paper_lantern": "🏮", + "red_square": "🟥", + "red_triangle_pointed_down": "🔻", + "red_triangle_pointed_up": "🔺", + "registered": "®", + "relieved_face": "😌", + "reminder_ribbon": "🎗", + "repeat_button": "🔁", + "repeat_single_button": "🔂", + "rescue_worker’s_helmet": "⛑", + "restroom": "🚻", + "reverse_button": "◀", + "revolving_hearts": "💞", + "rhinoceros": "🦏", + "ribbon": "🎀", + "rice_ball": "🍙", + "rice_cracker": "🍘", + "right-facing_fist": "🤜", + "right-facing_fist_dark_skin_tone": "🤜🏿", + "right-facing_fist_light_skin_tone": "🤜🏻", + "right-facing_fist_medium-dark_skin_tone": "🤜🏾", + "right-facing_fist_medium-light_skin_tone": "🤜🏼", + "right-facing_fist_medium_skin_tone": "🤜🏽", + "right_anger_bubble": "🗯", + "right_arrow": "➡", + "right_arrow_curving_down": "⤵", + "right_arrow_curving_left": "↩", + "right_arrow_curving_up": "⤴", + "ring": "💍", + "roasted_sweet_potato": "🍠", + "robot_face": "🤖", + "rocket": "🚀", + "roll_of_paper": "🧻", + "rolled-up_newspaper": "🗞", + "roller_coaster": "🎢", + "rolling_on_the_floor_laughing": "🤣", + "rooster": "🐓", + "rose": "🌹", + "rosette": "🏵", + "round_pushpin": "📍", + "rugby_football": "🏉", + "running_shirt": "🎽", + "running_shoe": "👟", + "sad_but_relieved_face": "😥", + "safety_pin": "🧷", + "safety_vest": "🦺", + "salt": "🧂", + "sailboat": "⛵", + "sake": "🍶", + "sandwich": "🥪", + "sari": "🥻", + "satellite": "📡", + "satellite_antenna": "📡", + "sauropod": "🦕", + "saxophone": "🎷", + "scarf": "🧣", + "school": "🏫", + "school_backpack": "🎒", + "scissors": "✂", + "scorpion": "🦂", + "scroll": "📜", + "seat": "💺", + "see-no-evil_monkey": "🙈", + "seedling": "🌱", + "selfie": "🤳", + "selfie_dark_skin_tone": "🤳🏿", + "selfie_light_skin_tone": "🤳🏻", + "selfie_medium-dark_skin_tone": "🤳🏾", + "selfie_medium-light_skin_tone": "🤳🏼", + "selfie_medium_skin_tone": "🤳🏽", + "service_dog": "🐕\u200d🦺", + "seven-thirty": "🕢", + "seven_o’clock": "🕖", + "shallow_pan_of_food": "🥘", + "shamrock": "☘", + "shark": "🦈", + "shaved_ice": "🍧", + "sheaf_of_rice": "🌾", + "shield": "🛡", + "shinto_shrine": "⛩", + "ship": "🚢", + "shooting_star": "🌠", + "shopping_bags": "🛍", + "shopping_cart": "🛒", + "shortcake": "🍰", + "shorts": "🩳", + "shower": "🚿", + "shrimp": "🦐", + "shuffle_tracks_button": "🔀", + "shushing_face": "🤫", + "sign_of_the_horns": "🤘", + "sign_of_the_horns_dark_skin_tone": "🤘🏿", + "sign_of_the_horns_light_skin_tone": "🤘🏻", + "sign_of_the_horns_medium-dark_skin_tone": "🤘🏾", + "sign_of_the_horns_medium-light_skin_tone": "🤘🏼", + "sign_of_the_horns_medium_skin_tone": "🤘🏽", + "six-thirty": "🕡", + "six_o’clock": "🕕", + "skateboard": "🛹", + "skier": "⛷", + "skis": "🎿", + "skull": "💀", + "skull_and_crossbones": "☠", + "skunk": "🦨", + "sled": "🛷", + "sleeping_face": "😴", + "sleepy_face": "😪", + "slightly_frowning_face": "🙁", + "slightly_smiling_face": "🙂", + "slot_machine": "🎰", + "sloth": "🦥", + "small_airplane": "🛩", + "small_blue_diamond": "🔹", + "small_orange_diamond": "🔸", + "smiling_cat_face_with_heart-eyes": "😻", + "smiling_face": "☺", + "smiling_face_with_halo": "😇", + "smiling_face_with_3_hearts": "🥰", + "smiling_face_with_heart-eyes": "😍", + "smiling_face_with_horns": "😈", + "smiling_face_with_smiling_eyes": "😊", + "smiling_face_with_sunglasses": "😎", + "smirking_face": "😏", + "snail": "🐌", + "snake": "🐍", + "sneezing_face": "🤧", + "snow-capped_mountain": "🏔", + "snowboarder": "🏂", + "snowboarder_dark_skin_tone": "🏂🏿", + "snowboarder_light_skin_tone": "🏂🏻", + "snowboarder_medium-dark_skin_tone": "🏂🏾", + "snowboarder_medium-light_skin_tone": "🏂🏼", + "snowboarder_medium_skin_tone": "🏂🏽", + "snowflake": "❄", + "snowman": "☃", + "snowman_without_snow": "⛄", + "soap": "🧼", + "soccer_ball": "⚽", + "socks": "🧦", + "softball": "🥎", + "soft_ice_cream": "🍦", + "spade_suit": "♠", + "spaghetti": "🍝", + "sparkle": "❇", + "sparkler": "🎇", + "sparkles": "✨", + "sparkling_heart": "💖", + "speak-no-evil_monkey": "🙊", + "speaker_high_volume": "🔊", + "speaker_low_volume": "🔈", + "speaker_medium_volume": "🔉", + "speaking_head": "🗣", + "speech_balloon": "💬", + "speedboat": "🚤", + "spider": "🕷", + "spider_web": "🕸", + "spiral_calendar": "🗓", + "spiral_notepad": "🗒", + "spiral_shell": "🐚", + "spoon": "🥄", + "sponge": "🧽", + "sport_utility_vehicle": "🚙", + "sports_medal": "🏅", + "spouting_whale": "🐳", + "squid": "🦑", + "squinting_face_with_tongue": "😝", + "stadium": "🏟", + "star-struck": "🤩", + "star_and_crescent": "☪", + "star_of_david": "✡", + "station": "🚉", + "steaming_bowl": "🍜", + "stethoscope": "🩺", + "stop_button": "⏹", + "stop_sign": "🛑", + "stopwatch": "⏱", + "straight_ruler": "📏", + "strawberry": "🍓", + "studio_microphone": "🎙", + "stuffed_flatbread": "🥙", + "sun": "☀", + "sun_behind_cloud": "⛅", + "sun_behind_large_cloud": "🌥", + "sun_behind_rain_cloud": "🌦", + "sun_behind_small_cloud": "🌤", + "sun_with_face": "🌞", + "sunflower": "🌻", + "sunglasses": "😎", + "sunrise": "🌅", + "sunrise_over_mountains": "🌄", + "sunset": "🌇", + "superhero": "🦸", + "supervillain": "🦹", + "sushi": "🍣", + "suspension_railway": "🚟", + "swan": "🦢", + "sweat_droplets": "💦", + "synagogue": "🕍", + "syringe": "💉", + "t-shirt": "👕", + "taco": "🌮", + "takeout_box": "🥡", + "tanabata_tree": "🎋", + "tangerine": "🍊", + "taxi": "🚕", + "teacup_without_handle": "🍵", + "tear-off_calendar": "📆", + "teddy_bear": "🧸", + "telephone": "☎", + "telephone_receiver": "📞", + "telescope": "🔭", + "television": "📺", + "ten-thirty": "🕥", + "ten_o’clock": "🕙", + "tennis": "🎾", + "tent": "⛺", + "test_tube": "🧪", + "thermometer": "🌡", + "thinking_face": "🤔", + "thought_balloon": "💭", + "thread": "🧵", + "three-thirty": "🕞", + "three_o’clock": "🕒", + "thumbs_down": "👎", + "thumbs_down_dark_skin_tone": "👎🏿", + "thumbs_down_light_skin_tone": "👎🏻", + "thumbs_down_medium-dark_skin_tone": "👎🏾", + "thumbs_down_medium-light_skin_tone": "👎🏼", + "thumbs_down_medium_skin_tone": "👎🏽", + "thumbs_up": "👍", + "thumbs_up_dark_skin_tone": "👍🏿", + "thumbs_up_light_skin_tone": "👍🏻", + "thumbs_up_medium-dark_skin_tone": "👍🏾", + "thumbs_up_medium-light_skin_tone": "👍🏼", + "thumbs_up_medium_skin_tone": "👍🏽", + "ticket": "🎫", + "tiger": "🐯", + "tiger_face": "🐯", + "timer_clock": "⏲", + "tired_face": "😫", + "toolbox": "🧰", + "toilet": "🚽", + "tomato": "🍅", + "tongue": "👅", + "tooth": "🦷", + "top_hat": "🎩", + "tornado": "🌪", + "trackball": "🖲", + "tractor": "🚜", + "trade_mark": "™", + "train": "🚋", + "tram": "🚊", + "tram_car": "🚋", + "triangular_flag": "🚩", + "triangular_ruler": "📐", + "trident_emblem": "🔱", + "trolleybus": "🚎", + "trophy": "🏆", + "tropical_drink": "🍹", + "tropical_fish": "🐠", + "trumpet": "🎺", + "tulip": "🌷", + "tumbler_glass": "🥃", + "turtle": "🐢", + "twelve-thirty": "🕧", + "twelve_o’clock": "🕛", + "two-hump_camel": "🐫", + "two-thirty": "🕝", + "two_hearts": "💕", + "two_men_holding_hands": "👬", + "two_o’clock": "🕑", + "two_women_holding_hands": "👭", + "umbrella": "☂", + "umbrella_on_ground": "⛱", + "umbrella_with_rain_drops": "☔", + "unamused_face": "😒", + "unicorn_face": "🦄", + "unlocked": "🔓", + "up-down_arrow": "↕", + "up-left_arrow": "↖", + "up-right_arrow": "↗", + "up_arrow": "⬆", + "upside-down_face": "🙃", + "upwards_button": "🔼", + "vampire": "🧛", + "vampire_dark_skin_tone": "🧛🏿", + "vampire_light_skin_tone": "🧛🏻", + "vampire_medium-dark_skin_tone": "🧛🏾", + "vampire_medium-light_skin_tone": "🧛🏼", + "vampire_medium_skin_tone": "🧛🏽", + "vertical_traffic_light": "🚦", + "vibration_mode": "📳", + "victory_hand": "✌", + "victory_hand_dark_skin_tone": "✌🏿", + "victory_hand_light_skin_tone": "✌🏻", + "victory_hand_medium-dark_skin_tone": "✌🏾", + "victory_hand_medium-light_skin_tone": "✌🏼", + "victory_hand_medium_skin_tone": "✌🏽", + "video_camera": "📹", + "video_game": "🎮", + "videocassette": "📼", + "violin": "🎻", + "volcano": "🌋", + "volleyball": "🏐", + "vulcan_salute": "🖖", + "vulcan_salute_dark_skin_tone": "🖖🏿", + "vulcan_salute_light_skin_tone": "🖖🏻", + "vulcan_salute_medium-dark_skin_tone": "🖖🏾", + "vulcan_salute_medium-light_skin_tone": "🖖🏼", + "vulcan_salute_medium_skin_tone": "🖖🏽", + "waffle": "🧇", + "waning_crescent_moon": "🌘", + "waning_gibbous_moon": "🌖", + "warning": "⚠", + "wastebasket": "🗑", + "watch": "⌚", + "water_buffalo": "🐃", + "water_closet": "🚾", + "water_wave": "🌊", + "watermelon": "🍉", + "waving_hand": "👋", + "waving_hand_dark_skin_tone": "👋🏿", + "waving_hand_light_skin_tone": "👋🏻", + "waving_hand_medium-dark_skin_tone": "👋🏾", + "waving_hand_medium-light_skin_tone": "👋🏼", + "waving_hand_medium_skin_tone": "👋🏽", + "wavy_dash": "〰", + "waxing_crescent_moon": "🌒", + "waxing_gibbous_moon": "🌔", + "weary_cat_face": "🙀", + "weary_face": "😩", + "wedding": "💒", + "whale": "🐳", + "wheel_of_dharma": "☸", + "wheelchair_symbol": "♿", + "white_circle": "⚪", + "white_exclamation_mark": "❕", + "white_flag": "🏳", + "white_flower": "💮", + "white_hair": "🦳", + "white-haired_man": "👨\u200d🦳", + "white-haired_woman": "👩\u200d🦳", + "white_heart": "🤍", + "white_heavy_check_mark": "✅", + "white_large_square": "⬜", + "white_medium-small_square": "◽", + "white_medium_square": "◻", + "white_medium_star": "⭐", + "white_question_mark": "❔", + "white_small_square": "▫", + "white_square_button": "🔳", + "wilted_flower": "🥀", + "wind_chime": "🎐", + "wind_face": "🌬", + "wine_glass": "🍷", + "winking_face": "😉", + "winking_face_with_tongue": "😜", + "wolf_face": "🐺", + "woman": "👩", + "woman_artist": "👩\u200d🎨", + "woman_artist_dark_skin_tone": "👩🏿\u200d🎨", + "woman_artist_light_skin_tone": "👩🏻\u200d🎨", + "woman_artist_medium-dark_skin_tone": "👩🏾\u200d🎨", + "woman_artist_medium-light_skin_tone": "👩🏼\u200d🎨", + "woman_artist_medium_skin_tone": "👩🏽\u200d🎨", + "woman_astronaut": "👩\u200d🚀", + "woman_astronaut_dark_skin_tone": "👩🏿\u200d🚀", + "woman_astronaut_light_skin_tone": "👩🏻\u200d🚀", + "woman_astronaut_medium-dark_skin_tone": "👩🏾\u200d🚀", + "woman_astronaut_medium-light_skin_tone": "👩🏼\u200d🚀", + "woman_astronaut_medium_skin_tone": "👩🏽\u200d🚀", + "woman_biking": "🚴\u200d♀️", + "woman_biking_dark_skin_tone": "🚴🏿\u200d♀️", + "woman_biking_light_skin_tone": "🚴🏻\u200d♀️", + "woman_biking_medium-dark_skin_tone": "🚴🏾\u200d♀️", + "woman_biking_medium-light_skin_tone": "🚴🏼\u200d♀️", + "woman_biking_medium_skin_tone": "🚴🏽\u200d♀️", + "woman_bouncing_ball": "⛹️\u200d♀️", + "woman_bouncing_ball_dark_skin_tone": "⛹🏿\u200d♀️", + "woman_bouncing_ball_light_skin_tone": "⛹🏻\u200d♀️", + "woman_bouncing_ball_medium-dark_skin_tone": "⛹🏾\u200d♀️", + "woman_bouncing_ball_medium-light_skin_tone": "⛹🏼\u200d♀️", + "woman_bouncing_ball_medium_skin_tone": "⛹🏽\u200d♀️", + "woman_bowing": "🙇\u200d♀️", + "woman_bowing_dark_skin_tone": "🙇🏿\u200d♀️", + "woman_bowing_light_skin_tone": "🙇🏻\u200d♀️", + "woman_bowing_medium-dark_skin_tone": "🙇🏾\u200d♀️", + "woman_bowing_medium-light_skin_tone": "🙇🏼\u200d♀️", + "woman_bowing_medium_skin_tone": "🙇🏽\u200d♀️", + "woman_cartwheeling": "🤸\u200d♀️", + "woman_cartwheeling_dark_skin_tone": "🤸🏿\u200d♀️", + "woman_cartwheeling_light_skin_tone": "🤸🏻\u200d♀️", + "woman_cartwheeling_medium-dark_skin_tone": "🤸🏾\u200d♀️", + "woman_cartwheeling_medium-light_skin_tone": "🤸🏼\u200d♀️", + "woman_cartwheeling_medium_skin_tone": "🤸🏽\u200d♀️", + "woman_climbing": "🧗\u200d♀️", + "woman_climbing_dark_skin_tone": "🧗🏿\u200d♀️", + "woman_climbing_light_skin_tone": "🧗🏻\u200d♀️", + "woman_climbing_medium-dark_skin_tone": "🧗🏾\u200d♀️", + "woman_climbing_medium-light_skin_tone": "🧗🏼\u200d♀️", + "woman_climbing_medium_skin_tone": "🧗🏽\u200d♀️", + "woman_construction_worker": "👷\u200d♀️", + "woman_construction_worker_dark_skin_tone": "👷🏿\u200d♀️", + "woman_construction_worker_light_skin_tone": "👷🏻\u200d♀️", + "woman_construction_worker_medium-dark_skin_tone": "👷🏾\u200d♀️", + "woman_construction_worker_medium-light_skin_tone": "👷🏼\u200d♀️", + "woman_construction_worker_medium_skin_tone": "👷🏽\u200d♀️", + "woman_cook": "👩\u200d🍳", + "woman_cook_dark_skin_tone": "👩🏿\u200d🍳", + "woman_cook_light_skin_tone": "👩🏻\u200d🍳", + "woman_cook_medium-dark_skin_tone": "👩🏾\u200d🍳", + "woman_cook_medium-light_skin_tone": "👩🏼\u200d🍳", + "woman_cook_medium_skin_tone": "👩🏽\u200d🍳", + "woman_dancing": "💃", + "woman_dancing_dark_skin_tone": "💃🏿", + "woman_dancing_light_skin_tone": "💃🏻", + "woman_dancing_medium-dark_skin_tone": "💃🏾", + "woman_dancing_medium-light_skin_tone": "💃🏼", + "woman_dancing_medium_skin_tone": "💃🏽", + "woman_dark_skin_tone": "👩🏿", + "woman_detective": "🕵️\u200d♀️", + "woman_detective_dark_skin_tone": "🕵🏿\u200d♀️", + "woman_detective_light_skin_tone": "🕵🏻\u200d♀️", + "woman_detective_medium-dark_skin_tone": "🕵🏾\u200d♀️", + "woman_detective_medium-light_skin_tone": "🕵🏼\u200d♀️", + "woman_detective_medium_skin_tone": "🕵🏽\u200d♀️", + "woman_elf": "🧝\u200d♀️", + "woman_elf_dark_skin_tone": "🧝🏿\u200d♀️", + "woman_elf_light_skin_tone": "🧝🏻\u200d♀️", + "woman_elf_medium-dark_skin_tone": "🧝🏾\u200d♀️", + "woman_elf_medium-light_skin_tone": "🧝🏼\u200d♀️", + "woman_elf_medium_skin_tone": "🧝🏽\u200d♀️", + "woman_facepalming": "🤦\u200d♀️", + "woman_facepalming_dark_skin_tone": "🤦🏿\u200d♀️", + "woman_facepalming_light_skin_tone": "🤦🏻\u200d♀️", + "woman_facepalming_medium-dark_skin_tone": "🤦🏾\u200d♀️", + "woman_facepalming_medium-light_skin_tone": "🤦🏼\u200d♀️", + "woman_facepalming_medium_skin_tone": "🤦🏽\u200d♀️", + "woman_factory_worker": "👩\u200d🏭", + "woman_factory_worker_dark_skin_tone": "👩🏿\u200d🏭", + "woman_factory_worker_light_skin_tone": "👩🏻\u200d🏭", + "woman_factory_worker_medium-dark_skin_tone": "👩🏾\u200d🏭", + "woman_factory_worker_medium-light_skin_tone": "👩🏼\u200d🏭", + "woman_factory_worker_medium_skin_tone": "👩🏽\u200d🏭", + "woman_fairy": "🧚\u200d♀️", + "woman_fairy_dark_skin_tone": "🧚🏿\u200d♀️", + "woman_fairy_light_skin_tone": "🧚🏻\u200d♀️", + "woman_fairy_medium-dark_skin_tone": "🧚🏾\u200d♀️", + "woman_fairy_medium-light_skin_tone": "🧚🏼\u200d♀️", + "woman_fairy_medium_skin_tone": "🧚🏽\u200d♀️", + "woman_farmer": "👩\u200d🌾", + "woman_farmer_dark_skin_tone": "👩🏿\u200d🌾", + "woman_farmer_light_skin_tone": "👩🏻\u200d🌾", + "woman_farmer_medium-dark_skin_tone": "👩🏾\u200d🌾", + "woman_farmer_medium-light_skin_tone": "👩🏼\u200d🌾", + "woman_farmer_medium_skin_tone": "👩🏽\u200d🌾", + "woman_firefighter": "👩\u200d🚒", + "woman_firefighter_dark_skin_tone": "👩🏿\u200d🚒", + "woman_firefighter_light_skin_tone": "👩🏻\u200d🚒", + "woman_firefighter_medium-dark_skin_tone": "👩🏾\u200d🚒", + "woman_firefighter_medium-light_skin_tone": "👩🏼\u200d🚒", + "woman_firefighter_medium_skin_tone": "👩🏽\u200d🚒", + "woman_frowning": "🙍\u200d♀️", + "woman_frowning_dark_skin_tone": "🙍🏿\u200d♀️", + "woman_frowning_light_skin_tone": "🙍🏻\u200d♀️", + "woman_frowning_medium-dark_skin_tone": "🙍🏾\u200d♀️", + "woman_frowning_medium-light_skin_tone": "🙍🏼\u200d♀️", + "woman_frowning_medium_skin_tone": "🙍🏽\u200d♀️", + "woman_genie": "🧞\u200d♀️", + "woman_gesturing_no": "🙅\u200d♀️", + "woman_gesturing_no_dark_skin_tone": "🙅🏿\u200d♀️", + "woman_gesturing_no_light_skin_tone": "🙅🏻\u200d♀️", + "woman_gesturing_no_medium-dark_skin_tone": "🙅🏾\u200d♀️", + "woman_gesturing_no_medium-light_skin_tone": "🙅🏼\u200d♀️", + "woman_gesturing_no_medium_skin_tone": "🙅🏽\u200d♀️", + "woman_gesturing_ok": "🙆\u200d♀️", + "woman_gesturing_ok_dark_skin_tone": "🙆🏿\u200d♀️", + "woman_gesturing_ok_light_skin_tone": "🙆🏻\u200d♀️", + "woman_gesturing_ok_medium-dark_skin_tone": "🙆🏾\u200d♀️", + "woman_gesturing_ok_medium-light_skin_tone": "🙆🏼\u200d♀️", + "woman_gesturing_ok_medium_skin_tone": "🙆🏽\u200d♀️", + "woman_getting_haircut": "💇\u200d♀️", + "woman_getting_haircut_dark_skin_tone": "💇🏿\u200d♀️", + "woman_getting_haircut_light_skin_tone": "💇🏻\u200d♀️", + "woman_getting_haircut_medium-dark_skin_tone": "💇🏾\u200d♀️", + "woman_getting_haircut_medium-light_skin_tone": "💇🏼\u200d♀️", + "woman_getting_haircut_medium_skin_tone": "💇🏽\u200d♀️", + "woman_getting_massage": "💆\u200d♀️", + "woman_getting_massage_dark_skin_tone": "💆🏿\u200d♀️", + "woman_getting_massage_light_skin_tone": "💆🏻\u200d♀️", + "woman_getting_massage_medium-dark_skin_tone": "💆🏾\u200d♀️", + "woman_getting_massage_medium-light_skin_tone": "💆🏼\u200d♀️", + "woman_getting_massage_medium_skin_tone": "💆🏽\u200d♀️", + "woman_golfing": "🏌️\u200d♀️", + "woman_golfing_dark_skin_tone": "🏌🏿\u200d♀️", + "woman_golfing_light_skin_tone": "🏌🏻\u200d♀️", + "woman_golfing_medium-dark_skin_tone": "🏌🏾\u200d♀️", + "woman_golfing_medium-light_skin_tone": "🏌🏼\u200d♀️", + "woman_golfing_medium_skin_tone": "🏌🏽\u200d♀️", + "woman_guard": "💂\u200d♀️", + "woman_guard_dark_skin_tone": "💂🏿\u200d♀️", + "woman_guard_light_skin_tone": "💂🏻\u200d♀️", + "woman_guard_medium-dark_skin_tone": "💂🏾\u200d♀️", + "woman_guard_medium-light_skin_tone": "💂🏼\u200d♀️", + "woman_guard_medium_skin_tone": "💂🏽\u200d♀️", + "woman_health_worker": "👩\u200d⚕️", + "woman_health_worker_dark_skin_tone": "👩🏿\u200d⚕️", + "woman_health_worker_light_skin_tone": "👩🏻\u200d⚕️", + "woman_health_worker_medium-dark_skin_tone": "👩🏾\u200d⚕️", + "woman_health_worker_medium-light_skin_tone": "👩🏼\u200d⚕️", + "woman_health_worker_medium_skin_tone": "👩🏽\u200d⚕️", + "woman_in_lotus_position": "🧘\u200d♀️", + "woman_in_lotus_position_dark_skin_tone": "🧘🏿\u200d♀️", + "woman_in_lotus_position_light_skin_tone": "🧘🏻\u200d♀️", + "woman_in_lotus_position_medium-dark_skin_tone": "🧘🏾\u200d♀️", + "woman_in_lotus_position_medium-light_skin_tone": "🧘🏼\u200d♀️", + "woman_in_lotus_position_medium_skin_tone": "🧘🏽\u200d♀️", + "woman_in_manual_wheelchair": "👩\u200d🦽", + "woman_in_motorized_wheelchair": "👩\u200d🦼", + "woman_in_steamy_room": "🧖\u200d♀️", + "woman_in_steamy_room_dark_skin_tone": "🧖🏿\u200d♀️", + "woman_in_steamy_room_light_skin_tone": "🧖🏻\u200d♀️", + "woman_in_steamy_room_medium-dark_skin_tone": "🧖🏾\u200d♀️", + "woman_in_steamy_room_medium-light_skin_tone": "🧖🏼\u200d♀️", + "woman_in_steamy_room_medium_skin_tone": "🧖🏽\u200d♀️", + "woman_judge": "👩\u200d⚖️", + "woman_judge_dark_skin_tone": "👩🏿\u200d⚖️", + "woman_judge_light_skin_tone": "👩🏻\u200d⚖️", + "woman_judge_medium-dark_skin_tone": "👩🏾\u200d⚖️", + "woman_judge_medium-light_skin_tone": "👩🏼\u200d⚖️", + "woman_judge_medium_skin_tone": "👩🏽\u200d⚖️", + "woman_juggling": "🤹\u200d♀️", + "woman_juggling_dark_skin_tone": "🤹🏿\u200d♀️", + "woman_juggling_light_skin_tone": "🤹🏻\u200d♀️", + "woman_juggling_medium-dark_skin_tone": "🤹🏾\u200d♀️", + "woman_juggling_medium-light_skin_tone": "🤹🏼\u200d♀️", + "woman_juggling_medium_skin_tone": "🤹🏽\u200d♀️", + "woman_lifting_weights": "🏋️\u200d♀️", + "woman_lifting_weights_dark_skin_tone": "🏋🏿\u200d♀️", + "woman_lifting_weights_light_skin_tone": "🏋🏻\u200d♀️", + "woman_lifting_weights_medium-dark_skin_tone": "🏋🏾\u200d♀️", + "woman_lifting_weights_medium-light_skin_tone": "🏋🏼\u200d♀️", + "woman_lifting_weights_medium_skin_tone": "🏋🏽\u200d♀️", + "woman_light_skin_tone": "👩🏻", + "woman_mage": "🧙\u200d♀️", + "woman_mage_dark_skin_tone": "🧙🏿\u200d♀️", + "woman_mage_light_skin_tone": "🧙🏻\u200d♀️", + "woman_mage_medium-dark_skin_tone": "🧙🏾\u200d♀️", + "woman_mage_medium-light_skin_tone": "🧙🏼\u200d♀️", + "woman_mage_medium_skin_tone": "🧙🏽\u200d♀️", + "woman_mechanic": "👩\u200d🔧", + "woman_mechanic_dark_skin_tone": "👩🏿\u200d🔧", + "woman_mechanic_light_skin_tone": "👩🏻\u200d🔧", + "woman_mechanic_medium-dark_skin_tone": "👩🏾\u200d🔧", + "woman_mechanic_medium-light_skin_tone": "👩🏼\u200d🔧", + "woman_mechanic_medium_skin_tone": "👩🏽\u200d🔧", + "woman_medium-dark_skin_tone": "👩🏾", + "woman_medium-light_skin_tone": "👩🏼", + "woman_medium_skin_tone": "👩🏽", + "woman_mountain_biking": "🚵\u200d♀️", + "woman_mountain_biking_dark_skin_tone": "🚵🏿\u200d♀️", + "woman_mountain_biking_light_skin_tone": "🚵🏻\u200d♀️", + "woman_mountain_biking_medium-dark_skin_tone": "🚵🏾\u200d♀️", + "woman_mountain_biking_medium-light_skin_tone": "🚵🏼\u200d♀️", + "woman_mountain_biking_medium_skin_tone": "🚵🏽\u200d♀️", + "woman_office_worker": "👩\u200d💼", + "woman_office_worker_dark_skin_tone": "👩🏿\u200d💼", + "woman_office_worker_light_skin_tone": "👩🏻\u200d💼", + "woman_office_worker_medium-dark_skin_tone": "👩🏾\u200d💼", + "woman_office_worker_medium-light_skin_tone": "👩🏼\u200d💼", + "woman_office_worker_medium_skin_tone": "👩🏽\u200d💼", + "woman_pilot": "👩\u200d✈️", + "woman_pilot_dark_skin_tone": "👩🏿\u200d✈️", + "woman_pilot_light_skin_tone": "👩🏻\u200d✈️", + "woman_pilot_medium-dark_skin_tone": "👩🏾\u200d✈️", + "woman_pilot_medium-light_skin_tone": "👩🏼\u200d✈️", + "woman_pilot_medium_skin_tone": "👩🏽\u200d✈️", + "woman_playing_handball": "🤾\u200d♀️", + "woman_playing_handball_dark_skin_tone": "🤾🏿\u200d♀️", + "woman_playing_handball_light_skin_tone": "🤾🏻\u200d♀️", + "woman_playing_handball_medium-dark_skin_tone": "🤾🏾\u200d♀️", + "woman_playing_handball_medium-light_skin_tone": "🤾🏼\u200d♀️", + "woman_playing_handball_medium_skin_tone": "🤾🏽\u200d♀️", + "woman_playing_water_polo": "🤽\u200d♀️", + "woman_playing_water_polo_dark_skin_tone": "🤽🏿\u200d♀️", + "woman_playing_water_polo_light_skin_tone": "🤽🏻\u200d♀️", + "woman_playing_water_polo_medium-dark_skin_tone": "🤽🏾\u200d♀️", + "woman_playing_water_polo_medium-light_skin_tone": "🤽🏼\u200d♀️", + "woman_playing_water_polo_medium_skin_tone": "🤽🏽\u200d♀️", + "woman_police_officer": "👮\u200d♀️", + "woman_police_officer_dark_skin_tone": "👮🏿\u200d♀️", + "woman_police_officer_light_skin_tone": "👮🏻\u200d♀️", + "woman_police_officer_medium-dark_skin_tone": "👮🏾\u200d♀️", + "woman_police_officer_medium-light_skin_tone": "👮🏼\u200d♀️", + "woman_police_officer_medium_skin_tone": "👮🏽\u200d♀️", + "woman_pouting": "🙎\u200d♀️", + "woman_pouting_dark_skin_tone": "🙎🏿\u200d♀️", + "woman_pouting_light_skin_tone": "🙎🏻\u200d♀️", + "woman_pouting_medium-dark_skin_tone": "🙎🏾\u200d♀️", + "woman_pouting_medium-light_skin_tone": "🙎🏼\u200d♀️", + "woman_pouting_medium_skin_tone": "🙎🏽\u200d♀️", + "woman_raising_hand": "🙋\u200d♀️", + "woman_raising_hand_dark_skin_tone": "🙋🏿\u200d♀️", + "woman_raising_hand_light_skin_tone": "🙋🏻\u200d♀️", + "woman_raising_hand_medium-dark_skin_tone": "🙋🏾\u200d♀️", + "woman_raising_hand_medium-light_skin_tone": "🙋🏼\u200d♀️", + "woman_raising_hand_medium_skin_tone": "🙋🏽\u200d♀️", + "woman_rowing_boat": "🚣\u200d♀️", + "woman_rowing_boat_dark_skin_tone": "🚣🏿\u200d♀️", + "woman_rowing_boat_light_skin_tone": "🚣🏻\u200d♀️", + "woman_rowing_boat_medium-dark_skin_tone": "🚣🏾\u200d♀️", + "woman_rowing_boat_medium-light_skin_tone": "🚣🏼\u200d♀️", + "woman_rowing_boat_medium_skin_tone": "🚣🏽\u200d♀️", + "woman_running": "🏃\u200d♀️", + "woman_running_dark_skin_tone": "🏃🏿\u200d♀️", + "woman_running_light_skin_tone": "🏃🏻\u200d♀️", + "woman_running_medium-dark_skin_tone": "🏃🏾\u200d♀️", + "woman_running_medium-light_skin_tone": "🏃🏼\u200d♀️", + "woman_running_medium_skin_tone": "🏃🏽\u200d♀️", + "woman_scientist": "👩\u200d🔬", + "woman_scientist_dark_skin_tone": "👩🏿\u200d🔬", + "woman_scientist_light_skin_tone": "👩🏻\u200d🔬", + "woman_scientist_medium-dark_skin_tone": "👩🏾\u200d🔬", + "woman_scientist_medium-light_skin_tone": "👩🏼\u200d🔬", + "woman_scientist_medium_skin_tone": "👩🏽\u200d🔬", + "woman_shrugging": "🤷\u200d♀️", + "woman_shrugging_dark_skin_tone": "🤷🏿\u200d♀️", + "woman_shrugging_light_skin_tone": "🤷🏻\u200d♀️", + "woman_shrugging_medium-dark_skin_tone": "🤷🏾\u200d♀️", + "woman_shrugging_medium-light_skin_tone": "🤷🏼\u200d♀️", + "woman_shrugging_medium_skin_tone": "🤷🏽\u200d♀️", + "woman_singer": "👩\u200d🎤", + "woman_singer_dark_skin_tone": "👩🏿\u200d🎤", + "woman_singer_light_skin_tone": "👩🏻\u200d🎤", + "woman_singer_medium-dark_skin_tone": "👩🏾\u200d🎤", + "woman_singer_medium-light_skin_tone": "👩🏼\u200d🎤", + "woman_singer_medium_skin_tone": "👩🏽\u200d🎤", + "woman_student": "👩\u200d🎓", + "woman_student_dark_skin_tone": "👩🏿\u200d🎓", + "woman_student_light_skin_tone": "👩🏻\u200d🎓", + "woman_student_medium-dark_skin_tone": "👩🏾\u200d🎓", + "woman_student_medium-light_skin_tone": "👩🏼\u200d🎓", + "woman_student_medium_skin_tone": "👩🏽\u200d🎓", + "woman_surfing": "🏄\u200d♀️", + "woman_surfing_dark_skin_tone": "🏄🏿\u200d♀️", + "woman_surfing_light_skin_tone": "🏄🏻\u200d♀️", + "woman_surfing_medium-dark_skin_tone": "🏄🏾\u200d♀️", + "woman_surfing_medium-light_skin_tone": "🏄🏼\u200d♀️", + "woman_surfing_medium_skin_tone": "🏄🏽\u200d♀️", + "woman_swimming": "🏊\u200d♀️", + "woman_swimming_dark_skin_tone": "🏊🏿\u200d♀️", + "woman_swimming_light_skin_tone": "🏊🏻\u200d♀️", + "woman_swimming_medium-dark_skin_tone": "🏊🏾\u200d♀️", + "woman_swimming_medium-light_skin_tone": "🏊🏼\u200d♀️", + "woman_swimming_medium_skin_tone": "🏊🏽\u200d♀️", + "woman_teacher": "👩\u200d🏫", + "woman_teacher_dark_skin_tone": "👩🏿\u200d🏫", + "woman_teacher_light_skin_tone": "👩🏻\u200d🏫", + "woman_teacher_medium-dark_skin_tone": "👩🏾\u200d🏫", + "woman_teacher_medium-light_skin_tone": "👩🏼\u200d🏫", + "woman_teacher_medium_skin_tone": "👩🏽\u200d🏫", + "woman_technologist": "👩\u200d💻", + "woman_technologist_dark_skin_tone": "👩🏿\u200d💻", + "woman_technologist_light_skin_tone": "👩🏻\u200d💻", + "woman_technologist_medium-dark_skin_tone": "👩🏾\u200d💻", + "woman_technologist_medium-light_skin_tone": "👩🏼\u200d💻", + "woman_technologist_medium_skin_tone": "👩🏽\u200d💻", + "woman_tipping_hand": "💁\u200d♀️", + "woman_tipping_hand_dark_skin_tone": "💁🏿\u200d♀️", + "woman_tipping_hand_light_skin_tone": "💁🏻\u200d♀️", + "woman_tipping_hand_medium-dark_skin_tone": "💁🏾\u200d♀️", + "woman_tipping_hand_medium-light_skin_tone": "💁🏼\u200d♀️", + "woman_tipping_hand_medium_skin_tone": "💁🏽\u200d♀️", + "woman_vampire": "🧛\u200d♀️", + "woman_vampire_dark_skin_tone": "🧛🏿\u200d♀️", + "woman_vampire_light_skin_tone": "🧛🏻\u200d♀️", + "woman_vampire_medium-dark_skin_tone": "🧛🏾\u200d♀️", + "woman_vampire_medium-light_skin_tone": "🧛🏼\u200d♀️", + "woman_vampire_medium_skin_tone": "🧛🏽\u200d♀️", + "woman_walking": "🚶\u200d♀️", + "woman_walking_dark_skin_tone": "🚶🏿\u200d♀️", + "woman_walking_light_skin_tone": "🚶🏻\u200d♀️", + "woman_walking_medium-dark_skin_tone": "🚶🏾\u200d♀️", + "woman_walking_medium-light_skin_tone": "🚶🏼\u200d♀️", + "woman_walking_medium_skin_tone": "🚶🏽\u200d♀️", + "woman_wearing_turban": "👳\u200d♀️", + "woman_wearing_turban_dark_skin_tone": "👳🏿\u200d♀️", + "woman_wearing_turban_light_skin_tone": "👳🏻\u200d♀️", + "woman_wearing_turban_medium-dark_skin_tone": "👳🏾\u200d♀️", + "woman_wearing_turban_medium-light_skin_tone": "👳🏼\u200d♀️", + "woman_wearing_turban_medium_skin_tone": "👳🏽\u200d♀️", + "woman_with_headscarf": "🧕", + "woman_with_headscarf_dark_skin_tone": "🧕🏿", + "woman_with_headscarf_light_skin_tone": "🧕🏻", + "woman_with_headscarf_medium-dark_skin_tone": "🧕🏾", + "woman_with_headscarf_medium-light_skin_tone": "🧕🏼", + "woman_with_headscarf_medium_skin_tone": "🧕🏽", + "woman_with_probing_cane": "👩\u200d🦯", + "woman_zombie": "🧟\u200d♀️", + "woman’s_boot": "👢", + "woman’s_clothes": "👚", + "woman’s_hat": "👒", + "woman’s_sandal": "👡", + "women_with_bunny_ears": "👯\u200d♀️", + "women_wrestling": "🤼\u200d♀️", + "women’s_room": "🚺", + "woozy_face": "🥴", + "world_map": "🗺", + "worried_face": "😟", + "wrapped_gift": "🎁", + "wrench": "🔧", + "writing_hand": "✍", + "writing_hand_dark_skin_tone": "✍🏿", + "writing_hand_light_skin_tone": "✍🏻", + "writing_hand_medium-dark_skin_tone": "✍🏾", + "writing_hand_medium-light_skin_tone": "✍🏼", + "writing_hand_medium_skin_tone": "✍🏽", + "yarn": "🧶", + "yawning_face": "🥱", + "yellow_circle": "🟡", + "yellow_heart": "💛", + "yellow_square": "🟨", + "yen_banknote": "💴", + "yo-yo": "🪀", + "yin_yang": "☯", + "zany_face": "🤪", + "zebra": "🦓", + "zipper-mouth_face": "🤐", + "zombie": "🧟", + "zzz": "💤", + "åland_islands": "🇦🇽", + "keycap_asterisk": "*⃣", + "keycap_digit_eight": "8⃣", + "keycap_digit_five": "5⃣", + "keycap_digit_four": "4⃣", + "keycap_digit_nine": "9⃣", + "keycap_digit_one": "1⃣", + "keycap_digit_seven": "7⃣", + "keycap_digit_six": "6⃣", + "keycap_digit_three": "3⃣", + "keycap_digit_two": "2⃣", + "keycap_digit_zero": "0⃣", + "keycap_number_sign": "#⃣", + "light_skin_tone": "🏻", + "medium_light_skin_tone": "🏼", + "medium_skin_tone": "🏽", + "medium_dark_skin_tone": "🏾", + "dark_skin_tone": "🏿", + "regional_indicator_symbol_letter_a": "🇦", + "regional_indicator_symbol_letter_b": "🇧", + "regional_indicator_symbol_letter_c": "🇨", + "regional_indicator_symbol_letter_d": "🇩", + "regional_indicator_symbol_letter_e": "🇪", + "regional_indicator_symbol_letter_f": "🇫", + "regional_indicator_symbol_letter_g": "🇬", + "regional_indicator_symbol_letter_h": "🇭", + "regional_indicator_symbol_letter_i": "🇮", + "regional_indicator_symbol_letter_j": "🇯", + "regional_indicator_symbol_letter_k": "🇰", + "regional_indicator_symbol_letter_l": "🇱", + "regional_indicator_symbol_letter_m": "🇲", + "regional_indicator_symbol_letter_n": "🇳", + "regional_indicator_symbol_letter_o": "🇴", + "regional_indicator_symbol_letter_p": "🇵", + "regional_indicator_symbol_letter_q": "🇶", + "regional_indicator_symbol_letter_r": "🇷", + "regional_indicator_symbol_letter_s": "🇸", + "regional_indicator_symbol_letter_t": "🇹", + "regional_indicator_symbol_letter_u": "🇺", + "regional_indicator_symbol_letter_v": "🇻", + "regional_indicator_symbol_letter_w": "🇼", + "regional_indicator_symbol_letter_x": "🇽", + "regional_indicator_symbol_letter_y": "🇾", + "regional_indicator_symbol_letter_z": "🇿", + "airplane_arriving": "🛬", + "space_invader": "👾", + "football": "🏈", + "anger": "💢", + "angry": "😠", + "anguished": "😧", + "signal_strength": "📶", + "arrows_counterclockwise": "🔄", + "arrow_heading_down": "⤵", + "arrow_heading_up": "⤴", + "art": "🎨", + "astonished": "😲", + "athletic_shoe": "👟", + "atm": "🏧", + "car": "🚗", + "red_car": "🚗", + "angel": "👼", + "back": "🔙", + "badminton_racquet_and_shuttlecock": "🏸", + "dollar": "💵", + "euro": "💶", + "pound": "💷", + "yen": "💴", + "barber": "💈", + "bath": "🛀", + "bear": "🐻", + "heartbeat": "💓", + "beer": "🍺", + "no_bell": "🔕", + "bento": "🍱", + "bike": "🚲", + "bicyclist": "🚴", + "8ball": "🎱", + "biohazard_sign": "☣", + "birthday": "🎂", + "black_circle_for_record": "⏺", + "clubs": "♣", + "diamonds": "♦", + "arrow_double_down": "⏬", + "hearts": "♥", + "rewind": "⏪", + "black_left__pointing_double_triangle_with_vertical_bar": "⏮", + "arrow_backward": "◀", + "black_medium_small_square": "◾", + "question": "❓", + "fast_forward": "⏩", + "black_right__pointing_double_triangle_with_vertical_bar": "⏭", + "arrow_forward": "▶", + "black_right__pointing_triangle_with_double_vertical_bar": "⏯", + "arrow_right": "➡", + "spades": "♠", + "black_square_for_stop": "⏹", + "sunny": "☀", + "phone": "☎", + "recycle": "♻", + "arrow_double_up": "⏫", + "busstop": "🚏", + "date": "📅", + "flags": "🎏", + "cat2": "🐈", + "joy_cat": "😹", + "smirk_cat": "😼", + "chart_with_downwards_trend": "📉", + "chart_with_upwards_trend": "📈", + "chart": "💹", + "mega": "📣", + "checkered_flag": "🏁", + "accept": "🉑", + "ideograph_advantage": "🉐", + "congratulations": "㊗", + "secret": "㊙", + "m": "Ⓜ", + "city_sunset": "🌆", + "clapper": "🎬", + "clap": "👏", + "beers": "🍻", + "clock830": "🕣", + "clock8": "🕗", + "clock1130": "🕦", + "clock11": "🕚", + "clock530": "🕠", + "clock5": "🕔", + "clock430": "🕟", + "clock4": "🕓", + "clock930": "🕤", + "clock9": "🕘", + "clock130": "🕜", + "clock1": "🕐", + "clock730": "🕢", + "clock7": "🕖", + "clock630": "🕡", + "clock6": "🕕", + "clock1030": "🕥", + "clock10": "🕙", + "clock330": "🕞", + "clock3": "🕒", + "clock1230": "🕧", + "clock12": "🕛", + "clock230": "🕝", + "clock2": "🕑", + "arrows_clockwise": "🔃", + "repeat": "🔁", + "repeat_one": "🔂", + "closed_lock_with_key": "🔐", + "mailbox_closed": "📪", + "mailbox": "📫", + "cloud_with_tornado": "🌪", + "cocktail": "🍸", + "boom": "💥", + "compression": "🗜", + "confounded": "😖", + "confused": "😕", + "rice": "🍚", + "cow2": "🐄", + "cricket_bat_and_ball": "🏏", + "x": "❌", + "cry": "😢", + "curry": "🍛", + "dagger_knife": "🗡", + "dancer": "💃", + "dark_sunglasses": "🕶", + "dash": "💨", + "truck": "🚚", + "derelict_house_building": "🏚", + "diamond_shape_with_a_dot_inside": "💠", + "dart": "🎯", + "disappointed_relieved": "😥", + "disappointed": "😞", + "do_not_litter": "🚯", + "dog2": "🐕", + "flipper": "🐬", + "loop": "➿", + "bangbang": "‼", + "double_vertical_bar": "⏸", + "dove_of_peace": "🕊", + "small_red_triangle_down": "🔻", + "arrow_down_small": "🔽", + "arrow_down": "⬇", + "dromedary_camel": "🐪", + "e__mail": "📧", + "corn": "🌽", + "ear_of_rice": "🌾", + "earth_americas": "🌎", + "earth_asia": "🌏", + "earth_africa": "🌍", + "eight_pointed_black_star": "✴", + "eight_spoked_asterisk": "✳", + "eject_symbol": "⏏", + "bulb": "💡", + "emoji_modifier_fitzpatrick_type__1__2": "🏻", + "emoji_modifier_fitzpatrick_type__3": "🏼", + "emoji_modifier_fitzpatrick_type__4": "🏽", + "emoji_modifier_fitzpatrick_type__5": "🏾", + "emoji_modifier_fitzpatrick_type__6": "🏿", + "end": "🔚", + "email": "✉", + "european_castle": "🏰", + "european_post_office": "🏤", + "interrobang": "⁉", + "expressionless": "😑", + "eyeglasses": "👓", + "massage": "💆", + "yum": "😋", + "scream": "😱", + "kissing_heart": "😘", + "sweat": "😓", + "face_with_head__bandage": "🤕", + "triumph": "😤", + "mask": "😷", + "no_good": "🙅", + "ok_woman": "🙆", + "open_mouth": "😮", + "cold_sweat": "😰", + "stuck_out_tongue": "😛", + "stuck_out_tongue_closed_eyes": "😝", + "stuck_out_tongue_winking_eye": "😜", + "joy": "😂", + "no_mouth": "😶", + "santa": "🎅", + "fax": "📠", + "fearful": "😨", + "field_hockey_stick_and_ball": "🏑", + "first_quarter_moon_with_face": "🌛", + "fish_cake": "🍥", + "fishing_pole_and_fish": "🎣", + "facepunch": "👊", + "punch": "👊", + "flag_for_afghanistan": "🇦🇫", + "flag_for_albania": "🇦🇱", + "flag_for_algeria": "🇩🇿", + "flag_for_american_samoa": "🇦🇸", + "flag_for_andorra": "🇦🇩", + "flag_for_angola": "🇦🇴", + "flag_for_anguilla": "🇦🇮", + "flag_for_antarctica": "🇦🇶", + "flag_for_antigua_&_barbuda": "🇦🇬", + "flag_for_argentina": "🇦🇷", + "flag_for_armenia": "🇦🇲", + "flag_for_aruba": "🇦🇼", + "flag_for_ascension_island": "🇦🇨", + "flag_for_australia": "🇦🇺", + "flag_for_austria": "🇦🇹", + "flag_for_azerbaijan": "🇦🇿", + "flag_for_bahamas": "🇧🇸", + "flag_for_bahrain": "🇧🇭", + "flag_for_bangladesh": "🇧🇩", + "flag_for_barbados": "🇧🇧", + "flag_for_belarus": "🇧🇾", + "flag_for_belgium": "🇧🇪", + "flag_for_belize": "🇧🇿", + "flag_for_benin": "🇧🇯", + "flag_for_bermuda": "🇧🇲", + "flag_for_bhutan": "🇧🇹", + "flag_for_bolivia": "🇧🇴", + "flag_for_bosnia_&_herzegovina": "🇧🇦", + "flag_for_botswana": "🇧🇼", + "flag_for_bouvet_island": "🇧🇻", + "flag_for_brazil": "🇧🇷", + "flag_for_british_indian_ocean_territory": "🇮🇴", + "flag_for_british_virgin_islands": "🇻🇬", + "flag_for_brunei": "🇧🇳", + "flag_for_bulgaria": "🇧🇬", + "flag_for_burkina_faso": "🇧🇫", + "flag_for_burundi": "🇧🇮", + "flag_for_cambodia": "🇰🇭", + "flag_for_cameroon": "🇨🇲", + "flag_for_canada": "🇨🇦", + "flag_for_canary_islands": "🇮🇨", + "flag_for_cape_verde": "🇨🇻", + "flag_for_caribbean_netherlands": "🇧🇶", + "flag_for_cayman_islands": "🇰🇾", + "flag_for_central_african_republic": "🇨🇫", + "flag_for_ceuta_&_melilla": "🇪🇦", + "flag_for_chad": "🇹🇩", + "flag_for_chile": "🇨🇱", + "flag_for_china": "🇨🇳", + "flag_for_christmas_island": "🇨🇽", + "flag_for_clipperton_island": "🇨🇵", + "flag_for_cocos__islands": "🇨🇨", + "flag_for_colombia": "🇨🇴", + "flag_for_comoros": "🇰🇲", + "flag_for_congo____brazzaville": "🇨🇬", + "flag_for_congo____kinshasa": "🇨🇩", + "flag_for_cook_islands": "🇨🇰", + "flag_for_costa_rica": "🇨🇷", + "flag_for_croatia": "🇭🇷", + "flag_for_cuba": "🇨🇺", + "flag_for_curaçao": "🇨🇼", + "flag_for_cyprus": "🇨🇾", + "flag_for_czech_republic": "🇨🇿", + "flag_for_côte_d’ivoire": "🇨🇮", + "flag_for_denmark": "🇩🇰", + "flag_for_diego_garcia": "🇩🇬", + "flag_for_djibouti": "🇩🇯", + "flag_for_dominica": "🇩🇲", + "flag_for_dominican_republic": "🇩🇴", + "flag_for_ecuador": "🇪🇨", + "flag_for_egypt": "🇪🇬", + "flag_for_el_salvador": "🇸🇻", + "flag_for_equatorial_guinea": "🇬🇶", + "flag_for_eritrea": "🇪🇷", + "flag_for_estonia": "🇪🇪", + "flag_for_ethiopia": "🇪🇹", + "flag_for_european_union": "🇪🇺", + "flag_for_falkland_islands": "🇫🇰", + "flag_for_faroe_islands": "🇫🇴", + "flag_for_fiji": "🇫🇯", + "flag_for_finland": "🇫🇮", + "flag_for_france": "🇫🇷", + "flag_for_french_guiana": "🇬🇫", + "flag_for_french_polynesia": "🇵🇫", + "flag_for_french_southern_territories": "🇹🇫", + "flag_for_gabon": "🇬🇦", + "flag_for_gambia": "🇬🇲", + "flag_for_georgia": "🇬🇪", + "flag_for_germany": "🇩🇪", + "flag_for_ghana": "🇬🇭", + "flag_for_gibraltar": "🇬🇮", + "flag_for_greece": "🇬🇷", + "flag_for_greenland": "🇬🇱", + "flag_for_grenada": "🇬🇩", + "flag_for_guadeloupe": "🇬🇵", + "flag_for_guam": "🇬🇺", + "flag_for_guatemala": "🇬🇹", + "flag_for_guernsey": "🇬🇬", + "flag_for_guinea": "🇬🇳", + "flag_for_guinea__bissau": "🇬🇼", + "flag_for_guyana": "🇬🇾", + "flag_for_haiti": "🇭🇹", + "flag_for_heard_&_mcdonald_islands": "🇭🇲", + "flag_for_honduras": "🇭🇳", + "flag_for_hong_kong": "🇭🇰", + "flag_for_hungary": "🇭🇺", + "flag_for_iceland": "🇮🇸", + "flag_for_india": "🇮🇳", + "flag_for_indonesia": "🇮🇩", + "flag_for_iran": "🇮🇷", + "flag_for_iraq": "🇮🇶", + "flag_for_ireland": "🇮🇪", + "flag_for_isle_of_man": "🇮🇲", + "flag_for_israel": "🇮🇱", + "flag_for_italy": "🇮🇹", + "flag_for_jamaica": "🇯🇲", + "flag_for_japan": "🇯🇵", + "flag_for_jersey": "🇯🇪", + "flag_for_jordan": "🇯🇴", + "flag_for_kazakhstan": "🇰🇿", + "flag_for_kenya": "🇰🇪", + "flag_for_kiribati": "🇰🇮", + "flag_for_kosovo": "🇽🇰", + "flag_for_kuwait": "🇰🇼", + "flag_for_kyrgyzstan": "🇰🇬", + "flag_for_laos": "🇱🇦", + "flag_for_latvia": "🇱🇻", + "flag_for_lebanon": "🇱🇧", + "flag_for_lesotho": "🇱🇸", + "flag_for_liberia": "🇱🇷", + "flag_for_libya": "🇱🇾", + "flag_for_liechtenstein": "🇱🇮", + "flag_for_lithuania": "🇱🇹", + "flag_for_luxembourg": "🇱🇺", + "flag_for_macau": "🇲🇴", + "flag_for_macedonia": "🇲🇰", + "flag_for_madagascar": "🇲🇬", + "flag_for_malawi": "🇲🇼", + "flag_for_malaysia": "🇲🇾", + "flag_for_maldives": "🇲🇻", + "flag_for_mali": "🇲🇱", + "flag_for_malta": "🇲🇹", + "flag_for_marshall_islands": "🇲🇭", + "flag_for_martinique": "🇲🇶", + "flag_for_mauritania": "🇲🇷", + "flag_for_mauritius": "🇲🇺", + "flag_for_mayotte": "🇾🇹", + "flag_for_mexico": "🇲🇽", + "flag_for_micronesia": "🇫🇲", + "flag_for_moldova": "🇲🇩", + "flag_for_monaco": "🇲🇨", + "flag_for_mongolia": "🇲🇳", + "flag_for_montenegro": "🇲🇪", + "flag_for_montserrat": "🇲🇸", + "flag_for_morocco": "🇲🇦", + "flag_for_mozambique": "🇲🇿", + "flag_for_myanmar": "🇲🇲", + "flag_for_namibia": "🇳🇦", + "flag_for_nauru": "🇳🇷", + "flag_for_nepal": "🇳🇵", + "flag_for_netherlands": "🇳🇱", + "flag_for_new_caledonia": "🇳🇨", + "flag_for_new_zealand": "🇳🇿", + "flag_for_nicaragua": "🇳🇮", + "flag_for_niger": "🇳🇪", + "flag_for_nigeria": "🇳🇬", + "flag_for_niue": "🇳🇺", + "flag_for_norfolk_island": "🇳🇫", + "flag_for_north_korea": "🇰🇵", + "flag_for_northern_mariana_islands": "🇲🇵", + "flag_for_norway": "🇳🇴", + "flag_for_oman": "🇴🇲", + "flag_for_pakistan": "🇵🇰", + "flag_for_palau": "🇵🇼", + "flag_for_palestinian_territories": "🇵🇸", + "flag_for_panama": "🇵🇦", + "flag_for_papua_new_guinea": "🇵🇬", + "flag_for_paraguay": "🇵🇾", + "flag_for_peru": "🇵🇪", + "flag_for_philippines": "🇵🇭", + "flag_for_pitcairn_islands": "🇵🇳", + "flag_for_poland": "🇵🇱", + "flag_for_portugal": "🇵🇹", + "flag_for_puerto_rico": "🇵🇷", + "flag_for_qatar": "🇶🇦", + "flag_for_romania": "🇷🇴", + "flag_for_russia": "🇷🇺", + "flag_for_rwanda": "🇷🇼", + "flag_for_réunion": "🇷🇪", + "flag_for_samoa": "🇼🇸", + "flag_for_san_marino": "🇸🇲", + "flag_for_saudi_arabia": "🇸🇦", + "flag_for_senegal": "🇸🇳", + "flag_for_serbia": "🇷🇸", + "flag_for_seychelles": "🇸🇨", + "flag_for_sierra_leone": "🇸🇱", + "flag_for_singapore": "🇸🇬", + "flag_for_sint_maarten": "🇸🇽", + "flag_for_slovakia": "🇸🇰", + "flag_for_slovenia": "🇸🇮", + "flag_for_solomon_islands": "🇸🇧", + "flag_for_somalia": "🇸🇴", + "flag_for_south_africa": "🇿🇦", + "flag_for_south_georgia_&_south_sandwich_islands": "🇬🇸", + "flag_for_south_korea": "🇰🇷", + "flag_for_south_sudan": "🇸🇸", + "flag_for_spain": "🇪🇸", + "flag_for_sri_lanka": "🇱🇰", + "flag_for_st._barthélemy": "🇧🇱", + "flag_for_st._helena": "🇸🇭", + "flag_for_st._kitts_&_nevis": "🇰🇳", + "flag_for_st._lucia": "🇱🇨", + "flag_for_st._martin": "🇲🇫", + "flag_for_st._pierre_&_miquelon": "🇵🇲", + "flag_for_st._vincent_&_grenadines": "🇻🇨", + "flag_for_sudan": "🇸🇩", + "flag_for_suriname": "🇸🇷", + "flag_for_svalbard_&_jan_mayen": "🇸🇯", + "flag_for_swaziland": "🇸🇿", + "flag_for_sweden": "🇸🇪", + "flag_for_switzerland": "🇨🇭", + "flag_for_syria": "🇸🇾", + "flag_for_são_tomé_&_príncipe": "🇸🇹", + "flag_for_taiwan": "🇹🇼", + "flag_for_tajikistan": "🇹🇯", + "flag_for_tanzania": "🇹🇿", + "flag_for_thailand": "🇹🇭", + "flag_for_timor__leste": "🇹🇱", + "flag_for_togo": "🇹🇬", + "flag_for_tokelau": "🇹🇰", + "flag_for_tonga": "🇹🇴", + "flag_for_trinidad_&_tobago": "🇹🇹", + "flag_for_tristan_da_cunha": "🇹🇦", + "flag_for_tunisia": "🇹🇳", + "flag_for_turkey": "🇹🇷", + "flag_for_turkmenistan": "🇹🇲", + "flag_for_turks_&_caicos_islands": "🇹🇨", + "flag_for_tuvalu": "🇹🇻", + "flag_for_u.s._outlying_islands": "🇺🇲", + "flag_for_u.s._virgin_islands": "🇻🇮", + "flag_for_uganda": "🇺🇬", + "flag_for_ukraine": "🇺🇦", + "flag_for_united_arab_emirates": "🇦🇪", + "flag_for_united_kingdom": "🇬🇧", + "flag_for_united_states": "🇺🇸", + "flag_for_uruguay": "🇺🇾", + "flag_for_uzbekistan": "🇺🇿", + "flag_for_vanuatu": "🇻🇺", + "flag_for_vatican_city": "🇻🇦", + "flag_for_venezuela": "🇻🇪", + "flag_for_vietnam": "🇻🇳", + "flag_for_wallis_&_futuna": "🇼🇫", + "flag_for_western_sahara": "🇪🇭", + "flag_for_yemen": "🇾🇪", + "flag_for_zambia": "🇿🇲", + "flag_for_zimbabwe": "🇿🇼", + "flag_for_åland_islands": "🇦🇽", + "golf": "⛳", + "fleur__de__lis": "⚜", + "muscle": "💪", + "flushed": "😳", + "frame_with_picture": "🖼", + "fries": "🍟", + "frog": "🐸", + "hatched_chick": "🐥", + "frowning": "😦", + "fuelpump": "⛽", + "full_moon_with_face": "🌝", + "gem": "💎", + "star2": "🌟", + "golfer": "🏌", + "mortar_board": "🎓", + "grimacing": "😬", + "smile_cat": "😸", + "grinning": "😀", + "grin": "😁", + "heartpulse": "💗", + "guardsman": "💂", + "haircut": "💇", + "hamster": "🐹", + "raising_hand": "🙋", + "headphones": "🎧", + "hear_no_evil": "🙉", + "cupid": "💘", + "gift_heart": "💝", + "heart": "❤", + "exclamation": "❗", + "heavy_exclamation_mark": "❗", + "heavy_heart_exclamation_mark_ornament": "❣", + "o": "⭕", + "helm_symbol": "⎈", + "helmet_with_white_cross": "⛑", + "high_heel": "👠", + "bullettrain_side": "🚄", + "bullettrain_front": "🚅", + "high_brightness": "🔆", + "zap": "⚡", + "hocho": "🔪", + "knife": "🔪", + "bee": "🐝", + "traffic_light": "🚥", + "racehorse": "🐎", + "coffee": "☕", + "hotsprings": "♨", + "hourglass": "⌛", + "hourglass_flowing_sand": "⏳", + "house_buildings": "🏘", + "100": "💯", + "hushed": "😯", + "ice_hockey_stick_and_puck": "🏒", + "imp": "👿", + "information_desk_person": "💁", + "information_source": "ℹ", + "capital_abcd": "🔠", + "abc": "🔤", + "abcd": "🔡", + "1234": "🔢", + "symbols": "🔣", + "izakaya_lantern": "🏮", + "lantern": "🏮", + "jack_o_lantern": "🎃", + "dolls": "🎎", + "japanese_goblin": "👺", + "japanese_ogre": "👹", + "beginner": "🔰", + "zero": "0️⃣", + "one": "1️⃣", + "ten": "🔟", + "two": "2️⃣", + "three": "3️⃣", + "four": "4️⃣", + "five": "5️⃣", + "six": "6️⃣", + "seven": "7️⃣", + "eight": "8️⃣", + "nine": "9️⃣", + "couplekiss": "💏", + "kissing_cat": "😽", + "kissing": "😗", + "kissing_closed_eyes": "😚", + "kissing_smiling_eyes": "😙", + "beetle": "🐞", + "large_blue_circle": "🔵", + "last_quarter_moon_with_face": "🌜", + "leaves": "🍃", + "mag": "🔍", + "left_right_arrow": "↔", + "leftwards_arrow_with_hook": "↩", + "arrow_left": "⬅", + "lock": "🔒", + "lock_with_ink_pen": "🔏", + "sob": "😭", + "low_brightness": "🔅", + "lower_left_ballpoint_pen": "🖊", + "lower_left_crayon": "🖍", + "lower_left_fountain_pen": "🖋", + "lower_left_paintbrush": "🖌", + "mahjong": "🀄", + "couple": "👫", + "man_in_business_suit_levitating": "🕴", + "man_with_gua_pi_mao": "👲", + "man_with_turban": "👳", + "mans_shoe": "👞", + "shoe": "👞", + "menorah_with_nine_branches": "🕎", + "mens": "🚹", + "minidisc": "💽", + "iphone": "📱", + "calling": "📲", + "money__mouth_face": "🤑", + "moneybag": "💰", + "rice_scene": "🎑", + "mountain_bicyclist": "🚵", + "mouse2": "🐁", + "lips": "👄", + "moyai": "🗿", + "notes": "🎶", + "nail_care": "💅", + "ab": "🆎", + "negative_squared_cross_mark": "❎", + "a": "🅰", + "b": "🅱", + "o2": "🅾", + "parking": "🅿", + "new_moon_with_face": "🌚", + "no_entry_sign": "🚫", + "underage": "🔞", + "non__potable_water": "🚱", + "arrow_upper_right": "↗", + "arrow_upper_left": "↖", + "office": "🏢", + "older_man": "👴", + "older_woman": "👵", + "om_symbol": "🕉", + "on": "🔛", + "book": "📖", + "unlock": "🔓", + "mailbox_with_no_mail": "📭", + "mailbox_with_mail": "📬", + "cd": "💿", + "tada": "🎉", + "feet": "🐾", + "walking": "🚶", + "pencil2": "✏", + "pensive": "😔", + "persevere": "😣", + "bow": "🙇", + "raised_hands": "🙌", + "person_with_ball": "⛹", + "person_with_blond_hair": "👱", + "pray": "🙏", + "person_with_pouting_face": "🙎", + "computer": "💻", + "pig2": "🐖", + "hankey": "💩", + "poop": "💩", + "shit": "💩", + "bamboo": "🎍", + "gun": "🔫", + "black_joker": "🃏", + "rotating_light": "🚨", + "cop": "👮", + "stew": "🍲", + "pouch": "👝", + "pouting_cat": "😾", + "rage": "😡", + "put_litter_in_its_place": "🚮", + "rabbit2": "🐇", + "racing_motorcycle": "🏍", + "radioactive_sign": "☢", + "fist": "✊", + "hand": "✋", + "raised_hand_with_fingers_splayed": "🖐", + "raised_hand_with_part_between_middle_and_ring_fingers": "🖖", + "blue_car": "🚙", + "apple": "🍎", + "relieved": "😌", + "reversed_hand_with_middle_finger_extended": "🖕", + "mag_right": "🔎", + "arrow_right_hook": "↪", + "sweet_potato": "🍠", + "robot": "🤖", + "rolled__up_newspaper": "🗞", + "rowboat": "🚣", + "runner": "🏃", + "running": "🏃", + "running_shirt_with_sash": "🎽", + "boat": "⛵", + "scales": "⚖", + "school_satchel": "🎒", + "scorpius": "♏", + "see_no_evil": "🙈", + "sheep": "🐑", + "stars": "🌠", + "cake": "🍰", + "six_pointed_star": "🔯", + "ski": "🎿", + "sleeping_accommodation": "🛌", + "sleeping": "😴", + "sleepy": "😪", + "sleuth_or_spy": "🕵", + "heart_eyes_cat": "😻", + "smiley_cat": "😺", + "innocent": "😇", + "heart_eyes": "😍", + "smiling_imp": "😈", + "smiley": "😃", + "sweat_smile": "😅", + "smile": "😄", + "laughing": "😆", + "satisfied": "😆", + "blush": "😊", + "smirk": "😏", + "smoking": "🚬", + "snow_capped_mountain": "🏔", + "soccer": "⚽", + "icecream": "🍦", + "soon": "🔜", + "arrow_lower_right": "↘", + "arrow_lower_left": "↙", + "speak_no_evil": "🙊", + "speaker": "🔈", + "mute": "🔇", + "sound": "🔉", + "loud_sound": "🔊", + "speaking_head_in_silhouette": "🗣", + "spiral_calendar_pad": "🗓", + "spiral_note_pad": "🗒", + "shell": "🐚", + "sweat_drops": "💦", + "u5272": "🈹", + "u5408": "🈴", + "u55b6": "🈺", + "u6307": "🈯", + "u6708": "🈷", + "u6709": "🈶", + "u6e80": "🈵", + "u7121": "🈚", + "u7533": "🈸", + "u7981": "🈲", + "u7a7a": "🈳", + "cl": "🆑", + "cool": "🆒", + "free": "🆓", + "id": "🆔", + "koko": "🈁", + "sa": "🈂", + "new": "🆕", + "ng": "🆖", + "ok": "🆗", + "sos": "🆘", + "up": "🆙", + "vs": "🆚", + "steam_locomotive": "🚂", + "ramen": "🍜", + "partly_sunny": "⛅", + "city_sunrise": "🌇", + "surfer": "🏄", + "swimmer": "🏊", + "shirt": "👕", + "tshirt": "👕", + "table_tennis_paddle_and_ball": "🏓", + "tea": "🍵", + "tv": "📺", + "three_button_mouse": "🖱", + "+1": "👍", + "thumbsup": "👍", + "__1": "👎", + "-1": "👎", + "thumbsdown": "👎", + "thunder_cloud_and_rain": "⛈", + "tiger2": "🐅", + "tophat": "🎩", + "top": "🔝", + "tm": "™", + "train2": "🚆", + "triangular_flag_on_post": "🚩", + "trident": "🔱", + "twisted_rightwards_arrows": "🔀", + "unamused": "😒", + "small_red_triangle": "🔺", + "arrow_up_small": "🔼", + "arrow_up_down": "↕", + "upside__down_face": "🙃", + "arrow_up": "⬆", + "v": "✌", + "vhs": "📼", + "wc": "🚾", + "ocean": "🌊", + "waving_black_flag": "🏴", + "wave": "👋", + "waving_white_flag": "🏳", + "moon": "🌔", + "scream_cat": "🙀", + "weary": "😩", + "weight_lifter": "🏋", + "whale2": "🐋", + "wheelchair": "♿", + "point_down": "👇", + "grey_exclamation": "❕", + "white_frowning_face": "☹", + "white_check_mark": "✅", + "point_left": "👈", + "white_medium_small_square": "◽", + "star": "⭐", + "grey_question": "❔", + "point_right": "👉", + "relaxed": "☺", + "white_sun_behind_cloud": "🌥", + "white_sun_behind_cloud_with_rain": "🌦", + "white_sun_with_small_cloud": "🌤", + "point_up_2": "👆", + "point_up": "☝", + "wind_blowing_face": "🌬", + "wink": "😉", + "wolf": "🐺", + "dancers": "👯", + "boot": "👢", + "womans_clothes": "👚", + "womans_hat": "👒", + "sandal": "👡", + "womens": "🚺", + "worried": "😟", + "gift": "🎁", + "zipper__mouth_face": "🤐", + "regional_indicator_a": "🇦", + "regional_indicator_b": "🇧", + "regional_indicator_c": "🇨", + "regional_indicator_d": "🇩", + "regional_indicator_e": "🇪", + "regional_indicator_f": "🇫", + "regional_indicator_g": "🇬", + "regional_indicator_h": "🇭", + "regional_indicator_i": "🇮", + "regional_indicator_j": "🇯", + "regional_indicator_k": "🇰", + "regional_indicator_l": "🇱", + "regional_indicator_m": "🇲", + "regional_indicator_n": "🇳", + "regional_indicator_o": "🇴", + "regional_indicator_p": "🇵", + "regional_indicator_q": "🇶", + "regional_indicator_r": "🇷", + "regional_indicator_s": "🇸", + "regional_indicator_t": "🇹", + "regional_indicator_u": "🇺", + "regional_indicator_v": "🇻", + "regional_indicator_w": "🇼", + "regional_indicator_x": "🇽", + "regional_indicator_y": "🇾", + "regional_indicator_z": "🇿", +} diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_replace.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_replace.py new file mode 100644 index 0000000..bb2cafa --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_emoji_replace.py @@ -0,0 +1,32 @@ +from typing import Callable, Match, Optional +import re + +from ._emoji_codes import EMOJI + + +_ReStringMatch = Match[str] # regex match object +_ReSubCallable = Callable[[_ReStringMatch], str] # Callable invoked by re.sub +_EmojiSubMethod = Callable[[_ReSubCallable, str], str] # Sub method of a compiled re + + +def _emoji_replace( + text: str, + default_variant: Optional[str] = None, + _emoji_sub: _EmojiSubMethod = re.compile(r"(:(\S*?)(?:(?:\-)(emoji|text))?:)").sub, +) -> str: + """Replace emoji code in text.""" + get_emoji = EMOJI.__getitem__ + variants = {"text": "\uFE0E", "emoji": "\uFE0F"} + get_variant = variants.get + default_variant_code = variants.get(default_variant, "") if default_variant else "" + + def do_replace(match: Match[str]) -> str: + emoji_code, emoji_name, variant = match.groups() + try: + return get_emoji(emoji_name.lower()) + get_variant( + variant, default_variant_code + ) + except KeyError: + return emoji_code + + return _emoji_sub(do_replace, text) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_export_format.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_export_format.py new file mode 100644 index 0000000..094d2dc --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_export_format.py @@ -0,0 +1,76 @@ +CONSOLE_HTML_FORMAT = """\ + + + + + + + +
{code}
+ + +""" + +CONSOLE_SVG_FORMAT = """\ + + + + + + + + + {lines} + + + {chrome} + + {backgrounds} + + {matrix} + + + +""" + +_SVG_FONT_FAMILY = "Rich Fira Code" +_SVG_CLASSES_PREFIX = "rich-svg" diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_extension.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_extension.py new file mode 100644 index 0000000..cbd6da9 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_extension.py @@ -0,0 +1,10 @@ +from typing import Any + + +def load_ipython_extension(ip: Any) -> None: # pragma: no cover + # prevent circular import + from pip._vendor.rich.pretty import install + from pip._vendor.rich.traceback import install as tr_install + + install() + tr_install() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_fileno.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_fileno.py new file mode 100644 index 0000000..b17ee65 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_fileno.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import IO, Callable + + +def get_fileno(file_like: IO[str]) -> int | None: + """Get fileno() from a file, accounting for poorly implemented file-like objects. + + Args: + file_like (IO): A file-like object. + + Returns: + int | None: The result of fileno if available, or None if operation failed. + """ + fileno: Callable[[], int] | None = getattr(file_like, "fileno", None) + if fileno is not None: + try: + return fileno() + except Exception: + # `fileno` is documented as potentially raising a OSError + # Alas, from the issues, there are so many poorly implemented file-like objects, + # that `fileno()` can raise just about anything. + return None + return None diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_inspect.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_inspect.py new file mode 100644 index 0000000..30446ce --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_inspect.py @@ -0,0 +1,270 @@ +from __future__ import absolute_import + +import inspect +from inspect import cleandoc, getdoc, getfile, isclass, ismodule, signature +from typing import Any, Collection, Iterable, Optional, Tuple, Type, Union + +from .console import Group, RenderableType +from .control import escape_control_codes +from .highlighter import ReprHighlighter +from .jupyter import JupyterMixin +from .panel import Panel +from .pretty import Pretty +from .table import Table +from .text import Text, TextType + + +def _first_paragraph(doc: str) -> str: + """Get the first paragraph from a docstring.""" + paragraph, _, _ = doc.partition("\n\n") + return paragraph + + +class Inspect(JupyterMixin): + """A renderable to inspect any Python Object. + + Args: + obj (Any): An object to inspect. + title (str, optional): Title to display over inspect result, or None use type. Defaults to None. + help (bool, optional): Show full help text rather than just first paragraph. Defaults to False. + methods (bool, optional): Enable inspection of callables. Defaults to False. + docs (bool, optional): Also render doc strings. Defaults to True. + private (bool, optional): Show private attributes (beginning with underscore). Defaults to False. + dunder (bool, optional): Show attributes starting with double underscore. Defaults to False. + sort (bool, optional): Sort attributes alphabetically. Defaults to True. + all (bool, optional): Show all attributes. Defaults to False. + value (bool, optional): Pretty print value of object. Defaults to True. + """ + + def __init__( + self, + obj: Any, + *, + title: Optional[TextType] = None, + help: bool = False, + methods: bool = False, + docs: bool = True, + private: bool = False, + dunder: bool = False, + sort: bool = True, + all: bool = True, + value: bool = True, + ) -> None: + self.highlighter = ReprHighlighter() + self.obj = obj + self.title = title or self._make_title(obj) + if all: + methods = private = dunder = True + self.help = help + self.methods = methods + self.docs = docs or help + self.private = private or dunder + self.dunder = dunder + self.sort = sort + self.value = value + + def _make_title(self, obj: Any) -> Text: + """Make a default title.""" + title_str = ( + str(obj) + if (isclass(obj) or callable(obj) or ismodule(obj)) + else str(type(obj)) + ) + title_text = self.highlighter(title_str) + return title_text + + def __rich__(self) -> Panel: + return Panel.fit( + Group(*self._render()), + title=self.title, + border_style="scope.border", + padding=(0, 1), + ) + + def _get_signature(self, name: str, obj: Any) -> Optional[Text]: + """Get a signature for a callable.""" + try: + _signature = str(signature(obj)) + ":" + except ValueError: + _signature = "(...)" + except TypeError: + return None + + source_filename: Optional[str] = None + try: + source_filename = getfile(obj) + except (OSError, TypeError): + # OSError is raised if obj has no source file, e.g. when defined in REPL. + pass + + callable_name = Text(name, style="inspect.callable") + if source_filename: + callable_name.stylize(f"link file://{source_filename}") + signature_text = self.highlighter(_signature) + + qualname = name or getattr(obj, "__qualname__", name) + + # If obj is a module, there may be classes (which are callable) to display + if inspect.isclass(obj): + prefix = "class" + elif inspect.iscoroutinefunction(obj): + prefix = "async def" + else: + prefix = "def" + + qual_signature = Text.assemble( + (f"{prefix} ", f"inspect.{prefix.replace(' ', '_')}"), + (qualname, "inspect.callable"), + signature_text, + ) + + return qual_signature + + def _render(self) -> Iterable[RenderableType]: + """Render object.""" + + def sort_items(item: Tuple[str, Any]) -> Tuple[bool, str]: + key, (_error, value) = item + return (callable(value), key.strip("_").lower()) + + def safe_getattr(attr_name: str) -> Tuple[Any, Any]: + """Get attribute or any exception.""" + try: + return (None, getattr(obj, attr_name)) + except Exception as error: + return (error, None) + + obj = self.obj + keys = dir(obj) + total_items = len(keys) + if not self.dunder: + keys = [key for key in keys if not key.startswith("__")] + if not self.private: + keys = [key for key in keys if not key.startswith("_")] + not_shown_count = total_items - len(keys) + items = [(key, safe_getattr(key)) for key in keys] + if self.sort: + items.sort(key=sort_items) + + items_table = Table.grid(padding=(0, 1), expand=False) + items_table.add_column(justify="right") + add_row = items_table.add_row + highlighter = self.highlighter + + if callable(obj): + signature = self._get_signature("", obj) + if signature is not None: + yield signature + yield "" + + if self.docs: + _doc = self._get_formatted_doc(obj) + if _doc is not None: + doc_text = Text(_doc, style="inspect.help") + doc_text = highlighter(doc_text) + yield doc_text + yield "" + + if self.value and not (isclass(obj) or callable(obj) or ismodule(obj)): + yield Panel( + Pretty(obj, indent_guides=True, max_length=10, max_string=60), + border_style="inspect.value.border", + ) + yield "" + + for key, (error, value) in items: + key_text = Text.assemble( + ( + key, + "inspect.attr.dunder" if key.startswith("__") else "inspect.attr", + ), + (" =", "inspect.equals"), + ) + if error is not None: + warning = key_text.copy() + warning.stylize("inspect.error") + add_row(warning, highlighter(repr(error))) + continue + + if callable(value): + if not self.methods: + continue + + _signature_text = self._get_signature(key, value) + if _signature_text is None: + add_row(key_text, Pretty(value, highlighter=highlighter)) + else: + if self.docs: + docs = self._get_formatted_doc(value) + if docs is not None: + _signature_text.append("\n" if "\n" in docs else " ") + doc = highlighter(docs) + doc.stylize("inspect.doc") + _signature_text.append(doc) + + add_row(key_text, _signature_text) + else: + add_row(key_text, Pretty(value, highlighter=highlighter)) + if items_table.row_count: + yield items_table + elif not_shown_count: + yield Text.from_markup( + f"[b cyan]{not_shown_count}[/][i] attribute(s) not shown.[/i] " + f"Run [b][magenta]inspect[/]([not b]inspect[/])[/b] for options." + ) + + def _get_formatted_doc(self, object_: Any) -> Optional[str]: + """ + Extract the docstring of an object, process it and returns it. + The processing consists in cleaning up the doctring's indentation, + taking only its 1st paragraph if `self.help` is not True, + and escape its control codes. + + Args: + object_ (Any): the object to get the docstring from. + + Returns: + Optional[str]: the processed docstring, or None if no docstring was found. + """ + docs = getdoc(object_) + if docs is None: + return None + docs = cleandoc(docs).strip() + if not self.help: + docs = _first_paragraph(docs) + return escape_control_codes(docs) + + +def get_object_types_mro(obj: Union[object, Type[Any]]) -> Tuple[type, ...]: + """Returns the MRO of an object's class, or of the object itself if it's a class.""" + if not hasattr(obj, "__mro__"): + # N.B. we cannot use `if type(obj) is type` here because it doesn't work with + # some types of classes, such as the ones that use abc.ABCMeta. + obj = type(obj) + return getattr(obj, "__mro__", ()) + + +def get_object_types_mro_as_strings(obj: object) -> Collection[str]: + """ + Returns the MRO of an object's class as full qualified names, or of the object itself if it's a class. + + Examples: + `object_types_mro_as_strings(JSONDecoder)` will return `['json.decoder.JSONDecoder', 'builtins.object']` + """ + return [ + f'{getattr(type_, "__module__", "")}.{getattr(type_, "__qualname__", "")}' + for type_ in get_object_types_mro(obj) + ] + + +def is_object_one_of_types( + obj: object, fully_qualified_types_names: Collection[str] +) -> bool: + """ + Returns `True` if the given object's class (or the object itself, if it's a class) has one of the + fully qualified names in its MRO. + """ + for type_name in get_object_types_mro_as_strings(obj): + if type_name in fully_qualified_types_names: + return True + return False diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_log_render.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_log_render.py new file mode 100644 index 0000000..fc16c84 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_log_render.py @@ -0,0 +1,94 @@ +from datetime import datetime +from typing import Iterable, List, Optional, TYPE_CHECKING, Union, Callable + + +from .text import Text, TextType + +if TYPE_CHECKING: + from .console import Console, ConsoleRenderable, RenderableType + from .table import Table + +FormatTimeCallable = Callable[[datetime], Text] + + +class LogRender: + def __init__( + self, + show_time: bool = True, + show_level: bool = False, + show_path: bool = True, + time_format: Union[str, FormatTimeCallable] = "[%x %X]", + omit_repeated_times: bool = True, + level_width: Optional[int] = 8, + ) -> None: + self.show_time = show_time + self.show_level = show_level + self.show_path = show_path + self.time_format = time_format + self.omit_repeated_times = omit_repeated_times + self.level_width = level_width + self._last_time: Optional[Text] = None + + def __call__( + self, + console: "Console", + renderables: Iterable["ConsoleRenderable"], + log_time: Optional[datetime] = None, + time_format: Optional[Union[str, FormatTimeCallable]] = None, + level: TextType = "", + path: Optional[str] = None, + line_no: Optional[int] = None, + link_path: Optional[str] = None, + ) -> "Table": + from .containers import Renderables + from .table import Table + + output = Table.grid(padding=(0, 1)) + output.expand = True + if self.show_time: + output.add_column(style="log.time") + if self.show_level: + output.add_column(style="log.level", width=self.level_width) + output.add_column(ratio=1, style="log.message", overflow="fold") + if self.show_path and path: + output.add_column(style="log.path") + row: List["RenderableType"] = [] + if self.show_time: + log_time = log_time or console.get_datetime() + time_format = time_format or self.time_format + if callable(time_format): + log_time_display = time_format(log_time) + else: + log_time_display = Text(log_time.strftime(time_format)) + if log_time_display == self._last_time and self.omit_repeated_times: + row.append(Text(" " * len(log_time_display))) + else: + row.append(log_time_display) + self._last_time = log_time_display + if self.show_level: + row.append(level) + + row.append(Renderables(renderables)) + if self.show_path and path: + path_text = Text() + path_text.append( + path, style=f"link file://{link_path}" if link_path else "" + ) + if line_no: + path_text.append(":") + path_text.append( + f"{line_no}", + style=f"link file://{link_path}#{line_no}" if link_path else "", + ) + row.append(path_text) + + output.add_row(*row) + return output + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console + + c = Console() + c.print("[on blue]Hello", justify="right") + c.log("[on blue]hello", justify="right") diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_loop.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_loop.py new file mode 100644 index 0000000..01c6caf --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_loop.py @@ -0,0 +1,43 @@ +from typing import Iterable, Tuple, TypeVar + +T = TypeVar("T") + + +def loop_first(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: + """Iterate and generate a tuple with a flag for first value.""" + iter_values = iter(values) + try: + value = next(iter_values) + except StopIteration: + return + yield True, value + for value in iter_values: + yield False, value + + +def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: + """Iterate and generate a tuple with a flag for last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + for value in iter_values: + yield False, previous_value + previous_value = value + yield True, previous_value + + +def loop_first_last(values: Iterable[T]) -> Iterable[Tuple[bool, bool, T]]: + """Iterate and generate a tuple with a flag for first and last value.""" + iter_values = iter(values) + try: + previous_value = next(iter_values) + except StopIteration: + return + first = True + for value in iter_values: + yield first, False, previous_value + first = False + previous_value = value + yield first, True, previous_value diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_null_file.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_null_file.py new file mode 100644 index 0000000..b659673 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_null_file.py @@ -0,0 +1,69 @@ +from types import TracebackType +from typing import IO, Iterable, Iterator, List, Optional, Type + + +class NullFile(IO[str]): + def close(self) -> None: + pass + + def isatty(self) -> bool: + return False + + def read(self, __n: int = 1) -> str: + return "" + + def readable(self) -> bool: + return False + + def readline(self, __limit: int = 1) -> str: + return "" + + def readlines(self, __hint: int = 1) -> List[str]: + return [] + + def seek(self, __offset: int, __whence: int = 1) -> int: + return 0 + + def seekable(self) -> bool: + return False + + def tell(self) -> int: + return 0 + + def truncate(self, __size: Optional[int] = 1) -> int: + return 0 + + def writable(self) -> bool: + return False + + def writelines(self, __lines: Iterable[str]) -> None: + pass + + def __next__(self) -> str: + return "" + + def __iter__(self) -> Iterator[str]: + return iter([""]) + + def __enter__(self) -> IO[str]: + pass + + def __exit__( + self, + __t: Optional[Type[BaseException]], + __value: Optional[BaseException], + __traceback: Optional[TracebackType], + ) -> None: + pass + + def write(self, text: str) -> int: + return 0 + + def flush(self) -> None: + pass + + def fileno(self) -> int: + return -1 + + +NULL_FILE = NullFile() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_palettes.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_palettes.py new file mode 100644 index 0000000..3c748d3 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_palettes.py @@ -0,0 +1,309 @@ +from .palette import Palette + + +# Taken from https://en.wikipedia.org/wiki/ANSI_escape_code (Windows 10 column) +WINDOWS_PALETTE = Palette( + [ + (12, 12, 12), + (197, 15, 31), + (19, 161, 14), + (193, 156, 0), + (0, 55, 218), + (136, 23, 152), + (58, 150, 221), + (204, 204, 204), + (118, 118, 118), + (231, 72, 86), + (22, 198, 12), + (249, 241, 165), + (59, 120, 255), + (180, 0, 158), + (97, 214, 214), + (242, 242, 242), + ] +) + +# # The standard ansi colors (including bright variants) +STANDARD_PALETTE = Palette( + [ + (0, 0, 0), + (170, 0, 0), + (0, 170, 0), + (170, 85, 0), + (0, 0, 170), + (170, 0, 170), + (0, 170, 170), + (170, 170, 170), + (85, 85, 85), + (255, 85, 85), + (85, 255, 85), + (255, 255, 85), + (85, 85, 255), + (255, 85, 255), + (85, 255, 255), + (255, 255, 255), + ] +) + + +# The 256 color palette +EIGHT_BIT_PALETTE = Palette( + [ + (0, 0, 0), + (128, 0, 0), + (0, 128, 0), + (128, 128, 0), + (0, 0, 128), + (128, 0, 128), + (0, 128, 128), + (192, 192, 192), + (128, 128, 128), + (255, 0, 0), + (0, 255, 0), + (255, 255, 0), + (0, 0, 255), + (255, 0, 255), + (0, 255, 255), + (255, 255, 255), + (0, 0, 0), + (0, 0, 95), + (0, 0, 135), + (0, 0, 175), + (0, 0, 215), + (0, 0, 255), + (0, 95, 0), + (0, 95, 95), + (0, 95, 135), + (0, 95, 175), + (0, 95, 215), + (0, 95, 255), + (0, 135, 0), + (0, 135, 95), + (0, 135, 135), + (0, 135, 175), + (0, 135, 215), + (0, 135, 255), + (0, 175, 0), + (0, 175, 95), + (0, 175, 135), + (0, 175, 175), + (0, 175, 215), + (0, 175, 255), + (0, 215, 0), + (0, 215, 95), + (0, 215, 135), + (0, 215, 175), + (0, 215, 215), + (0, 215, 255), + (0, 255, 0), + (0, 255, 95), + (0, 255, 135), + (0, 255, 175), + (0, 255, 215), + (0, 255, 255), + (95, 0, 0), + (95, 0, 95), + (95, 0, 135), + (95, 0, 175), + (95, 0, 215), + (95, 0, 255), + (95, 95, 0), + (95, 95, 95), + (95, 95, 135), + (95, 95, 175), + (95, 95, 215), + (95, 95, 255), + (95, 135, 0), + (95, 135, 95), + (95, 135, 135), + (95, 135, 175), + (95, 135, 215), + (95, 135, 255), + (95, 175, 0), + (95, 175, 95), + (95, 175, 135), + (95, 175, 175), + (95, 175, 215), + (95, 175, 255), + (95, 215, 0), + (95, 215, 95), + (95, 215, 135), + (95, 215, 175), + (95, 215, 215), + (95, 215, 255), + (95, 255, 0), + (95, 255, 95), + (95, 255, 135), + (95, 255, 175), + (95, 255, 215), + (95, 255, 255), + (135, 0, 0), + (135, 0, 95), + (135, 0, 135), + (135, 0, 175), + (135, 0, 215), + (135, 0, 255), + (135, 95, 0), + (135, 95, 95), + (135, 95, 135), + (135, 95, 175), + (135, 95, 215), + (135, 95, 255), + (135, 135, 0), + (135, 135, 95), + (135, 135, 135), + (135, 135, 175), + (135, 135, 215), + (135, 135, 255), + (135, 175, 0), + (135, 175, 95), + (135, 175, 135), + (135, 175, 175), + (135, 175, 215), + (135, 175, 255), + (135, 215, 0), + (135, 215, 95), + (135, 215, 135), + (135, 215, 175), + (135, 215, 215), + (135, 215, 255), + (135, 255, 0), + (135, 255, 95), + (135, 255, 135), + (135, 255, 175), + (135, 255, 215), + (135, 255, 255), + (175, 0, 0), + (175, 0, 95), + (175, 0, 135), + (175, 0, 175), + (175, 0, 215), + (175, 0, 255), + (175, 95, 0), + (175, 95, 95), + (175, 95, 135), + (175, 95, 175), + (175, 95, 215), + (175, 95, 255), + (175, 135, 0), + (175, 135, 95), + (175, 135, 135), + (175, 135, 175), + (175, 135, 215), + (175, 135, 255), + (175, 175, 0), + (175, 175, 95), + (175, 175, 135), + (175, 175, 175), + (175, 175, 215), + (175, 175, 255), + (175, 215, 0), + (175, 215, 95), + (175, 215, 135), + (175, 215, 175), + (175, 215, 215), + (175, 215, 255), + (175, 255, 0), + (175, 255, 95), + (175, 255, 135), + (175, 255, 175), + (175, 255, 215), + (175, 255, 255), + (215, 0, 0), + (215, 0, 95), + (215, 0, 135), + (215, 0, 175), + (215, 0, 215), + (215, 0, 255), + (215, 95, 0), + (215, 95, 95), + (215, 95, 135), + (215, 95, 175), + (215, 95, 215), + (215, 95, 255), + (215, 135, 0), + (215, 135, 95), + (215, 135, 135), + (215, 135, 175), + (215, 135, 215), + (215, 135, 255), + (215, 175, 0), + (215, 175, 95), + (215, 175, 135), + (215, 175, 175), + (215, 175, 215), + (215, 175, 255), + (215, 215, 0), + (215, 215, 95), + (215, 215, 135), + (215, 215, 175), + (215, 215, 215), + (215, 215, 255), + (215, 255, 0), + (215, 255, 95), + (215, 255, 135), + (215, 255, 175), + (215, 255, 215), + (215, 255, 255), + (255, 0, 0), + (255, 0, 95), + (255, 0, 135), + (255, 0, 175), + (255, 0, 215), + (255, 0, 255), + (255, 95, 0), + (255, 95, 95), + (255, 95, 135), + (255, 95, 175), + (255, 95, 215), + (255, 95, 255), + (255, 135, 0), + (255, 135, 95), + (255, 135, 135), + (255, 135, 175), + (255, 135, 215), + (255, 135, 255), + (255, 175, 0), + (255, 175, 95), + (255, 175, 135), + (255, 175, 175), + (255, 175, 215), + (255, 175, 255), + (255, 215, 0), + (255, 215, 95), + (255, 215, 135), + (255, 215, 175), + (255, 215, 215), + (255, 215, 255), + (255, 255, 0), + (255, 255, 95), + (255, 255, 135), + (255, 255, 175), + (255, 255, 215), + (255, 255, 255), + (8, 8, 8), + (18, 18, 18), + (28, 28, 28), + (38, 38, 38), + (48, 48, 48), + (58, 58, 58), + (68, 68, 68), + (78, 78, 78), + (88, 88, 88), + (98, 98, 98), + (108, 108, 108), + (118, 118, 118), + (128, 128, 128), + (138, 138, 138), + (148, 148, 148), + (158, 158, 158), + (168, 168, 168), + (178, 178, 178), + (188, 188, 188), + (198, 198, 198), + (208, 208, 208), + (218, 218, 218), + (228, 228, 228), + (238, 238, 238), + ] +) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_pick.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_pick.py new file mode 100644 index 0000000..4f6d8b2 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_pick.py @@ -0,0 +1,17 @@ +from typing import Optional + + +def pick_bool(*values: Optional[bool]) -> bool: + """Pick the first non-none bool or return the last value. + + Args: + *values (bool): Any number of boolean or None values. + + Returns: + bool: First non-none boolean. + """ + assert values, "1 or more values required" + for value in values: + if value is not None: + return value + return bool(value) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_ratio.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_ratio.py new file mode 100644 index 0000000..e8a3a67 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_ratio.py @@ -0,0 +1,160 @@ +import sys +from fractions import Fraction +from math import ceil +from typing import cast, List, Optional, Sequence + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from pip._vendor.typing_extensions import Protocol # pragma: no cover + + +class Edge(Protocol): + """Any object that defines an edge (such as Layout).""" + + size: Optional[int] = None + ratio: int = 1 + minimum_size: int = 1 + + +def ratio_resolve(total: int, edges: Sequence[Edge]) -> List[int]: + """Divide total space to satisfy size, ratio, and minimum_size, constraints. + + The returned list of integers should add up to total in most cases, unless it is + impossible to satisfy all the constraints. For instance, if there are two edges + with a minimum size of 20 each and `total` is 30 then the returned list will be + greater than total. In practice, this would mean that a Layout object would + clip the rows that would overflow the screen height. + + Args: + total (int): Total number of characters. + edges (List[Edge]): Edges within total space. + + Returns: + List[int]: Number of characters for each edge. + """ + # Size of edge or None for yet to be determined + sizes = [(edge.size or None) for edge in edges] + + _Fraction = Fraction + + # While any edges haven't been calculated + while None in sizes: + # Get flexible edges and index to map these back on to sizes list + flexible_edges = [ + (index, edge) + for index, (size, edge) in enumerate(zip(sizes, edges)) + if size is None + ] + # Remaining space in total + remaining = total - sum(size or 0 for size in sizes) + if remaining <= 0: + # No room for flexible edges + return [ + ((edge.minimum_size or 1) if size is None else size) + for size, edge in zip(sizes, edges) + ] + # Calculate number of characters in a ratio portion + portion = _Fraction( + remaining, sum((edge.ratio or 1) for _, edge in flexible_edges) + ) + + # If any edges will be less than their minimum, replace size with the minimum + for index, edge in flexible_edges: + if portion * edge.ratio <= edge.minimum_size: + sizes[index] = edge.minimum_size + # New fixed size will invalidate calculations, so we need to repeat the process + break + else: + # Distribute flexible space and compensate for rounding error + # Since edge sizes can only be integers we need to add the remainder + # to the following line + remainder = _Fraction(0) + for index, edge in flexible_edges: + size, remainder = divmod(portion * edge.ratio + remainder, 1) + sizes[index] = size + break + # Sizes now contains integers only + return cast(List[int], sizes) + + +def ratio_reduce( + total: int, ratios: List[int], maximums: List[int], values: List[int] +) -> List[int]: + """Divide an integer total in to parts based on ratios. + + Args: + total (int): The total to divide. + ratios (List[int]): A list of integer ratios. + maximums (List[int]): List of maximums values for each slot. + values (List[int]): List of values + + Returns: + List[int]: A list of integers guaranteed to sum to total. + """ + ratios = [ratio if _max else 0 for ratio, _max in zip(ratios, maximums)] + total_ratio = sum(ratios) + if not total_ratio: + return values[:] + total_remaining = total + result: List[int] = [] + append = result.append + for ratio, maximum, value in zip(ratios, maximums, values): + if ratio and total_ratio > 0: + distributed = min(maximum, round(ratio * total_remaining / total_ratio)) + append(value - distributed) + total_remaining -= distributed + total_ratio -= ratio + else: + append(value) + return result + + +def ratio_distribute( + total: int, ratios: List[int], minimums: Optional[List[int]] = None +) -> List[int]: + """Distribute an integer total in to parts based on ratios. + + Args: + total (int): The total to divide. + ratios (List[int]): A list of integer ratios. + minimums (List[int]): List of minimum values for each slot. + + Returns: + List[int]: A list of integers guaranteed to sum to total. + """ + if minimums: + ratios = [ratio if _min else 0 for ratio, _min in zip(ratios, minimums)] + total_ratio = sum(ratios) + assert total_ratio > 0, "Sum of ratios must be > 0" + + total_remaining = total + distributed_total: List[int] = [] + append = distributed_total.append + if minimums is None: + _minimums = [0] * len(ratios) + else: + _minimums = minimums + for ratio, minimum in zip(ratios, _minimums): + if total_ratio > 0: + distributed = max(minimum, ceil(ratio * total_remaining / total_ratio)) + else: + distributed = total_remaining + append(distributed) + total_ratio -= ratio + total_remaining -= distributed + return distributed_total + + +if __name__ == "__main__": + from dataclasses import dataclass + + @dataclass + class E: + + size: Optional[int] = None + ratio: int = 1 + minimum_size: int = 1 + + resolved = ratio_resolve(110, [E(None, 1, 1), E(None, 1, 1), E(None, 1, 1)]) + print(sum(resolved)) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_spinners.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_spinners.py new file mode 100644 index 0000000..d0bb1fe --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_spinners.py @@ -0,0 +1,482 @@ +""" +Spinners are from: +* cli-spinners: + MIT License + Copyright (c) Sindre Sorhus (sindresorhus.com) + 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. +""" + +SPINNERS = { + "dots": { + "interval": 80, + "frames": "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏", + }, + "dots2": {"interval": 80, "frames": "⣾⣽⣻⢿⡿⣟⣯⣷"}, + "dots3": { + "interval": 80, + "frames": "⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓", + }, + "dots4": { + "interval": 80, + "frames": "⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆", + }, + "dots5": { + "interval": 80, + "frames": "⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋", + }, + "dots6": { + "interval": 80, + "frames": "⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁", + }, + "dots7": { + "interval": 80, + "frames": "⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈", + }, + "dots8": { + "interval": 80, + "frames": "⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈", + }, + "dots9": {"interval": 80, "frames": "⢹⢺⢼⣸⣇⡧⡗⡏"}, + "dots10": {"interval": 80, "frames": "⢄⢂⢁⡁⡈⡐⡠"}, + "dots11": {"interval": 100, "frames": "⠁⠂⠄⡀⢀⠠⠐⠈"}, + "dots12": { + "interval": 80, + "frames": [ + "⢀⠀", + "⡀⠀", + "⠄⠀", + "⢂⠀", + "⡂⠀", + "⠅⠀", + "⢃⠀", + "⡃⠀", + "⠍⠀", + "⢋⠀", + "⡋⠀", + "⠍⠁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⢈⠩", + "⡀⢙", + "⠄⡙", + "⢂⠩", + "⡂⢘", + "⠅⡘", + "⢃⠨", + "⡃⢐", + "⠍⡐", + "⢋⠠", + "⡋⢀", + "⠍⡁", + "⢋⠁", + "⡋⠁", + "⠍⠉", + "⠋⠉", + "⠋⠉", + "⠉⠙", + "⠉⠙", + "⠉⠩", + "⠈⢙", + "⠈⡙", + "⠈⠩", + "⠀⢙", + "⠀⡙", + "⠀⠩", + "⠀⢘", + "⠀⡘", + "⠀⠨", + "⠀⢐", + "⠀⡐", + "⠀⠠", + "⠀⢀", + "⠀⡀", + ], + }, + "dots8Bit": { + "interval": 80, + "frames": "⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙" + "⡚⡛⡜⡝⡞⡟⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻" + "⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕" + "⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯⢰⢱⢲⢳⢴⢵⢶⢷" + "⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿", + }, + "line": {"interval": 130, "frames": ["-", "\\", "|", "/"]}, + "line2": {"interval": 100, "frames": "⠂-–—–-"}, + "pipe": {"interval": 100, "frames": "┤┘┴└├┌┬┐"}, + "simpleDots": {"interval": 400, "frames": [". ", ".. ", "...", " "]}, + "simpleDotsScrolling": { + "interval": 200, + "frames": [". ", ".. ", "...", " ..", " .", " "], + }, + "star": {"interval": 70, "frames": "✶✸✹✺✹✷"}, + "star2": {"interval": 80, "frames": "+x*"}, + "flip": { + "interval": 70, + "frames": "___-``'´-___", + }, + "hamburger": {"interval": 100, "frames": "☱☲☴"}, + "growVertical": { + "interval": 120, + "frames": "▁▃▄▅▆▇▆▅▄▃", + }, + "growHorizontal": { + "interval": 120, + "frames": "▏▎▍▌▋▊▉▊▋▌▍▎", + }, + "balloon": {"interval": 140, "frames": " .oO@* "}, + "balloon2": {"interval": 120, "frames": ".oO°Oo."}, + "noise": {"interval": 100, "frames": "▓▒░"}, + "bounce": {"interval": 120, "frames": "⠁⠂⠄⠂"}, + "boxBounce": {"interval": 120, "frames": "▖▘▝▗"}, + "boxBounce2": {"interval": 100, "frames": "▌▀▐▄"}, + "triangle": {"interval": 50, "frames": "◢◣◤◥"}, + "arc": {"interval": 100, "frames": "◜◠◝◞◡◟"}, + "circle": {"interval": 120, "frames": "◡⊙◠"}, + "squareCorners": {"interval": 180, "frames": "◰◳◲◱"}, + "circleQuarters": {"interval": 120, "frames": "◴◷◶◵"}, + "circleHalves": {"interval": 50, "frames": "◐◓◑◒"}, + "squish": {"interval": 100, "frames": "╫╪"}, + "toggle": {"interval": 250, "frames": "⊶⊷"}, + "toggle2": {"interval": 80, "frames": "▫▪"}, + "toggle3": {"interval": 120, "frames": "□■"}, + "toggle4": {"interval": 100, "frames": "■□▪▫"}, + "toggle5": {"interval": 100, "frames": "▮▯"}, + "toggle6": {"interval": 300, "frames": "ဝ၀"}, + "toggle7": {"interval": 80, "frames": "⦾⦿"}, + "toggle8": {"interval": 100, "frames": "◍◌"}, + "toggle9": {"interval": 100, "frames": "◉◎"}, + "toggle10": {"interval": 100, "frames": "㊂㊀㊁"}, + "toggle11": {"interval": 50, "frames": "⧇⧆"}, + "toggle12": {"interval": 120, "frames": "☗☖"}, + "toggle13": {"interval": 80, "frames": "=*-"}, + "arrow": {"interval": 100, "frames": "←↖↑↗→↘↓↙"}, + "arrow2": { + "interval": 80, + "frames": ["⬆️ ", "↗️ ", "➡️ ", "↘️ ", "⬇️ ", "↙️ ", "⬅️ ", "↖️ "], + }, + "arrow3": { + "interval": 120, + "frames": ["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸"], + }, + "bouncingBar": { + "interval": 80, + "frames": [ + "[ ]", + "[= ]", + "[== ]", + "[=== ]", + "[ ===]", + "[ ==]", + "[ =]", + "[ ]", + "[ =]", + "[ ==]", + "[ ===]", + "[====]", + "[=== ]", + "[== ]", + "[= ]", + ], + }, + "bouncingBall": { + "interval": 80, + "frames": [ + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "( ●)", + "( ● )", + "( ● )", + "( ● )", + "( ● )", + "(● )", + ], + }, + "smiley": {"interval": 200, "frames": ["😄 ", "😝 "]}, + "monkey": {"interval": 300, "frames": ["🙈 ", "🙈 ", "🙉 ", "🙊 "]}, + "hearts": {"interval": 100, "frames": ["💛 ", "💙 ", "💜 ", "💚 ", "❤️ "]}, + "clock": { + "interval": 100, + "frames": [ + "🕛 ", + "🕐 ", + "🕑 ", + "🕒 ", + "🕓 ", + "🕔 ", + "🕕 ", + "🕖 ", + "🕗 ", + "🕘 ", + "🕙 ", + "🕚 ", + ], + }, + "earth": {"interval": 180, "frames": ["🌍 ", "🌎 ", "🌏 "]}, + "material": { + "interval": 17, + "frames": [ + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "███████▁▁▁▁▁▁▁▁▁▁▁▁▁", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "██████████▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "█████████████▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁██████████████▁▁▁▁", + "▁▁▁██████████████▁▁▁", + "▁▁▁▁█████████████▁▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁██████████████▁▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁██████████████▁", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁██████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁█████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁████████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁███████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁██████████", + "▁▁▁▁▁▁▁▁▁▁▁▁████████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "████████▁▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "█████████▁▁▁▁▁▁▁▁▁▁▁", + "███████████▁▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "████████████▁▁▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "██████████████▁▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁██████████████▁▁▁▁▁", + "▁▁▁█████████████▁▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁████████████▁▁▁", + "▁▁▁▁▁▁███████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁█████████▁▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁█████████▁▁", + "▁▁▁▁▁▁▁▁▁▁█████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁████████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁███████▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁███████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", + ], + }, + "moon": { + "interval": 80, + "frames": ["🌑 ", "🌒 ", "🌓 ", "🌔 ", "🌕 ", "🌖 ", "🌗 ", "🌘 "], + }, + "runner": {"interval": 140, "frames": ["🚶 ", "🏃 "]}, + "pong": { + "interval": 80, + "frames": [ + "▐⠂ ▌", + "▐⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂▌", + "▐ ⠠▌", + "▐ ⡀▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐ ⠠ ▌", + "▐ ⠂ ▌", + "▐ ⠈ ▌", + "▐ ⠂ ▌", + "▐ ⠠ ▌", + "▐ ⡀ ▌", + "▐⠠ ▌", + ], + }, + "shark": { + "interval": 120, + "frames": [ + "▐|\\____________▌", + "▐_|\\___________▌", + "▐__|\\__________▌", + "▐___|\\_________▌", + "▐____|\\________▌", + "▐_____|\\_______▌", + "▐______|\\______▌", + "▐_______|\\_____▌", + "▐________|\\____▌", + "▐_________|\\___▌", + "▐__________|\\__▌", + "▐___________|\\_▌", + "▐____________|\\▌", + "▐____________/|▌", + "▐___________/|_▌", + "▐__________/|__▌", + "▐_________/|___▌", + "▐________/|____▌", + "▐_______/|_____▌", + "▐______/|______▌", + "▐_____/|_______▌", + "▐____/|________▌", + "▐___/|_________▌", + "▐__/|__________▌", + "▐_/|___________▌", + "▐/|____________▌", + ], + }, + "dqpb": {"interval": 100, "frames": "dqpb"}, + "weather": { + "interval": 100, + "frames": [ + "☀️ ", + "☀️ ", + "☀️ ", + "🌤 ", + "⛅️ ", + "🌥 ", + "☁️ ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "🌧 ", + "🌨 ", + "⛈ ", + "🌨 ", + "🌧 ", + "🌨 ", + "☁️ ", + "🌥 ", + "⛅️ ", + "🌤 ", + "☀️ ", + "☀️ ", + ], + }, + "christmas": {"interval": 400, "frames": "🌲🎄"}, + "grenade": { + "interval": 80, + "frames": [ + "، ", + "′ ", + " ´ ", + " ‾ ", + " ⸌", + " ⸊", + " |", + " ⁎", + " ⁕", + " ෴ ", + " ⁓", + " ", + " ", + " ", + ], + }, + "point": {"interval": 125, "frames": ["∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"]}, + "layer": {"interval": 150, "frames": "-=≡"}, + "betaWave": { + "interval": 80, + "frames": [ + "ρββββββ", + "βρβββββ", + "ββρββββ", + "βββρβββ", + "ββββρββ", + "βββββρβ", + "ββββββρ", + ], + }, + "aesthetic": { + "interval": 80, + "frames": [ + "▰▱▱▱▱▱▱", + "▰▰▱▱▱▱▱", + "▰▰▰▱▱▱▱", + "▰▰▰▰▱▱▱", + "▰▰▰▰▰▱▱", + "▰▰▰▰▰▰▱", + "▰▰▰▰▰▰▰", + "▰▱▱▱▱▱▱", + ], + }, +} diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_stack.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_stack.py new file mode 100644 index 0000000..194564e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_stack.py @@ -0,0 +1,16 @@ +from typing import List, TypeVar + +T = TypeVar("T") + + +class Stack(List[T]): + """A small shim over builtin list.""" + + @property + def top(self) -> T: + """Get top of stack.""" + return self[-1] + + def push(self, item: T) -> None: + """Push an item on to the stack (append in stack nomenclature).""" + self.append(item) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_timer.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_timer.py new file mode 100644 index 0000000..a2ca6be --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_timer.py @@ -0,0 +1,19 @@ +""" +Timer context manager, only used in debug. + +""" + +from time import time + +import contextlib +from typing import Generator + + +@contextlib.contextmanager +def timer(subject: str = "time") -> Generator[None, None, None]: + """print the elapsed time. (only used in debugging)""" + start = time() + yield + elapsed = time() - start + elapsed_ms = elapsed * 1000 + print(f"{subject} elapsed {elapsed_ms:.1f}ms") diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_win32_console.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_win32_console.py new file mode 100644 index 0000000..81b1082 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_win32_console.py @@ -0,0 +1,662 @@ +"""Light wrapper around the Win32 Console API - this module should only be imported on Windows + +The API that this module wraps is documented at https://docs.microsoft.com/en-us/windows/console/console-functions +""" +import ctypes +import sys +from typing import Any + +windll: Any = None +if sys.platform == "win32": + windll = ctypes.LibraryLoader(ctypes.WinDLL) +else: + raise ImportError(f"{__name__} can only be imported on Windows") + +import time +from ctypes import Structure, byref, wintypes +from typing import IO, NamedTuple, Type, cast + +from pip._vendor.rich.color import ColorSystem +from pip._vendor.rich.style import Style + +STDOUT = -11 +ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4 + +COORD = wintypes._COORD + + +class LegacyWindowsError(Exception): + pass + + +class WindowsCoordinates(NamedTuple): + """Coordinates in the Windows Console API are (y, x), not (x, y). + This class is intended to prevent that confusion. + Rows and columns are indexed from 0. + This class can be used in place of wintypes._COORD in arguments and argtypes. + """ + + row: int + col: int + + @classmethod + def from_param(cls, value: "WindowsCoordinates") -> COORD: + """Converts a WindowsCoordinates into a wintypes _COORD structure. + This classmethod is internally called by ctypes to perform the conversion. + + Args: + value (WindowsCoordinates): The input coordinates to convert. + + Returns: + wintypes._COORD: The converted coordinates struct. + """ + return COORD(value.col, value.row) + + +class CONSOLE_SCREEN_BUFFER_INFO(Structure): + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + + +class CONSOLE_CURSOR_INFO(ctypes.Structure): + _fields_ = [("dwSize", wintypes.DWORD), ("bVisible", wintypes.BOOL)] + + +_GetStdHandle = windll.kernel32.GetStdHandle +_GetStdHandle.argtypes = [ + wintypes.DWORD, +] +_GetStdHandle.restype = wintypes.HANDLE + + +def GetStdHandle(handle: int = STDOUT) -> wintypes.HANDLE: + """Retrieves a handle to the specified standard device (standard input, standard output, or standard error). + + Args: + handle (int): Integer identifier for the handle. Defaults to -11 (stdout). + + Returns: + wintypes.HANDLE: The handle + """ + return cast(wintypes.HANDLE, _GetStdHandle(handle)) + + +_GetConsoleMode = windll.kernel32.GetConsoleMode +_GetConsoleMode.argtypes = [wintypes.HANDLE, wintypes.LPDWORD] +_GetConsoleMode.restype = wintypes.BOOL + + +def GetConsoleMode(std_handle: wintypes.HANDLE) -> int: + """Retrieves the current input mode of a console's input buffer + or the current output mode of a console screen buffer. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + + Raises: + LegacyWindowsError: If any error occurs while calling the Windows console API. + + Returns: + int: Value representing the current console mode as documented at + https://docs.microsoft.com/en-us/windows/console/getconsolemode#parameters + """ + + console_mode = wintypes.DWORD() + success = bool(_GetConsoleMode(std_handle, console_mode)) + if not success: + raise LegacyWindowsError("Unable to get legacy Windows Console Mode") + return console_mode.value + + +_FillConsoleOutputCharacterW = windll.kernel32.FillConsoleOutputCharacterW +_FillConsoleOutputCharacterW.argtypes = [ + wintypes.HANDLE, + ctypes.c_char, + wintypes.DWORD, + cast(Type[COORD], WindowsCoordinates), + ctypes.POINTER(wintypes.DWORD), +] +_FillConsoleOutputCharacterW.restype = wintypes.BOOL + + +def FillConsoleOutputCharacter( + std_handle: wintypes.HANDLE, + char: str, + length: int, + start: WindowsCoordinates, +) -> int: + """Writes a character to the console screen buffer a specified number of times, beginning at the specified coordinates. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + char (str): The character to write. Must be a string of length 1. + length (int): The number of times to write the character. + start (WindowsCoordinates): The coordinates to start writing at. + + Returns: + int: The number of characters written. + """ + character = ctypes.c_char(char.encode()) + num_characters = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + _FillConsoleOutputCharacterW( + std_handle, + character, + num_characters, + start, + byref(num_written), + ) + return num_written.value + + +_FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute +_FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + cast(Type[COORD], WindowsCoordinates), + ctypes.POINTER(wintypes.DWORD), +] +_FillConsoleOutputAttribute.restype = wintypes.BOOL + + +def FillConsoleOutputAttribute( + std_handle: wintypes.HANDLE, + attributes: int, + length: int, + start: WindowsCoordinates, +) -> int: + """Sets the character attributes for a specified number of character cells, + beginning at the specified coordinates in a screen buffer. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + attributes (int): Integer value representing the foreground and background colours of the cells. + length (int): The number of cells to set the output attribute of. + start (WindowsCoordinates): The coordinates of the first cell whose attributes are to be set. + + Returns: + int: The number of cells whose attributes were actually set. + """ + num_cells = wintypes.DWORD(length) + style_attrs = wintypes.WORD(attributes) + num_written = wintypes.DWORD(0) + _FillConsoleOutputAttribute( + std_handle, style_attrs, num_cells, start, byref(num_written) + ) + return num_written.value + + +_SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute +_SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, +] +_SetConsoleTextAttribute.restype = wintypes.BOOL + + +def SetConsoleTextAttribute( + std_handle: wintypes.HANDLE, attributes: wintypes.WORD +) -> bool: + """Set the colour attributes for all text written after this function is called. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + attributes (int): Integer value representing the foreground and background colours. + + + Returns: + bool: True if the attribute was set successfully, otherwise False. + """ + return bool(_SetConsoleTextAttribute(std_handle, attributes)) + + +_GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo +_GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(CONSOLE_SCREEN_BUFFER_INFO), +] +_GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + +def GetConsoleScreenBufferInfo( + std_handle: wintypes.HANDLE, +) -> CONSOLE_SCREEN_BUFFER_INFO: + """Retrieves information about the specified console screen buffer. + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + + Returns: + CONSOLE_SCREEN_BUFFER_INFO: A CONSOLE_SCREEN_BUFFER_INFO ctype struct contain information about + screen size, cursor position, colour attributes, and more.""" + console_screen_buffer_info = CONSOLE_SCREEN_BUFFER_INFO() + _GetConsoleScreenBufferInfo(std_handle, byref(console_screen_buffer_info)) + return console_screen_buffer_info + + +_SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition +_SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + cast(Type[COORD], WindowsCoordinates), +] +_SetConsoleCursorPosition.restype = wintypes.BOOL + + +def SetConsoleCursorPosition( + std_handle: wintypes.HANDLE, coords: WindowsCoordinates +) -> bool: + """Set the position of the cursor in the console screen + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + coords (WindowsCoordinates): The coordinates to move the cursor to. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_SetConsoleCursorPosition(std_handle, coords)) + + +_GetConsoleCursorInfo = windll.kernel32.GetConsoleCursorInfo +_GetConsoleCursorInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(CONSOLE_CURSOR_INFO), +] +_GetConsoleCursorInfo.restype = wintypes.BOOL + + +def GetConsoleCursorInfo( + std_handle: wintypes.HANDLE, cursor_info: CONSOLE_CURSOR_INFO +) -> bool: + """Get the cursor info - used to get cursor visibility and width + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + cursor_info (CONSOLE_CURSOR_INFO): CONSOLE_CURSOR_INFO ctype struct that receives information + about the console's cursor. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_GetConsoleCursorInfo(std_handle, byref(cursor_info))) + + +_SetConsoleCursorInfo = windll.kernel32.SetConsoleCursorInfo +_SetConsoleCursorInfo.argtypes = [ + wintypes.HANDLE, + ctypes.POINTER(CONSOLE_CURSOR_INFO), +] +_SetConsoleCursorInfo.restype = wintypes.BOOL + + +def SetConsoleCursorInfo( + std_handle: wintypes.HANDLE, cursor_info: CONSOLE_CURSOR_INFO +) -> bool: + """Set the cursor info - used for adjusting cursor visibility and width + + Args: + std_handle (wintypes.HANDLE): A handle to the console input buffer or the console screen buffer. + cursor_info (CONSOLE_CURSOR_INFO): CONSOLE_CURSOR_INFO ctype struct containing the new cursor info. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_SetConsoleCursorInfo(std_handle, byref(cursor_info))) + + +_SetConsoleTitle = windll.kernel32.SetConsoleTitleW +_SetConsoleTitle.argtypes = [wintypes.LPCWSTR] +_SetConsoleTitle.restype = wintypes.BOOL + + +def SetConsoleTitle(title: str) -> bool: + """Sets the title of the current console window + + Args: + title (str): The new title of the console window. + + Returns: + bool: True if the function succeeds, otherwise False. + """ + return bool(_SetConsoleTitle(title)) + + +class LegacyWindowsTerm: + """This class allows interaction with the legacy Windows Console API. It should only be used in the context + of environments where virtual terminal processing is not available. However, if it is used in a Windows environment, + the entire API should work. + + Args: + file (IO[str]): The file which the Windows Console API HANDLE is retrieved from, defaults to sys.stdout. + """ + + BRIGHT_BIT = 8 + + # Indices are ANSI color numbers, values are the corresponding Windows Console API color numbers + ANSI_TO_WINDOWS = [ + 0, # black The Windows colours are defined in wincon.h as follows: + 4, # red define FOREGROUND_BLUE 0x0001 -- 0000 0001 + 2, # green define FOREGROUND_GREEN 0x0002 -- 0000 0010 + 6, # yellow define FOREGROUND_RED 0x0004 -- 0000 0100 + 1, # blue define FOREGROUND_INTENSITY 0x0008 -- 0000 1000 + 5, # magenta define BACKGROUND_BLUE 0x0010 -- 0001 0000 + 3, # cyan define BACKGROUND_GREEN 0x0020 -- 0010 0000 + 7, # white define BACKGROUND_RED 0x0040 -- 0100 0000 + 8, # bright black (grey) define BACKGROUND_INTENSITY 0x0080 -- 1000 0000 + 12, # bright red + 10, # bright green + 14, # bright yellow + 9, # bright blue + 13, # bright magenta + 11, # bright cyan + 15, # bright white + ] + + def __init__(self, file: "IO[str]") -> None: + handle = GetStdHandle(STDOUT) + self._handle = handle + default_text = GetConsoleScreenBufferInfo(handle).wAttributes + self._default_text = default_text + + self._default_fore = default_text & 7 + self._default_back = (default_text >> 4) & 7 + self._default_attrs = self._default_fore | (self._default_back << 4) + + self._file = file + self.write = file.write + self.flush = file.flush + + @property + def cursor_position(self) -> WindowsCoordinates: + """Returns the current position of the cursor (0-based) + + Returns: + WindowsCoordinates: The current cursor position. + """ + coord: COORD = GetConsoleScreenBufferInfo(self._handle).dwCursorPosition + return WindowsCoordinates(row=cast(int, coord.Y), col=cast(int, coord.X)) + + @property + def screen_size(self) -> WindowsCoordinates: + """Returns the current size of the console screen buffer, in character columns and rows + + Returns: + WindowsCoordinates: The width and height of the screen as WindowsCoordinates. + """ + screen_size: COORD = GetConsoleScreenBufferInfo(self._handle).dwSize + return WindowsCoordinates( + row=cast(int, screen_size.Y), col=cast(int, screen_size.X) + ) + + def write_text(self, text: str) -> None: + """Write text directly to the terminal without any modification of styles + + Args: + text (str): The text to write to the console + """ + self.write(text) + self.flush() + + def write_styled(self, text: str, style: Style) -> None: + """Write styled text to the terminal. + + Args: + text (str): The text to write + style (Style): The style of the text + """ + color = style.color + bgcolor = style.bgcolor + if style.reverse: + color, bgcolor = bgcolor, color + + if color: + fore = color.downgrade(ColorSystem.WINDOWS).number + fore = fore if fore is not None else 7 # Default to ANSI 7: White + if style.bold: + fore = fore | self.BRIGHT_BIT + if style.dim: + fore = fore & ~self.BRIGHT_BIT + fore = self.ANSI_TO_WINDOWS[fore] + else: + fore = self._default_fore + + if bgcolor: + back = bgcolor.downgrade(ColorSystem.WINDOWS).number + back = back if back is not None else 0 # Default to ANSI 0: Black + back = self.ANSI_TO_WINDOWS[back] + else: + back = self._default_back + + assert fore is not None + assert back is not None + + SetConsoleTextAttribute( + self._handle, attributes=ctypes.c_ushort(fore | (back << 4)) + ) + self.write_text(text) + SetConsoleTextAttribute(self._handle, attributes=self._default_text) + + def move_cursor_to(self, new_position: WindowsCoordinates) -> None: + """Set the position of the cursor + + Args: + new_position (WindowsCoordinates): The WindowsCoordinates representing the new position of the cursor. + """ + if new_position.col < 0 or new_position.row < 0: + return + SetConsoleCursorPosition(self._handle, coords=new_position) + + def erase_line(self) -> None: + """Erase all content on the line the cursor is currently located at""" + screen_size = self.screen_size + cursor_position = self.cursor_position + cells_to_erase = screen_size.col + start_coordinates = WindowsCoordinates(row=cursor_position.row, col=0) + FillConsoleOutputCharacter( + self._handle, " ", length=cells_to_erase, start=start_coordinates + ) + FillConsoleOutputAttribute( + self._handle, + self._default_attrs, + length=cells_to_erase, + start=start_coordinates, + ) + + def erase_end_of_line(self) -> None: + """Erase all content from the cursor position to the end of that line""" + cursor_position = self.cursor_position + cells_to_erase = self.screen_size.col - cursor_position.col + FillConsoleOutputCharacter( + self._handle, " ", length=cells_to_erase, start=cursor_position + ) + FillConsoleOutputAttribute( + self._handle, + self._default_attrs, + length=cells_to_erase, + start=cursor_position, + ) + + def erase_start_of_line(self) -> None: + """Erase all content from the cursor position to the start of that line""" + row, col = self.cursor_position + start = WindowsCoordinates(row, 0) + FillConsoleOutputCharacter(self._handle, " ", length=col, start=start) + FillConsoleOutputAttribute( + self._handle, self._default_attrs, length=col, start=start + ) + + def move_cursor_up(self) -> None: + """Move the cursor up a single cell""" + cursor_position = self.cursor_position + SetConsoleCursorPosition( + self._handle, + coords=WindowsCoordinates( + row=cursor_position.row - 1, col=cursor_position.col + ), + ) + + def move_cursor_down(self) -> None: + """Move the cursor down a single cell""" + cursor_position = self.cursor_position + SetConsoleCursorPosition( + self._handle, + coords=WindowsCoordinates( + row=cursor_position.row + 1, + col=cursor_position.col, + ), + ) + + def move_cursor_forward(self) -> None: + """Move the cursor forward a single cell. Wrap to the next line if required.""" + row, col = self.cursor_position + if col == self.screen_size.col - 1: + row += 1 + col = 0 + else: + col += 1 + SetConsoleCursorPosition( + self._handle, coords=WindowsCoordinates(row=row, col=col) + ) + + def move_cursor_to_column(self, column: int) -> None: + """Move cursor to the column specified by the zero-based column index, staying on the same row + + Args: + column (int): The zero-based column index to move the cursor to. + """ + row, _ = self.cursor_position + SetConsoleCursorPosition(self._handle, coords=WindowsCoordinates(row, column)) + + def move_cursor_backward(self) -> None: + """Move the cursor backward a single cell. Wrap to the previous line if required.""" + row, col = self.cursor_position + if col == 0: + row -= 1 + col = self.screen_size.col - 1 + else: + col -= 1 + SetConsoleCursorPosition( + self._handle, coords=WindowsCoordinates(row=row, col=col) + ) + + def hide_cursor(self) -> None: + """Hide the cursor""" + current_cursor_size = self._get_cursor_size() + invisible_cursor = CONSOLE_CURSOR_INFO(dwSize=current_cursor_size, bVisible=0) + SetConsoleCursorInfo(self._handle, cursor_info=invisible_cursor) + + def show_cursor(self) -> None: + """Show the cursor""" + current_cursor_size = self._get_cursor_size() + visible_cursor = CONSOLE_CURSOR_INFO(dwSize=current_cursor_size, bVisible=1) + SetConsoleCursorInfo(self._handle, cursor_info=visible_cursor) + + def set_title(self, title: str) -> None: + """Set the title of the terminal window + + Args: + title (str): The new title of the console window + """ + assert len(title) < 255, "Console title must be less than 255 characters" + SetConsoleTitle(title) + + def _get_cursor_size(self) -> int: + """Get the percentage of the character cell that is filled by the cursor""" + cursor_info = CONSOLE_CURSOR_INFO() + GetConsoleCursorInfo(self._handle, cursor_info=cursor_info) + return int(cursor_info.dwSize) + + +if __name__ == "__main__": + handle = GetStdHandle() + + from pip._vendor.rich.console import Console + + console = Console() + + term = LegacyWindowsTerm(sys.stdout) + term.set_title("Win32 Console Examples") + + style = Style(color="black", bgcolor="red") + + heading = Style.parse("black on green") + + # Check colour output + console.rule("Checking colour output") + console.print("[on red]on red!") + console.print("[blue]blue!") + console.print("[yellow]yellow!") + console.print("[bold yellow]bold yellow!") + console.print("[bright_yellow]bright_yellow!") + console.print("[dim bright_yellow]dim bright_yellow!") + console.print("[italic cyan]italic cyan!") + console.print("[bold white on blue]bold white on blue!") + console.print("[reverse bold white on blue]reverse bold white on blue!") + console.print("[bold black on cyan]bold black on cyan!") + console.print("[black on green]black on green!") + console.print("[blue on green]blue on green!") + console.print("[white on black]white on black!") + console.print("[black on white]black on white!") + console.print("[#1BB152 on #DA812D]#1BB152 on #DA812D!") + + # Check cursor movement + console.rule("Checking cursor movement") + console.print() + term.move_cursor_backward() + term.move_cursor_backward() + term.write_text("went back and wrapped to prev line") + time.sleep(1) + term.move_cursor_up() + term.write_text("we go up") + time.sleep(1) + term.move_cursor_down() + term.write_text("and down") + time.sleep(1) + term.move_cursor_up() + term.move_cursor_backward() + term.move_cursor_backward() + term.write_text("we went up and back 2") + time.sleep(1) + term.move_cursor_down() + term.move_cursor_backward() + term.move_cursor_backward() + term.write_text("we went down and back 2") + time.sleep(1) + + # Check erasing of lines + term.hide_cursor() + console.print() + console.rule("Checking line erasing") + console.print("\n...Deleting to the start of the line...") + term.write_text("The red arrow shows the cursor location, and direction of erase") + time.sleep(1) + term.move_cursor_to_column(16) + term.write_styled("<", Style.parse("black on red")) + term.move_cursor_backward() + time.sleep(1) + term.erase_start_of_line() + time.sleep(1) + + console.print("\n\n...And to the end of the line...") + term.write_text("The red arrow shows the cursor location, and direction of erase") + time.sleep(1) + + term.move_cursor_to_column(16) + term.write_styled(">", Style.parse("black on red")) + time.sleep(1) + term.erase_end_of_line() + time.sleep(1) + + console.print("\n\n...Now the whole line will be erased...") + term.write_styled("I'm going to disappear!", style=Style.parse("black on cyan")) + time.sleep(1) + term.erase_line() + + term.show_cursor() + print("\n") diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows.py new file mode 100644 index 0000000..10fc0d7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows.py @@ -0,0 +1,72 @@ +import sys +from dataclasses import dataclass + + +@dataclass +class WindowsConsoleFeatures: + """Windows features available.""" + + vt: bool = False + """The console supports VT codes.""" + truecolor: bool = False + """The console supports truecolor.""" + + +try: + import ctypes + from ctypes import LibraryLoader + + if sys.platform == "win32": + windll = LibraryLoader(ctypes.WinDLL) + else: + windll = None + raise ImportError("Not windows") + + from pip._vendor.rich._win32_console import ( + ENABLE_VIRTUAL_TERMINAL_PROCESSING, + GetConsoleMode, + GetStdHandle, + LegacyWindowsError, + ) + +except (AttributeError, ImportError, ValueError): + + # Fallback if we can't load the Windows DLL + def get_windows_console_features() -> WindowsConsoleFeatures: + features = WindowsConsoleFeatures() + return features + +else: + + def get_windows_console_features() -> WindowsConsoleFeatures: + """Get windows console features. + + Returns: + WindowsConsoleFeatures: An instance of WindowsConsoleFeatures. + """ + handle = GetStdHandle() + try: + console_mode = GetConsoleMode(handle) + success = True + except LegacyWindowsError: + console_mode = 0 + success = False + vt = bool(success and console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) + truecolor = False + if vt: + win_version = sys.getwindowsversion() + truecolor = win_version.major > 10 or ( + win_version.major == 10 and win_version.build >= 15063 + ) + features = WindowsConsoleFeatures(vt=vt, truecolor=truecolor) + return features + + +if __name__ == "__main__": + import platform + + features = get_windows_console_features() + from pip._vendor.rich import print + + print(f'platform="{platform.system()}"') + print(repr(features)) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows_renderer.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows_renderer.py new file mode 100644 index 0000000..5ece056 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_windows_renderer.py @@ -0,0 +1,56 @@ +from typing import Iterable, Sequence, Tuple, cast + +from pip._vendor.rich._win32_console import LegacyWindowsTerm, WindowsCoordinates +from pip._vendor.rich.segment import ControlCode, ControlType, Segment + + +def legacy_windows_render(buffer: Iterable[Segment], term: LegacyWindowsTerm) -> None: + """Makes appropriate Windows Console API calls based on the segments in the buffer. + + Args: + buffer (Iterable[Segment]): Iterable of Segments to convert to Win32 API calls. + term (LegacyWindowsTerm): Used to call the Windows Console API. + """ + for text, style, control in buffer: + if not control: + if style: + term.write_styled(text, style) + else: + term.write_text(text) + else: + control_codes: Sequence[ControlCode] = control + for control_code in control_codes: + control_type = control_code[0] + if control_type == ControlType.CURSOR_MOVE_TO: + _, x, y = cast(Tuple[ControlType, int, int], control_code) + term.move_cursor_to(WindowsCoordinates(row=y - 1, col=x - 1)) + elif control_type == ControlType.CARRIAGE_RETURN: + term.write_text("\r") + elif control_type == ControlType.HOME: + term.move_cursor_to(WindowsCoordinates(0, 0)) + elif control_type == ControlType.CURSOR_UP: + term.move_cursor_up() + elif control_type == ControlType.CURSOR_DOWN: + term.move_cursor_down() + elif control_type == ControlType.CURSOR_FORWARD: + term.move_cursor_forward() + elif control_type == ControlType.CURSOR_BACKWARD: + term.move_cursor_backward() + elif control_type == ControlType.CURSOR_MOVE_TO_COLUMN: + _, column = cast(Tuple[ControlType, int], control_code) + term.move_cursor_to_column(column - 1) + elif control_type == ControlType.HIDE_CURSOR: + term.hide_cursor() + elif control_type == ControlType.SHOW_CURSOR: + term.show_cursor() + elif control_type == ControlType.ERASE_IN_LINE: + _, mode = cast(Tuple[ControlType, int], control_code) + if mode == 0: + term.erase_end_of_line() + elif mode == 1: + term.erase_start_of_line() + elif mode == 2: + term.erase_line() + elif control_type == ControlType.SET_WINDOW_TITLE: + _, title = cast(Tuple[ControlType, str], control_code) + term.set_title(title) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_wrap.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_wrap.py new file mode 100644 index 0000000..c45f193 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/_wrap.py @@ -0,0 +1,56 @@ +import re +from typing import Iterable, List, Tuple + +from ._loop import loop_last +from .cells import cell_len, chop_cells + +re_word = re.compile(r"\s*\S+\s*") + + +def words(text: str) -> Iterable[Tuple[int, int, str]]: + position = 0 + word_match = re_word.match(text, position) + while word_match is not None: + start, end = word_match.span() + word = word_match.group(0) + yield start, end, word + word_match = re_word.match(text, end) + + +def divide_line(text: str, width: int, fold: bool = True) -> List[int]: + divides: List[int] = [] + append = divides.append + line_position = 0 + _cell_len = cell_len + for start, _end, word in words(text): + word_length = _cell_len(word.rstrip()) + if line_position + word_length > width: + if word_length > width: + if fold: + chopped_words = chop_cells(word, max_size=width, position=0) + for last, line in loop_last(chopped_words): + if start: + append(start) + + if last: + line_position = _cell_len(line) + else: + start += len(line) + else: + if start: + append(start) + line_position = _cell_len(word) + elif line_position and start: + append(start) + line_position = _cell_len(word) + else: + line_position += _cell_len(word) + return divides + + +if __name__ == "__main__": # pragma: no cover + from .console import Console + + console = Console(width=10) + console.print("12345 abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ 12345") + print(chop_cells("abcdefghijklmnopqrstuvwxyz", 10, position=2)) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/abc.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/abc.py new file mode 100644 index 0000000..e6e498e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/abc.py @@ -0,0 +1,33 @@ +from abc import ABC + + +class RichRenderable(ABC): + """An abstract base class for Rich renderables. + + Note that there is no need to extend this class, the intended use is to check if an + object supports the Rich renderable protocol. For example:: + + if isinstance(my_object, RichRenderable): + console.print(my_object) + + """ + + @classmethod + def __subclasshook__(cls, other: type) -> bool: + """Check if this class supports the rich render protocol.""" + return hasattr(other, "__rich_console__") or hasattr(other, "__rich__") + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.text import Text + + t = Text() + print(isinstance(Text, RichRenderable)) + print(isinstance(t, RichRenderable)) + + class Foo: + pass + + f = Foo() + print(isinstance(f, RichRenderable)) + print(isinstance("", RichRenderable)) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/align.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/align.py new file mode 100644 index 0000000..c310b66 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/align.py @@ -0,0 +1,311 @@ +import sys +from itertools import chain +from typing import TYPE_CHECKING, Iterable, Optional + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + +from .constrain import Constrain +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import StyleType + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderableType, RenderResult + +AlignMethod = Literal["left", "center", "right"] +VerticalAlignMethod = Literal["top", "middle", "bottom"] + + +class Align(JupyterMixin): + """Align a renderable by adding spaces if necessary. + + Args: + renderable (RenderableType): A console renderable. + align (AlignMethod): One of "left", "center", or "right"" + style (StyleType, optional): An optional style to apply to the background. + vertical (Optional[VerticalAlginMethod], optional): Optional vertical align, one of "top", "middle", or "bottom". Defaults to None. + pad (bool, optional): Pad the right with spaces. Defaults to True. + width (int, optional): Restrict contents to given width, or None to use default width. Defaults to None. + height (int, optional): Set height of align renderable, or None to fit to contents. Defaults to None. + + Raises: + ValueError: if ``align`` is not one of the expected values. + """ + + def __init__( + self, + renderable: "RenderableType", + align: AlignMethod = "left", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> None: + if align not in ("left", "center", "right"): + raise ValueError( + f'invalid value for align, expected "left", "center", or "right" (not {align!r})' + ) + if vertical is not None and vertical not in ("top", "middle", "bottom"): + raise ValueError( + f'invalid value for vertical, expected "top", "middle", or "bottom" (not {vertical!r})' + ) + self.renderable = renderable + self.align = align + self.style = style + self.vertical = vertical + self.pad = pad + self.width = width + self.height = height + + def __repr__(self) -> str: + return f"Align({self.renderable!r}, {self.align!r})" + + @classmethod + def left( + cls, + renderable: "RenderableType", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> "Align": + """Align a renderable to the left.""" + return cls( + renderable, + "left", + style=style, + vertical=vertical, + pad=pad, + width=width, + height=height, + ) + + @classmethod + def center( + cls, + renderable: "RenderableType", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> "Align": + """Align a renderable to the center.""" + return cls( + renderable, + "center", + style=style, + vertical=vertical, + pad=pad, + width=width, + height=height, + ) + + @classmethod + def right( + cls, + renderable: "RenderableType", + style: Optional[StyleType] = None, + *, + vertical: Optional[VerticalAlignMethod] = None, + pad: bool = True, + width: Optional[int] = None, + height: Optional[int] = None, + ) -> "Align": + """Align a renderable to the right.""" + return cls( + renderable, + "right", + style=style, + vertical=vertical, + pad=pad, + width=width, + height=height, + ) + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + align = self.align + width = console.measure(self.renderable, options=options).maximum + rendered = console.render( + Constrain( + self.renderable, width if self.width is None else min(width, self.width) + ), + options.update(height=None), + ) + lines = list(Segment.split_lines(rendered)) + width, height = Segment.get_shape(lines) + lines = Segment.set_shape(lines, width, height) + new_line = Segment.line() + excess_space = options.max_width - width + style = console.get_style(self.style) if self.style is not None else None + + def generate_segments() -> Iterable[Segment]: + if excess_space <= 0: + # Exact fit + for line in lines: + yield from line + yield new_line + + elif align == "left": + # Pad on the right + pad = Segment(" " * excess_space, style) if self.pad else None + for line in lines: + yield from line + if pad: + yield pad + yield new_line + + elif align == "center": + # Pad left and right + left = excess_space // 2 + pad = Segment(" " * left, style) + pad_right = ( + Segment(" " * (excess_space - left), style) if self.pad else None + ) + for line in lines: + if left: + yield pad + yield from line + if pad_right: + yield pad_right + yield new_line + + elif align == "right": + # Padding on left + pad = Segment(" " * excess_space, style) + for line in lines: + yield pad + yield from line + yield new_line + + blank_line = ( + Segment(f"{' ' * (self.width or options.max_width)}\n", style) + if self.pad + else Segment("\n") + ) + + def blank_lines(count: int) -> Iterable[Segment]: + if count > 0: + for _ in range(count): + yield blank_line + + vertical_height = self.height or options.height + iter_segments: Iterable[Segment] + if self.vertical and vertical_height is not None: + if self.vertical == "top": + bottom_space = vertical_height - height + iter_segments = chain(generate_segments(), blank_lines(bottom_space)) + elif self.vertical == "middle": + top_space = (vertical_height - height) // 2 + bottom_space = vertical_height - top_space - height + iter_segments = chain( + blank_lines(top_space), + generate_segments(), + blank_lines(bottom_space), + ) + else: # self.vertical == "bottom": + top_space = vertical_height - height + iter_segments = chain(blank_lines(top_space), generate_segments()) + else: + iter_segments = generate_segments() + if self.style: + style = console.get_style(self.style) + iter_segments = Segment.apply_style(iter_segments, style) + yield from iter_segments + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + measurement = Measurement.get(console, options, self.renderable) + return measurement + + +class VerticalCenter(JupyterMixin): + """Vertically aligns a renderable. + + Warn: + This class is deprecated and may be removed in a future version. Use Align class with + `vertical="middle"`. + + Args: + renderable (RenderableType): A renderable object. + """ + + def __init__( + self, + renderable: "RenderableType", + style: Optional[StyleType] = None, + ) -> None: + self.renderable = renderable + self.style = style + + def __repr__(self) -> str: + return f"VerticalCenter({self.renderable!r})" + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + style = console.get_style(self.style) if self.style is not None else None + lines = console.render_lines( + self.renderable, options.update(height=None), pad=False + ) + width, _height = Segment.get_shape(lines) + new_line = Segment.line() + height = options.height or options.size.height + top_space = (height - len(lines)) // 2 + bottom_space = height - top_space - len(lines) + blank_line = Segment(f"{' ' * width}", style) + + def blank_lines(count: int) -> Iterable[Segment]: + for _ in range(count): + yield blank_line + yield new_line + + if top_space > 0: + yield from blank_lines(top_space) + for line in lines: + yield from line + yield new_line + if bottom_space > 0: + yield from blank_lines(bottom_space) + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> Measurement: + measurement = Measurement.get(console, options, self.renderable) + return measurement + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console, Group + from pip._vendor.rich.highlighter import ReprHighlighter + from pip._vendor.rich.panel import Panel + + highlighter = ReprHighlighter() + console = Console() + + panel = Panel( + Group( + Align.left(highlighter("align='left'")), + Align.center(highlighter("align='center'")), + Align.right(highlighter("align='right'")), + ), + width=60, + style="on dark_blue", + title="Align", + ) + + console.print( + Align.center(panel, vertical="middle", style="on red", height=console.height) + ) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/ansi.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/ansi.py new file mode 100644 index 0000000..66365e6 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/ansi.py @@ -0,0 +1,240 @@ +import re +import sys +from contextlib import suppress +from typing import Iterable, NamedTuple, Optional + +from .color import Color +from .style import Style +from .text import Text + +re_ansi = re.compile( + r""" +(?:\x1b\](.*?)\x1b\\)| +(?:\x1b([(@-Z\\-_]|\[[0-?]*[ -/]*[@-~])) +""", + re.VERBOSE, +) + + +class _AnsiToken(NamedTuple): + """Result of ansi tokenized string.""" + + plain: str = "" + sgr: Optional[str] = "" + osc: Optional[str] = "" + + +def _ansi_tokenize(ansi_text: str) -> Iterable[_AnsiToken]: + """Tokenize a string in to plain text and ANSI codes. + + Args: + ansi_text (str): A String containing ANSI codes. + + Yields: + AnsiToken: A named tuple of (plain, sgr, osc) + """ + + position = 0 + sgr: Optional[str] + osc: Optional[str] + for match in re_ansi.finditer(ansi_text): + start, end = match.span(0) + osc, sgr = match.groups() + if start > position: + yield _AnsiToken(ansi_text[position:start]) + if sgr: + if sgr == "(": + position = end + 1 + continue + if sgr.endswith("m"): + yield _AnsiToken("", sgr[1:-1], osc) + else: + yield _AnsiToken("", sgr, osc) + position = end + if position < len(ansi_text): + yield _AnsiToken(ansi_text[position:]) + + +SGR_STYLE_MAP = { + 1: "bold", + 2: "dim", + 3: "italic", + 4: "underline", + 5: "blink", + 6: "blink2", + 7: "reverse", + 8: "conceal", + 9: "strike", + 21: "underline2", + 22: "not dim not bold", + 23: "not italic", + 24: "not underline", + 25: "not blink", + 26: "not blink2", + 27: "not reverse", + 28: "not conceal", + 29: "not strike", + 30: "color(0)", + 31: "color(1)", + 32: "color(2)", + 33: "color(3)", + 34: "color(4)", + 35: "color(5)", + 36: "color(6)", + 37: "color(7)", + 39: "default", + 40: "on color(0)", + 41: "on color(1)", + 42: "on color(2)", + 43: "on color(3)", + 44: "on color(4)", + 45: "on color(5)", + 46: "on color(6)", + 47: "on color(7)", + 49: "on default", + 51: "frame", + 52: "encircle", + 53: "overline", + 54: "not frame not encircle", + 55: "not overline", + 90: "color(8)", + 91: "color(9)", + 92: "color(10)", + 93: "color(11)", + 94: "color(12)", + 95: "color(13)", + 96: "color(14)", + 97: "color(15)", + 100: "on color(8)", + 101: "on color(9)", + 102: "on color(10)", + 103: "on color(11)", + 104: "on color(12)", + 105: "on color(13)", + 106: "on color(14)", + 107: "on color(15)", +} + + +class AnsiDecoder: + """Translate ANSI code in to styled Text.""" + + def __init__(self) -> None: + self.style = Style.null() + + def decode(self, terminal_text: str) -> Iterable[Text]: + """Decode ANSI codes in an iterable of lines. + + Args: + lines (Iterable[str]): An iterable of lines of terminal output. + + Yields: + Text: Marked up Text. + """ + for line in terminal_text.splitlines(): + yield self.decode_line(line) + + def decode_line(self, line: str) -> Text: + """Decode a line containing ansi codes. + + Args: + line (str): A line of terminal output. + + Returns: + Text: A Text instance marked up according to ansi codes. + """ + from_ansi = Color.from_ansi + from_rgb = Color.from_rgb + _Style = Style + text = Text() + append = text.append + line = line.rsplit("\r", 1)[-1] + for plain_text, sgr, osc in _ansi_tokenize(line): + if plain_text: + append(plain_text, self.style or None) + elif osc is not None: + if osc.startswith("8;"): + _params, semicolon, link = osc[2:].partition(";") + if semicolon: + self.style = self.style.update_link(link or None) + elif sgr is not None: + # Translate in to semi-colon separated codes + # Ignore invalid codes, because we want to be lenient + codes = [ + min(255, int(_code) if _code else 0) + for _code in sgr.split(";") + if _code.isdigit() or _code == "" + ] + iter_codes = iter(codes) + for code in iter_codes: + if code == 0: + # reset + self.style = _Style.null() + elif code in SGR_STYLE_MAP: + # styles + self.style += _Style.parse(SGR_STYLE_MAP[code]) + elif code == 38: + #  Foreground + with suppress(StopIteration): + color_type = next(iter_codes) + if color_type == 5: + self.style += _Style.from_color( + from_ansi(next(iter_codes)) + ) + elif color_type == 2: + self.style += _Style.from_color( + from_rgb( + next(iter_codes), + next(iter_codes), + next(iter_codes), + ) + ) + elif code == 48: + # Background + with suppress(StopIteration): + color_type = next(iter_codes) + if color_type == 5: + self.style += _Style.from_color( + None, from_ansi(next(iter_codes)) + ) + elif color_type == 2: + self.style += _Style.from_color( + None, + from_rgb( + next(iter_codes), + next(iter_codes), + next(iter_codes), + ), + ) + + return text + + +if sys.platform != "win32" and __name__ == "__main__": # pragma: no cover + import io + import os + import pty + import sys + + decoder = AnsiDecoder() + + stdout = io.BytesIO() + + def read(fd: int) -> bytes: + data = os.read(fd, 1024) + stdout.write(data) + return data + + pty.spawn(sys.argv[1:], read) + + from .console import Console + + console = Console(record=True) + + stdout_result = stdout.getvalue().decode("utf-8") + print(stdout_result) + + for line in decoder.decode(stdout_result): + console.print(line) + + console.save_html("stdout.html") diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/bar.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/bar.py new file mode 100644 index 0000000..ed86a55 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/bar.py @@ -0,0 +1,94 @@ +from typing import Optional, Union + +from .color import Color +from .console import Console, ConsoleOptions, RenderResult +from .jupyter import JupyterMixin +from .measure import Measurement +from .segment import Segment +from .style import Style + +# There are left-aligned characters for 1/8 to 7/8, but +# the right-aligned characters exist only for 1/8 and 4/8. +BEGIN_BLOCK_ELEMENTS = ["█", "█", "█", "▐", "▐", "▐", "▕", "▕"] +END_BLOCK_ELEMENTS = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"] +FULL_BLOCK = "█" + + +class Bar(JupyterMixin): + """Renders a solid block bar. + + Args: + size (float): Value for the end of the bar. + begin (float): Begin point (between 0 and size, inclusive). + end (float): End point (between 0 and size, inclusive). + width (int, optional): Width of the bar, or ``None`` for maximum width. Defaults to None. + color (Union[Color, str], optional): Color of the bar. Defaults to "default". + bgcolor (Union[Color, str], optional): Color of bar background. Defaults to "default". + """ + + def __init__( + self, + size: float, + begin: float, + end: float, + *, + width: Optional[int] = None, + color: Union[Color, str] = "default", + bgcolor: Union[Color, str] = "default", + ): + self.size = size + self.begin = max(begin, 0) + self.end = min(end, size) + self.width = width + self.style = Style(color=color, bgcolor=bgcolor) + + def __repr__(self) -> str: + return f"Bar({self.size}, {self.begin}, {self.end})" + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + + width = min( + self.width if self.width is not None else options.max_width, + options.max_width, + ) + + if self.begin >= self.end: + yield Segment(" " * width, self.style) + yield Segment.line() + return + + prefix_complete_eights = int(width * 8 * self.begin / self.size) + prefix_bar_count = prefix_complete_eights // 8 + prefix_eights_count = prefix_complete_eights % 8 + + body_complete_eights = int(width * 8 * self.end / self.size) + body_bar_count = body_complete_eights // 8 + body_eights_count = body_complete_eights % 8 + + # When start and end fall into the same cell, we ideally should render + # a symbol that's "center-aligned", but there is no good symbol in Unicode. + # In this case, we fall back to right-aligned block symbol for simplicity. + + prefix = " " * prefix_bar_count + if prefix_eights_count: + prefix += BEGIN_BLOCK_ELEMENTS[prefix_eights_count] + + body = FULL_BLOCK * body_bar_count + if body_eights_count: + body += END_BLOCK_ELEMENTS[body_eights_count] + + suffix = " " * (width - len(body)) + + yield Segment(prefix + body[len(prefix) :] + suffix, self.style) + yield Segment.line() + + def __rich_measure__( + self, console: Console, options: ConsoleOptions + ) -> Measurement: + return ( + Measurement(self.width, self.width) + if self.width is not None + else Measurement(4, options.max_width) + ) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/box.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/box.py new file mode 100644 index 0000000..97d2a94 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/box.py @@ -0,0 +1,517 @@ +import sys +from typing import TYPE_CHECKING, Iterable, List + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + + +from ._loop import loop_last + +if TYPE_CHECKING: + from pip._vendor.rich.console import ConsoleOptions + + +class Box: + """Defines characters to render boxes. + + ┌─┬┐ top + │ ││ head + ├─┼┤ head_row + │ ││ mid + ├─┼┤ row + ├─┼┤ foot_row + │ ││ foot + └─┴┘ bottom + + Args: + box (str): Characters making up box. + ascii (bool, optional): True if this box uses ascii characters only. Default is False. + """ + + def __init__(self, box: str, *, ascii: bool = False) -> None: + self._box = box + self.ascii = ascii + line1, line2, line3, line4, line5, line6, line7, line8 = box.splitlines() + # top + self.top_left, self.top, self.top_divider, self.top_right = iter(line1) + # head + self.head_left, _, self.head_vertical, self.head_right = iter(line2) + # head_row + ( + self.head_row_left, + self.head_row_horizontal, + self.head_row_cross, + self.head_row_right, + ) = iter(line3) + + # mid + self.mid_left, _, self.mid_vertical, self.mid_right = iter(line4) + # row + self.row_left, self.row_horizontal, self.row_cross, self.row_right = iter(line5) + # foot_row + ( + self.foot_row_left, + self.foot_row_horizontal, + self.foot_row_cross, + self.foot_row_right, + ) = iter(line6) + # foot + self.foot_left, _, self.foot_vertical, self.foot_right = iter(line7) + # bottom + self.bottom_left, self.bottom, self.bottom_divider, self.bottom_right = iter( + line8 + ) + + def __repr__(self) -> str: + return "Box(...)" + + def __str__(self) -> str: + return self._box + + def substitute(self, options: "ConsoleOptions", safe: bool = True) -> "Box": + """Substitute this box for another if it won't render due to platform issues. + + Args: + options (ConsoleOptions): Console options used in rendering. + safe (bool, optional): Substitute this for another Box if there are known problems + displaying on the platform (currently only relevant on Windows). Default is True. + + Returns: + Box: A different Box or the same Box. + """ + box = self + if options.legacy_windows and safe: + box = LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box) + if options.ascii_only and not box.ascii: + box = ASCII + return box + + def get_plain_headed_box(self) -> "Box": + """If this box uses special characters for the borders of the header, then + return the equivalent box that does not. + + Returns: + Box: The most similar Box that doesn't use header-specific box characters. + If the current Box already satisfies this criterion, then it's returned. + """ + return PLAIN_HEADED_SUBSTITUTIONS.get(self, self) + + def get_top(self, widths: Iterable[int]) -> str: + """Get the top of a simple box. + + Args: + widths (List[int]): Widths of columns. + + Returns: + str: A string of box characters. + """ + + parts: List[str] = [] + append = parts.append + append(self.top_left) + for last, width in loop_last(widths): + append(self.top * width) + if not last: + append(self.top_divider) + append(self.top_right) + return "".join(parts) + + def get_row( + self, + widths: Iterable[int], + level: Literal["head", "row", "foot", "mid"] = "row", + edge: bool = True, + ) -> str: + """Get the top of a simple box. + + Args: + width (List[int]): Widths of columns. + + Returns: + str: A string of box characters. + """ + if level == "head": + left = self.head_row_left + horizontal = self.head_row_horizontal + cross = self.head_row_cross + right = self.head_row_right + elif level == "row": + left = self.row_left + horizontal = self.row_horizontal + cross = self.row_cross + right = self.row_right + elif level == "mid": + left = self.mid_left + horizontal = " " + cross = self.mid_vertical + right = self.mid_right + elif level == "foot": + left = self.foot_row_left + horizontal = self.foot_row_horizontal + cross = self.foot_row_cross + right = self.foot_row_right + else: + raise ValueError("level must be 'head', 'row' or 'foot'") + + parts: List[str] = [] + append = parts.append + if edge: + append(left) + for last, width in loop_last(widths): + append(horizontal * width) + if not last: + append(cross) + if edge: + append(right) + return "".join(parts) + + def get_bottom(self, widths: Iterable[int]) -> str: + """Get the bottom of a simple box. + + Args: + widths (List[int]): Widths of columns. + + Returns: + str: A string of box characters. + """ + + parts: List[str] = [] + append = parts.append + append(self.bottom_left) + for last, width in loop_last(widths): + append(self.bottom * width) + if not last: + append(self.bottom_divider) + append(self.bottom_right) + return "".join(parts) + + +ASCII: Box = Box( + """\ ++--+ +| || +|-+| +| || +|-+| +|-+| +| || ++--+ +""", + ascii=True, +) + +ASCII2: Box = Box( + """\ ++-++ +| || ++-++ +| || ++-++ ++-++ +| || ++-++ +""", + ascii=True, +) + +ASCII_DOUBLE_HEAD: Box = Box( + """\ ++-++ +| || ++=++ +| || ++-++ ++-++ +| || ++-++ +""", + ascii=True, +) + +SQUARE: Box = Box( + """\ +┌─┬┐ +│ ││ +├─┼┤ +│ ││ +├─┼┤ +├─┼┤ +│ ││ +└─┴┘ +""" +) + +SQUARE_DOUBLE_HEAD: Box = Box( + """\ +┌─┬┐ +│ ││ +╞═╪╡ +│ ││ +├─┼┤ +├─┼┤ +│ ││ +└─┴┘ +""" +) + +MINIMAL: Box = Box( + """\ + ╷ + │ +╶─┼╴ + │ +╶─┼╴ +╶─┼╴ + │ + ╵ +""" +) + + +MINIMAL_HEAVY_HEAD: Box = Box( + """\ + ╷ + │ +╺━┿╸ + │ +╶─┼╴ +╶─┼╴ + │ + ╵ +""" +) + +MINIMAL_DOUBLE_HEAD: Box = Box( + """\ + ╷ + │ + ═╪ + │ + ─┼ + ─┼ + │ + ╵ +""" +) + + +SIMPLE: Box = Box( + """\ + + + ── + + + ── + + +""" +) + +SIMPLE_HEAD: Box = Box( + """\ + + + ── + + + + + +""" +) + + +SIMPLE_HEAVY: Box = Box( + """\ + + + ━━ + + + ━━ + + +""" +) + + +HORIZONTALS: Box = Box( + """\ + ── + + ── + + ── + ── + + ── +""" +) + +ROUNDED: Box = Box( + """\ +╭─┬╮ +│ ││ +├─┼┤ +│ ││ +├─┼┤ +├─┼┤ +│ ││ +╰─┴╯ +""" +) + +HEAVY: Box = Box( + """\ +┏━┳┓ +┃ ┃┃ +┣━╋┫ +┃ ┃┃ +┣━╋┫ +┣━╋┫ +┃ ┃┃ +┗━┻┛ +""" +) + +HEAVY_EDGE: Box = Box( + """\ +┏━┯┓ +┃ │┃ +┠─┼┨ +┃ │┃ +┠─┼┨ +┠─┼┨ +┃ │┃ +┗━┷┛ +""" +) + +HEAVY_HEAD: Box = Box( + """\ +┏━┳┓ +┃ ┃┃ +┡━╇┩ +│ ││ +├─┼┤ +├─┼┤ +│ ││ +└─┴┘ +""" +) + +DOUBLE: Box = Box( + """\ +╔═╦╗ +║ ║║ +╠═╬╣ +║ ║║ +╠═╬╣ +╠═╬╣ +║ ║║ +╚═╩╝ +""" +) + +DOUBLE_EDGE: Box = Box( + """\ +╔═╤╗ +║ │║ +╟─┼╢ +║ │║ +╟─┼╢ +╟─┼╢ +║ │║ +╚═╧╝ +""" +) + +MARKDOWN: Box = Box( + """\ + +| || +|-|| +| || +|-|| +|-|| +| || + +""", + ascii=True, +) + +# Map Boxes that don't render with raster fonts on to equivalent that do +LEGACY_WINDOWS_SUBSTITUTIONS = { + ROUNDED: SQUARE, + MINIMAL_HEAVY_HEAD: MINIMAL, + SIMPLE_HEAVY: SIMPLE, + HEAVY: SQUARE, + HEAVY_EDGE: SQUARE, + HEAVY_HEAD: SQUARE, +} + +# Map headed boxes to their headerless equivalents +PLAIN_HEADED_SUBSTITUTIONS = { + HEAVY_HEAD: SQUARE, + SQUARE_DOUBLE_HEAD: SQUARE, + MINIMAL_DOUBLE_HEAD: MINIMAL, + MINIMAL_HEAVY_HEAD: MINIMAL, + ASCII_DOUBLE_HEAD: ASCII2, +} + + +if __name__ == "__main__": # pragma: no cover + + from pip._vendor.rich.columns import Columns + from pip._vendor.rich.panel import Panel + + from . import box as box + from .console import Console + from .table import Table + from .text import Text + + console = Console(record=True) + + BOXES = [ + "ASCII", + "ASCII2", + "ASCII_DOUBLE_HEAD", + "SQUARE", + "SQUARE_DOUBLE_HEAD", + "MINIMAL", + "MINIMAL_HEAVY_HEAD", + "MINIMAL_DOUBLE_HEAD", + "SIMPLE", + "SIMPLE_HEAD", + "SIMPLE_HEAVY", + "HORIZONTALS", + "ROUNDED", + "HEAVY", + "HEAVY_EDGE", + "HEAVY_HEAD", + "DOUBLE", + "DOUBLE_EDGE", + "MARKDOWN", + ] + + console.print(Panel("[bold green]Box Constants", style="green"), justify="center") + console.print() + + columns = Columns(expand=True, padding=2) + for box_name in sorted(BOXES): + table = Table( + show_footer=True, style="dim", border_style="not dim", expand=True + ) + table.add_column("Header 1", "Footer 1") + table.add_column("Header 2", "Footer 2") + table.add_row("Cell", "Cell") + table.add_row("Cell", "Cell") + table.box = getattr(box, box_name) + table.title = Text(f"box.{box_name}", style="magenta") + columns.add_renderable(table) + console.print(columns) + + # console.save_svg("box.svg") diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/cells.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/cells.py new file mode 100644 index 0000000..9354f9e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/cells.py @@ -0,0 +1,154 @@ +import re +from functools import lru_cache +from typing import Callable, List + +from ._cell_widths import CELL_WIDTHS + +# Regex to match sequence of the most common character ranges +_is_single_cell_widths = re.compile("^[\u0020-\u006f\u00a0\u02ff\u0370-\u0482]*$").match + + +@lru_cache(4096) +def cached_cell_len(text: str) -> int: + """Get the number of cells required to display text. + + This method always caches, which may use up a lot of memory. It is recommended to use + `cell_len` over this method. + + Args: + text (str): Text to display. + + Returns: + int: Get the number of cells required to display text. + """ + _get_size = get_character_cell_size + total_size = sum(_get_size(character) for character in text) + return total_size + + +def cell_len(text: str, _cell_len: Callable[[str], int] = cached_cell_len) -> int: + """Get the number of cells required to display text. + + Args: + text (str): Text to display. + + Returns: + int: Get the number of cells required to display text. + """ + if len(text) < 512: + return _cell_len(text) + _get_size = get_character_cell_size + total_size = sum(_get_size(character) for character in text) + return total_size + + +@lru_cache(maxsize=4096) +def get_character_cell_size(character: str) -> int: + """Get the cell size of a character. + + Args: + character (str): A single character. + + Returns: + int: Number of cells (0, 1 or 2) occupied by that character. + """ + return _get_codepoint_cell_size(ord(character)) + + +@lru_cache(maxsize=4096) +def _get_codepoint_cell_size(codepoint: int) -> int: + """Get the cell size of a character. + + Args: + codepoint (int): Codepoint of a character. + + Returns: + int: Number of cells (0, 1 or 2) occupied by that character. + """ + + _table = CELL_WIDTHS + lower_bound = 0 + upper_bound = len(_table) - 1 + index = (lower_bound + upper_bound) // 2 + while True: + start, end, width = _table[index] + if codepoint < start: + upper_bound = index - 1 + elif codepoint > end: + lower_bound = index + 1 + else: + return 0 if width == -1 else width + if upper_bound < lower_bound: + break + index = (lower_bound + upper_bound) // 2 + return 1 + + +def set_cell_size(text: str, total: int) -> str: + """Set the length of a string to fit within given number of cells.""" + + if _is_single_cell_widths(text): + size = len(text) + if size < total: + return text + " " * (total - size) + return text[:total] + + if total <= 0: + return "" + cell_size = cell_len(text) + if cell_size == total: + return text + if cell_size < total: + return text + " " * (total - cell_size) + + start = 0 + end = len(text) + + # Binary search until we find the right size + while True: + pos = (start + end) // 2 + before = text[: pos + 1] + before_len = cell_len(before) + if before_len == total + 1 and cell_len(before[-1]) == 2: + return before[:-1] + " " + if before_len == total: + return before + if before_len > total: + end = pos + else: + start = pos + + +# TODO: This is inefficient +# TODO: This might not work with CWJ type characters +def chop_cells(text: str, max_size: int, position: int = 0) -> List[str]: + """Break text in to equal (cell) length strings, returning the characters in reverse + order""" + _get_character_cell_size = get_character_cell_size + characters = [ + (character, _get_character_cell_size(character)) for character in text + ] + total_size = position + lines: List[List[str]] = [[]] + append = lines[-1].append + + for character, size in reversed(characters): + if total_size + size > max_size: + lines.append([character]) + append = lines[-1].append + total_size = size + else: + total_size += size + append(character) + + return ["".join(line) for line in lines] + + +if __name__ == "__main__": # pragma: no cover + + print(get_character_cell_size("😽")) + for line in chop_cells("""这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑。""", 8): + print(line) + for n in range(80, 1, -1): + print(set_cell_size("""这是对亚洲语言支持的测试。面对模棱两可的想法,拒绝猜测的诱惑。""", n) + "|") + print("x" * n) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color.py new file mode 100644 index 0000000..dfe4559 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color.py @@ -0,0 +1,622 @@ +import platform +import re +from colorsys import rgb_to_hls +from enum import IntEnum +from functools import lru_cache +from typing import TYPE_CHECKING, NamedTuple, Optional, Tuple + +from ._palettes import EIGHT_BIT_PALETTE, STANDARD_PALETTE, WINDOWS_PALETTE +from .color_triplet import ColorTriplet +from .repr import Result, rich_repr +from .terminal_theme import DEFAULT_TERMINAL_THEME + +if TYPE_CHECKING: # pragma: no cover + from .terminal_theme import TerminalTheme + from .text import Text + + +WINDOWS = platform.system() == "Windows" + + +class ColorSystem(IntEnum): + """One of the 3 color system supported by terminals.""" + + STANDARD = 1 + EIGHT_BIT = 2 + TRUECOLOR = 3 + WINDOWS = 4 + + def __repr__(self) -> str: + return f"ColorSystem.{self.name}" + + def __str__(self) -> str: + return repr(self) + + +class ColorType(IntEnum): + """Type of color stored in Color class.""" + + DEFAULT = 0 + STANDARD = 1 + EIGHT_BIT = 2 + TRUECOLOR = 3 + WINDOWS = 4 + + def __repr__(self) -> str: + return f"ColorType.{self.name}" + + +ANSI_COLOR_NAMES = { + "black": 0, + "red": 1, + "green": 2, + "yellow": 3, + "blue": 4, + "magenta": 5, + "cyan": 6, + "white": 7, + "bright_black": 8, + "bright_red": 9, + "bright_green": 10, + "bright_yellow": 11, + "bright_blue": 12, + "bright_magenta": 13, + "bright_cyan": 14, + "bright_white": 15, + "grey0": 16, + "gray0": 16, + "navy_blue": 17, + "dark_blue": 18, + "blue3": 20, + "blue1": 21, + "dark_green": 22, + "deep_sky_blue4": 25, + "dodger_blue3": 26, + "dodger_blue2": 27, + "green4": 28, + "spring_green4": 29, + "turquoise4": 30, + "deep_sky_blue3": 32, + "dodger_blue1": 33, + "green3": 40, + "spring_green3": 41, + "dark_cyan": 36, + "light_sea_green": 37, + "deep_sky_blue2": 38, + "deep_sky_blue1": 39, + "spring_green2": 47, + "cyan3": 43, + "dark_turquoise": 44, + "turquoise2": 45, + "green1": 46, + "spring_green1": 48, + "medium_spring_green": 49, + "cyan2": 50, + "cyan1": 51, + "dark_red": 88, + "deep_pink4": 125, + "purple4": 55, + "purple3": 56, + "blue_violet": 57, + "orange4": 94, + "grey37": 59, + "gray37": 59, + "medium_purple4": 60, + "slate_blue3": 62, + "royal_blue1": 63, + "chartreuse4": 64, + "dark_sea_green4": 71, + "pale_turquoise4": 66, + "steel_blue": 67, + "steel_blue3": 68, + "cornflower_blue": 69, + "chartreuse3": 76, + "cadet_blue": 73, + "sky_blue3": 74, + "steel_blue1": 81, + "pale_green3": 114, + "sea_green3": 78, + "aquamarine3": 79, + "medium_turquoise": 80, + "chartreuse2": 112, + "sea_green2": 83, + "sea_green1": 85, + "aquamarine1": 122, + "dark_slate_gray2": 87, + "dark_magenta": 91, + "dark_violet": 128, + "purple": 129, + "light_pink4": 95, + "plum4": 96, + "medium_purple3": 98, + "slate_blue1": 99, + "yellow4": 106, + "wheat4": 101, + "grey53": 102, + "gray53": 102, + "light_slate_grey": 103, + "light_slate_gray": 103, + "medium_purple": 104, + "light_slate_blue": 105, + "dark_olive_green3": 149, + "dark_sea_green": 108, + "light_sky_blue3": 110, + "sky_blue2": 111, + "dark_sea_green3": 150, + "dark_slate_gray3": 116, + "sky_blue1": 117, + "chartreuse1": 118, + "light_green": 120, + "pale_green1": 156, + "dark_slate_gray1": 123, + "red3": 160, + "medium_violet_red": 126, + "magenta3": 164, + "dark_orange3": 166, + "indian_red": 167, + "hot_pink3": 168, + "medium_orchid3": 133, + "medium_orchid": 134, + "medium_purple2": 140, + "dark_goldenrod": 136, + "light_salmon3": 173, + "rosy_brown": 138, + "grey63": 139, + "gray63": 139, + "medium_purple1": 141, + "gold3": 178, + "dark_khaki": 143, + "navajo_white3": 144, + "grey69": 145, + "gray69": 145, + "light_steel_blue3": 146, + "light_steel_blue": 147, + "yellow3": 184, + "dark_sea_green2": 157, + "light_cyan3": 152, + "light_sky_blue1": 153, + "green_yellow": 154, + "dark_olive_green2": 155, + "dark_sea_green1": 193, + "pale_turquoise1": 159, + "deep_pink3": 162, + "magenta2": 200, + "hot_pink2": 169, + "orchid": 170, + "medium_orchid1": 207, + "orange3": 172, + "light_pink3": 174, + "pink3": 175, + "plum3": 176, + "violet": 177, + "light_goldenrod3": 179, + "tan": 180, + "misty_rose3": 181, + "thistle3": 182, + "plum2": 183, + "khaki3": 185, + "light_goldenrod2": 222, + "light_yellow3": 187, + "grey84": 188, + "gray84": 188, + "light_steel_blue1": 189, + "yellow2": 190, + "dark_olive_green1": 192, + "honeydew2": 194, + "light_cyan1": 195, + "red1": 196, + "deep_pink2": 197, + "deep_pink1": 199, + "magenta1": 201, + "orange_red1": 202, + "indian_red1": 204, + "hot_pink": 206, + "dark_orange": 208, + "salmon1": 209, + "light_coral": 210, + "pale_violet_red1": 211, + "orchid2": 212, + "orchid1": 213, + "orange1": 214, + "sandy_brown": 215, + "light_salmon1": 216, + "light_pink1": 217, + "pink1": 218, + "plum1": 219, + "gold1": 220, + "navajo_white1": 223, + "misty_rose1": 224, + "thistle1": 225, + "yellow1": 226, + "light_goldenrod1": 227, + "khaki1": 228, + "wheat1": 229, + "cornsilk1": 230, + "grey100": 231, + "gray100": 231, + "grey3": 232, + "gray3": 232, + "grey7": 233, + "gray7": 233, + "grey11": 234, + "gray11": 234, + "grey15": 235, + "gray15": 235, + "grey19": 236, + "gray19": 236, + "grey23": 237, + "gray23": 237, + "grey27": 238, + "gray27": 238, + "grey30": 239, + "gray30": 239, + "grey35": 240, + "gray35": 240, + "grey39": 241, + "gray39": 241, + "grey42": 242, + "gray42": 242, + "grey46": 243, + "gray46": 243, + "grey50": 244, + "gray50": 244, + "grey54": 245, + "gray54": 245, + "grey58": 246, + "gray58": 246, + "grey62": 247, + "gray62": 247, + "grey66": 248, + "gray66": 248, + "grey70": 249, + "gray70": 249, + "grey74": 250, + "gray74": 250, + "grey78": 251, + "gray78": 251, + "grey82": 252, + "gray82": 252, + "grey85": 253, + "gray85": 253, + "grey89": 254, + "gray89": 254, + "grey93": 255, + "gray93": 255, +} + + +class ColorParseError(Exception): + """The color could not be parsed.""" + + +RE_COLOR = re.compile( + r"""^ +\#([0-9a-f]{6})$| +color\(([0-9]{1,3})\)$| +rgb\(([\d\s,]+)\)$ +""", + re.VERBOSE, +) + + +@rich_repr +class Color(NamedTuple): + """Terminal color definition.""" + + name: str + """The name of the color (typically the input to Color.parse).""" + type: ColorType + """The type of the color.""" + number: Optional[int] = None + """The color number, if a standard color, or None.""" + triplet: Optional[ColorTriplet] = None + """A triplet of color components, if an RGB color.""" + + def __rich__(self) -> "Text": + """Displays the actual color if Rich printed.""" + from .style import Style + from .text import Text + + return Text.assemble( + f"", + ) + + def __rich_repr__(self) -> Result: + yield self.name + yield self.type + yield "number", self.number, None + yield "triplet", self.triplet, None + + @property + def system(self) -> ColorSystem: + """Get the native color system for this color.""" + if self.type == ColorType.DEFAULT: + return ColorSystem.STANDARD + return ColorSystem(int(self.type)) + + @property + def is_system_defined(self) -> bool: + """Check if the color is ultimately defined by the system.""" + return self.system not in (ColorSystem.EIGHT_BIT, ColorSystem.TRUECOLOR) + + @property + def is_default(self) -> bool: + """Check if the color is a default color.""" + return self.type == ColorType.DEFAULT + + def get_truecolor( + self, theme: Optional["TerminalTheme"] = None, foreground: bool = True + ) -> ColorTriplet: + """Get an equivalent color triplet for this color. + + Args: + theme (TerminalTheme, optional): Optional terminal theme, or None to use default. Defaults to None. + foreground (bool, optional): True for a foreground color, or False for background. Defaults to True. + + Returns: + ColorTriplet: A color triplet containing RGB components. + """ + + if theme is None: + theme = DEFAULT_TERMINAL_THEME + if self.type == ColorType.TRUECOLOR: + assert self.triplet is not None + return self.triplet + elif self.type == ColorType.EIGHT_BIT: + assert self.number is not None + return EIGHT_BIT_PALETTE[self.number] + elif self.type == ColorType.STANDARD: + assert self.number is not None + return theme.ansi_colors[self.number] + elif self.type == ColorType.WINDOWS: + assert self.number is not None + return WINDOWS_PALETTE[self.number] + else: # self.type == ColorType.DEFAULT: + assert self.number is None + return theme.foreground_color if foreground else theme.background_color + + @classmethod + def from_ansi(cls, number: int) -> "Color": + """Create a Color number from it's 8-bit ansi number. + + Args: + number (int): A number between 0-255 inclusive. + + Returns: + Color: A new Color instance. + """ + return cls( + name=f"color({number})", + type=(ColorType.STANDARD if number < 16 else ColorType.EIGHT_BIT), + number=number, + ) + + @classmethod + def from_triplet(cls, triplet: "ColorTriplet") -> "Color": + """Create a truecolor RGB color from a triplet of values. + + Args: + triplet (ColorTriplet): A color triplet containing red, green and blue components. + + Returns: + Color: A new color object. + """ + return cls(name=triplet.hex, type=ColorType.TRUECOLOR, triplet=triplet) + + @classmethod + def from_rgb(cls, red: float, green: float, blue: float) -> "Color": + """Create a truecolor from three color components in the range(0->255). + + Args: + red (float): Red component in range 0-255. + green (float): Green component in range 0-255. + blue (float): Blue component in range 0-255. + + Returns: + Color: A new color object. + """ + return cls.from_triplet(ColorTriplet(int(red), int(green), int(blue))) + + @classmethod + def default(cls) -> "Color": + """Get a Color instance representing the default color. + + Returns: + Color: Default color. + """ + return cls(name="default", type=ColorType.DEFAULT) + + @classmethod + @lru_cache(maxsize=1024) + def parse(cls, color: str) -> "Color": + """Parse a color definition.""" + original_color = color + color = color.lower().strip() + + if color == "default": + return cls(color, type=ColorType.DEFAULT) + + color_number = ANSI_COLOR_NAMES.get(color) + if color_number is not None: + return cls( + color, + type=(ColorType.STANDARD if color_number < 16 else ColorType.EIGHT_BIT), + number=color_number, + ) + + color_match = RE_COLOR.match(color) + if color_match is None: + raise ColorParseError(f"{original_color!r} is not a valid color") + + color_24, color_8, color_rgb = color_match.groups() + if color_24: + triplet = ColorTriplet( + int(color_24[0:2], 16), int(color_24[2:4], 16), int(color_24[4:6], 16) + ) + return cls(color, ColorType.TRUECOLOR, triplet=triplet) + + elif color_8: + number = int(color_8) + if number > 255: + raise ColorParseError(f"color number must be <= 255 in {color!r}") + return cls( + color, + type=(ColorType.STANDARD if number < 16 else ColorType.EIGHT_BIT), + number=number, + ) + + else: # color_rgb: + components = color_rgb.split(",") + if len(components) != 3: + raise ColorParseError( + f"expected three components in {original_color!r}" + ) + red, green, blue = components + triplet = ColorTriplet(int(red), int(green), int(blue)) + if not all(component <= 255 for component in triplet): + raise ColorParseError( + f"color components must be <= 255 in {original_color!r}" + ) + return cls(color, ColorType.TRUECOLOR, triplet=triplet) + + @lru_cache(maxsize=1024) + def get_ansi_codes(self, foreground: bool = True) -> Tuple[str, ...]: + """Get the ANSI escape codes for this color.""" + _type = self.type + if _type == ColorType.DEFAULT: + return ("39" if foreground else "49",) + + elif _type == ColorType.WINDOWS: + number = self.number + assert number is not None + fore, back = (30, 40) if number < 8 else (82, 92) + return (str(fore + number if foreground else back + number),) + + elif _type == ColorType.STANDARD: + number = self.number + assert number is not None + fore, back = (30, 40) if number < 8 else (82, 92) + return (str(fore + number if foreground else back + number),) + + elif _type == ColorType.EIGHT_BIT: + assert self.number is not None + return ("38" if foreground else "48", "5", str(self.number)) + + else: # self.standard == ColorStandard.TRUECOLOR: + assert self.triplet is not None + red, green, blue = self.triplet + return ("38" if foreground else "48", "2", str(red), str(green), str(blue)) + + @lru_cache(maxsize=1024) + def downgrade(self, system: ColorSystem) -> "Color": + """Downgrade a color system to a system with fewer colors.""" + + if self.type in (ColorType.DEFAULT, system): + return self + # Convert to 8-bit color from truecolor color + if system == ColorSystem.EIGHT_BIT and self.system == ColorSystem.TRUECOLOR: + assert self.triplet is not None + _h, l, s = rgb_to_hls(*self.triplet.normalized) + # If saturation is under 15% assume it is grayscale + if s < 0.15: + gray = round(l * 25.0) + if gray == 0: + color_number = 16 + elif gray == 25: + color_number = 231 + else: + color_number = 231 + gray + return Color(self.name, ColorType.EIGHT_BIT, number=color_number) + + red, green, blue = self.triplet + six_red = red / 95 if red < 95 else 1 + (red - 95) / 40 + six_green = green / 95 if green < 95 else 1 + (green - 95) / 40 + six_blue = blue / 95 if blue < 95 else 1 + (blue - 95) / 40 + + color_number = ( + 16 + 36 * round(six_red) + 6 * round(six_green) + round(six_blue) + ) + return Color(self.name, ColorType.EIGHT_BIT, number=color_number) + + # Convert to standard from truecolor or 8-bit + elif system == ColorSystem.STANDARD: + if self.system == ColorSystem.TRUECOLOR: + assert self.triplet is not None + triplet = self.triplet + else: # self.system == ColorSystem.EIGHT_BIT + assert self.number is not None + triplet = ColorTriplet(*EIGHT_BIT_PALETTE[self.number]) + + color_number = STANDARD_PALETTE.match(triplet) + return Color(self.name, ColorType.STANDARD, number=color_number) + + elif system == ColorSystem.WINDOWS: + if self.system == ColorSystem.TRUECOLOR: + assert self.triplet is not None + triplet = self.triplet + else: # self.system == ColorSystem.EIGHT_BIT + assert self.number is not None + if self.number < 16: + return Color(self.name, ColorType.WINDOWS, number=self.number) + triplet = ColorTriplet(*EIGHT_BIT_PALETTE[self.number]) + + color_number = WINDOWS_PALETTE.match(triplet) + return Color(self.name, ColorType.WINDOWS, number=color_number) + + return self + + +def parse_rgb_hex(hex_color: str) -> ColorTriplet: + """Parse six hex characters in to RGB triplet.""" + assert len(hex_color) == 6, "must be 6 characters" + color = ColorTriplet( + int(hex_color[0:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16) + ) + return color + + +def blend_rgb( + color1: ColorTriplet, color2: ColorTriplet, cross_fade: float = 0.5 +) -> ColorTriplet: + """Blend one RGB color in to another.""" + r1, g1, b1 = color1 + r2, g2, b2 = color2 + new_color = ColorTriplet( + int(r1 + (r2 - r1) * cross_fade), + int(g1 + (g2 - g1) * cross_fade), + int(b1 + (b2 - b1) * cross_fade), + ) + return new_color + + +if __name__ == "__main__": # pragma: no cover + + from .console import Console + from .table import Table + from .text import Text + + console = Console() + + table = Table(show_footer=False, show_edge=True) + table.add_column("Color", width=10, overflow="ellipsis") + table.add_column("Number", justify="right", style="yellow") + table.add_column("Name", style="green") + table.add_column("Hex", style="blue") + table.add_column("RGB", style="magenta") + + colors = sorted((v, k) for k, v in ANSI_COLOR_NAMES.items()) + for color_number, name in colors: + if "grey" in name: + continue + color_cell = Text(" " * 10, style=f"on {name}") + if color_number < 16: + table.add_row(color_cell, f"{color_number}", Text(f'"{name}"')) + else: + color = EIGHT_BIT_PALETTE[color_number] # type: ignore[has-type] + table.add_row( + color_cell, str(color_number), Text(f'"{name}"'), color.hex, color.rgb + ) + + console.print(table) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color_triplet.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color_triplet.py new file mode 100644 index 0000000..02cab32 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/color_triplet.py @@ -0,0 +1,38 @@ +from typing import NamedTuple, Tuple + + +class ColorTriplet(NamedTuple): + """The red, green, and blue components of a color.""" + + red: int + """Red component in 0 to 255 range.""" + green: int + """Green component in 0 to 255 range.""" + blue: int + """Blue component in 0 to 255 range.""" + + @property + def hex(self) -> str: + """get the color triplet in CSS style.""" + red, green, blue = self + return f"#{red:02x}{green:02x}{blue:02x}" + + @property + def rgb(self) -> str: + """The color in RGB format. + + Returns: + str: An rgb color, e.g. ``"rgb(100,23,255)"``. + """ + red, green, blue = self + return f"rgb({red},{green},{blue})" + + @property + def normalized(self) -> Tuple[float, float, float]: + """Convert components into floats between 0 and 1. + + Returns: + Tuple[float, float, float]: A tuple of three normalized colour components. + """ + red, green, blue = self + return red / 255.0, green / 255.0, blue / 255.0 diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/columns.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/columns.py new file mode 100644 index 0000000..669a3a7 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/columns.py @@ -0,0 +1,187 @@ +from collections import defaultdict +from itertools import chain +from operator import itemgetter +from typing import Dict, Iterable, List, Optional, Tuple + +from .align import Align, AlignMethod +from .console import Console, ConsoleOptions, RenderableType, RenderResult +from .constrain import Constrain +from .measure import Measurement +from .padding import Padding, PaddingDimensions +from .table import Table +from .text import TextType +from .jupyter import JupyterMixin + + +class Columns(JupyterMixin): + """Display renderables in neat columns. + + Args: + renderables (Iterable[RenderableType]): Any number of Rich renderables (including str). + width (int, optional): The desired width of the columns, or None to auto detect. Defaults to None. + padding (PaddingDimensions, optional): Optional padding around cells. Defaults to (0, 1). + expand (bool, optional): Expand columns to full width. Defaults to False. + equal (bool, optional): Arrange in to equal sized columns. Defaults to False. + column_first (bool, optional): Align items from top to bottom (rather than left to right). Defaults to False. + right_to_left (bool, optional): Start column from right hand side. Defaults to False. + align (str, optional): Align value ("left", "right", or "center") or None for default. Defaults to None. + title (TextType, optional): Optional title for Columns. + """ + + def __init__( + self, + renderables: Optional[Iterable[RenderableType]] = None, + padding: PaddingDimensions = (0, 1), + *, + width: Optional[int] = None, + expand: bool = False, + equal: bool = False, + column_first: bool = False, + right_to_left: bool = False, + align: Optional[AlignMethod] = None, + title: Optional[TextType] = None, + ) -> None: + self.renderables = list(renderables or []) + self.width = width + self.padding = padding + self.expand = expand + self.equal = equal + self.column_first = column_first + self.right_to_left = right_to_left + self.align: Optional[AlignMethod] = align + self.title = title + + def add_renderable(self, renderable: RenderableType) -> None: + """Add a renderable to the columns. + + Args: + renderable (RenderableType): Any renderable object. + """ + self.renderables.append(renderable) + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + render_str = console.render_str + renderables = [ + render_str(renderable) if isinstance(renderable, str) else renderable + for renderable in self.renderables + ] + if not renderables: + return + _top, right, _bottom, left = Padding.unpack(self.padding) + width_padding = max(left, right) + max_width = options.max_width + widths: Dict[int, int] = defaultdict(int) + column_count = len(renderables) + + get_measurement = Measurement.get + renderable_widths = [ + get_measurement(console, options, renderable).maximum + for renderable in renderables + ] + if self.equal: + renderable_widths = [max(renderable_widths)] * len(renderable_widths) + + def iter_renderables( + column_count: int, + ) -> Iterable[Tuple[int, Optional[RenderableType]]]: + item_count = len(renderables) + if self.column_first: + width_renderables = list(zip(renderable_widths, renderables)) + + column_lengths: List[int] = [item_count // column_count] * column_count + for col_no in range(item_count % column_count): + column_lengths[col_no] += 1 + + row_count = (item_count + column_count - 1) // column_count + cells = [[-1] * column_count for _ in range(row_count)] + row = col = 0 + for index in range(item_count): + cells[row][col] = index + column_lengths[col] -= 1 + if column_lengths[col]: + row += 1 + else: + col += 1 + row = 0 + for index in chain.from_iterable(cells): + if index == -1: + break + yield width_renderables[index] + else: + yield from zip(renderable_widths, renderables) + # Pad odd elements with spaces + if item_count % column_count: + for _ in range(column_count - (item_count % column_count)): + yield 0, None + + table = Table.grid(padding=self.padding, collapse_padding=True, pad_edge=False) + table.expand = self.expand + table.title = self.title + + if self.width is not None: + column_count = (max_width) // (self.width + width_padding) + for _ in range(column_count): + table.add_column(width=self.width) + else: + while column_count > 1: + widths.clear() + column_no = 0 + for renderable_width, _ in iter_renderables(column_count): + widths[column_no] = max(widths[column_no], renderable_width) + total_width = sum(widths.values()) + width_padding * ( + len(widths) - 1 + ) + if total_width > max_width: + column_count = len(widths) - 1 + break + else: + column_no = (column_no + 1) % column_count + else: + break + + get_renderable = itemgetter(1) + _renderables = [ + get_renderable(_renderable) + for _renderable in iter_renderables(column_count) + ] + if self.equal: + _renderables = [ + None + if renderable is None + else Constrain(renderable, renderable_widths[0]) + for renderable in _renderables + ] + if self.align: + align = self.align + _Align = Align + _renderables = [ + None if renderable is None else _Align(renderable, align) + for renderable in _renderables + ] + + right_to_left = self.right_to_left + add_row = table.add_row + for start in range(0, len(_renderables), column_count): + row = _renderables[start : start + column_count] + if right_to_left: + row = row[::-1] + add_row(*row) + yield table + + +if __name__ == "__main__": # pragma: no cover + import os + + console = Console() + + files = [f"{i} {s}" for i, s in enumerate(sorted(os.listdir()))] + columns = Columns(files, padding=(0, 1), expand=False, equal=False) + console.print(columns) + console.rule() + columns.column_first = True + console.print(columns) + columns.right_to_left = True + console.rule() + console.print(columns) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/console.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/console.py new file mode 100644 index 0000000..e559cbb --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/console.py @@ -0,0 +1,2633 @@ +import inspect +import os +import platform +import sys +import threading +import zlib +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from datetime import datetime +from functools import wraps +from getpass import getpass +from html import escape +from inspect import isclass +from itertools import islice +from math import ceil +from time import monotonic +from types import FrameType, ModuleType, TracebackType +from typing import ( + IO, + TYPE_CHECKING, + Any, + Callable, + Dict, + Iterable, + List, + Mapping, + NamedTuple, + Optional, + TextIO, + Tuple, + Type, + Union, + cast, +) + +from pip._vendor.rich._null_file import NULL_FILE + +if sys.version_info >= (3, 8): + from typing import Literal, Protocol, runtime_checkable +else: + from pip._vendor.typing_extensions import ( + Literal, + Protocol, + runtime_checkable, + ) # pragma: no cover + +from . import errors, themes +from ._emoji_replace import _emoji_replace +from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT +from ._fileno import get_fileno +from ._log_render import FormatTimeCallable, LogRender +from .align import Align, AlignMethod +from .color import ColorSystem, blend_rgb +from .control import Control +from .emoji import EmojiVariant +from .highlighter import NullHighlighter, ReprHighlighter +from .markup import render as render_markup +from .measure import Measurement, measure_renderables +from .pager import Pager, SystemPager +from .pretty import Pretty, is_expandable +from .protocol import rich_cast +from .region import Region +from .scope import render_scope +from .screen import Screen +from .segment import Segment +from .style import Style, StyleType +from .styled import Styled +from .terminal_theme import DEFAULT_TERMINAL_THEME, SVG_EXPORT_THEME, TerminalTheme +from .text import Text, TextType +from .theme import Theme, ThemeStack + +if TYPE_CHECKING: + from ._windows import WindowsConsoleFeatures + from .live import Live + from .status import Status + +JUPYTER_DEFAULT_COLUMNS = 115 +JUPYTER_DEFAULT_LINES = 100 +WINDOWS = platform.system() == "Windows" + +HighlighterType = Callable[[Union[str, "Text"]], "Text"] +JustifyMethod = Literal["default", "left", "center", "right", "full"] +OverflowMethod = Literal["fold", "crop", "ellipsis", "ignore"] + + +class NoChange: + pass + + +NO_CHANGE = NoChange() + +try: + _STDIN_FILENO = sys.__stdin__.fileno() +except Exception: + _STDIN_FILENO = 0 +try: + _STDOUT_FILENO = sys.__stdout__.fileno() +except Exception: + _STDOUT_FILENO = 1 +try: + _STDERR_FILENO = sys.__stderr__.fileno() +except Exception: + _STDERR_FILENO = 2 + +_STD_STREAMS = (_STDIN_FILENO, _STDOUT_FILENO, _STDERR_FILENO) +_STD_STREAMS_OUTPUT = (_STDOUT_FILENO, _STDERR_FILENO) + + +_TERM_COLORS = { + "kitty": ColorSystem.EIGHT_BIT, + "256color": ColorSystem.EIGHT_BIT, + "16color": ColorSystem.STANDARD, +} + + +class ConsoleDimensions(NamedTuple): + """Size of the terminal.""" + + width: int + """The width of the console in 'cells'.""" + height: int + """The height of the console in lines.""" + + +@dataclass +class ConsoleOptions: + """Options for __rich_console__ method.""" + + size: ConsoleDimensions + """Size of console.""" + legacy_windows: bool + """legacy_windows: flag for legacy windows.""" + min_width: int + """Minimum width of renderable.""" + max_width: int + """Maximum width of renderable.""" + is_terminal: bool + """True if the target is a terminal, otherwise False.""" + encoding: str + """Encoding of terminal.""" + max_height: int + """Height of container (starts as terminal)""" + justify: Optional[JustifyMethod] = None + """Justify value override for renderable.""" + overflow: Optional[OverflowMethod] = None + """Overflow value override for renderable.""" + no_wrap: Optional[bool] = False + """Disable wrapping for text.""" + highlight: Optional[bool] = None + """Highlight override for render_str.""" + markup: Optional[bool] = None + """Enable markup when rendering strings.""" + height: Optional[int] = None + + @property + def ascii_only(self) -> bool: + """Check if renderables should use ascii only.""" + return not self.encoding.startswith("utf") + + def copy(self) -> "ConsoleOptions": + """Return a copy of the options. + + Returns: + ConsoleOptions: a copy of self. + """ + options: ConsoleOptions = ConsoleOptions.__new__(ConsoleOptions) + options.__dict__ = self.__dict__.copy() + return options + + def update( + self, + *, + width: Union[int, NoChange] = NO_CHANGE, + min_width: Union[int, NoChange] = NO_CHANGE, + max_width: Union[int, NoChange] = NO_CHANGE, + justify: Union[Optional[JustifyMethod], NoChange] = NO_CHANGE, + overflow: Union[Optional[OverflowMethod], NoChange] = NO_CHANGE, + no_wrap: Union[Optional[bool], NoChange] = NO_CHANGE, + highlight: Union[Optional[bool], NoChange] = NO_CHANGE, + markup: Union[Optional[bool], NoChange] = NO_CHANGE, + height: Union[Optional[int], NoChange] = NO_CHANGE, + ) -> "ConsoleOptions": + """Update values, return a copy.""" + options = self.copy() + if not isinstance(width, NoChange): + options.min_width = options.max_width = max(0, width) + if not isinstance(min_width, NoChange): + options.min_width = min_width + if not isinstance(max_width, NoChange): + options.max_width = max_width + if not isinstance(justify, NoChange): + options.justify = justify + if not isinstance(overflow, NoChange): + options.overflow = overflow + if not isinstance(no_wrap, NoChange): + options.no_wrap = no_wrap + if not isinstance(highlight, NoChange): + options.highlight = highlight + if not isinstance(markup, NoChange): + options.markup = markup + if not isinstance(height, NoChange): + if height is not None: + options.max_height = height + options.height = None if height is None else max(0, height) + return options + + def update_width(self, width: int) -> "ConsoleOptions": + """Update just the width, return a copy. + + Args: + width (int): New width (sets both min_width and max_width) + + Returns: + ~ConsoleOptions: New console options instance. + """ + options = self.copy() + options.min_width = options.max_width = max(0, width) + return options + + def update_height(self, height: int) -> "ConsoleOptions": + """Update the height, and return a copy. + + Args: + height (int): New height + + Returns: + ~ConsoleOptions: New Console options instance. + """ + options = self.copy() + options.max_height = options.height = height + return options + + def reset_height(self) -> "ConsoleOptions": + """Return a copy of the options with height set to ``None``. + + Returns: + ~ConsoleOptions: New console options instance. + """ + options = self.copy() + options.height = None + return options + + def update_dimensions(self, width: int, height: int) -> "ConsoleOptions": + """Update the width and height, and return a copy. + + Args: + width (int): New width (sets both min_width and max_width). + height (int): New height. + + Returns: + ~ConsoleOptions: New console options instance. + """ + options = self.copy() + options.min_width = options.max_width = max(0, width) + options.height = options.max_height = height + return options + + +@runtime_checkable +class RichCast(Protocol): + """An object that may be 'cast' to a console renderable.""" + + def __rich__( + self, + ) -> Union["ConsoleRenderable", "RichCast", str]: # pragma: no cover + ... + + +@runtime_checkable +class ConsoleRenderable(Protocol): + """An object that supports the console protocol.""" + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": # pragma: no cover + ... + + +# A type that may be rendered by Console. +RenderableType = Union[ConsoleRenderable, RichCast, str] + +# The result of calling a __rich_console__ method. +RenderResult = Iterable[Union[RenderableType, Segment]] + +_null_highlighter = NullHighlighter() + + +class CaptureError(Exception): + """An error in the Capture context manager.""" + + +class NewLine: + """A renderable to generate new line(s)""" + + def __init__(self, count: int = 1) -> None: + self.count = count + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> Iterable[Segment]: + yield Segment("\n" * self.count) + + +class ScreenUpdate: + """Render a list of lines at a given offset.""" + + def __init__(self, lines: List[List[Segment]], x: int, y: int) -> None: + self._lines = lines + self.x = x + self.y = y + + def __rich_console__( + self, console: "Console", options: ConsoleOptions + ) -> RenderResult: + x = self.x + move_to = Control.move_to + for offset, line in enumerate(self._lines, self.y): + yield move_to(x, offset) + yield from line + + +class Capture: + """Context manager to capture the result of printing to the console. + See :meth:`~rich.console.Console.capture` for how to use. + + Args: + console (Console): A console instance to capture output. + """ + + def __init__(self, console: "Console") -> None: + self._console = console + self._result: Optional[str] = None + + def __enter__(self) -> "Capture": + self._console.begin_capture() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self._result = self._console.end_capture() + + def get(self) -> str: + """Get the result of the capture.""" + if self._result is None: + raise CaptureError( + "Capture result is not available until context manager exits." + ) + return self._result + + +class ThemeContext: + """A context manager to use a temporary theme. See :meth:`~rich.console.Console.use_theme` for usage.""" + + def __init__(self, console: "Console", theme: Theme, inherit: bool = True) -> None: + self.console = console + self.theme = theme + self.inherit = inherit + + def __enter__(self) -> "ThemeContext": + self.console.push_theme(self.theme) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.console.pop_theme() + + +class PagerContext: + """A context manager that 'pages' content. See :meth:`~rich.console.Console.pager` for usage.""" + + def __init__( + self, + console: "Console", + pager: Optional[Pager] = None, + styles: bool = False, + links: bool = False, + ) -> None: + self._console = console + self.pager = SystemPager() if pager is None else pager + self.styles = styles + self.links = links + + def __enter__(self) -> "PagerContext": + self._console._enter_buffer() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if exc_type is None: + with self._console._lock: + buffer: List[Segment] = self._console._buffer[:] + del self._console._buffer[:] + segments: Iterable[Segment] = buffer + if not self.styles: + segments = Segment.strip_styles(segments) + elif not self.links: + segments = Segment.strip_links(segments) + content = self._console._render_buffer(segments) + self.pager.show(content) + self._console._exit_buffer() + + +class ScreenContext: + """A context manager that enables an alternative screen. See :meth:`~rich.console.Console.screen` for usage.""" + + def __init__( + self, console: "Console", hide_cursor: bool, style: StyleType = "" + ) -> None: + self.console = console + self.hide_cursor = hide_cursor + self.screen = Screen(style=style) + self._changed = False + + def update( + self, *renderables: RenderableType, style: Optional[StyleType] = None + ) -> None: + """Update the screen. + + Args: + renderable (RenderableType, optional): Optional renderable to replace current renderable, + or None for no change. Defaults to None. + style: (Style, optional): Replacement style, or None for no change. Defaults to None. + """ + if renderables: + self.screen.renderable = ( + Group(*renderables) if len(renderables) > 1 else renderables[0] + ) + if style is not None: + self.screen.style = style + self.console.print(self.screen, end="") + + def __enter__(self) -> "ScreenContext": + self._changed = self.console.set_alt_screen(True) + if self._changed and self.hide_cursor: + self.console.show_cursor(False) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if self._changed: + self.console.set_alt_screen(False) + if self.hide_cursor: + self.console.show_cursor(True) + + +class Group: + """Takes a group of renderables and returns a renderable object that renders the group. + + Args: + renderables (Iterable[RenderableType]): An iterable of renderable objects. + fit (bool, optional): Fit dimension of group to contents, or fill available space. Defaults to True. + """ + + def __init__(self, *renderables: "RenderableType", fit: bool = True) -> None: + self._renderables = renderables + self.fit = fit + self._render: Optional[List[RenderableType]] = None + + @property + def renderables(self) -> List["RenderableType"]: + if self._render is None: + self._render = list(self._renderables) + return self._render + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + if self.fit: + return measure_renderables(console, options, self.renderables) + else: + return Measurement(options.max_width, options.max_width) + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> RenderResult: + yield from self.renderables + + +def group(fit: bool = True) -> Callable[..., Callable[..., Group]]: + """A decorator that turns an iterable of renderables in to a group. + + Args: + fit (bool, optional): Fit dimension of group to contents, or fill available space. Defaults to True. + """ + + def decorator( + method: Callable[..., Iterable[RenderableType]] + ) -> Callable[..., Group]: + """Convert a method that returns an iterable of renderables in to a Group.""" + + @wraps(method) + def _replace(*args: Any, **kwargs: Any) -> Group: + renderables = method(*args, **kwargs) + return Group(*renderables, fit=fit) + + return _replace + + return decorator + + +def _is_jupyter() -> bool: # pragma: no cover + """Check if we're running in a Jupyter notebook.""" + try: + get_ipython # type: ignore[name-defined] + except NameError: + return False + ipython = get_ipython() # type: ignore[name-defined] + shell = ipython.__class__.__name__ + if ( + "google.colab" in str(ipython.__class__) + or os.getenv("DATABRICKS_RUNTIME_VERSION") + or shell == "ZMQInteractiveShell" + ): + return True # Jupyter notebook or qtconsole + elif shell == "TerminalInteractiveShell": + return False # Terminal running IPython + else: + return False # Other type (?) + + +COLOR_SYSTEMS = { + "standard": ColorSystem.STANDARD, + "256": ColorSystem.EIGHT_BIT, + "truecolor": ColorSystem.TRUECOLOR, + "windows": ColorSystem.WINDOWS, +} + +_COLOR_SYSTEMS_NAMES = {system: name for name, system in COLOR_SYSTEMS.items()} + + +@dataclass +class ConsoleThreadLocals(threading.local): + """Thread local values for Console context.""" + + theme_stack: ThemeStack + buffer: List[Segment] = field(default_factory=list) + buffer_index: int = 0 + + +class RenderHook(ABC): + """Provides hooks in to the render process.""" + + @abstractmethod + def process_renderables( + self, renderables: List[ConsoleRenderable] + ) -> List[ConsoleRenderable]: + """Called with a list of objects to render. + + This method can return a new list of renderables, or modify and return the same list. + + Args: + renderables (List[ConsoleRenderable]): A number of renderable objects. + + Returns: + List[ConsoleRenderable]: A replacement list of renderables. + """ + + +_windows_console_features: Optional["WindowsConsoleFeatures"] = None + + +def get_windows_console_features() -> "WindowsConsoleFeatures": # pragma: no cover + global _windows_console_features + if _windows_console_features is not None: + return _windows_console_features + from ._windows import get_windows_console_features + + _windows_console_features = get_windows_console_features() + return _windows_console_features + + +def detect_legacy_windows() -> bool: + """Detect legacy Windows.""" + return WINDOWS and not get_windows_console_features().vt + + +class Console: + """A high level console interface. + + Args: + color_system (str, optional): The color system supported by your terminal, + either ``"standard"``, ``"256"`` or ``"truecolor"``. Leave as ``"auto"`` to autodetect. + force_terminal (Optional[bool], optional): Enable/disable terminal control codes, or None to auto-detect terminal. Defaults to None. + force_jupyter (Optional[bool], optional): Enable/disable Jupyter rendering, or None to auto-detect Jupyter. Defaults to None. + force_interactive (Optional[bool], optional): Enable/disable interactive mode, or None to auto detect. Defaults to None. + soft_wrap (Optional[bool], optional): Set soft wrap default on print method. Defaults to False. + theme (Theme, optional): An optional style theme object, or ``None`` for default theme. + stderr (bool, optional): Use stderr rather than stdout if ``file`` is not specified. Defaults to False. + file (IO, optional): A file object where the console should write to. Defaults to stdout. + quiet (bool, Optional): Boolean to suppress all output. Defaults to False. + width (int, optional): The width of the terminal. Leave as default to auto-detect width. + height (int, optional): The height of the terminal. Leave as default to auto-detect height. + style (StyleType, optional): Style to apply to all output, or None for no style. Defaults to None. + no_color (Optional[bool], optional): Enabled no color mode, or None to auto detect. Defaults to None. + tab_size (int, optional): Number of spaces used to replace a tab character. Defaults to 8. + record (bool, optional): Boolean to enable recording of terminal output, + required to call :meth:`export_html`, :meth:`export_svg`, and :meth:`export_text`. Defaults to False. + markup (bool, optional): Boolean to enable :ref:`console_markup`. Defaults to True. + emoji (bool, optional): Enable emoji code. Defaults to True. + emoji_variant (str, optional): Optional emoji variant, either "text" or "emoji". Defaults to None. + highlight (bool, optional): Enable automatic highlighting. Defaults to True. + log_time (bool, optional): Boolean to enable logging of time by :meth:`log` methods. Defaults to True. + log_path (bool, optional): Boolean to enable the logging of the caller by :meth:`log`. Defaults to True. + log_time_format (Union[str, TimeFormatterCallable], optional): If ``log_time`` is enabled, either string for strftime or callable that formats the time. Defaults to "[%X] ". + highlighter (HighlighterType, optional): Default highlighter. + legacy_windows (bool, optional): Enable legacy Windows mode, or ``None`` to auto detect. Defaults to ``None``. + safe_box (bool, optional): Restrict box options that don't render on legacy Windows. + get_datetime (Callable[[], datetime], optional): Callable that gets the current time as a datetime.datetime object (used by Console.log), + or None for datetime.now. + get_time (Callable[[], time], optional): Callable that gets the current time in seconds, default uses time.monotonic. + """ + + _environ: Mapping[str, str] = os.environ + + def __init__( + self, + *, + color_system: Optional[ + Literal["auto", "standard", "256", "truecolor", "windows"] + ] = "auto", + force_terminal: Optional[bool] = None, + force_jupyter: Optional[bool] = None, + force_interactive: Optional[bool] = None, + soft_wrap: bool = False, + theme: Optional[Theme] = None, + stderr: bool = False, + file: Optional[IO[str]] = None, + quiet: bool = False, + width: Optional[int] = None, + height: Optional[int] = None, + style: Optional[StyleType] = None, + no_color: Optional[bool] = None, + tab_size: int = 8, + record: bool = False, + markup: bool = True, + emoji: bool = True, + emoji_variant: Optional[EmojiVariant] = None, + highlight: bool = True, + log_time: bool = True, + log_path: bool = True, + log_time_format: Union[str, FormatTimeCallable] = "[%X]", + highlighter: Optional["HighlighterType"] = ReprHighlighter(), + legacy_windows: Optional[bool] = None, + safe_box: bool = True, + get_datetime: Optional[Callable[[], datetime]] = None, + get_time: Optional[Callable[[], float]] = None, + _environ: Optional[Mapping[str, str]] = None, + ): + # Copy of os.environ allows us to replace it for testing + if _environ is not None: + self._environ = _environ + + self.is_jupyter = _is_jupyter() if force_jupyter is None else force_jupyter + if self.is_jupyter: + if width is None: + jupyter_columns = self._environ.get("JUPYTER_COLUMNS") + if jupyter_columns is not None and jupyter_columns.isdigit(): + width = int(jupyter_columns) + else: + width = JUPYTER_DEFAULT_COLUMNS + if height is None: + jupyter_lines = self._environ.get("JUPYTER_LINES") + if jupyter_lines is not None and jupyter_lines.isdigit(): + height = int(jupyter_lines) + else: + height = JUPYTER_DEFAULT_LINES + + self.tab_size = tab_size + self.record = record + self._markup = markup + self._emoji = emoji + self._emoji_variant: Optional[EmojiVariant] = emoji_variant + self._highlight = highlight + self.legacy_windows: bool = ( + (detect_legacy_windows() and not self.is_jupyter) + if legacy_windows is None + else legacy_windows + ) + + if width is None: + columns = self._environ.get("COLUMNS") + if columns is not None and columns.isdigit(): + width = int(columns) - self.legacy_windows + if height is None: + lines = self._environ.get("LINES") + if lines is not None and lines.isdigit(): + height = int(lines) + + self.soft_wrap = soft_wrap + self._width = width + self._height = height + + self._color_system: Optional[ColorSystem] + + self._force_terminal = None + if force_terminal is not None: + self._force_terminal = force_terminal + + self._file = file + self.quiet = quiet + self.stderr = stderr + + if color_system is None: + self._color_system = None + elif color_system == "auto": + self._color_system = self._detect_color_system() + else: + self._color_system = COLOR_SYSTEMS[color_system] + + self._lock = threading.RLock() + self._log_render = LogRender( + show_time=log_time, + show_path=log_path, + time_format=log_time_format, + ) + self.highlighter: HighlighterType = highlighter or _null_highlighter + self.safe_box = safe_box + self.get_datetime = get_datetime or datetime.now + self.get_time = get_time or monotonic + self.style = style + self.no_color = ( + no_color if no_color is not None else "NO_COLOR" in self._environ + ) + self.is_interactive = ( + (self.is_terminal and not self.is_dumb_terminal) + if force_interactive is None + else force_interactive + ) + + self._record_buffer_lock = threading.RLock() + self._thread_locals = ConsoleThreadLocals( + theme_stack=ThemeStack(themes.DEFAULT if theme is None else theme) + ) + self._record_buffer: List[Segment] = [] + self._render_hooks: List[RenderHook] = [] + self._live: Optional["Live"] = None + self._is_alt_screen = False + + def __repr__(self) -> str: + return f"" + + @property + def file(self) -> IO[str]: + """Get the file object to write to.""" + file = self._file or (sys.stderr if self.stderr else sys.stdout) + file = getattr(file, "rich_proxied_file", file) + if file is None: + file = NULL_FILE + return file + + @file.setter + def file(self, new_file: IO[str]) -> None: + """Set a new file object.""" + self._file = new_file + + @property + def _buffer(self) -> List[Segment]: + """Get a thread local buffer.""" + return self._thread_locals.buffer + + @property + def _buffer_index(self) -> int: + """Get a thread local buffer.""" + return self._thread_locals.buffer_index + + @_buffer_index.setter + def _buffer_index(self, value: int) -> None: + self._thread_locals.buffer_index = value + + @property + def _theme_stack(self) -> ThemeStack: + """Get the thread local theme stack.""" + return self._thread_locals.theme_stack + + def _detect_color_system(self) -> Optional[ColorSystem]: + """Detect color system from env vars.""" + if self.is_jupyter: + return ColorSystem.TRUECOLOR + if not self.is_terminal or self.is_dumb_terminal: + return None + if WINDOWS: # pragma: no cover + if self.legacy_windows: # pragma: no cover + return ColorSystem.WINDOWS + windows_console_features = get_windows_console_features() + return ( + ColorSystem.TRUECOLOR + if windows_console_features.truecolor + else ColorSystem.EIGHT_BIT + ) + else: + color_term = self._environ.get("COLORTERM", "").strip().lower() + if color_term in ("truecolor", "24bit"): + return ColorSystem.TRUECOLOR + term = self._environ.get("TERM", "").strip().lower() + _term_name, _hyphen, colors = term.rpartition("-") + color_system = _TERM_COLORS.get(colors, ColorSystem.STANDARD) + return color_system + + def _enter_buffer(self) -> None: + """Enter in to a buffer context, and buffer all output.""" + self._buffer_index += 1 + + def _exit_buffer(self) -> None: + """Leave buffer context, and render content if required.""" + self._buffer_index -= 1 + self._check_buffer() + + def set_live(self, live: "Live") -> None: + """Set Live instance. Used by Live context manager. + + Args: + live (Live): Live instance using this Console. + + Raises: + errors.LiveError: If this Console has a Live context currently active. + """ + with self._lock: + if self._live is not None: + raise errors.LiveError("Only one live display may be active at once") + self._live = live + + def clear_live(self) -> None: + """Clear the Live instance.""" + with self._lock: + self._live = None + + def push_render_hook(self, hook: RenderHook) -> None: + """Add a new render hook to the stack. + + Args: + hook (RenderHook): Render hook instance. + """ + with self._lock: + self._render_hooks.append(hook) + + def pop_render_hook(self) -> None: + """Pop the last renderhook from the stack.""" + with self._lock: + self._render_hooks.pop() + + def __enter__(self) -> "Console": + """Own context manager to enter buffer context.""" + self._enter_buffer() + return self + + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: + """Exit buffer context.""" + self._exit_buffer() + + def begin_capture(self) -> None: + """Begin capturing console output. Call :meth:`end_capture` to exit capture mode and return output.""" + self._enter_buffer() + + def end_capture(self) -> str: + """End capture mode and return captured string. + + Returns: + str: Console output. + """ + render_result = self._render_buffer(self._buffer) + del self._buffer[:] + self._exit_buffer() + return render_result + + def push_theme(self, theme: Theme, *, inherit: bool = True) -> None: + """Push a new theme on to the top of the stack, replacing the styles from the previous theme. + Generally speaking, you should call :meth:`~rich.console.Console.use_theme` to get a context manager, rather + than calling this method directly. + + Args: + theme (Theme): A theme instance. + inherit (bool, optional): Inherit existing styles. Defaults to True. + """ + self._theme_stack.push_theme(theme, inherit=inherit) + + def pop_theme(self) -> None: + """Remove theme from top of stack, restoring previous theme.""" + self._theme_stack.pop_theme() + + def use_theme(self, theme: Theme, *, inherit: bool = True) -> ThemeContext: + """Use a different theme for the duration of the context manager. + + Args: + theme (Theme): Theme instance to user. + inherit (bool, optional): Inherit existing console styles. Defaults to True. + + Returns: + ThemeContext: [description] + """ + return ThemeContext(self, theme, inherit) + + @property + def color_system(self) -> Optional[str]: + """Get color system string. + + Returns: + Optional[str]: "standard", "256" or "truecolor". + """ + + if self._color_system is not None: + return _COLOR_SYSTEMS_NAMES[self._color_system] + else: + return None + + @property + def encoding(self) -> str: + """Get the encoding of the console file, e.g. ``"utf-8"``. + + Returns: + str: A standard encoding string. + """ + return (getattr(self.file, "encoding", "utf-8") or "utf-8").lower() + + @property + def is_terminal(self) -> bool: + """Check if the console is writing to a terminal. + + Returns: + bool: True if the console writing to a device capable of + understanding terminal codes, otherwise False. + """ + if self._force_terminal is not None: + return self._force_terminal + + if hasattr(sys.stdin, "__module__") and sys.stdin.__module__.startswith( + "idlelib" + ): + # Return False for Idle which claims to be a tty but can't handle ansi codes + return False + + if self.is_jupyter: + # return False for Jupyter, which may have FORCE_COLOR set + return False + + # If FORCE_COLOR env var has any value at all, we assume a terminal. + force_color = self._environ.get("FORCE_COLOR") + if force_color is not None: + self._force_terminal = True + return True + + isatty: Optional[Callable[[], bool]] = getattr(self.file, "isatty", None) + try: + return False if isatty is None else isatty() + except ValueError: + # in some situation (at the end of a pytest run for example) isatty() can raise + # ValueError: I/O operation on closed file + # return False because we aren't in a terminal anymore + return False + + @property + def is_dumb_terminal(self) -> bool: + """Detect dumb terminal. + + Returns: + bool: True if writing to a dumb terminal, otherwise False. + + """ + _term = self._environ.get("TERM", "") + is_dumb = _term.lower() in ("dumb", "unknown") + return self.is_terminal and is_dumb + + @property + def options(self) -> ConsoleOptions: + """Get default console options.""" + return ConsoleOptions( + max_height=self.size.height, + size=self.size, + legacy_windows=self.legacy_windows, + min_width=1, + max_width=self.width, + encoding=self.encoding, + is_terminal=self.is_terminal, + ) + + @property + def size(self) -> ConsoleDimensions: + """Get the size of the console. + + Returns: + ConsoleDimensions: A named tuple containing the dimensions. + """ + + if self._width is not None and self._height is not None: + return ConsoleDimensions(self._width - self.legacy_windows, self._height) + + if self.is_dumb_terminal: + return ConsoleDimensions(80, 25) + + width: Optional[int] = None + height: Optional[int] = None + + if WINDOWS: # pragma: no cover + try: + width, height = os.get_terminal_size() + except (AttributeError, ValueError, OSError): # Probably not a terminal + pass + else: + for file_descriptor in _STD_STREAMS: + try: + width, height = os.get_terminal_size(file_descriptor) + except (AttributeError, ValueError, OSError): + pass + else: + break + + columns = self._environ.get("COLUMNS") + if columns is not None and columns.isdigit(): + width = int(columns) + lines = self._environ.get("LINES") + if lines is not None and lines.isdigit(): + height = int(lines) + + # get_terminal_size can report 0, 0 if run from pseudo-terminal + width = width or 80 + height = height or 25 + return ConsoleDimensions( + width - self.legacy_windows if self._width is None else self._width, + height if self._height is None else self._height, + ) + + @size.setter + def size(self, new_size: Tuple[int, int]) -> None: + """Set a new size for the terminal. + + Args: + new_size (Tuple[int, int]): New width and height. + """ + width, height = new_size + self._width = width + self._height = height + + @property + def width(self) -> int: + """Get the width of the console. + + Returns: + int: The width (in characters) of the console. + """ + return self.size.width + + @width.setter + def width(self, width: int) -> None: + """Set width. + + Args: + width (int): New width. + """ + self._width = width + + @property + def height(self) -> int: + """Get the height of the console. + + Returns: + int: The height (in lines) of the console. + """ + return self.size.height + + @height.setter + def height(self, height: int) -> None: + """Set height. + + Args: + height (int): new height. + """ + self._height = height + + def bell(self) -> None: + """Play a 'bell' sound (if supported by the terminal).""" + self.control(Control.bell()) + + def capture(self) -> Capture: + """A context manager to *capture* the result of print() or log() in a string, + rather than writing it to the console. + + Example: + >>> from rich.console import Console + >>> console = Console() + >>> with console.capture() as capture: + ... console.print("[bold magenta]Hello World[/]") + >>> print(capture.get()) + + Returns: + Capture: Context manager with disables writing to the terminal. + """ + capture = Capture(self) + return capture + + def pager( + self, pager: Optional[Pager] = None, styles: bool = False, links: bool = False + ) -> PagerContext: + """A context manager to display anything printed within a "pager". The pager application + is defined by the system and will typically support at least pressing a key to scroll. + + Args: + pager (Pager, optional): A pager object, or None to use :class:`~rich.pager.SystemPager`. Defaults to None. + styles (bool, optional): Show styles in pager. Defaults to False. + links (bool, optional): Show links in pager. Defaults to False. + + Example: + >>> from rich.console import Console + >>> from rich.__main__ import make_test_card + >>> console = Console() + >>> with console.pager(): + console.print(make_test_card()) + + Returns: + PagerContext: A context manager. + """ + return PagerContext(self, pager=pager, styles=styles, links=links) + + def line(self, count: int = 1) -> None: + """Write new line(s). + + Args: + count (int, optional): Number of new lines. Defaults to 1. + """ + + assert count >= 0, "count must be >= 0" + self.print(NewLine(count)) + + def clear(self, home: bool = True) -> None: + """Clear the screen. + + Args: + home (bool, optional): Also move the cursor to 'home' position. Defaults to True. + """ + if home: + self.control(Control.clear(), Control.home()) + else: + self.control(Control.clear()) + + def status( + self, + status: RenderableType, + *, + spinner: str = "dots", + spinner_style: StyleType = "status.spinner", + speed: float = 1.0, + refresh_per_second: float = 12.5, + ) -> "Status": + """Display a status and spinner. + + Args: + status (RenderableType): A status renderable (str or Text typically). + spinner (str, optional): Name of spinner animation (see python -m rich.spinner). Defaults to "dots". + spinner_style (StyleType, optional): Style of spinner. Defaults to "status.spinner". + speed (float, optional): Speed factor for spinner animation. Defaults to 1.0. + refresh_per_second (float, optional): Number of refreshes per second. Defaults to 12.5. + + Returns: + Status: A Status object that may be used as a context manager. + """ + from .status import Status + + status_renderable = Status( + status, + console=self, + spinner=spinner, + spinner_style=spinner_style, + speed=speed, + refresh_per_second=refresh_per_second, + ) + return status_renderable + + def show_cursor(self, show: bool = True) -> bool: + """Show or hide the cursor. + + Args: + show (bool, optional): Set visibility of the cursor. + """ + if self.is_terminal: + self.control(Control.show_cursor(show)) + return True + return False + + def set_alt_screen(self, enable: bool = True) -> bool: + """Enables alternative screen mode. + + Note, if you enable this mode, you should ensure that is disabled before + the application exits. See :meth:`~rich.Console.screen` for a context manager + that handles this for you. + + Args: + enable (bool, optional): Enable (True) or disable (False) alternate screen. Defaults to True. + + Returns: + bool: True if the control codes were written. + + """ + changed = False + if self.is_terminal and not self.legacy_windows: + self.control(Control.alt_screen(enable)) + changed = True + self._is_alt_screen = enable + return changed + + @property + def is_alt_screen(self) -> bool: + """Check if the alt screen was enabled. + + Returns: + bool: True if the alt screen was enabled, otherwise False. + """ + return self._is_alt_screen + + def set_window_title(self, title: str) -> bool: + """Set the title of the console terminal window. + + Warning: There is no means within Rich of "resetting" the window title to its + previous value, meaning the title you set will persist even after your application + exits. + + ``fish`` shell resets the window title before and after each command by default, + negating this issue. Windows Terminal and command prompt will also reset the title for you. + Most other shells and terminals, however, do not do this. + + Some terminals may require configuration changes before you can set the title. + Some terminals may not support setting the title at all. + + Other software (including the terminal itself, the shell, custom prompts, plugins, etc.) + may also set the terminal window title. This could result in whatever value you write + using this method being overwritten. + + Args: + title (str): The new title of the terminal window. + + Returns: + bool: True if the control code to change the terminal title was + written, otherwise False. Note that a return value of True + does not guarantee that the window title has actually changed, + since the feature may be unsupported/disabled in some terminals. + """ + if self.is_terminal: + self.control(Control.title(title)) + return True + return False + + def screen( + self, hide_cursor: bool = True, style: Optional[StyleType] = None + ) -> "ScreenContext": + """Context manager to enable and disable 'alternative screen' mode. + + Args: + hide_cursor (bool, optional): Also hide the cursor. Defaults to False. + style (Style, optional): Optional style for screen. Defaults to None. + + Returns: + ~ScreenContext: Context which enables alternate screen on enter, and disables it on exit. + """ + return ScreenContext(self, hide_cursor=hide_cursor, style=style or "") + + def measure( + self, renderable: RenderableType, *, options: Optional[ConsoleOptions] = None + ) -> Measurement: + """Measure a renderable. Returns a :class:`~rich.measure.Measurement` object which contains + information regarding the number of characters required to print the renderable. + + Args: + renderable (RenderableType): Any renderable or string. + options (Optional[ConsoleOptions], optional): Options to use when measuring, or None + to use default options. Defaults to None. + + Returns: + Measurement: A measurement of the renderable. + """ + measurement = Measurement.get(self, options or self.options, renderable) + return measurement + + def render( + self, renderable: RenderableType, options: Optional[ConsoleOptions] = None + ) -> Iterable[Segment]: + """Render an object in to an iterable of `Segment` instances. + + This method contains the logic for rendering objects with the console protocol. + You are unlikely to need to use it directly, unless you are extending the library. + + Args: + renderable (RenderableType): An object supporting the console protocol, or + an object that may be converted to a string. + options (ConsoleOptions, optional): An options object, or None to use self.options. Defaults to None. + + Returns: + Iterable[Segment]: An iterable of segments that may be rendered. + """ + + _options = options or self.options + if _options.max_width < 1: + # No space to render anything. This prevents potential recursion errors. + return + render_iterable: RenderResult + + renderable = rich_cast(renderable) + if hasattr(renderable, "__rich_console__") and not isclass(renderable): + render_iterable = renderable.__rich_console__(self, _options) # type: ignore[union-attr] + elif isinstance(renderable, str): + text_renderable = self.render_str( + renderable, highlight=_options.highlight, markup=_options.markup + ) + render_iterable = text_renderable.__rich_console__(self, _options) + else: + raise errors.NotRenderableError( + f"Unable to render {renderable!r}; " + "A str, Segment or object with __rich_console__ method is required" + ) + + try: + iter_render = iter(render_iterable) + except TypeError: + raise errors.NotRenderableError( + f"object {render_iterable!r} is not renderable" + ) + _Segment = Segment + _options = _options.reset_height() + for render_output in iter_render: + if isinstance(render_output, _Segment): + yield render_output + else: + yield from self.render(render_output, _options) + + def render_lines( + self, + renderable: RenderableType, + options: Optional[ConsoleOptions] = None, + *, + style: Optional[Style] = None, + pad: bool = True, + new_lines: bool = False, + ) -> List[List[Segment]]: + """Render objects in to a list of lines. + + The output of render_lines is useful when further formatting of rendered console text + is required, such as the Panel class which draws a border around any renderable object. + + Args: + renderable (RenderableType): Any object renderable in the console. + options (Optional[ConsoleOptions], optional): Console options, or None to use self.options. Default to ``None``. + style (Style, optional): Optional style to apply to renderables. Defaults to ``None``. + pad (bool, optional): Pad lines shorter than render width. Defaults to ``True``. + new_lines (bool, optional): Include "\n" characters at end of lines. + + Returns: + List[List[Segment]]: A list of lines, where a line is a list of Segment objects. + """ + with self._lock: + render_options = options or self.options + _rendered = self.render(renderable, render_options) + if style: + _rendered = Segment.apply_style(_rendered, style) + + render_height = render_options.height + if render_height is not None: + render_height = max(0, render_height) + + lines = list( + islice( + Segment.split_and_crop_lines( + _rendered, + render_options.max_width, + include_new_lines=new_lines, + pad=pad, + style=style, + ), + None, + render_height, + ) + ) + if render_options.height is not None: + extra_lines = render_options.height - len(lines) + if extra_lines > 0: + pad_line = [ + [Segment(" " * render_options.max_width, style), Segment("\n")] + if new_lines + else [Segment(" " * render_options.max_width, style)] + ] + lines.extend(pad_line * extra_lines) + + return lines + + def render_str( + self, + text: str, + *, + style: Union[str, Style] = "", + justify: Optional[JustifyMethod] = None, + overflow: Optional[OverflowMethod] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + highlighter: Optional[HighlighterType] = None, + ) -> "Text": + """Convert a string to a Text instance. This is called automatically if + you print or log a string. + + Args: + text (str): Text to render. + style (Union[str, Style], optional): Style to apply to rendered text. + justify (str, optional): Justify method: "default", "left", "center", "full", or "right". Defaults to ``None``. + overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to ``None``. + emoji (Optional[bool], optional): Enable emoji, or ``None`` to use Console default. + markup (Optional[bool], optional): Enable markup, or ``None`` to use Console default. + highlight (Optional[bool], optional): Enable highlighting, or ``None`` to use Console default. + highlighter (HighlighterType, optional): Optional highlighter to apply. + Returns: + ConsoleRenderable: Renderable object. + + """ + emoji_enabled = emoji or (emoji is None and self._emoji) + markup_enabled = markup or (markup is None and self._markup) + highlight_enabled = highlight or (highlight is None and self._highlight) + + if markup_enabled: + rich_text = render_markup( + text, + style=style, + emoji=emoji_enabled, + emoji_variant=self._emoji_variant, + ) + rich_text.justify = justify + rich_text.overflow = overflow + else: + rich_text = Text( + _emoji_replace(text, default_variant=self._emoji_variant) + if emoji_enabled + else text, + justify=justify, + overflow=overflow, + style=style, + ) + + _highlighter = (highlighter or self.highlighter) if highlight_enabled else None + if _highlighter is not None: + highlight_text = _highlighter(str(rich_text)) + highlight_text.copy_styles(rich_text) + return highlight_text + + return rich_text + + def get_style( + self, name: Union[str, Style], *, default: Optional[Union[Style, str]] = None + ) -> Style: + """Get a Style instance by its theme name or parse a definition. + + Args: + name (str): The name of a style or a style definition. + + Returns: + Style: A Style object. + + Raises: + MissingStyle: If no style could be parsed from name. + + """ + if isinstance(name, Style): + return name + + try: + style = self._theme_stack.get(name) + if style is None: + style = Style.parse(name) + return style.copy() if style.link else style + except errors.StyleSyntaxError as error: + if default is not None: + return self.get_style(default) + raise errors.MissingStyle( + f"Failed to get style {name!r}; {error}" + ) from None + + def _collect_renderables( + self, + objects: Iterable[Any], + sep: str, + end: str, + *, + justify: Optional[JustifyMethod] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + ) -> List[ConsoleRenderable]: + """Combine a number of renderables and text into one renderable. + + Args: + objects (Iterable[Any]): Anything that Rich can render. + sep (str): String to write between print data. + end (str): String to write at end of print data. + justify (str, optional): One of "left", "right", "center", or "full". Defaults to ``None``. + emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. + markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. + + Returns: + List[ConsoleRenderable]: A list of things to render. + """ + renderables: List[ConsoleRenderable] = [] + _append = renderables.append + text: List[Text] = [] + append_text = text.append + + append = _append + if justify in ("left", "center", "right"): + + def align_append(renderable: RenderableType) -> None: + _append(Align(renderable, cast(AlignMethod, justify))) + + append = align_append + + _highlighter: HighlighterType = _null_highlighter + if highlight or (highlight is None and self._highlight): + _highlighter = self.highlighter + + def check_text() -> None: + if text: + sep_text = Text(sep, justify=justify, end=end) + append(sep_text.join(text)) + text.clear() + + for renderable in objects: + renderable = rich_cast(renderable) + if isinstance(renderable, str): + append_text( + self.render_str( + renderable, emoji=emoji, markup=markup, highlighter=_highlighter + ) + ) + elif isinstance(renderable, Text): + append_text(renderable) + elif isinstance(renderable, ConsoleRenderable): + check_text() + append(renderable) + elif is_expandable(renderable): + check_text() + append(Pretty(renderable, highlighter=_highlighter)) + else: + append_text(_highlighter(str(renderable))) + + check_text() + + if self.style is not None: + style = self.get_style(self.style) + renderables = [Styled(renderable, style) for renderable in renderables] + + return renderables + + def rule( + self, + title: TextType = "", + *, + characters: str = "─", + style: Union[str, Style] = "rule.line", + align: AlignMethod = "center", + ) -> None: + """Draw a line with optional centered title. + + Args: + title (str, optional): Text to render over the rule. Defaults to "". + characters (str, optional): Character(s) to form the line. Defaults to "─". + style (str, optional): Style of line. Defaults to "rule.line". + align (str, optional): How to align the title, one of "left", "center", or "right". Defaults to "center". + """ + from .rule import Rule + + rule = Rule(title=title, characters=characters, style=style, align=align) + self.print(rule) + + def control(self, *control: Control) -> None: + """Insert non-printing control codes. + + Args: + control_codes (str): Control codes, such as those that may move the cursor. + """ + if not self.is_dumb_terminal: + with self: + self._buffer.extend(_control.segment for _control in control) + + def out( + self, + *objects: Any, + sep: str = " ", + end: str = "\n", + style: Optional[Union[str, Style]] = None, + highlight: Optional[bool] = None, + ) -> None: + """Output to the terminal. This is a low-level way of writing to the terminal which unlike + :meth:`~rich.console.Console.print` won't pretty print, wrap text, or apply markup, but will + optionally apply highlighting and a basic style. + + Args: + sep (str, optional): String to write between print data. Defaults to " ". + end (str, optional): String to write at end of print data. Defaults to "\\\\n". + style (Union[str, Style], optional): A style to apply to output. Defaults to None. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use + console default. Defaults to ``None``. + """ + raw_output: str = sep.join(str(_object) for _object in objects) + self.print( + raw_output, + style=style, + highlight=highlight, + emoji=False, + markup=False, + no_wrap=True, + overflow="ignore", + crop=False, + end=end, + ) + + def print( + self, + *objects: Any, + sep: str = " ", + end: str = "\n", + style: Optional[Union[str, Style]] = None, + justify: Optional[JustifyMethod] = None, + overflow: Optional[OverflowMethod] = None, + no_wrap: Optional[bool] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + width: Optional[int] = None, + height: Optional[int] = None, + crop: bool = True, + soft_wrap: Optional[bool] = None, + new_line_start: bool = False, + ) -> None: + """Print to the console. + + Args: + objects (positional args): Objects to log to the terminal. + sep (str, optional): String to write between print data. Defaults to " ". + end (str, optional): String to write at end of print data. Defaults to "\\\\n". + style (Union[str, Style], optional): A style to apply to output. Defaults to None. + justify (str, optional): Justify method: "default", "left", "right", "center", or "full". Defaults to ``None``. + overflow (str, optional): Overflow method: "ignore", "crop", "fold", or "ellipsis". Defaults to None. + no_wrap (Optional[bool], optional): Disable word wrapping. Defaults to None. + emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. Defaults to ``None``. + markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. Defaults to ``None``. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. Defaults to ``None``. + width (Optional[int], optional): Width of output, or ``None`` to auto-detect. Defaults to ``None``. + crop (Optional[bool], optional): Crop output to width of terminal. Defaults to True. + soft_wrap (bool, optional): Enable soft wrap mode which disables word wrapping and cropping of text or ``None`` for + Console default. Defaults to ``None``. + new_line_start (bool, False): Insert a new line at the start if the output contains more than one line. Defaults to ``False``. + """ + if not objects: + objects = (NewLine(),) + + if soft_wrap is None: + soft_wrap = self.soft_wrap + if soft_wrap: + if no_wrap is None: + no_wrap = True + if overflow is None: + overflow = "ignore" + crop = False + render_hooks = self._render_hooks[:] + with self: + renderables = self._collect_renderables( + objects, + sep, + end, + justify=justify, + emoji=emoji, + markup=markup, + highlight=highlight, + ) + for hook in render_hooks: + renderables = hook.process_renderables(renderables) + render_options = self.options.update( + justify=justify, + overflow=overflow, + width=min(width, self.width) if width is not None else NO_CHANGE, + height=height, + no_wrap=no_wrap, + markup=markup, + highlight=highlight, + ) + + new_segments: List[Segment] = [] + extend = new_segments.extend + render = self.render + if style is None: + for renderable in renderables: + extend(render(renderable, render_options)) + else: + for renderable in renderables: + extend( + Segment.apply_style( + render(renderable, render_options), self.get_style(style) + ) + ) + if new_line_start: + if ( + len("".join(segment.text for segment in new_segments).splitlines()) + > 1 + ): + new_segments.insert(0, Segment.line()) + if crop: + buffer_extend = self._buffer.extend + for line in Segment.split_and_crop_lines( + new_segments, self.width, pad=False + ): + buffer_extend(line) + else: + self._buffer.extend(new_segments) + + def print_json( + self, + json: Optional[str] = None, + *, + data: Any = None, + indent: Union[None, int, str] = 2, + highlight: bool = True, + skip_keys: bool = False, + ensure_ascii: bool = False, + check_circular: bool = True, + allow_nan: bool = True, + default: Optional[Callable[[Any], Any]] = None, + sort_keys: bool = False, + ) -> None: + """Pretty prints JSON. Output will be valid JSON. + + Args: + json (Optional[str]): A string containing JSON. + data (Any): If json is not supplied, then encode this data. + indent (Union[None, int, str], optional): Number of spaces to indent. Defaults to 2. + highlight (bool, optional): Enable highlighting of output: Defaults to True. + skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False. + ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False. + check_circular (bool, optional): Check for circular references. Defaults to True. + allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True. + default (Callable, optional): A callable that converts values that can not be encoded + in to something that can be JSON encoded. Defaults to None. + sort_keys (bool, optional): Sort dictionary keys. Defaults to False. + """ + from pip._vendor.rich.json import JSON + + if json is None: + json_renderable = JSON.from_data( + data, + indent=indent, + highlight=highlight, + skip_keys=skip_keys, + ensure_ascii=ensure_ascii, + check_circular=check_circular, + allow_nan=allow_nan, + default=default, + sort_keys=sort_keys, + ) + else: + if not isinstance(json, str): + raise TypeError( + f"json must be str. Did you mean print_json(data={json!r}) ?" + ) + json_renderable = JSON( + json, + indent=indent, + highlight=highlight, + skip_keys=skip_keys, + ensure_ascii=ensure_ascii, + check_circular=check_circular, + allow_nan=allow_nan, + default=default, + sort_keys=sort_keys, + ) + self.print(json_renderable, soft_wrap=True) + + def update_screen( + self, + renderable: RenderableType, + *, + region: Optional[Region] = None, + options: Optional[ConsoleOptions] = None, + ) -> None: + """Update the screen at a given offset. + + Args: + renderable (RenderableType): A Rich renderable. + region (Region, optional): Region of screen to update, or None for entire screen. Defaults to None. + x (int, optional): x offset. Defaults to 0. + y (int, optional): y offset. Defaults to 0. + + Raises: + errors.NoAltScreen: If the Console isn't in alt screen mode. + + """ + if not self.is_alt_screen: + raise errors.NoAltScreen("Alt screen must be enabled to call update_screen") + render_options = options or self.options + if region is None: + x = y = 0 + render_options = render_options.update_dimensions( + render_options.max_width, render_options.height or self.height + ) + else: + x, y, width, height = region + render_options = render_options.update_dimensions(width, height) + + lines = self.render_lines(renderable, options=render_options) + self.update_screen_lines(lines, x, y) + + def update_screen_lines( + self, lines: List[List[Segment]], x: int = 0, y: int = 0 + ) -> None: + """Update lines of the screen at a given offset. + + Args: + lines (List[List[Segment]]): Rendered lines (as produced by :meth:`~rich.Console.render_lines`). + x (int, optional): x offset (column no). Defaults to 0. + y (int, optional): y offset (column no). Defaults to 0. + + Raises: + errors.NoAltScreen: If the Console isn't in alt screen mode. + """ + if not self.is_alt_screen: + raise errors.NoAltScreen("Alt screen must be enabled to call update_screen") + screen_update = ScreenUpdate(lines, x, y) + segments = self.render(screen_update) + self._buffer.extend(segments) + self._check_buffer() + + def print_exception( + self, + *, + width: Optional[int] = 100, + extra_lines: int = 3, + theme: Optional[str] = None, + word_wrap: bool = False, + show_locals: bool = False, + suppress: Iterable[Union[str, ModuleType]] = (), + max_frames: int = 100, + ) -> None: + """Prints a rich render of the last exception and traceback. + + Args: + width (Optional[int], optional): Number of characters used to render code. Defaults to 100. + extra_lines (int, optional): Additional lines of code to render. Defaults to 3. + theme (str, optional): Override pygments theme used in traceback + word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. + show_locals (bool, optional): Enable display of local variables. Defaults to False. + suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback. + max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100. + """ + from .traceback import Traceback + + traceback = Traceback( + width=width, + extra_lines=extra_lines, + theme=theme, + word_wrap=word_wrap, + show_locals=show_locals, + suppress=suppress, + max_frames=max_frames, + ) + self.print(traceback) + + @staticmethod + def _caller_frame_info( + offset: int, + currentframe: Callable[[], Optional[FrameType]] = inspect.currentframe, + ) -> Tuple[str, int, Dict[str, Any]]: + """Get caller frame information. + + Args: + offset (int): the caller offset within the current frame stack. + currentframe (Callable[[], Optional[FrameType]], optional): the callable to use to + retrieve the current frame. Defaults to ``inspect.currentframe``. + + Returns: + Tuple[str, int, Dict[str, Any]]: A tuple containing the filename, the line number and + the dictionary of local variables associated with the caller frame. + + Raises: + RuntimeError: If the stack offset is invalid. + """ + # Ignore the frame of this local helper + offset += 1 + + frame = currentframe() + if frame is not None: + # Use the faster currentframe where implemented + while offset and frame is not None: + frame = frame.f_back + offset -= 1 + assert frame is not None + return frame.f_code.co_filename, frame.f_lineno, frame.f_locals + else: + # Fallback to the slower stack + frame_info = inspect.stack()[offset] + return frame_info.filename, frame_info.lineno, frame_info.frame.f_locals + + def log( + self, + *objects: Any, + sep: str = " ", + end: str = "\n", + style: Optional[Union[str, Style]] = None, + justify: Optional[JustifyMethod] = None, + emoji: Optional[bool] = None, + markup: Optional[bool] = None, + highlight: Optional[bool] = None, + log_locals: bool = False, + _stack_offset: int = 1, + ) -> None: + """Log rich content to the terminal. + + Args: + objects (positional args): Objects to log to the terminal. + sep (str, optional): String to write between print data. Defaults to " ". + end (str, optional): String to write at end of print data. Defaults to "\\\\n". + style (Union[str, Style], optional): A style to apply to output. Defaults to None. + justify (str, optional): One of "left", "right", "center", or "full". Defaults to ``None``. + overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to None. + emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. Defaults to None. + markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. Defaults to None. + highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. Defaults to None. + log_locals (bool, optional): Boolean to enable logging of locals where ``log()`` + was called. Defaults to False. + _stack_offset (int, optional): Offset of caller from end of call stack. Defaults to 1. + """ + if not objects: + objects = (NewLine(),) + + render_hooks = self._render_hooks[:] + + with self: + renderables = self._collect_renderables( + objects, + sep, + end, + justify=justify, + emoji=emoji, + markup=markup, + highlight=highlight, + ) + if style is not None: + renderables = [Styled(renderable, style) for renderable in renderables] + + filename, line_no, locals = self._caller_frame_info(_stack_offset) + link_path = None if filename.startswith("<") else os.path.abspath(filename) + path = filename.rpartition(os.sep)[-1] + if log_locals: + locals_map = { + key: value + for key, value in locals.items() + if not key.startswith("__") + } + renderables.append(render_scope(locals_map, title="[i]locals")) + + renderables = [ + self._log_render( + self, + renderables, + log_time=self.get_datetime(), + path=path, + line_no=line_no, + link_path=link_path, + ) + ] + for hook in render_hooks: + renderables = hook.process_renderables(renderables) + new_segments: List[Segment] = [] + extend = new_segments.extend + render = self.render + render_options = self.options + for renderable in renderables: + extend(render(renderable, render_options)) + buffer_extend = self._buffer.extend + for line in Segment.split_and_crop_lines( + new_segments, self.width, pad=False + ): + buffer_extend(line) + + def _check_buffer(self) -> None: + """Check if the buffer may be rendered. Render it if it can (e.g. Console.quiet is False) + Rendering is supported on Windows, Unix and Jupyter environments. For + legacy Windows consoles, the win32 API is called directly. + This method will also record what it renders if recording is enabled via Console.record. + """ + if self.quiet: + del self._buffer[:] + return + with self._lock: + if self.record: + with self._record_buffer_lock: + self._record_buffer.extend(self._buffer[:]) + + if self._buffer_index == 0: + if self.is_jupyter: # pragma: no cover + from .jupyter import display + + display(self._buffer, self._render_buffer(self._buffer[:])) + del self._buffer[:] + else: + if WINDOWS: + use_legacy_windows_render = False + if self.legacy_windows: + fileno = get_fileno(self.file) + if fileno is not None: + use_legacy_windows_render = ( + fileno in _STD_STREAMS_OUTPUT + ) + + if use_legacy_windows_render: + from pip._vendor.rich._win32_console import LegacyWindowsTerm + from pip._vendor.rich._windows_renderer import legacy_windows_render + + buffer = self._buffer[:] + if self.no_color and self._color_system: + buffer = list(Segment.remove_color(buffer)) + + legacy_windows_render(buffer, LegacyWindowsTerm(self.file)) + else: + # Either a non-std stream on legacy Windows, or modern Windows. + text = self._render_buffer(self._buffer[:]) + # https://bugs.python.org/issue37871 + # https://github.com/python/cpython/issues/82052 + # We need to avoid writing more than 32Kb in a single write, due to the above bug + write = self.file.write + # Worse case scenario, every character is 4 bytes of utf-8 + MAX_WRITE = 32 * 1024 // 4 + try: + if len(text) <= MAX_WRITE: + write(text) + else: + batch: List[str] = [] + batch_append = batch.append + size = 0 + for line in text.splitlines(True): + if size + len(line) > MAX_WRITE and batch: + write("".join(batch)) + batch.clear() + size = 0 + batch_append(line) + size += len(line) + if batch: + write("".join(batch)) + batch.clear() + except UnicodeEncodeError as error: + error.reason = f"{error.reason}\n*** You may need to add PYTHONIOENCODING=utf-8 to your environment ***" + raise + else: + text = self._render_buffer(self._buffer[:]) + try: + self.file.write(text) + except UnicodeEncodeError as error: + error.reason = f"{error.reason}\n*** You may need to add PYTHONIOENCODING=utf-8 to your environment ***" + raise + + self.file.flush() + del self._buffer[:] + + def _render_buffer(self, buffer: Iterable[Segment]) -> str: + """Render buffered output, and clear buffer.""" + output: List[str] = [] + append = output.append + color_system = self._color_system + legacy_windows = self.legacy_windows + not_terminal = not self.is_terminal + if self.no_color and color_system: + buffer = Segment.remove_color(buffer) + for text, style, control in buffer: + if style: + append( + style.render( + text, + color_system=color_system, + legacy_windows=legacy_windows, + ) + ) + elif not (not_terminal and control): + append(text) + + rendered = "".join(output) + return rendered + + def input( + self, + prompt: TextType = "", + *, + markup: bool = True, + emoji: bool = True, + password: bool = False, + stream: Optional[TextIO] = None, + ) -> str: + """Displays a prompt and waits for input from the user. The prompt may contain color / style. + + It works in the same way as Python's builtin :func:`input` function and provides elaborate line editing and history features if Python's builtin :mod:`readline` module is previously loaded. + + Args: + prompt (Union[str, Text]): Text to render in the prompt. + markup (bool, optional): Enable console markup (requires a str prompt). Defaults to True. + emoji (bool, optional): Enable emoji (requires a str prompt). Defaults to True. + password: (bool, optional): Hide typed text. Defaults to False. + stream: (TextIO, optional): Optional file to read input from (rather than stdin). Defaults to None. + + Returns: + str: Text read from stdin. + """ + if prompt: + self.print(prompt, markup=markup, emoji=emoji, end="") + if password: + result = getpass("", stream=stream) + else: + if stream: + result = stream.readline() + else: + result = input() + return result + + def export_text(self, *, clear: bool = True, styles: bool = False) -> str: + """Generate text from console contents (requires record=True argument in constructor). + + Args: + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + styles (bool, optional): If ``True``, ansi escape codes will be included. ``False`` for plain text. + Defaults to ``False``. + + Returns: + str: String containing console contents. + + """ + assert ( + self.record + ), "To export console contents set record=True in the constructor or instance" + + with self._record_buffer_lock: + if styles: + text = "".join( + (style.render(text) if style else text) + for text, style, _ in self._record_buffer + ) + else: + text = "".join( + segment.text + for segment in self._record_buffer + if not segment.control + ) + if clear: + del self._record_buffer[:] + return text + + def save_text(self, path: str, *, clear: bool = True, styles: bool = False) -> None: + """Generate text from console and save to a given location (requires record=True argument in constructor). + + Args: + path (str): Path to write text files. + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + styles (bool, optional): If ``True``, ansi style codes will be included. ``False`` for plain text. + Defaults to ``False``. + + """ + text = self.export_text(clear=clear, styles=styles) + with open(path, "wt", encoding="utf-8") as write_file: + write_file.write(text) + + def export_html( + self, + *, + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: Optional[str] = None, + inline_styles: bool = False, + ) -> str: + """Generate HTML from console contents (requires record=True argument in constructor). + + Args: + theme (TerminalTheme, optional): TerminalTheme object containing console colors. + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + code_format (str, optional): Format string to render HTML. In addition to '{foreground}', + '{background}', and '{code}', should contain '{stylesheet}' if inline_styles is ``False``. + inline_styles (bool, optional): If ``True`` styles will be inlined in to spans, which makes files + larger but easier to cut and paste markup. If ``False``, styles will be embedded in a style tag. + Defaults to False. + + Returns: + str: String containing console contents as HTML. + """ + assert ( + self.record + ), "To export console contents set record=True in the constructor or instance" + fragments: List[str] = [] + append = fragments.append + _theme = theme or DEFAULT_TERMINAL_THEME + stylesheet = "" + + render_code_format = CONSOLE_HTML_FORMAT if code_format is None else code_format + + with self._record_buffer_lock: + if inline_styles: + for text, style, _ in Segment.filter_control( + Segment.simplify(self._record_buffer) + ): + text = escape(text) + if style: + rule = style.get_html_style(_theme) + if style.link: + text = f'{text}' + text = f'{text}' if rule else text + append(text) + else: + styles: Dict[str, int] = {} + for text, style, _ in Segment.filter_control( + Segment.simplify(self._record_buffer) + ): + text = escape(text) + if style: + rule = style.get_html_style(_theme) + style_number = styles.setdefault(rule, len(styles) + 1) + if style.link: + text = f'{text}' + else: + text = f'{text}' + append(text) + stylesheet_rules: List[str] = [] + stylesheet_append = stylesheet_rules.append + for style_rule, style_number in styles.items(): + if style_rule: + stylesheet_append(f".r{style_number} {{{style_rule}}}") + stylesheet = "\n".join(stylesheet_rules) + + rendered_code = render_code_format.format( + code="".join(fragments), + stylesheet=stylesheet, + foreground=_theme.foreground_color.hex, + background=_theme.background_color.hex, + ) + if clear: + del self._record_buffer[:] + return rendered_code + + def save_html( + self, + path: str, + *, + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: str = CONSOLE_HTML_FORMAT, + inline_styles: bool = False, + ) -> None: + """Generate HTML from console contents and write to a file (requires record=True argument in constructor). + + Args: + path (str): Path to write html file. + theme (TerminalTheme, optional): TerminalTheme object containing console colors. + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``. + code_format (str, optional): Format string to render HTML. In addition to '{foreground}', + '{background}', and '{code}', should contain '{stylesheet}' if inline_styles is ``False``. + inline_styles (bool, optional): If ``True`` styles will be inlined in to spans, which makes files + larger but easier to cut and paste markup. If ``False``, styles will be embedded in a style tag. + Defaults to False. + + """ + html = self.export_html( + theme=theme, + clear=clear, + code_format=code_format, + inline_styles=inline_styles, + ) + with open(path, "wt", encoding="utf-8") as write_file: + write_file.write(html) + + def export_svg( + self, + *, + title: str = "Rich", + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: str = CONSOLE_SVG_FORMAT, + font_aspect_ratio: float = 0.61, + unique_id: Optional[str] = None, + ) -> str: + """ + Generate an SVG from the console contents (requires record=True in Console constructor). + + Args: + title (str, optional): The title of the tab in the output image + theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True`` + code_format (str, optional): Format string used to generate the SVG. Rich will inject a number of variables + into the string in order to form the final SVG output. The default template used and the variables + injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable. + font_aspect_ratio (float, optional): The width to height ratio of the font used in the ``code_format`` + string. Defaults to 0.61, which is the width to height ratio of Fira Code (the default font). + If you aren't specifying a different font inside ``code_format``, you probably don't need this. + unique_id (str, optional): unique id that is used as the prefix for various elements (CSS styles, node + ids). If not set, this defaults to a computed value based on the recorded content. + """ + + from pip._vendor.rich.cells import cell_len + + style_cache: Dict[Style, str] = {} + + def get_svg_style(style: Style) -> str: + """Convert a Style to CSS rules for SVG.""" + if style in style_cache: + return style_cache[style] + css_rules = [] + color = ( + _theme.foreground_color + if (style.color is None or style.color.is_default) + else style.color.get_truecolor(_theme) + ) + bgcolor = ( + _theme.background_color + if (style.bgcolor is None or style.bgcolor.is_default) + else style.bgcolor.get_truecolor(_theme) + ) + if style.reverse: + color, bgcolor = bgcolor, color + if style.dim: + color = blend_rgb(color, bgcolor, 0.4) + css_rules.append(f"fill: {color.hex}") + if style.bold: + css_rules.append("font-weight: bold") + if style.italic: + css_rules.append("font-style: italic;") + if style.underline: + css_rules.append("text-decoration: underline;") + if style.strike: + css_rules.append("text-decoration: line-through;") + + css = ";".join(css_rules) + style_cache[style] = css + return css + + _theme = theme or SVG_EXPORT_THEME + + width = self.width + char_height = 20 + char_width = char_height * font_aspect_ratio + line_height = char_height * 1.22 + + margin_top = 1 + margin_right = 1 + margin_bottom = 1 + margin_left = 1 + + padding_top = 40 + padding_right = 8 + padding_bottom = 8 + padding_left = 8 + + padding_width = padding_left + padding_right + padding_height = padding_top + padding_bottom + margin_width = margin_left + margin_right + margin_height = margin_top + margin_bottom + + text_backgrounds: List[str] = [] + text_group: List[str] = [] + classes: Dict[str, int] = {} + style_no = 1 + + def escape_text(text: str) -> str: + """HTML escape text and replace spaces with nbsp.""" + return escape(text).replace(" ", " ") + + def make_tag( + name: str, content: Optional[str] = None, **attribs: object + ) -> str: + """Make a tag from name, content, and attributes.""" + + def stringify(value: object) -> str: + if isinstance(value, (float)): + return format(value, "g") + return str(value) + + tag_attribs = " ".join( + f'{k.lstrip("_").replace("_", "-")}="{stringify(v)}"' + for k, v in attribs.items() + ) + return ( + f"<{name} {tag_attribs}>{content}" + if content + else f"<{name} {tag_attribs}/>" + ) + + with self._record_buffer_lock: + segments = list(Segment.filter_control(self._record_buffer)) + if clear: + self._record_buffer.clear() + + if unique_id is None: + unique_id = "terminal-" + str( + zlib.adler32( + ("".join(repr(segment) for segment in segments)).encode( + "utf-8", + "ignore", + ) + + title.encode("utf-8", "ignore") + ) + ) + y = 0 + for y, line in enumerate(Segment.split_and_crop_lines(segments, length=width)): + x = 0 + for text, style, _control in line: + style = style or Style() + rules = get_svg_style(style) + if rules not in classes: + classes[rules] = style_no + style_no += 1 + class_name = f"r{classes[rules]}" + + if style.reverse: + has_background = True + background = ( + _theme.foreground_color.hex + if style.color is None + else style.color.get_truecolor(_theme).hex + ) + else: + bgcolor = style.bgcolor + has_background = bgcolor is not None and not bgcolor.is_default + background = ( + _theme.background_color.hex + if style.bgcolor is None + else style.bgcolor.get_truecolor(_theme).hex + ) + + text_length = cell_len(text) + if has_background: + text_backgrounds.append( + make_tag( + "rect", + fill=background, + x=x * char_width, + y=y * line_height + 1.5, + width=char_width * text_length, + height=line_height + 0.25, + shape_rendering="crispEdges", + ) + ) + + if text != " " * len(text): + text_group.append( + make_tag( + "text", + escape_text(text), + _class=f"{unique_id}-{class_name}", + x=x * char_width, + y=y * line_height + char_height, + textLength=char_width * len(text), + clip_path=f"url(#{unique_id}-line-{y})", + ) + ) + x += cell_len(text) + + line_offsets = [line_no * line_height + 1.5 for line_no in range(y)] + lines = "\n".join( + f""" + {make_tag("rect", x=0, y=offset, width=char_width * width, height=line_height + 0.25)} + """ + for line_no, offset in enumerate(line_offsets) + ) + + styles = "\n".join( + f".{unique_id}-r{rule_no} {{ {css} }}" for css, rule_no in classes.items() + ) + backgrounds = "".join(text_backgrounds) + matrix = "".join(text_group) + + terminal_width = ceil(width * char_width + padding_width) + terminal_height = (y + 1) * line_height + padding_height + chrome = make_tag( + "rect", + fill=_theme.background_color.hex, + stroke="rgba(255,255,255,0.35)", + stroke_width="1", + x=margin_left, + y=margin_top, + width=terminal_width, + height=terminal_height, + rx=8, + ) + + title_color = _theme.foreground_color.hex + if title: + chrome += make_tag( + "text", + escape_text(title), + _class=f"{unique_id}-title", + fill=title_color, + text_anchor="middle", + x=terminal_width // 2, + y=margin_top + char_height + 6, + ) + chrome += f""" + + + + + + """ + + svg = code_format.format( + unique_id=unique_id, + char_width=char_width, + char_height=char_height, + line_height=line_height, + terminal_width=char_width * width - 1, + terminal_height=(y + 1) * line_height - 1, + width=terminal_width + margin_width, + height=terminal_height + margin_height, + terminal_x=margin_left + padding_left, + terminal_y=margin_top + padding_top, + styles=styles, + chrome=chrome, + backgrounds=backgrounds, + matrix=matrix, + lines=lines, + ) + return svg + + def save_svg( + self, + path: str, + *, + title: str = "Rich", + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: str = CONSOLE_SVG_FORMAT, + font_aspect_ratio: float = 0.61, + unique_id: Optional[str] = None, + ) -> None: + """Generate an SVG file from the console contents (requires record=True in Console constructor). + + Args: + path (str): The path to write the SVG to. + title (str, optional): The title of the tab in the output image + theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal + clear (bool, optional): Clear record buffer after exporting. Defaults to ``True`` + code_format (str, optional): Format string used to generate the SVG. Rich will inject a number of variables + into the string in order to form the final SVG output. The default template used and the variables + injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable. + font_aspect_ratio (float, optional): The width to height ratio of the font used in the ``code_format`` + string. Defaults to 0.61, which is the width to height ratio of Fira Code (the default font). + If you aren't specifying a different font inside ``code_format``, you probably don't need this. + unique_id (str, optional): unique id that is used as the prefix for various elements (CSS styles, node + ids). If not set, this defaults to a computed value based on the recorded content. + """ + svg = self.export_svg( + title=title, + theme=theme, + clear=clear, + code_format=code_format, + font_aspect_ratio=font_aspect_ratio, + unique_id=unique_id, + ) + with open(path, "wt", encoding="utf-8") as write_file: + write_file.write(svg) + + +def _svg_hash(svg_main_code: str) -> str: + """Returns a unique hash for the given SVG main code. + + Args: + svg_main_code (str): The content we're going to inject in the SVG envelope. + + Returns: + str: a hash of the given content + """ + return str(zlib.adler32(svg_main_code.encode())) + + +if __name__ == "__main__": # pragma: no cover + console = Console(record=True) + + console.log( + "JSONRPC [i]request[/i]", + 5, + 1.3, + True, + False, + None, + { + "jsonrpc": "2.0", + "method": "subtract", + "params": {"minuend": 42, "subtrahend": 23}, + "id": 3, + }, + ) + + console.log("Hello, World!", "{'a': 1}", repr(console)) + + console.print( + { + "name": None, + "empty": [], + "quiz": { + "sport": { + "answered": True, + "q1": { + "question": "Which one is correct team name in NBA?", + "options": [ + "New York Bulls", + "Los Angeles Kings", + "Golden State Warriors", + "Huston Rocket", + ], + "answer": "Huston Rocket", + }, + }, + "maths": { + "answered": False, + "q1": { + "question": "5 + 7 = ?", + "options": [10, 11, 12, 13], + "answer": 12, + }, + "q2": { + "question": "12 - 8 = ?", + "options": [1, 2, 3, 4], + "answer": 4, + }, + }, + }, + } + ) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/constrain.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/constrain.py new file mode 100644 index 0000000..65fdf56 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/constrain.py @@ -0,0 +1,37 @@ +from typing import Optional, TYPE_CHECKING + +from .jupyter import JupyterMixin +from .measure import Measurement + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderableType, RenderResult + + +class Constrain(JupyterMixin): + """Constrain the width of a renderable to a given number of characters. + + Args: + renderable (RenderableType): A renderable object. + width (int, optional): The maximum width (in characters) to render. Defaults to 80. + """ + + def __init__(self, renderable: "RenderableType", width: Optional[int] = 80) -> None: + self.renderable = renderable + self.width = width + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + if self.width is None: + yield self.renderable + else: + child_options = options.update_width(min(self.width, options.max_width)) + yield from console.render(self.renderable, child_options) + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + if self.width is not None: + options = options.update_width(self.width) + measurement = Measurement.get(console, options, self.renderable) + return measurement diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/containers.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/containers.py new file mode 100644 index 0000000..e29cf36 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/containers.py @@ -0,0 +1,167 @@ +from itertools import zip_longest +from typing import ( + Iterator, + Iterable, + List, + Optional, + Union, + overload, + TypeVar, + TYPE_CHECKING, +) + +if TYPE_CHECKING: + from .console import ( + Console, + ConsoleOptions, + JustifyMethod, + OverflowMethod, + RenderResult, + RenderableType, + ) + from .text import Text + +from .cells import cell_len +from .measure import Measurement + +T = TypeVar("T") + + +class Renderables: + """A list subclass which renders its contents to the console.""" + + def __init__( + self, renderables: Optional[Iterable["RenderableType"]] = None + ) -> None: + self._renderables: List["RenderableType"] = ( + list(renderables) if renderables is not None else [] + ) + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + """Console render method to insert line-breaks.""" + yield from self._renderables + + def __rich_measure__( + self, console: "Console", options: "ConsoleOptions" + ) -> "Measurement": + dimensions = [ + Measurement.get(console, options, renderable) + for renderable in self._renderables + ] + if not dimensions: + return Measurement(1, 1) + _min = max(dimension.minimum for dimension in dimensions) + _max = max(dimension.maximum for dimension in dimensions) + return Measurement(_min, _max) + + def append(self, renderable: "RenderableType") -> None: + self._renderables.append(renderable) + + def __iter__(self) -> Iterable["RenderableType"]: + return iter(self._renderables) + + +class Lines: + """A list subclass which can render to the console.""" + + def __init__(self, lines: Iterable["Text"] = ()) -> None: + self._lines: List["Text"] = list(lines) + + def __repr__(self) -> str: + return f"Lines({self._lines!r})" + + def __iter__(self) -> Iterator["Text"]: + return iter(self._lines) + + @overload + def __getitem__(self, index: int) -> "Text": + ... + + @overload + def __getitem__(self, index: slice) -> List["Text"]: + ... + + def __getitem__(self, index: Union[slice, int]) -> Union["Text", List["Text"]]: + return self._lines[index] + + def __setitem__(self, index: int, value: "Text") -> "Lines": + self._lines[index] = value + return self + + def __len__(self) -> int: + return self._lines.__len__() + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + """Console render method to insert line-breaks.""" + yield from self._lines + + def append(self, line: "Text") -> None: + self._lines.append(line) + + def extend(self, lines: Iterable["Text"]) -> None: + self._lines.extend(lines) + + def pop(self, index: int = -1) -> "Text": + return self._lines.pop(index) + + def justify( + self, + console: "Console", + width: int, + justify: "JustifyMethod" = "left", + overflow: "OverflowMethod" = "fold", + ) -> None: + """Justify and overflow text to a given width. + + Args: + console (Console): Console instance. + width (int): Number of characters per line. + justify (str, optional): Default justify method for text: "left", "center", "full" or "right". Defaults to "left". + overflow (str, optional): Default overflow for text: "crop", "fold", or "ellipsis". Defaults to "fold". + + """ + from .text import Text + + if justify == "left": + for line in self._lines: + line.truncate(width, overflow=overflow, pad=True) + elif justify == "center": + for line in self._lines: + line.rstrip() + line.truncate(width, overflow=overflow) + line.pad_left((width - cell_len(line.plain)) // 2) + line.pad_right(width - cell_len(line.plain)) + elif justify == "right": + for line in self._lines: + line.rstrip() + line.truncate(width, overflow=overflow) + line.pad_left(width - cell_len(line.plain)) + elif justify == "full": + for line_index, line in enumerate(self._lines): + if line_index == len(self._lines) - 1: + break + words = line.split(" ") + words_size = sum(cell_len(word.plain) for word in words) + num_spaces = len(words) - 1 + spaces = [1 for _ in range(num_spaces)] + index = 0 + if spaces: + while words_size + num_spaces < width: + spaces[len(spaces) - index - 1] += 1 + num_spaces += 1 + index = (index + 1) % len(spaces) + tokens: List[Text] = [] + for index, (word, next_word) in enumerate( + zip_longest(words, words[1:]) + ): + tokens.append(word) + if index < len(spaces): + style = word.get_style_at_offset(console, -1) + next_style = next_word.get_style_at_offset(console, 0) + space_style = style if style == next_style else line.style + tokens.append(Text(" " * spaces[index], style=space_style)) + self[line_index] = Text("").join(tokens) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/control.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/control.py new file mode 100644 index 0000000..88fcb92 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/control.py @@ -0,0 +1,225 @@ +import sys +import time +from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Union + +if sys.version_info >= (3, 8): + from typing import Final +else: + from pip._vendor.typing_extensions import Final # pragma: no cover + +from .segment import ControlCode, ControlType, Segment + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderResult + +STRIP_CONTROL_CODES: Final = [ + 7, # Bell + 8, # Backspace + 11, # Vertical tab + 12, # Form feed + 13, # Carriage return +] +_CONTROL_STRIP_TRANSLATE: Final = { + _codepoint: None for _codepoint in STRIP_CONTROL_CODES +} + +CONTROL_ESCAPE: Final = { + 7: "\\a", + 8: "\\b", + 11: "\\v", + 12: "\\f", + 13: "\\r", +} + +CONTROL_CODES_FORMAT: Dict[int, Callable[..., str]] = { + ControlType.BELL: lambda: "\x07", + ControlType.CARRIAGE_RETURN: lambda: "\r", + ControlType.HOME: lambda: "\x1b[H", + ControlType.CLEAR: lambda: "\x1b[2J", + ControlType.ENABLE_ALT_SCREEN: lambda: "\x1b[?1049h", + ControlType.DISABLE_ALT_SCREEN: lambda: "\x1b[?1049l", + ControlType.SHOW_CURSOR: lambda: "\x1b[?25h", + ControlType.HIDE_CURSOR: lambda: "\x1b[?25l", + ControlType.CURSOR_UP: lambda param: f"\x1b[{param}A", + ControlType.CURSOR_DOWN: lambda param: f"\x1b[{param}B", + ControlType.CURSOR_FORWARD: lambda param: f"\x1b[{param}C", + ControlType.CURSOR_BACKWARD: lambda param: f"\x1b[{param}D", + ControlType.CURSOR_MOVE_TO_COLUMN: lambda param: f"\x1b[{param+1}G", + ControlType.ERASE_IN_LINE: lambda param: f"\x1b[{param}K", + ControlType.CURSOR_MOVE_TO: lambda x, y: f"\x1b[{y+1};{x+1}H", + ControlType.SET_WINDOW_TITLE: lambda title: f"\x1b]0;{title}\x07", +} + + +class Control: + """A renderable that inserts a control code (non printable but may move cursor). + + Args: + *codes (str): Positional arguments are either a :class:`~rich.segment.ControlType` enum or a + tuple of ControlType and an integer parameter + """ + + __slots__ = ["segment"] + + def __init__(self, *codes: Union[ControlType, ControlCode]) -> None: + control_codes: List[ControlCode] = [ + (code,) if isinstance(code, ControlType) else code for code in codes + ] + _format_map = CONTROL_CODES_FORMAT + rendered_codes = "".join( + _format_map[code](*parameters) for code, *parameters in control_codes + ) + self.segment = Segment(rendered_codes, None, control_codes) + + @classmethod + def bell(cls) -> "Control": + """Ring the 'bell'.""" + return cls(ControlType.BELL) + + @classmethod + def home(cls) -> "Control": + """Move cursor to 'home' position.""" + return cls(ControlType.HOME) + + @classmethod + def move(cls, x: int = 0, y: int = 0) -> "Control": + """Move cursor relative to current position. + + Args: + x (int): X offset. + y (int): Y offset. + + Returns: + ~Control: Control object. + + """ + + def get_codes() -> Iterable[ControlCode]: + control = ControlType + if x: + yield ( + control.CURSOR_FORWARD if x > 0 else control.CURSOR_BACKWARD, + abs(x), + ) + if y: + yield ( + control.CURSOR_DOWN if y > 0 else control.CURSOR_UP, + abs(y), + ) + + control = cls(*get_codes()) + return control + + @classmethod + def move_to_column(cls, x: int, y: int = 0) -> "Control": + """Move to the given column, optionally add offset to row. + + Returns: + x (int): absolute x (column) + y (int): optional y offset (row) + + Returns: + ~Control: Control object. + """ + + return ( + cls( + (ControlType.CURSOR_MOVE_TO_COLUMN, x), + ( + ControlType.CURSOR_DOWN if y > 0 else ControlType.CURSOR_UP, + abs(y), + ), + ) + if y + else cls((ControlType.CURSOR_MOVE_TO_COLUMN, x)) + ) + + @classmethod + def move_to(cls, x: int, y: int) -> "Control": + """Move cursor to absolute position. + + Args: + x (int): x offset (column) + y (int): y offset (row) + + Returns: + ~Control: Control object. + """ + return cls((ControlType.CURSOR_MOVE_TO, x, y)) + + @classmethod + def clear(cls) -> "Control": + """Clear the screen.""" + return cls(ControlType.CLEAR) + + @classmethod + def show_cursor(cls, show: bool) -> "Control": + """Show or hide the cursor.""" + return cls(ControlType.SHOW_CURSOR if show else ControlType.HIDE_CURSOR) + + @classmethod + def alt_screen(cls, enable: bool) -> "Control": + """Enable or disable alt screen.""" + if enable: + return cls(ControlType.ENABLE_ALT_SCREEN, ControlType.HOME) + else: + return cls(ControlType.DISABLE_ALT_SCREEN) + + @classmethod + def title(cls, title: str) -> "Control": + """Set the terminal window title + + Args: + title (str): The new terminal window title + """ + return cls((ControlType.SET_WINDOW_TITLE, title)) + + def __str__(self) -> str: + return self.segment.text + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + if self.segment.text: + yield self.segment + + +def strip_control_codes( + text: str, _translate_table: Dict[int, None] = _CONTROL_STRIP_TRANSLATE +) -> str: + """Remove control codes from text. + + Args: + text (str): A string possibly contain control codes. + + Returns: + str: String with control codes removed. + """ + return text.translate(_translate_table) + + +def escape_control_codes( + text: str, + _translate_table: Dict[int, str] = CONTROL_ESCAPE, +) -> str: + """Replace control codes with their "escaped" equivalent in the given text. + (e.g. "\b" becomes "\\b") + + Args: + text (str): A string possibly containing control codes. + + Returns: + str: String with control codes replaced with their escaped version. + """ + return text.translate(_translate_table) + + +if __name__ == "__main__": # pragma: no cover + from pip._vendor.rich.console import Console + + console = Console() + console.print("Look at the title of your terminal window ^") + # console.print(Control((ControlType.SET_WINDOW_TITLE, "Hello, world!"))) + for i in range(10): + console.set_window_title("🚀 Loading" + "." * i) + time.sleep(0.5) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/default_styles.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/default_styles.py new file mode 100644 index 0000000..dca3719 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/default_styles.py @@ -0,0 +1,190 @@ +from typing import Dict + +from .style import Style + +DEFAULT_STYLES: Dict[str, Style] = { + "none": Style.null(), + "reset": Style( + color="default", + bgcolor="default", + dim=False, + bold=False, + italic=False, + underline=False, + blink=False, + blink2=False, + reverse=False, + conceal=False, + strike=False, + ), + "dim": Style(dim=True), + "bright": Style(dim=False), + "bold": Style(bold=True), + "strong": Style(bold=True), + "code": Style(reverse=True, bold=True), + "italic": Style(italic=True), + "emphasize": Style(italic=True), + "underline": Style(underline=True), + "blink": Style(blink=True), + "blink2": Style(blink2=True), + "reverse": Style(reverse=True), + "strike": Style(strike=True), + "black": Style(color="black"), + "red": Style(color="red"), + "green": Style(color="green"), + "yellow": Style(color="yellow"), + "magenta": Style(color="magenta"), + "cyan": Style(color="cyan"), + "white": Style(color="white"), + "inspect.attr": Style(color="yellow", italic=True), + "inspect.attr.dunder": Style(color="yellow", italic=True, dim=True), + "inspect.callable": Style(bold=True, color="red"), + "inspect.async_def": Style(italic=True, color="bright_cyan"), + "inspect.def": Style(italic=True, color="bright_cyan"), + "inspect.class": Style(italic=True, color="bright_cyan"), + "inspect.error": Style(bold=True, color="red"), + "inspect.equals": Style(), + "inspect.help": Style(color="cyan"), + "inspect.doc": Style(dim=True), + "inspect.value.border": Style(color="green"), + "live.ellipsis": Style(bold=True, color="red"), + "layout.tree.row": Style(dim=False, color="red"), + "layout.tree.column": Style(dim=False, color="blue"), + "logging.keyword": Style(bold=True, color="yellow"), + "logging.level.notset": Style(dim=True), + "logging.level.debug": Style(color="green"), + "logging.level.info": Style(color="blue"), + "logging.level.warning": Style(color="red"), + "logging.level.error": Style(color="red", bold=True), + "logging.level.critical": Style(color="red", bold=True, reverse=True), + "log.level": Style.null(), + "log.time": Style(color="cyan", dim=True), + "log.message": Style.null(), + "log.path": Style(dim=True), + "repr.ellipsis": Style(color="yellow"), + "repr.indent": Style(color="green", dim=True), + "repr.error": Style(color="red", bold=True), + "repr.str": Style(color="green", italic=False, bold=False), + "repr.brace": Style(bold=True), + "repr.comma": Style(bold=True), + "repr.ipv4": Style(bold=True, color="bright_green"), + "repr.ipv6": Style(bold=True, color="bright_green"), + "repr.eui48": Style(bold=True, color="bright_green"), + "repr.eui64": Style(bold=True, color="bright_green"), + "repr.tag_start": Style(bold=True), + "repr.tag_name": Style(color="bright_magenta", bold=True), + "repr.tag_contents": Style(color="default"), + "repr.tag_end": Style(bold=True), + "repr.attrib_name": Style(color="yellow", italic=False), + "repr.attrib_equal": Style(bold=True), + "repr.attrib_value": Style(color="magenta", italic=False), + "repr.number": Style(color="cyan", bold=True, italic=False), + "repr.number_complex": Style(color="cyan", bold=True, italic=False), # same + "repr.bool_true": Style(color="bright_green", italic=True), + "repr.bool_false": Style(color="bright_red", italic=True), + "repr.none": Style(color="magenta", italic=True), + "repr.url": Style(underline=True, color="bright_blue", italic=False, bold=False), + "repr.uuid": Style(color="bright_yellow", bold=False), + "repr.call": Style(color="magenta", bold=True), + "repr.path": Style(color="magenta"), + "repr.filename": Style(color="bright_magenta"), + "rule.line": Style(color="bright_green"), + "rule.text": Style.null(), + "json.brace": Style(bold=True), + "json.bool_true": Style(color="bright_green", italic=True), + "json.bool_false": Style(color="bright_red", italic=True), + "json.null": Style(color="magenta", italic=True), + "json.number": Style(color="cyan", bold=True, italic=False), + "json.str": Style(color="green", italic=False, bold=False), + "json.key": Style(color="blue", bold=True), + "prompt": Style.null(), + "prompt.choices": Style(color="magenta", bold=True), + "prompt.default": Style(color="cyan", bold=True), + "prompt.invalid": Style(color="red"), + "prompt.invalid.choice": Style(color="red"), + "pretty": Style.null(), + "scope.border": Style(color="blue"), + "scope.key": Style(color="yellow", italic=True), + "scope.key.special": Style(color="yellow", italic=True, dim=True), + "scope.equals": Style(color="red"), + "table.header": Style(bold=True), + "table.footer": Style(bold=True), + "table.cell": Style.null(), + "table.title": Style(italic=True), + "table.caption": Style(italic=True, dim=True), + "traceback.error": Style(color="red", italic=True), + "traceback.border.syntax_error": Style(color="bright_red"), + "traceback.border": Style(color="red"), + "traceback.text": Style.null(), + "traceback.title": Style(color="red", bold=True), + "traceback.exc_type": Style(color="bright_red", bold=True), + "traceback.exc_value": Style.null(), + "traceback.offset": Style(color="bright_red", bold=True), + "bar.back": Style(color="grey23"), + "bar.complete": Style(color="rgb(249,38,114)"), + "bar.finished": Style(color="rgb(114,156,31)"), + "bar.pulse": Style(color="rgb(249,38,114)"), + "progress.description": Style.null(), + "progress.filesize": Style(color="green"), + "progress.filesize.total": Style(color="green"), + "progress.download": Style(color="green"), + "progress.elapsed": Style(color="yellow"), + "progress.percentage": Style(color="magenta"), + "progress.remaining": Style(color="cyan"), + "progress.data.speed": Style(color="red"), + "progress.spinner": Style(color="green"), + "status.spinner": Style(color="green"), + "tree": Style(), + "tree.line": Style(), + "markdown.paragraph": Style(), + "markdown.text": Style(), + "markdown.em": Style(italic=True), + "markdown.emph": Style(italic=True), # For commonmark backwards compatibility + "markdown.strong": Style(bold=True), + "markdown.code": Style(bold=True, color="cyan", bgcolor="black"), + "markdown.code_block": Style(color="cyan", bgcolor="black"), + "markdown.block_quote": Style(color="magenta"), + "markdown.list": Style(color="cyan"), + "markdown.item": Style(), + "markdown.item.bullet": Style(color="yellow", bold=True), + "markdown.item.number": Style(color="yellow", bold=True), + "markdown.hr": Style(color="yellow"), + "markdown.h1.border": Style(), + "markdown.h1": Style(bold=True), + "markdown.h2": Style(bold=True, underline=True), + "markdown.h3": Style(bold=True), + "markdown.h4": Style(bold=True, dim=True), + "markdown.h5": Style(underline=True), + "markdown.h6": Style(italic=True), + "markdown.h7": Style(italic=True, dim=True), + "markdown.link": Style(color="bright_blue"), + "markdown.link_url": Style(color="blue", underline=True), + "markdown.s": Style(strike=True), + "iso8601.date": Style(color="blue"), + "iso8601.time": Style(color="magenta"), + "iso8601.timezone": Style(color="yellow"), +} + + +if __name__ == "__main__": # pragma: no cover + import argparse + import io + + from pip._vendor.rich.console import Console + from pip._vendor.rich.table import Table + from pip._vendor.rich.text import Text + + parser = argparse.ArgumentParser() + parser.add_argument("--html", action="store_true", help="Export as HTML table") + args = parser.parse_args() + html: bool = args.html + console = Console(record=True, width=70, file=io.StringIO()) if html else Console() + + table = Table("Name", "Styling") + + for style_name, style in DEFAULT_STYLES.items(): + table.add_row(Text(style_name, style=style), str(style)) + + console.print(table) + if html: + print(console.export_html(inline_styles=True)) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/diagnose.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/diagnose.py new file mode 100644 index 0000000..ad36183 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/diagnose.py @@ -0,0 +1,37 @@ +import os +import platform + +from pip._vendor.rich import inspect +from pip._vendor.rich.console import Console, get_windows_console_features +from pip._vendor.rich.panel import Panel +from pip._vendor.rich.pretty import Pretty + + +def report() -> None: # pragma: no cover + """Print a report to the terminal with debugging information""" + console = Console() + inspect(console) + features = get_windows_console_features() + inspect(features) + + env_names = ( + "TERM", + "COLORTERM", + "CLICOLOR", + "NO_COLOR", + "TERM_PROGRAM", + "COLUMNS", + "LINES", + "JUPYTER_COLUMNS", + "JUPYTER_LINES", + "JPY_PARENT_PID", + "VSCODE_VERBOSE_LOGGING", + ) + env = {name: os.getenv(name) for name in env_names} + console.print(Panel.fit((Pretty(env)), title="[b]Environment Variables")) + + console.print(f'platform="{platform.system()}"') + + +if __name__ == "__main__": # pragma: no cover + report() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/emoji.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/emoji.py new file mode 100644 index 0000000..791f046 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/emoji.py @@ -0,0 +1,96 @@ +import sys +from typing import TYPE_CHECKING, Optional, Union + +from .jupyter import JupyterMixin +from .segment import Segment +from .style import Style +from ._emoji_codes import EMOJI +from ._emoji_replace import _emoji_replace + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from pip._vendor.typing_extensions import Literal # pragma: no cover + + +if TYPE_CHECKING: + from .console import Console, ConsoleOptions, RenderResult + + +EmojiVariant = Literal["emoji", "text"] + + +class NoEmoji(Exception): + """No emoji by that name.""" + + +class Emoji(JupyterMixin): + __slots__ = ["name", "style", "_char", "variant"] + + VARIANTS = {"text": "\uFE0E", "emoji": "\uFE0F"} + + def __init__( + self, + name: str, + style: Union[str, Style] = "none", + variant: Optional[EmojiVariant] = None, + ) -> None: + """A single emoji character. + + Args: + name (str): Name of emoji. + style (Union[str, Style], optional): Optional style. Defaults to None. + + Raises: + NoEmoji: If the emoji doesn't exist. + """ + self.name = name + self.style = style + self.variant = variant + try: + self._char = EMOJI[name] + except KeyError: + raise NoEmoji(f"No emoji called {name!r}") + if variant is not None: + self._char += self.VARIANTS.get(variant, "") + + @classmethod + def replace(cls, text: str) -> str: + """Replace emoji markup with corresponding unicode characters. + + Args: + text (str): A string with emojis codes, e.g. "Hello :smiley:!" + + Returns: + str: A string with emoji codes replaces with actual emoji. + """ + return _emoji_replace(text) + + def __repr__(self) -> str: + return f"" + + def __str__(self) -> str: + return self._char + + def __rich_console__( + self, console: "Console", options: "ConsoleOptions" + ) -> "RenderResult": + yield Segment(self._char, console.get_style(self.style)) + + +if __name__ == "__main__": # pragma: no cover + import sys + + from pip._vendor.rich.columns import Columns + from pip._vendor.rich.console import Console + + console = Console(record=True) + + columns = Columns( + (f":{name}: {name}" for name in sorted(EMOJI.keys()) if "\u200D" not in name), + column_first=True, + ) + + console.print(columns) + if len(sys.argv) > 1: + console.save_html(sys.argv[1]) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/errors.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/errors.py new file mode 100644 index 0000000..0bcbe53 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/errors.py @@ -0,0 +1,34 @@ +class ConsoleError(Exception): + """An error in console operation.""" + + +class StyleError(Exception): + """An error in styles.""" + + +class StyleSyntaxError(ConsoleError): + """Style was badly formatted.""" + + +class MissingStyle(StyleError): + """No such style.""" + + +class StyleStackError(ConsoleError): + """Style stack is invalid.""" + + +class NotRenderableError(ConsoleError): + """Object is not renderable.""" + + +class MarkupError(ConsoleError): + """Markup was badly formatted.""" + + +class LiveError(ConsoleError): + """Error related to Live display.""" + + +class NoAltScreen(ConsoleError): + """Alt screen mode was required.""" diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/file_proxy.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/file_proxy.py new file mode 100644 index 0000000..4b0b0da --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/file_proxy.py @@ -0,0 +1,57 @@ +import io +from typing import IO, TYPE_CHECKING, Any, List + +from .ansi import AnsiDecoder +from .text import Text + +if TYPE_CHECKING: + from .console import Console + + +class FileProxy(io.TextIOBase): + """Wraps a file (e.g. sys.stdout) and redirects writes to a console.""" + + def __init__(self, console: "Console", file: IO[str]) -> None: + self.__console = console + self.__file = file + self.__buffer: List[str] = [] + self.__ansi_decoder = AnsiDecoder() + + @property + def rich_proxied_file(self) -> IO[str]: + """Get proxied file.""" + return self.__file + + def __getattr__(self, name: str) -> Any: + return getattr(self.__file, name) + + def write(self, text: str) -> int: + if not isinstance(text, str): + raise TypeError(f"write() argument must be str, not {type(text).__name__}") + buffer = self.__buffer + lines: List[str] = [] + while text: + line, new_line, text = text.partition("\n") + if new_line: + lines.append("".join(buffer) + line) + buffer.clear() + else: + buffer.append(line) + break + if lines: + console = self.__console + with console: + output = Text("\n").join( + self.__ansi_decoder.decode_line(line) for line in lines + ) + console.print(output) + return len(text) + + def flush(self) -> None: + output = "".join(self.__buffer) + if output: + self.__console.print(output) + del self.__buffer[:] + + def fileno(self) -> int: + return self.__file.fileno() diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/filesize.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/filesize.py new file mode 100644 index 0000000..99f118e --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/filesize.py @@ -0,0 +1,89 @@ +# coding: utf-8 +"""Functions for reporting filesizes. Borrowed from https://github.com/PyFilesystem/pyfilesystem2 + +The functions declared in this module should cover the different +use cases needed to generate a string representation of a file size +using several different units. Since there are many standards regarding +file size units, three different functions have been implemented. + +See Also: + * `Wikipedia: Binary prefix `_ + +""" + +__all__ = ["decimal"] + +from typing import Iterable, List, Optional, Tuple + + +def _to_str( + size: int, + suffixes: Iterable[str], + base: int, + *, + precision: Optional[int] = 1, + separator: Optional[str] = " ", +) -> str: + if size == 1: + return "1 byte" + elif size < base: + return "{:,} bytes".format(size) + + for i, suffix in enumerate(suffixes, 2): # noqa: B007 + unit = base**i + if size < unit: + break + return "{:,.{precision}f}{separator}{}".format( + (base * size / unit), + suffix, + precision=precision, + separator=separator, + ) + + +def pick_unit_and_suffix(size: int, suffixes: List[str], base: int) -> Tuple[int, str]: + """Pick a suffix and base for the given size.""" + for i, suffix in enumerate(suffixes): + unit = base**i + if size < unit * base: + break + return unit, suffix + + +def decimal( + size: int, + *, + precision: Optional[int] = 1, + separator: Optional[str] = " ", +) -> str: + """Convert a filesize in to a string (powers of 1000, SI prefixes). + + In this convention, ``1000 B = 1 kB``. + + This is typically the format used to advertise the storage + capacity of USB flash drives and the like (*256 MB* meaning + actually a storage capacity of more than *256 000 000 B*), + or used by **Mac OS X** since v10.6 to report file sizes. + + Arguments: + int (size): A file size. + int (precision): The number of decimal places to include (default = 1). + str (separator): The string to separate the value from the units (default = " "). + + Returns: + `str`: A string containing a abbreviated file size and units. + + Example: + >>> filesize.decimal(30000) + '30.0 kB' + >>> filesize.decimal(30000, precision=2, separator="") + '30.00kB' + + """ + return _to_str( + size, + ("kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"), + 1000, + precision=precision, + separator=separator, + ) diff --git a/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/highlighter.py b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/highlighter.py new file mode 100644 index 0000000..c264679 --- /dev/null +++ b/elitebot/lib/python3.11/site-packages/pip/_vendor/rich/highlighter.py @@ -0,0 +1,232 @@ +import re +from abc import ABC, abstractmethod +from typing import List, Union + +from .text import Span, Text + + +def _combine_regex(*regexes: str) -> str: + """Combine a number of regexes in to a single regex. + + Returns: + str: New regex with all regexes ORed together. + """ + return "|".join(regexes) + + +class Highlighter(ABC): + """Abstract base class for highlighters.""" + + def __call__(self, text: Union[str, Text]) -> Text: + """Highlight a str or Text instance. + + Args: + text (Union[str, ~Text]): Text to highlight. + + Raises: + TypeError: If not called with text or str. + + Returns: + Text: A test instance with highlighting applied. + """ + if isinstance(text, str): + highlight_text = Text(text) + elif isinstance(text, Text): + highlight_text = text.copy() + else: + raise TypeError(f"str or Text instance required, not {text!r}") + self.highlight(highlight_text) + return highlight_text + + @abstractmethod + def highlight(self, text: Text) -> None: + """Apply highlighting in place to text. + + Args: + text (~Text): A text object highlight. + """ + + +class NullHighlighter(Highlighter): + """A highlighter object that doesn't highlight. + + May be used to disable highlighting entirely. + + """ + + def highlight(self, text: Text) -> None: + """Nothing to do""" + + +class RegexHighlighter(Highlighter): + """Applies highlighting from a list of regular expressions.""" + + highlights: List[str] = [] + base_style: str = "" + + def highlight(self, text: Text) -> None: + """Highlight :class:`rich.text.Text` using regular expressions. + + Args: + text (~Text): Text to highlighted. + + """ + + highlight_regex = text.highlight_regex + for re_highlight in self.highlights: + highlight_regex(re_highlight, style_prefix=self.base_style) + + +class ReprHighlighter(RegexHighlighter): + """Highlights the text typically produced from ``__repr__`` methods.""" + + base_style = "repr." + highlights = [ + r"(?P<)(?P[-\w.:|]*)(?P[\w\W]*)(?P>)", + r'(?P[\w_]{1,50})=(?P"?[\w_]+"?)?', + r"(?P[][{}()])", + _combine_regex( + r"(?P[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})", + r"(?P([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})", + r"(?P(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})", + r"(?P(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})", + r"(?P[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})", + r"(?P[\w.]*?)\(", + r"\b(?PTrue)\b|\b(?PFalse)\b|\b(?PNone)\b", + r"(?P\.\.\.)", + r"(?P(?(?\B(/[-\w._+]+)*\/)(?P[-\w._+]*)?", + r"(?b?'''.*?(?(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#]*)", + ), + ] + + +class JSONHighlighter(RegexHighlighter): + """Highlights JSON""" + + # Captures the start and end of JSON strings, handling escaped quotes + JSON_STR = r"(?b?\".*?(?[\{\[\(\)\]\}])", + r"\b(?Ptrue)\b|\b(?Pfalse)\b|\b(?Pnull)\b", + r"(?P(? None: + super().highlight(text) + + # Additional work to handle highlighting JSON keys + plain = text.plain + append = text.spans.append + whitespace = self.JSON_WHITESPACE + for match in re.finditer(self.JSON_STR, plain): + start, end = match.span() + cursor = end + while cursor < len(plain): + char = plain[cursor] + cursor += 1 + if char == ":": + append(Span(start, end, "json.key")) + elif char in whitespace: + continue + break + + +class ISO8601Highlighter(RegexHighlighter): + """Highlights the ISO8601 date time strings. + Regex reference: https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html + """ + + base_style = "iso8601." + highlights = [ + # + # Dates + # + # Calendar month (e.g. 2008-08). The hyphen is required + r"^(?P[0-9]{4})-(?P1[0-2]|0[1-9])$", + # Calendar date w/o hyphens (e.g. 20080830) + r"^(?P(?P[0-9]{4})(?P1[0-2]|0[1-9])(?P3[01]|0[1-9]|[12][0-9]))$", + # Ordinal date (e.g. 2008-243). The hyphen is optional + r"^(?P(?P[0-9]{4})-?(?P36[0-6]|3[0-5][0-9]|[12][0-9]{2}|0[1-9][0-9]|00[1-9]))$", + # + # Weeks + # + # Week of the year (e.g., 2008-W35). The hyphen is optional + r"^(?P(?P[0-9]{4})-?W(?P5[0-3]|[1-4][0-9]|0[1-9]))$", + # Week date (e.g., 2008-W35-6). The hyphens are optional + r"^(?P(?P[0-9]{4})-?W(?P5[0-3]|[1-4][0-9]|0[1-9])-?(?P[1-7]))$", + # + # Times + # + # Hours and minutes (e.g., 17:21). The colon is optional + r"^(?P