From 3392b5cefa4fc0efd178fe625bbb2aa00c763f74 Mon Sep 17 00:00:00 2001 From: Federico Denkena Date: Wed, 26 Jul 2023 21:33:29 +0200 Subject: [PATCH] latest update --- .../typing_extensions.cpython-311.pyc | Bin 0 -> 131518 bytes .../urls/__pycache__/__init__.cpython-311.pyc | Bin 559 -> 559 bytes .../admin/__pycache__/forms.cpython-311.pyc | Bin 1927 -> 1927 bytes .../__pycache__/0001_initial.cpython-311.pyc | Bin 2452 -> 2452 bytes ...2_logentry_remove_auto_add.cpython-311.pyc | Bin 977 -> 977 bytes ...ry_add_action_flag_choices.cpython-311.pyc | Bin 976 -> 976 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 205 -> 205 bytes .../__pycache__/decorators.cpython-311.pyc | Bin 3875 -> 3875 bytes .../auth/__pycache__/views.cpython-311.pyc | Bin 21375 -> 21375 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 213 -> 213 bytes .../createsuperuser.cpython-311.pyc | Bin 15169 -> 15169 bytes .../__pycache__/0001_initial.cpython-311.pyc | Bin 4867 -> 4867 bytes ...permission_name_max_length.cpython-311.pyc | Bin 861 -> 861 bytes ...lter_user_email_max_length.cpython-311.pyc | Bin 912 -> 912 bytes ...4_alter_user_username_opts.cpython-311.pyc | Bin 1217 -> 1217 bytes ...alter_user_last_login_null.cpython-311.pyc | Bin 897 -> 897 bytes ..._require_contenttypes_0002.cpython-311.pyc | Bin 672 -> 672 bytes ...idators_add_error_messages.cpython-311.pyc | Bin 1226 -> 1226 bytes ...r_user_username_max_length.cpython-311.pyc | Bin 1232 -> 1232 bytes ..._user_last_name_max_length.cpython-311.pyc | Bin 913 -> 913 bytes ...lter_group_name_max_length.cpython-311.pyc | Bin 888 -> 888 bytes ...1_update_proxy_permissions.cpython-311.pyc | Bin 4481 -> 4481 bytes ...user_first_name_max_length.cpython-311.pyc | Bin 910 -> 910 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 204 -> 204 bytes .../__pycache__/0001_initial.cpython-311.pyc | Bin 1722 -> 1722 bytes ...2_remove_content_type_name.cpython-311.pyc | Bin 2061 -> 2061 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 212 -> 212 bytes .../__pycache__/0001_initial.cpython-311.pyc | Bin 1464 -> 1464 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 208 -> 208 bytes .../__pycache__/locmem.cpython-311.pyc | Bin 8905 -> 8905 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 199 -> 199 bytes .../backends/__pycache__/base.cpython-311.pyc | Bin 2858 -> 2858 bytes .../backends/__pycache__/smtp.cpython-311.pyc | Bin 7588 -> 7588 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 203 -> 203 bytes .../__pycache__/base.cpython-311.pyc | Bin 22716 -> 22716 bytes .../__pycache__/client.cpython-311.pyc | Bin 3401 -> 3401 bytes .../__pycache__/creation.cpython-311.pyc | Bin 5582 -> 5582 bytes .../__pycache__/features.cpython-311.pyc | Bin 6192 -> 6192 bytes .../__pycache__/introspection.cpython-311.pyc | Bin 13088 -> 13088 bytes .../__pycache__/operations.cpython-311.pyc | Bin 20900 -> 20900 bytes .../__pycache__/psycopg_any.cpython-311.pyc | Bin 6287 -> 6287 bytes .../__pycache__/schema.cpython-311.pyc | Bin 15007 -> 15007 bytes .../__pycache__/executor.cpython-311.pyc | Bin 20286 -> 20286 bytes .../__pycache__/graph.cpython-311.pyc | Bin 19598 -> 19598 bytes .../__pycache__/loader.cpython-311.pyc | Bin 18886 -> 18886 bytes .../__pycache__/recorder.cpython-311.pyc | Bin 6640 -> 6640 bytes .../views/__pycache__/csrf.cpython-311.pyc | Bin 6322 -> 6322 bytes .../__pycache__/defaults.cpython-311.pyc | Bin 5177 -> 5177 bytes .../AUTHORS.txt | 1 + .../INSTALLER | 0 .../LICENSE.txt | 0 .../METADATA | 2 +- .../RECORD | 28 +- .../REQUESTED | 0 .../WHEEL | 0 .../entry_points.txt | 0 .../top_level.txt | 0 lib/python3.11/site-packages/pip/__init__.py | 2 +- .../pip/__pycache__/__init__.cpython-311.pyc | Bin 764 -> 766 bytes .../pip/__pycache__/__main__.cpython-311.pyc | Bin 883 -> 883 bytes .../__pip-runner__.cpython-311.pyc | Bin 2503 -> 2503 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 949 -> 949 bytes .../__pycache__/build_env.cpython-311.pyc | Bin 16069 -> 16069 bytes .../__pycache__/cache.cpython-311.pyc | Bin 14267 -> 14267 bytes .../__pycache__/configuration.cpython-311.pyc | Bin 19516 -> 19516 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 37618 -> 37618 bytes .../__pycache__/main.cpython-311.pyc | Bin 749 -> 749 bytes .../__pycache__/pyproject.cpython-311.pyc | Bin 5611 -> 5611 bytes .../self_outdated_check.cpython-311.pyc | Bin 11319 -> 11319 bytes .../__pycache__/wheel_builder.cpython-311.pyc | Bin 15253 -> 15253 bytes .../cli/__pycache__/__init__.cpython-311.pyc | Bin 284 -> 284 bytes .../autocompletion.cpython-311.pyc | Bin 10074 -> 10074 bytes .../__pycache__/base_command.cpython-311.pyc | Bin 11846 -> 11846 bytes .../__pycache__/cmdoptions.cpython-311.pyc | Bin 33745 -> 33745 bytes .../command_context.cpython-311.pyc | Bin 2106 -> 2106 bytes .../cli/__pycache__/main.cpython-311.pyc | Bin 2576 -> 2576 bytes .../__pycache__/main_parser.cpython-311.pyc | Bin 5520 -> 5520 bytes .../cli/__pycache__/parser.cpython-311.pyc | Bin 17021 -> 17021 bytes .../__pycache__/progress_bars.cpython-311.pyc | Bin 3168 -> 3168 bytes .../__pycache__/req_command.cpython-311.pyc | Bin 20267 -> 20314 bytes .../cli/__pycache__/spinners.cpython-311.pyc | Bin 8833 -> 8833 bytes .../__pycache__/status_codes.cpython-311.pyc | Bin 372 -> 372 bytes .../pip/_internal/cli/req_command.py | 3 + .../__pycache__/__init__.cpython-311.pyc | Bin 4452 -> 4452 bytes .../__pycache__/cache.cpython-311.pyc | Bin 10551 -> 10551 bytes .../__pycache__/check.cpython-311.pyc | Bin 2407 -> 2407 bytes .../__pycache__/completion.cpython-311.pyc | Bin 5317 -> 5317 bytes .../__pycache__/configuration.cpython-311.pyc | Bin 14893 -> 14893 bytes .../__pycache__/debug.cpython-311.pyc | Bin 12001 -> 12001 bytes .../__pycache__/download.cpython-311.pyc | Bin 7941 -> 7941 bytes .../__pycache__/freeze.cpython-311.pyc | Bin 4657 -> 4657 bytes .../commands/__pycache__/hash.cpython-311.pyc | Bin 3354 -> 3354 bytes .../commands/__pycache__/help.cpython-311.pyc | Bin 1966 -> 1966 bytes .../__pycache__/index.cpython-311.pyc | Bin 7789 -> 7789 bytes .../__pycache__/inspect.cpython-311.pyc | Bin 4442 -> 4442 bytes .../__pycache__/install.cpython-311.pyc | Bin 31203 -> 31203 bytes .../commands/__pycache__/list.cpython-311.pyc | Bin 17212 -> 17212 bytes .../__pycache__/search.cpython-311.pyc | Bin 8948 -> 8948 bytes .../commands/__pycache__/show.cpython-311.pyc | Bin 11291 -> 11291 bytes .../__pycache__/uninstall.cpython-311.pyc | Bin 5142 -> 5142 bytes .../__pycache__/wheel.cpython-311.pyc | Bin 9398 -> 9398 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 1034 -> 1034 bytes .../__pycache__/base.cpython-311.pyc | Bin 2406 -> 2406 bytes .../__pycache__/installed.cpython-311.pyc | Bin 1543 -> 1543 bytes .../__pycache__/sdist.cpython-311.pyc | Bin 8945 -> 8945 bytes .../__pycache__/wheel.cpython-311.pyc | Bin 2137 -> 2137 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 238 -> 238 bytes .../__pycache__/collector.cpython-311.pyc | Bin 24544 -> 24544 bytes .../package_finder.cpython-311.pyc | Bin 44216 -> 44216 bytes .../index/__pycache__/sources.cpython-311.pyc | Bin 11020 -> 11020 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 18176 -> 18176 bytes .../__pycache__/_distutils.cpython-311.pyc | Bin 7585 -> 7585 bytes .../__pycache__/_sysconfig.cpython-311.pyc | Bin 8880 -> 8880 bytes .../__pycache__/base.cpython-311.pyc | Bin 4001 -> 4001 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 6409 -> 6409 bytes .../__pycache__/_json.cpython-311.pyc | Bin 3563 -> 3563 bytes .../metadata/__pycache__/base.cpython-311.pyc | Bin 38008 -> 38008 bytes .../__pycache__/pkg_resources.cpython-311.pyc | Bin 16856 -> 16856 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 355 -> 355 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 3562 -> 3562 bytes .../__pycache__/_dists.cpython-311.pyc | Bin 14578 -> 14578 bytes .../__pycache__/_envs.cpython-311.pyc | Bin 12488 -> 12488 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 272 -> 272 bytes .../__pycache__/candidate.cpython-311.pyc | Bin 2091 -> 2091 bytes .../__pycache__/direct_url.cpython-311.pyc | Bin 12799 -> 12799 bytes .../format_control.cpython-311.pyc | Bin 4655 -> 4655 bytes .../models/__pycache__/index.cpython-311.pyc | Bin 1897 -> 1897 bytes .../installation_report.cpython-311.pyc | Bin 2560 -> 2560 bytes .../models/__pycache__/link.cpython-311.pyc | Bin 28659 -> 28659 bytes .../models/__pycache__/scheme.cpython-311.pyc | Bin 1263 -> 1263 bytes .../__pycache__/search_scope.cpython-311.pyc | Bin 5826 -> 5826 bytes .../selection_prefs.cpython-311.pyc | Bin 1994 -> 1994 bytes .../__pycache__/target_python.cpython-311.pyc | Bin 4756 -> 4756 bytes .../models/__pycache__/wheel.cpython-311.pyc | Bin 6419 -> 6419 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 260 -> 260 bytes .../network/__pycache__/auth.cpython-311.pyc | Bin 23987 -> 23987 bytes .../network/__pycache__/cache.cpython-311.pyc | Bin 5183 -> 5183 bytes .../__pycache__/download.cpython-311.pyc | Bin 9575 -> 9575 bytes .../__pycache__/lazy_wheel.cpython-311.pyc | Bin 13021 -> 13021 bytes .../__pycache__/session.cpython-311.pyc | Bin 21288 -> 21432 bytes .../network/__pycache__/utils.cpython-311.pyc | Bin 2409 -> 2409 bytes .../__pycache__/xmlrpc.cpython-311.pyc | Bin 3188 -> 3188 bytes .../pip/_internal/network/session.py | 10 +- .../__pycache__/__init__.cpython-311.pyc | Bin 198 -> 198 bytes .../__pycache__/check.cpython-311.pyc | Bin 8461 -> 8461 bytes .../__pycache__/freeze.cpython-311.pyc | Bin 11594 -> 11594 bytes .../__pycache__/prepare.cpython-311.pyc | Bin 27701 -> 27944 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 204 -> 204 bytes .../__pycache__/build_tracker.cpython-311.pyc | Bin 8127 -> 8127 bytes .../__pycache__/metadata.cpython-311.pyc | Bin 2275 -> 2275 bytes .../metadata_editable.cpython-311.pyc | Bin 2311 -> 2311 bytes .../metadata_legacy.cpython-311.pyc | Bin 3711 -> 3711 bytes .../build/__pycache__/wheel.cpython-311.pyc | Bin 1941 -> 1941 bytes .../wheel_editable.cpython-311.pyc | Bin 2385 -> 2385 bytes .../__pycache__/wheel_legacy.cpython-311.pyc | Bin 4492 -> 4492 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 272 -> 272 bytes .../editable_legacy.cpython-311.pyc | Bin 2185 -> 2185 bytes .../install/__pycache__/wheel.cpython-311.pyc | Bin 40238 -> 40238 bytes .../pip/_internal/operations/prepare.py | 9 + .../req/__pycache__/__init__.cpython-311.pyc | Bin 4386 -> 4386 bytes .../__pycache__/constructors.cpython-311.pyc | Bin 20698 -> 20698 bytes .../req/__pycache__/req_file.cpython-311.pyc | Bin 22743 -> 22743 bytes .../__pycache__/req_install.cpython-311.pyc | Bin 38081 -> 38081 bytes .../req/__pycache__/req_set.cpython-311.pyc | Bin 7954 -> 7954 bytes .../__pycache__/req_uninstall.cpython-311.pyc | Bin 37480 -> 37480 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 198 -> 198 bytes .../__pycache__/base.cpython-311.pyc | Bin 1369 -> 1369 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 205 -> 205 bytes .../__pycache__/resolver.cpython-311.pyc | Bin 23795 -> 23795 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 209 -> 209 bytes .../__pycache__/base.cpython-311.pyc | Bin 9622 -> 9622 bytes .../__pycache__/candidates.cpython-311.pyc | Bin 28796 -> 28796 bytes .../__pycache__/factory.cpython-311.pyc | Bin 31921 -> 31921 bytes .../found_candidates.cpython-311.pyc | Bin 6757 -> 6757 bytes .../__pycache__/provider.cpython-311.pyc | Bin 11448 -> 11448 bytes .../__pycache__/reporter.cpython-311.pyc | Bin 5439 -> 5439 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 11119 -> 11119 bytes .../__pycache__/resolver.cpython-311.pyc | Bin 12420 -> 12420 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 193 -> 193 bytes .../__pycache__/_jaraco_text.cpython-311.pyc | Bin 4757 -> 4757 bytes .../utils/__pycache__/_log.cpython-311.pyc | Bin 2014 -> 2014 bytes .../utils/__pycache__/appdirs.cpython-311.pyc | Bin 2552 -> 2552 bytes .../utils/__pycache__/compat.cpython-311.pyc | Bin 2260 -> 2260 bytes .../compatibility_tags.cpython-311.pyc | Bin 6752 -> 6752 bytes .../__pycache__/datetime.cpython-311.pyc | Bin 710 -> 710 bytes .../__pycache__/deprecation.cpython-311.pyc | Bin 4679 -> 4679 bytes .../direct_url_helpers.cpython-311.pyc | Bin 3716 -> 3716 bytes .../__pycache__/egg_link.cpython-311.pyc | Bin 3231 -> 3231 bytes .../__pycache__/encoding.cpython-311.pyc | Bin 2316 -> 2316 bytes .../__pycache__/entrypoints.cpython-311.pyc | Bin 4238 -> 4238 bytes .../__pycache__/filesystem.cpython-311.pyc | Bin 8223 -> 8223 bytes .../__pycache__/filetypes.cpython-311.pyc | Bin 1309 -> 1309 bytes .../utils/__pycache__/glibc.cpython-311.pyc | Bin 2605 -> 2605 bytes .../utils/__pycache__/hashes.cpython-311.pyc | Bin 8764 -> 8764 bytes .../inject_securetransport.cpython-311.pyc | Bin 1327 -> 1327 bytes .../utils/__pycache__/logging.cpython-311.pyc | Bin 15452 -> 15452 bytes .../utils/__pycache__/misc.cpython-311.pyc | Bin 36977 -> 37052 bytes .../utils/__pycache__/models.cpython-311.pyc | Bin 2933 -> 2933 bytes .../__pycache__/packaging.cpython-311.pyc | Bin 2800 -> 2800 bytes .../setuptools_build.cpython-311.pyc | Bin 4865 -> 4865 bytes .../__pycache__/subprocess.cpython-311.pyc | Bin 9887 -> 9887 bytes .../__pycache__/temp_dir.cpython-311.pyc | Bin 11414 -> 11414 bytes .../__pycache__/unpacking.cpython-311.pyc | Bin 12889 -> 12889 bytes .../utils/__pycache__/urls.cpython-311.pyc | Bin 2686 -> 2686 bytes .../__pycache__/virtualenv.cpython-311.pyc | Bin 4933 -> 4933 bytes .../utils/__pycache__/wheel.cpython-311.pyc | Bin 7103 -> 7103 bytes .../site-packages/pip/_internal/utils/misc.py | 20 +- .../vcs/__pycache__/__init__.cpython-311.pyc | Bin 628 -> 628 bytes .../vcs/__pycache__/bazaar.cpython-311.pyc | Bin 5853 -> 5853 bytes .../vcs/__pycache__/git.cpython-311.pyc | Bin 21517 -> 21517 bytes .../vcs/__pycache__/mercurial.cpython-311.pyc | Bin 8708 -> 8708 bytes .../__pycache__/subversion.cpython-311.pyc | Bin 14596 -> 14596 bytes .../versioncontrol.cpython-311.pyc | Bin 31865 -> 31865 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 5606 -> 5606 bytes .../_vendor/__pycache__/six.cpython-311.pyc | Bin 46408 -> 46408 bytes .../typing_extensions.cpython-311.pyc | Bin 131578 -> 131578 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 835 -> 835 bytes .../__pycache__/_cmd.cpython-311.pyc | Bin 2690 -> 2690 bytes .../__pycache__/adapter.cpython-311.pyc | Bin 5497 -> 5497 bytes .../__pycache__/cache.cpython-311.pyc | Bin 3771 -> 3771 bytes .../__pycache__/compat.cpython-311.pyc | Bin 1128 -> 1128 bytes .../__pycache__/controller.cpython-311.pyc | Bin 16443 -> 16443 bytes .../__pycache__/filewrapper.cpython-311.pyc | Bin 4230 -> 4230 bytes .../__pycache__/heuristics.cpython-311.pyc | Bin 6675 -> 6675 bytes .../__pycache__/serialize.cpython-311.pyc | Bin 8390 -> 8390 bytes .../__pycache__/wrapper.cpython-311.pyc | Bin 956 -> 956 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 410 -> 410 bytes .../__pycache__/file_cache.cpython-311.pyc | Bin 8393 -> 8393 bytes .../__pycache__/redis_cache.cpython-311.pyc | Bin 2490 -> 2490 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 335 -> 335 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 736 -> 736 bytes .../certifi/__pycache__/core.cpython-311.pyc | Bin 3358 -> 3358 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 5067 -> 5067 bytes .../__pycache__/big5freq.cpython-311.pyc | Bin 27197 -> 27197 bytes .../__pycache__/big5prober.cpython-311.pyc | Bin 1672 -> 1672 bytes .../chardistribution.cpython-311.pyc | Bin 11264 -> 11264 bytes .../charsetgroupprober.cpython-311.pyc | Bin 4294 -> 4294 bytes .../__pycache__/charsetprober.cpython-311.pyc | Bin 5540 -> 5540 bytes .../codingstatemachine.cpython-311.pyc | Bin 3991 -> 3991 bytes .../codingstatemachinedict.cpython-311.pyc | Bin 947 -> 947 bytes .../__pycache__/cp949prober.cpython-311.pyc | Bin 1681 -> 1681 bytes .../chardet/__pycache__/enums.cpython-311.pyc | Bin 3382 -> 3382 bytes .../__pycache__/escprober.cpython-311.pyc | Bin 4898 -> 4898 bytes .../chardet/__pycache__/escsm.cpython-311.pyc | Bin 12637 -> 12637 bytes .../__pycache__/eucjpprober.cpython-311.pyc | Bin 4724 -> 4724 bytes .../__pycache__/euckrfreq.cpython-311.pyc | Bin 12080 -> 12080 bytes .../__pycache__/euckrprober.cpython-311.pyc | Bin 1673 -> 1673 bytes .../__pycache__/euctwfreq.cpython-311.pyc | Bin 27202 -> 27202 bytes .../__pycache__/euctwprober.cpython-311.pyc | Bin 1673 -> 1673 bytes .../__pycache__/gb2312freq.cpython-311.pyc | Bin 19124 -> 19124 bytes .../__pycache__/gb2312prober.cpython-311.pyc | Bin 1688 -> 1688 bytes .../__pycache__/hebrewprober.cpython-311.pyc | Bin 5677 -> 5677 bytes .../__pycache__/jisfreq.cpython-311.pyc | Bin 22153 -> 22153 bytes .../__pycache__/johabfreq.cpython-311.pyc | Bin 84657 -> 84657 bytes .../__pycache__/johabprober.cpython-311.pyc | Bin 1679 -> 1679 bytes .../__pycache__/jpcntx.cpython-311.pyc | Bin 40161 -> 40161 bytes .../langbulgarianmodel.cpython-311.pyc | Bin 85831 -> 85831 bytes .../langgreekmodel.cpython-311.pyc | Bin 79253 -> 79253 bytes .../langhebrewmodel.cpython-311.pyc | Bin 80015 -> 80015 bytes .../langhungarianmodel.cpython-311.pyc | Bin 85785 -> 85785 bytes .../langrussianmodel.cpython-311.pyc | Bin 108732 -> 108732 bytes .../__pycache__/langthaimodel.cpython-311.pyc | Bin 80193 -> 80193 bytes .../langturkishmodel.cpython-311.pyc | Bin 80032 -> 80032 bytes .../__pycache__/latin1prober.cpython-311.pyc | Bin 7328 -> 7328 bytes .../macromanprober.cpython-311.pyc | Bin 7495 -> 7495 bytes .../mbcharsetprober.cpython-311.pyc | Bin 4116 -> 4116 bytes .../mbcsgroupprober.cpython-311.pyc | Bin 1986 -> 1986 bytes .../__pycache__/mbcssm.cpython-311.pyc | Bin 31726 -> 31726 bytes .../__pycache__/resultdict.cpython-311.pyc | Bin 765 -> 765 bytes .../sbcharsetprober.cpython-311.pyc | Bin 6391 -> 6391 bytes .../sbcsgroupprober.cpython-311.pyc | Bin 2936 -> 2936 bytes .../__pycache__/sjisprober.cpython-311.pyc | Bin 4829 -> 4829 bytes .../universaldetector.cpython-311.pyc | Bin 12457 -> 12457 bytes .../__pycache__/utf1632prober.cpython-311.pyc | Bin 10577 -> 10577 bytes .../__pycache__/utf8prober.cpython-311.pyc | Bin 3464 -> 3464 bytes .../__pycache__/version.cpython-311.pyc | Bin 500 -> 500 bytes .../cli/__pycache__/__init__.cpython-311.pyc | Bin 197 -> 197 bytes .../__pycache__/chardetect.cpython-311.pyc | Bin 4336 -> 4336 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 202 -> 202 bytes .../__pycache__/languages.cpython-311.pyc | Bin 10802 -> 10802 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 569 -> 569 bytes .../colorama/__pycache__/ansi.cpython-311.pyc | Bin 4567 -> 4567 bytes .../__pycache__/ansitowin32.cpython-311.pyc | Bin 16213 -> 16213 bytes .../__pycache__/initialise.cpython-311.pyc | Bin 3930 -> 3930 bytes .../__pycache__/win32.cpython-311.pyc | Bin 7918 -> 7918 bytes .../__pycache__/winterm.cpython-311.pyc | Bin 9144 -> 9144 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 200 -> 200 bytes .../__pycache__/ansi_test.cpython-311.pyc | Bin 5845 -> 5845 bytes .../ansitowin32_test.cpython-311.pyc | Bin 21512 -> 21512 bytes .../initialise_test.cpython-311.pyc | Bin 14139 -> 14139 bytes .../__pycache__/isatty_test.cpython-311.pyc | Bin 6704 -> 6704 bytes .../tests/__pycache__/utils.cpython-311.pyc | Bin 2879 -> 2879 bytes .../__pycache__/winterm_test.cpython-311.pyc | Bin 7232 -> 7232 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 1438 -> 1438 bytes .../__pycache__/compat.cpython-311.pyc | Bin 52304 -> 52304 bytes .../__pycache__/database.cpython-311.pyc | Bin 72092 -> 72092 bytes .../distlib/__pycache__/index.cpython-311.pyc | Bin 26681 -> 26681 bytes .../__pycache__/locators.cpython-311.pyc | Bin 65857 -> 65857 bytes .../__pycache__/manifest.cpython-311.pyc | Bin 17024 -> 17024 bytes .../__pycache__/markers.cpython-311.pyc | Bin 8160 -> 8160 bytes .../__pycache__/metadata.cpython-311.pyc | Bin 47108 -> 47108 bytes .../__pycache__/resources.cpython-311.pyc | Bin 18987 -> 18987 bytes .../__pycache__/scripts.cpython-311.pyc | Bin 21263 -> 21263 bytes .../distlib/__pycache__/util.cpython-311.pyc | Bin 97442 -> 97442 bytes .../__pycache__/version.cpython-311.pyc | Bin 34569 -> 34569 bytes .../distlib/__pycache__/wheel.cpython-311.pyc | Bin 60373 -> 60373 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 1191 -> 1191 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 325 -> 325 bytes .../distro/__pycache__/distro.cpython-311.pyc | Bin 57724 -> 57724 bytes .../idna/__pycache__/__init__.cpython-311.pyc | Bin 1092 -> 1092 bytes .../idna/__pycache__/codec.cpython-311.pyc | Bin 5383 -> 5383 bytes .../idna/__pycache__/compat.cpython-311.pyc | Bin 1009 -> 1009 bytes .../idna/__pycache__/core.cpython-311.pyc | Bin 19444 -> 19444 bytes .../idna/__pycache__/idnadata.cpython-311.pyc | Bin 38968 -> 38968 bytes .../__pycache__/intranges.cpython-311.pyc | Bin 2977 -> 2977 bytes .../__pycache__/package_data.cpython-311.pyc | Bin 212 -> 212 bytes .../__pycache__/uts46data.cpython-311.pyc | Bin 163192 -> 163192 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 2071 -> 2071 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 2372 -> 2372 bytes .../msgpack/__pycache__/ext.cpython-311.pyc | Bin 9157 -> 9157 bytes .../__pycache__/fallback.cpython-311.pyc | Bin 47145 -> 47145 bytes .../__pycache__/__about__.cpython-311.pyc | Bin 636 -> 636 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 557 -> 557 bytes .../__pycache__/_manylinux.cpython-311.pyc | Bin 13223 -> 13223 bytes .../__pycache__/_musllinux.cpython-311.pyc | Bin 7991 -> 7991 bytes .../__pycache__/_structures.cpython-311.pyc | Bin 3679 -> 3679 bytes .../__pycache__/markers.cpython-311.pyc | Bin 16519 -> 16519 bytes .../__pycache__/requirements.cpython-311.pyc | Bin 7634 -> 7634 bytes .../__pycache__/specifiers.cpython-311.pyc | Bin 34357 -> 34357 bytes .../__pycache__/tags.cpython-311.pyc | Bin 21342 -> 21342 bytes .../__pycache__/utils.cpython-311.pyc | Bin 6677 -> 6677 bytes .../__pycache__/version.cpython-311.pyc | Bin 21869 -> 21869 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 160137 -> 160137 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 17490 -> 17490 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 2270 -> 2270 bytes .../__pycache__/android.cpython-311.pyc | Bin 10456 -> 10456 bytes .../__pycache__/api.cpython-311.pyc | Bin 10549 -> 10549 bytes .../__pycache__/macos.cpython-311.pyc | Bin 6061 -> 6061 bytes .../__pycache__/unix.cpython-311.pyc | Bin 13767 -> 13767 bytes .../__pycache__/version.cpython-311.pyc | Bin 307 -> 307 bytes .../__pycache__/windows.cpython-311.pyc | Bin 13935 -> 13935 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 3826 -> 3826 bytes .../__pycache__/__main__.cpython-311.pyc | Bin 775 -> 775 bytes .../__pycache__/cmdline.cpython-311.pyc | Bin 30286 -> 30286 bytes .../__pycache__/console.cpython-311.pyc | Bin 3038 -> 3038 bytes .../__pycache__/filter.cpython-311.pyc | Bin 3499 -> 3499 bytes .../__pycache__/formatter.cpython-311.pyc | Bin 4814 -> 4814 bytes .../__pycache__/lexer.cpython-311.pyc | Bin 42302 -> 42302 bytes .../__pycache__/modeline.cpython-311.pyc | Bin 1718 -> 1718 bytes .../__pycache__/plugin.cpython-311.pyc | Bin 3731 -> 3731 bytes .../__pycache__/regexopt.cpython-311.pyc | Bin 5025 -> 5025 bytes .../__pycache__/scanner.cpython-311.pyc | Bin 4880 -> 4880 bytes .../__pycache__/sphinxext.cpython-311.pyc | Bin 12825 -> 12825 bytes .../__pycache__/style.cpython-311.pyc | Bin 7419 -> 7419 bytes .../__pycache__/token.cpython-311.pyc | Bin 7459 -> 7459 bytes .../__pycache__/unistring.cpython-311.pyc | Bin 33832 -> 33832 bytes .../pygments/__pycache__/util.cpython-311.pyc | Bin 15684 -> 15684 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 40099 -> 40099 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 7757 -> 7757 bytes .../__pycache__/_mapping.cpython-311.pyc | Bin 4217 -> 4217 bytes .../__pycache__/bbcode.cpython-311.pyc | Bin 4473 -> 4473 bytes .../__pycache__/groff.cpython-311.pyc | Bin 7846 -> 7846 bytes .../__pycache__/html.cpython-311.pyc | Bin 42635 -> 42635 bytes .../__pycache__/img.cpython-311.pyc | Bin 28563 -> 28563 bytes .../__pycache__/irc.cpython-311.pyc | Bin 6399 -> 6399 bytes .../__pycache__/latex.cpython-311.pyc | Bin 21799 -> 21799 bytes .../__pycache__/other.cpython-311.pyc | Bin 7627 -> 7627 bytes .../__pycache__/pangomarkup.cpython-311.pyc | Bin 3171 -> 3171 bytes .../__pycache__/rtf.cpython-311.pyc | Bin 6838 -> 6838 bytes .../__pycache__/svg.cpython-311.pyc | Bin 9658 -> 9658 bytes .../__pycache__/terminal.cpython-311.pyc | Bin 6037 -> 6037 bytes .../__pycache__/terminal256.cpython-311.pyc | Bin 16403 -> 16403 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 16343 -> 16343 bytes .../__pycache__/_mapping.cpython-311.pyc | Bin 64785 -> 64785 bytes .../lexers/__pycache__/python.cpython-311.pyc | Bin 43299 -> 43299 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 4674 -> 4674 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 8223 -> 8223 bytes .../__pycache__/actions.cpython-311.pyc | Bin 9114 -> 9114 bytes .../__pycache__/common.cpython-311.pyc | Bin 14861 -> 14861 bytes .../__pycache__/core.cpython-311.pyc | Bin 295434 -> 295434 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 13701 -> 13701 bytes .../__pycache__/helpers.cpython-311.pyc | Bin 54120 -> 54120 bytes .../__pycache__/results.cpython-311.pyc | Bin 37841 -> 37841 bytes .../__pycache__/testing.cpython-311.pyc | Bin 19504 -> 19504 bytes .../__pycache__/unicode.cpython-311.pyc | Bin 15192 -> 15192 bytes .../__pycache__/util.cpython-311.pyc | Bin 16775 -> 16775 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 28783 -> 28783 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 700 -> 700 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 398 -> 398 bytes .../__pycache__/_impl.cpython-311.pyc | Bin 16664 -> 16664 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 1160 -> 1160 bytes .../__pycache__/_in_process.cpython-311.pyc | Bin 16482 -> 16482 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 6431 -> 6431 bytes .../__pycache__/__version__.cpython-311.pyc | Bin 581 -> 581 bytes .../_internal_utils.cpython-311.pyc | Bin 2145 -> 2145 bytes .../__pycache__/adapters.cpython-311.pyc | Bin 23198 -> 23198 bytes .../requests/__pycache__/api.cpython-311.pyc | Bin 7498 -> 7498 bytes .../requests/__pycache__/auth.cpython-311.pyc | Bin 14625 -> 14625 bytes .../__pycache__/certs.cpython-311.pyc | Bin 977 -> 977 bytes .../__pycache__/compat.cpython-311.pyc | Bin 1803 -> 1803 bytes .../__pycache__/cookies.cpython-311.pyc | Bin 27105 -> 27105 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 8520 -> 8520 bytes .../requests/__pycache__/help.cpython-311.pyc | Bin 4515 -> 4515 bytes .../__pycache__/hooks.cpython-311.pyc | Bin 1245 -> 1245 bytes .../__pycache__/models.cpython-311.pyc | Bin 38776 -> 38776 bytes .../__pycache__/packages.cpython-311.pyc | Bin 825 -> 825 bytes .../__pycache__/sessions.cpython-311.pyc | Bin 29688 -> 29688 bytes .../__pycache__/status_codes.cpython-311.pyc | Bin 6232 -> 6232 bytes .../__pycache__/structures.cpython-311.pyc | Bin 6217 -> 6217 bytes .../__pycache__/utils.cpython-311.pyc | Bin 40251 -> 40251 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 748 -> 748 bytes .../__pycache__/providers.cpython-311.pyc | Bin 7066 -> 7066 bytes .../__pycache__/reporters.cpython-311.pyc | Bin 2830 -> 2830 bytes .../__pycache__/resolvers.cpython-311.pyc | Bin 29230 -> 29230 bytes .../__pycache__/structs.cpython-311.pyc | Bin 11467 -> 11467 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 203 -> 203 bytes .../collections_abc.cpython-311.pyc | Bin 478 -> 478 bytes .../rich/__pycache__/__init__.cpython-311.pyc | Bin 7491 -> 7491 bytes .../rich/__pycache__/__main__.cpython-311.pyc | Bin 11569 -> 11569 bytes .../__pycache__/_cell_widths.cpython-311.pyc | Bin 7830 -> 7830 bytes .../__pycache__/_emoji_codes.cpython-311.pyc | Bin 208517 -> 208517 bytes .../_emoji_replace.cpython-311.pyc | Bin 1929 -> 1929 bytes .../_export_format.cpython-311.pyc | Bin 2320 -> 2320 bytes .../__pycache__/_extension.cpython-311.pyc | Bin 630 -> 630 bytes .../rich/__pycache__/_fileno.cpython-311.pyc | Bin 972 -> 972 bytes .../rich/__pycache__/_inspect.cpython-311.pyc | Bin 14182 -> 14182 bytes .../__pycache__/_log_render.cpython-311.pyc | Bin 4764 -> 4764 bytes .../rich/__pycache__/_loop.cpython-311.pyc | Bin 2110 -> 2110 bytes .../__pycache__/_null_file.cpython-311.pyc | Bin 4169 -> 4169 bytes .../__pycache__/_palettes.cpython-311.pyc | Bin 5246 -> 5246 bytes .../rich/__pycache__/_pick.cpython-311.pyc | Bin 791 -> 791 bytes .../rich/__pycache__/_ratio.cpython-311.pyc | Bin 7929 -> 7929 bytes .../__pycache__/_spinners.cpython-311.pyc | Bin 13679 -> 13679 bytes .../rich/__pycache__/_stack.cpython-311.pyc | Bin 1125 -> 1125 bytes .../rich/__pycache__/_timer.cpython-311.pyc | Bin 978 -> 978 bytes .../_win32_console.cpython-311.pyc | Bin 30166 -> 30166 bytes .../rich/__pycache__/_windows.cpython-311.pyc | Bin 2825 -> 2825 bytes .../_windows_renderer.cpython-311.pyc | Bin 4016 -> 4016 bytes .../rich/__pycache__/_wrap.cpython-311.pyc | Bin 2781 -> 2781 bytes .../rich/__pycache__/abc.cpython-311.pyc | Bin 1922 -> 1922 bytes .../rich/__pycache__/align.cpython-311.pyc | Bin 13464 -> 13464 bytes .../rich/__pycache__/ansi.cpython-311.pyc | Bin 10495 -> 10495 bytes .../rich/__pycache__/bar.cpython-311.pyc | Bin 4544 -> 4544 bytes .../rich/__pycache__/box.cpython-311.pyc | Bin 12986 -> 12986 bytes .../rich/__pycache__/cells.cpython-311.pyc | Bin 6616 -> 6616 bytes .../rich/__pycache__/color.cpython-311.pyc | Bin 27800 -> 27800 bytes .../__pycache__/color_triplet.cpython-311.pyc | Bin 1870 -> 1870 bytes .../rich/__pycache__/columns.cpython-311.pyc | Bin 10641 -> 10641 bytes .../rich/__pycache__/console.cpython-311.pyc | Bin 123744 -> 123744 bytes .../__pycache__/constrain.cpython-311.pyc | Bin 2462 -> 2462 bytes .../__pycache__/containers.cpython-311.pyc | Bin 10803 -> 10803 bytes .../rich/__pycache__/control.cpython-311.pyc | Bin 11894 -> 11894 bytes .../default_styles.cpython-311.pyc | Bin 12597 -> 12597 bytes .../rich/__pycache__/diagnose.cpython-311.pyc | Bin 1817 -> 1817 bytes .../rich/__pycache__/emoji.cpython-311.pyc | Bin 4795 -> 4795 bytes .../rich/__pycache__/errors.cpython-311.pyc | Bin 2326 -> 2326 bytes .../__pycache__/file_proxy.cpython-311.pyc | Bin 4030 -> 4030 bytes .../rich/__pycache__/filesize.cpython-311.pyc | Bin 3298 -> 3298 bytes .../__pycache__/highlighter.cpython-311.pyc | Bin 10984 -> 10984 bytes .../rich/__pycache__/json.cpython-311.pyc | Bin 6541 -> 6541 bytes .../rich/__pycache__/jupyter.cpython-311.pyc | Bin 6401 -> 6401 bytes .../rich/__pycache__/layout.cpython-311.pyc | Bin 23308 -> 23308 bytes .../rich/__pycache__/live.cpython-311.pyc | Bin 21294 -> 21294 bytes .../__pycache__/live_render.cpython-311.pyc | Bin 5142 -> 5142 bytes .../rich/__pycache__/logging.cpython-311.pyc | Bin 14513 -> 14513 bytes .../rich/__pycache__/markup.cpython-311.pyc | Bin 10435 -> 10435 bytes .../rich/__pycache__/measure.cpython-311.pyc | Bin 7268 -> 7268 bytes .../rich/__pycache__/padding.cpython-311.pyc | Bin 7484 -> 7484 bytes .../rich/__pycache__/pager.cpython-311.pyc | Bin 2242 -> 2242 bytes .../rich/__pycache__/palette.cpython-311.pyc | Bin 5975 -> 5975 bytes .../rich/__pycache__/panel.cpython-311.pyc | Bin 12731 -> 12731 bytes .../rich/__pycache__/pretty.cpython-311.pyc | Bin 44345 -> 44345 bytes .../rich/__pycache__/progress.cpython-311.pyc | Bin 82611 -> 82611 bytes .../__pycache__/progress_bar.cpython-311.pyc | Bin 11009 -> 11009 bytes .../rich/__pycache__/prompt.cpython-311.pyc | Bin 16375 -> 16375 bytes .../rich/__pycache__/protocol.cpython-311.pyc | Bin 2093 -> 2093 bytes .../rich/__pycache__/region.cpython-311.pyc | Bin 656 -> 656 bytes .../rich/__pycache__/repr.cpython-311.pyc | Bin 7623 -> 7623 bytes .../rich/__pycache__/rule.cpython-311.pyc | Bin 7162 -> 7162 bytes .../rich/__pycache__/scope.cpython-311.pyc | Bin 4348 -> 4348 bytes .../rich/__pycache__/screen.cpython-311.pyc | Bin 2771 -> 2771 bytes .../rich/__pycache__/segment.cpython-311.pyc | Bin 31601 -> 31601 bytes .../rich/__pycache__/spinner.cpython-311.pyc | Bin 6877 -> 6877 bytes .../rich/__pycache__/status.cpython-311.pyc | Bin 6755 -> 6755 bytes .../rich/__pycache__/style.cpython-311.pyc | Bin 35195 -> 35195 bytes .../rich/__pycache__/styled.cpython-311.pyc | Bin 2436 -> 2436 bytes .../rich/__pycache__/syntax.cpython-311.pyc | Bin 42646 -> 42646 bytes .../rich/__pycache__/table.cpython-311.pyc | Bin 48797 -> 48797 bytes .../terminal_theme.cpython-311.pyc | Bin 3702 -> 3702 bytes .../rich/__pycache__/text.cpython-311.pyc | Bin 64955 -> 64955 bytes .../rich/__pycache__/theme.cpython-311.pyc | Bin 7301 -> 7301 bytes .../rich/__pycache__/themes.cpython-311.pyc | Bin 352 -> 352 bytes .../__pycache__/traceback.cpython-311.pyc | Bin 34564 -> 34564 bytes .../rich/__pycache__/tree.cpython-311.pyc | Bin 12523 -> 12523 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 29043 -> 29043 bytes .../__pycache__/_asyncio.cpython-311.pyc | Bin 5219 -> 5219 bytes .../__pycache__/_utils.cpython-311.pyc | Bin 2559 -> 2559 bytes .../__pycache__/after.cpython-311.pyc | Bin 1754 -> 1754 bytes .../__pycache__/before.cpython-311.pyc | Bin 1588 -> 1588 bytes .../__pycache__/before_sleep.cpython-311.pyc | Bin 2371 -> 2371 bytes .../tenacity/__pycache__/nap.cpython-311.pyc | Bin 1562 -> 1562 bytes .../__pycache__/retry.cpython-311.pyc | Bin 15938 -> 15938 bytes .../tenacity/__pycache__/stop.cpython-311.pyc | Bin 6291 -> 6291 bytes .../__pycache__/tornadoweb.cpython-311.pyc | Bin 2908 -> 2908 bytes .../tenacity/__pycache__/wait.cpython-311.pyc | Bin 13297 -> 13297 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 407 -> 407 bytes .../tomli/__pycache__/_parser.cpython-311.pyc | Bin 30846 -> 30846 bytes .../tomli/__pycache__/_re.cpython-311.pyc | Bin 4486 -> 4486 bytes .../tomli/__pycache__/_types.cpython-311.pyc | Bin 399 -> 399 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 3705 -> 3705 bytes .../__pycache__/_collections.cpython-311.pyc | Bin 18293 -> 18293 bytes .../__pycache__/_version.cpython-311.pyc | Bin 215 -> 215 bytes .../__pycache__/connection.cpython-311.pyc | Bin 22061 -> 22061 bytes .../connectionpool.cpython-311.pyc | Bin 38273 -> 38273 bytes .../__pycache__/exceptions.cpython-311.pyc | Bin 16119 -> 16119 bytes .../__pycache__/fields.cpython-311.pyc | Bin 11412 -> 11412 bytes .../__pycache__/filepost.cpython-311.pyc | Bin 4493 -> 4493 bytes .../__pycache__/poolmanager.cpython-311.pyc | Bin 21611 -> 21611 bytes .../__pycache__/request.cpython-311.pyc | Bin 6656 -> 6656 bytes .../__pycache__/response.cpython-311.pyc | Bin 36539 -> 36539 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 201 -> 201 bytes .../_appengine_environ.cpython-311.pyc | Bin 1940 -> 1940 bytes .../__pycache__/appengine.cpython-311.pyc | Bin 12147 -> 12147 bytes .../__pycache__/ntlmpool.cpython-311.pyc | Bin 6224 -> 6224 bytes .../__pycache__/pyopenssl.cpython-311.pyc | Bin 25733 -> 25733 bytes .../securetransport.cpython-311.pyc | Bin 36840 -> 36840 bytes .../contrib/__pycache__/socks.cpython-311.pyc | Bin 8085 -> 8085 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 218 -> 218 bytes .../__pycache__/bindings.cpython-311.pyc | Bin 16965 -> 16965 bytes .../__pycache__/low_level.cpython-311.pyc | Bin 15602 -> 15602 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 202 -> 202 bytes .../packages/__pycache__/six.cpython-311.pyc | Bin 46444 -> 46444 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 212 -> 212 bytes .../__pycache__/makefile.cpython-311.pyc | Bin 1959 -> 1959 bytes .../weakref_finalize.cpython-311.pyc | Bin 7987 -> 7987 bytes .../util/__pycache__/__init__.cpython-311.pyc | Bin 1404 -> 1404 bytes .../__pycache__/connection.cpython-311.pyc | Bin 5131 -> 5131 bytes .../util/__pycache__/proxy.cpython-311.pyc | Bin 1713 -> 1713 bytes .../util/__pycache__/queue.cpython-311.pyc | Bin 1496 -> 1496 bytes .../util/__pycache__/request.cpython-311.pyc | Bin 4616 -> 4616 bytes .../util/__pycache__/response.cpython-311.pyc | Bin 3485 -> 3485 bytes .../util/__pycache__/retry.cpython-311.pyc | Bin 22753 -> 22753 bytes .../util/__pycache__/ssl_.cpython-311.pyc | Bin 16816 -> 16816 bytes .../ssl_match_hostname.cpython-311.pyc | Bin 5795 -> 5795 bytes .../__pycache__/ssltransport.cpython-311.pyc | Bin 11624 -> 11624 bytes .../util/__pycache__/timeout.cpython-311.pyc | Bin 11338 -> 11338 bytes .../util/__pycache__/url.cpython-311.pyc | Bin 17579 -> 17579 bytes .../util/__pycache__/wait.cpython-311.pyc | Bin 4998 -> 4998 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 12878 -> 12878 bytes .../__pycache__/labels.cpython-311.pyc | Bin 7278 -> 7278 bytes .../__pycache__/mklabels.cpython-311.pyc | Bin 3206 -> 3206 bytes .../__pycache__/tests.cpython-311.pyc | Bin 11184 -> 11184 bytes .../x_user_defined.cpython-311.pyc | Bin 3558 -> 3558 bytes .../psycopg-3.1.9.dist-info/INSTALLER | 1 + .../psycopg-3.1.9.dist-info/LICENSE.txt | 165 + .../psycopg-3.1.9.dist-info/METADATA | 93 + .../psycopg-3.1.9.dist-info/RECORD | 132 + .../psycopg-3.1.9.dist-info/REQUESTED | 0 .../psycopg-3.1.9.dist-info/WHEEL | 5 + .../psycopg-3.1.9.dist-info/top_level.txt | 1 + .../site-packages/psycopg/__init__.py | 110 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 3191 bytes .../__pycache__/_adapters_map.cpython-311.pyc | Bin 0 -> 13457 bytes .../__pycache__/_cmodule.cpython-311.pyc | Bin 0 -> 896 bytes .../__pycache__/_column.cpython-311.pyc | Bin 0 -> 7162 bytes .../__pycache__/_compat.cpython-311.pyc | Bin 0 -> 2444 bytes .../psycopg/__pycache__/_dns.cpython-311.pyc | Bin 0 -> 12473 bytes .../__pycache__/_encodings.cpython-311.pyc | Bin 0 -> 7523 bytes .../__pycache__/_enums.cpython-311.pyc | Bin 0 -> 2673 bytes .../__pycache__/_pipeline.cpython-311.pyc | Bin 0 -> 18178 bytes .../__pycache__/_preparing.cpython-311.pyc | Bin 0 -> 8938 bytes .../__pycache__/_queries.cpython-311.pyc | Bin 0 -> 16899 bytes .../__pycache__/_struct.cpython-311.pyc | Bin 0 -> 3921 bytes .../psycopg/__pycache__/_tpc.cpython-311.pyc | Bin 0 -> 6341 bytes .../__pycache__/_transform.cpython-311.pyc | Bin 0 -> 16238 bytes .../__pycache__/_typeinfo.cpython-311.pyc | Bin 0 -> 23797 bytes .../psycopg/__pycache__/_tz.cpython-311.pyc | Bin 0 -> 2167 bytes .../__pycache__/_wrappers.cpython-311.pyc | Bin 0 -> 7299 bytes .../psycopg/__pycache__/abc.cpython-311.pyc | Bin 0 -> 12508 bytes .../psycopg/__pycache__/adapt.cpython-311.pyc | Bin 0 -> 7339 bytes .../__pycache__/client_cursor.cpython-311.pyc | Bin 0 -> 4701 bytes .../__pycache__/connection.cpython-311.pyc | Bin 0 -> 53152 bytes .../connection_async.cpython-311.pyc | Bin 0 -> 28474 bytes .../__pycache__/conninfo.cpython-311.pyc | Bin 0 -> 19267 bytes .../psycopg/__pycache__/copy.cpython-311.pyc | Bin 0 -> 44159 bytes .../__pycache__/cursor.cpython-311.pyc | Bin 0 -> 44812 bytes .../__pycache__/cursor_async.cpython-311.pyc | Bin 0 -> 17163 bytes .../__pycache__/dbapi20.cpython-311.pyc | Bin 0 -> 7693 bytes .../__pycache__/errors.cpython-311.pyc | Bin 0 -> 81575 bytes .../__pycache__/generators.cpython-311.pyc | Bin 0 -> 11876 bytes .../__pycache__/postgres.cpython-311.pyc | Bin 0 -> 8241 bytes .../psycopg/__pycache__/rows.cpython-311.pyc | Bin 0 -> 12689 bytes .../__pycache__/server_cursor.cpython-311.pyc | Bin 0 -> 28174 bytes .../psycopg/__pycache__/sql.cpython-311.pyc | Bin 0 -> 24261 bytes .../__pycache__/transaction.cpython-311.pyc | Bin 0 -> 15556 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 263 bytes .../__pycache__/waiting.cpython-311.pyc | Bin 0 -> 13346 bytes .../site-packages/psycopg/_adapters_map.py | 295 ++ .../site-packages/psycopg/_cmodule.py | 24 + .../site-packages/psycopg/_column.py | 142 + .../site-packages/psycopg/_compat.py | 72 + lib/python3.11/site-packages/psycopg/_dns.py | 223 ++ .../site-packages/psycopg/_encodings.py | 170 + .../site-packages/psycopg/_enums.py | 79 + .../site-packages/psycopg/_pipeline.py | 287 ++ .../site-packages/psycopg/_preparing.py | 198 ++ .../site-packages/psycopg/_queries.py | 375 ++ .../site-packages/psycopg/_struct.py | 57 + lib/python3.11/site-packages/psycopg/_tpc.py | 116 + .../site-packages/psycopg/_transform.py | 350 ++ .../site-packages/psycopg/_typeinfo.py | 500 +++ lib/python3.11/site-packages/psycopg/_tz.py | 44 + .../site-packages/psycopg/_wrappers.py | 137 + lib/python3.11/site-packages/psycopg/abc.py | 265 ++ lib/python3.11/site-packages/psycopg/adapt.py | 162 + .../site-packages/psycopg/client_cursor.py | 95 + .../site-packages/psycopg/connection.py | 1031 ++++++ .../site-packages/psycopg/connection_async.py | 431 +++ .../site-packages/psycopg/conninfo.py | 378 ++ lib/python3.11/site-packages/psycopg/copy.py | 902 +++++ .../site-packages/psycopg/crdb/__init__.py | 19 + .../crdb/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 610 bytes .../crdb/__pycache__/_types.cpython-311.pyc | Bin 0 -> 9698 bytes .../__pycache__/connection.cpython-311.pyc | Bin 0 -> 9138 bytes .../site-packages/psycopg/crdb/_types.py | 163 + .../site-packages/psycopg/crdb/connection.py | 185 + .../site-packages/psycopg/cursor.py | 915 +++++ .../site-packages/psycopg/cursor_async.py | 249 ++ .../site-packages/psycopg/dbapi20.py | 112 + .../site-packages/psycopg/errors.py | 1544 +++++++++ .../site-packages/psycopg/generators.py | 320 ++ .../site-packages/psycopg/postgres.py | 124 + .../site-packages/psycopg/pq/__init__.py | 133 + .../pq/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4700 bytes .../pq/__pycache__/_debug.cpython-311.pyc | Bin 0 -> 5922 bytes .../pq/__pycache__/_enums.cpython-311.pyc | Bin 0 -> 6174 bytes .../pq/__pycache__/_pq_ctypes.cpython-311.pyc | Bin 0 -> 21077 bytes .../pq/__pycache__/abc.cpython-311.pyc | Bin 0 -> 19510 bytes .../pq/__pycache__/misc.cpython-311.pyc | Bin 0 -> 6878 bytes .../pq/__pycache__/pq_ctypes.cpython-311.pyc | Bin 0 -> 59538 bytes .../site-packages/psycopg/pq/_debug.py | 106 + .../site-packages/psycopg/pq/_enums.py | 249 ++ .../site-packages/psycopg/pq/_pq_ctypes.py | 804 +++++ .../site-packages/psycopg/pq/abc.py | 384 +++ .../site-packages/psycopg/pq/misc.py | 146 + .../site-packages/psycopg/pq/pq_ctypes.py | 1088 ++++++ lib/python3.11/site-packages/psycopg/py.typed | 0 lib/python3.11/site-packages/psycopg/rows.py | 256 ++ .../site-packages/psycopg/server_cursor.py | 478 +++ lib/python3.11/site-packages/psycopg/sql.py | 467 +++ .../site-packages/psycopg/transaction.py | 290 ++ .../site-packages/psycopg/types/__init__.py | 11 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 354 bytes .../types/__pycache__/array.cpython-311.pyc | Bin 0 -> 24560 bytes .../types/__pycache__/bool.cpython-311.pyc | Bin 0 -> 3220 bytes .../__pycache__/composite.cpython-311.pyc | Bin 0 -> 16560 bytes .../__pycache__/datetime.cpython-311.pyc | Bin 0 -> 43745 bytes .../types/__pycache__/enum.cpython-311.pyc | Bin 0 -> 9444 bytes .../types/__pycache__/hstore.cpython-311.pyc | Bin 0 -> 6478 bytes .../types/__pycache__/json.cpython-311.pyc | Bin 0 -> 12165 bytes .../__pycache__/multirange.cpython-311.pyc | Bin 0 -> 29067 bytes .../types/__pycache__/net.cpython-311.pyc | Bin 0 -> 13103 bytes .../types/__pycache__/none.cpython-311.pyc | Bin 0 -> 1517 bytes .../types/__pycache__/numeric.cpython-311.pyc | Bin 0 -> 27107 bytes .../types/__pycache__/range.cpython-311.pyc | Bin 0 -> 34417 bytes .../types/__pycache__/shapely.cpython-311.pyc | Bin 0 -> 4764 bytes .../types/__pycache__/string.cpython-311.pyc | Bin 0 -> 13683 bytes .../types/__pycache__/uuid.cpython-311.pyc | Bin 0 -> 4042 bytes .../site-packages/psycopg/types/array.py | 460 +++ .../site-packages/psycopg/types/bool.py | 48 + .../site-packages/psycopg/types/composite.py | 292 ++ .../site-packages/psycopg/types/datetime.py | 730 ++++ .../site-packages/psycopg/types/enum.py | 177 + .../site-packages/psycopg/types/hstore.py | 130 + .../site-packages/psycopg/types/json.py | 228 ++ .../site-packages/psycopg/types/multirange.py | 511 +++ .../site-packages/psycopg/types/net.py | 201 ++ .../site-packages/psycopg/types/none.py | 25 + .../site-packages/psycopg/types/numeric.py | 495 +++ .../site-packages/psycopg/types/range.py | 698 ++++ .../site-packages/psycopg/types/shapely.py | 75 + .../site-packages/psycopg/types/string.py | 229 ++ .../site-packages/psycopg/types/uuid.py | 62 + .../site-packages/psycopg/version.py | 14 + .../site-packages/psycopg/waiting.py | 324 ++ .../INSTALLER | 1 + .../typing_extensions-4.7.1.dist-info/LICENSE | 279 ++ .../METADATA | 69 + .../typing_extensions-4.7.1.dist-info/RECORD | 7 + .../typing_extensions-4.7.1.dist-info/WHEEL | 4 + .../site-packages/typing_extensions.py | 3072 +++++++++++++++++ .../__pycache__/settings.cpython-311.pyc | Bin 2725 -> 2849 bytes templates/anmeldung.html | 4 +- templates/datenschutz.html | 57 +- templates/drama.html | 2 +- templates/footer.html | 5 +- templates/impressum.html | 6 +- templates/ueber.html | 2 - website/__pycache__/views.cpython-311.pyc | Bin 6230 -> 8074 bytes website/views.py | 24 +- 700 files changed, 23092 insertions(+), 97 deletions(-) create mode 100644 lib/python3.11/site-packages/__pycache__/typing_extensions.cpython-311.pyc rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/AUTHORS.txt (99%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/INSTALLER (100%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/LICENSE.txt (100%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/METADATA (97%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/RECORD (97%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/REQUESTED (100%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/WHEEL (100%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/entry_points.txt (100%) rename lib/python3.11/site-packages/{pip-23.2.dist-info => pip-23.2.1.dist-info}/top_level.txt (100%) create mode 100644 lib/python3.11/site-packages/psycopg-3.1.9.dist-info/INSTALLER create mode 100644 lib/python3.11/site-packages/psycopg-3.1.9.dist-info/LICENSE.txt create mode 100644 lib/python3.11/site-packages/psycopg-3.1.9.dist-info/METADATA create mode 100644 lib/python3.11/site-packages/psycopg-3.1.9.dist-info/RECORD create mode 100644 lib/python3.11/site-packages/psycopg-3.1.9.dist-info/REQUESTED create mode 100644 lib/python3.11/site-packages/psycopg-3.1.9.dist-info/WHEEL create mode 100644 lib/python3.11/site-packages/psycopg-3.1.9.dist-info/top_level.txt create mode 100644 lib/python3.11/site-packages/psycopg/__init__.py create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/__init__.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_adapters_map.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_cmodule.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_column.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_compat.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_dns.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_encodings.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_enums.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_pipeline.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_preparing.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_queries.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_struct.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_tpc.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_transform.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_typeinfo.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_tz.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/_wrappers.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/abc.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/adapt.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/client_cursor.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/connection.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/connection_async.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/conninfo.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/copy.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/cursor.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/cursor_async.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/dbapi20.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/errors.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/generators.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/postgres.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/rows.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/server_cursor.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/sql.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/transaction.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/version.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/__pycache__/waiting.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/_adapters_map.py create mode 100644 lib/python3.11/site-packages/psycopg/_cmodule.py create mode 100644 lib/python3.11/site-packages/psycopg/_column.py create mode 100644 lib/python3.11/site-packages/psycopg/_compat.py create mode 100644 lib/python3.11/site-packages/psycopg/_dns.py create mode 100644 lib/python3.11/site-packages/psycopg/_encodings.py create mode 100644 lib/python3.11/site-packages/psycopg/_enums.py create mode 100644 lib/python3.11/site-packages/psycopg/_pipeline.py create mode 100644 lib/python3.11/site-packages/psycopg/_preparing.py create mode 100644 lib/python3.11/site-packages/psycopg/_queries.py create mode 100644 lib/python3.11/site-packages/psycopg/_struct.py create mode 100644 lib/python3.11/site-packages/psycopg/_tpc.py create mode 100644 lib/python3.11/site-packages/psycopg/_transform.py create mode 100644 lib/python3.11/site-packages/psycopg/_typeinfo.py create mode 100644 lib/python3.11/site-packages/psycopg/_tz.py create mode 100644 lib/python3.11/site-packages/psycopg/_wrappers.py create mode 100644 lib/python3.11/site-packages/psycopg/abc.py create mode 100644 lib/python3.11/site-packages/psycopg/adapt.py create mode 100644 lib/python3.11/site-packages/psycopg/client_cursor.py create mode 100644 lib/python3.11/site-packages/psycopg/connection.py create mode 100644 lib/python3.11/site-packages/psycopg/connection_async.py create mode 100644 lib/python3.11/site-packages/psycopg/conninfo.py create mode 100644 lib/python3.11/site-packages/psycopg/copy.py create mode 100644 lib/python3.11/site-packages/psycopg/crdb/__init__.py create mode 100644 lib/python3.11/site-packages/psycopg/crdb/__pycache__/__init__.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/crdb/__pycache__/_types.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/crdb/__pycache__/connection.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/crdb/_types.py create mode 100644 lib/python3.11/site-packages/psycopg/crdb/connection.py create mode 100644 lib/python3.11/site-packages/psycopg/cursor.py create mode 100644 lib/python3.11/site-packages/psycopg/cursor_async.py create mode 100644 lib/python3.11/site-packages/psycopg/dbapi20.py create mode 100644 lib/python3.11/site-packages/psycopg/errors.py create mode 100644 lib/python3.11/site-packages/psycopg/generators.py create mode 100644 lib/python3.11/site-packages/psycopg/postgres.py create mode 100644 lib/python3.11/site-packages/psycopg/pq/__init__.py create mode 100644 lib/python3.11/site-packages/psycopg/pq/__pycache__/__init__.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/pq/__pycache__/_debug.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/pq/__pycache__/_enums.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/pq/__pycache__/_pq_ctypes.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/pq/__pycache__/abc.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/pq/__pycache__/misc.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/pq/__pycache__/pq_ctypes.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/pq/_debug.py create mode 100644 lib/python3.11/site-packages/psycopg/pq/_enums.py create mode 100644 lib/python3.11/site-packages/psycopg/pq/_pq_ctypes.py create mode 100644 lib/python3.11/site-packages/psycopg/pq/abc.py create mode 100644 lib/python3.11/site-packages/psycopg/pq/misc.py create mode 100644 lib/python3.11/site-packages/psycopg/pq/pq_ctypes.py create mode 100644 lib/python3.11/site-packages/psycopg/py.typed create mode 100644 lib/python3.11/site-packages/psycopg/rows.py create mode 100644 lib/python3.11/site-packages/psycopg/server_cursor.py create mode 100644 lib/python3.11/site-packages/psycopg/sql.py create mode 100644 lib/python3.11/site-packages/psycopg/transaction.py create mode 100644 lib/python3.11/site-packages/psycopg/types/__init__.py create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/__init__.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/array.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/bool.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/composite.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/datetime.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/enum.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/hstore.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/json.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/multirange.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/net.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/none.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/numeric.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/range.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/shapely.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/string.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/__pycache__/uuid.cpython-311.pyc create mode 100644 lib/python3.11/site-packages/psycopg/types/array.py create mode 100644 lib/python3.11/site-packages/psycopg/types/bool.py create mode 100644 lib/python3.11/site-packages/psycopg/types/composite.py create mode 100644 lib/python3.11/site-packages/psycopg/types/datetime.py create mode 100644 lib/python3.11/site-packages/psycopg/types/enum.py create mode 100644 lib/python3.11/site-packages/psycopg/types/hstore.py create mode 100644 lib/python3.11/site-packages/psycopg/types/json.py create mode 100644 lib/python3.11/site-packages/psycopg/types/multirange.py create mode 100644 lib/python3.11/site-packages/psycopg/types/net.py create mode 100644 lib/python3.11/site-packages/psycopg/types/none.py create mode 100644 lib/python3.11/site-packages/psycopg/types/numeric.py create mode 100644 lib/python3.11/site-packages/psycopg/types/range.py create mode 100644 lib/python3.11/site-packages/psycopg/types/shapely.py create mode 100644 lib/python3.11/site-packages/psycopg/types/string.py create mode 100644 lib/python3.11/site-packages/psycopg/types/uuid.py create mode 100644 lib/python3.11/site-packages/psycopg/version.py create mode 100644 lib/python3.11/site-packages/psycopg/waiting.py create mode 100644 lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/INSTALLER create mode 100644 lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/LICENSE create mode 100644 lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/METADATA create mode 100644 lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/RECORD create mode 100644 lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/WHEEL create mode 100644 lib/python3.11/site-packages/typing_extensions.py diff --git a/lib/python3.11/site-packages/__pycache__/typing_extensions.cpython-311.pyc b/lib/python3.11/site-packages/__pycache__/typing_extensions.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ffd1b0cd4fc4389635017927abd6ce366e0e2d25 GIT binary patch literal 131518 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/django/conf/urls/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/django/conf/urls/__pycache__/__init__.cpython-311.pyc index 70f2a0a7e793975e8d1db3da04e27ade20f6d22a..2235887eb2a14a7409b01163a7094e68830ccca7 100644 GIT binary patch delta 20 acmZ3_vYv%|IWI340}yOowReu15PIWI340}yOowReu15PIWI340}$lg-?owaC^G;&ZUzbf diff --git a/lib/python3.11/site-packages/django/contrib/admin/migrations/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/admin/migrations/__pycache__/__init__.cpython-311.pyc index 03aee7aec524d45f2acf1befa10cc5404fcb1e83..4c170f9005ffc5a7fdd2855c242f2afcaccc2776 100644 GIT binary patch delta 19 ZcmX@hc$SfSIWI340}yOowRApkXs1?vC+ delta 19 ZcmX@hc$SfSIWI340}$lg-!_r^5CAmE1=0Wj diff --git a/lib/python3.11/site-packages/django/contrib/auth/__pycache__/decorators.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/__pycache__/decorators.cpython-311.pyc index f391b7bef09640677b2aa4cfd831a0be5e288df4..b4f5d68d1f6b4ce788cbd1440564ed1b8ff7d96d 100644 GIT binary patch delta 20 acmZ21w^)vQIWI340}yOowRchy_*v delta 20 acmZ21w^)vQIWI340}$lg-?oukf*$}kt_3{+ diff --git a/lib/python3.11/site-packages/django/contrib/auth/__pycache__/views.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/__pycache__/views.cpython-311.pyc index ac3057235517375b422d92e18bf7eee09131e1eb..3ce144765663cc4e4b6a361481f320314018c57c 100644 GIT binary patch delta 22 ccmeyrjPd_6M(*Xjyj%=Guyxh$joc-{0AFGUzyJUM delta 22 ccmeyrjPd_6M(*Xjyj%=GkaK_AM(&be0A7d(rvLx| diff --git a/lib/python3.11/site-packages/django/contrib/auth/management/commands/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/management/commands/__pycache__/__init__.cpython-311.pyc index 9abdba8bc167af2e2c1412f7b9cf5a28f10b5eb5..3f1b65a0a21fb3b5457f64d7f964fc886dbd7fe8 100644 GIT binary patch delta 19 Zcmcc0c$JZRIWI340}yOowRDF8OI1_J;9 delta 19 Zcmcc0c$JZRIWI340}$lg-!_r^6aY2x1?m6* diff --git a/lib/python3.11/site-packages/django/contrib/auth/management/commands/__pycache__/createsuperuser.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/management/commands/__pycache__/createsuperuser.cpython-311.pyc index d79d4fef335360aaf68013257476afc8260b4dd5..ef5876062d4253bd8d9a096e9346c1c5148ffec4 100644 GIT binary patch delta 20 acmX?DcCd_lIWI340}yOowRIQQF diff --git a/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0001_initial.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0001_initial.cpython-311.pyc index 591877a56e9531ce5bb53e35c6120f6837d55df6..3956893bbd30eb23a9350e16f9ecfa3616473e99 100644 GIT binary patch delta 20 acmZoxYgXf4&dbZi00diC?cT`!LkIvis|E=G delta 20 acmZoxYgXf4&dbZi00cSrw{7J9Ap`(5(FO1T diff --git a/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0002_alter_permission_name_max_length.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0002_alter_permission_name_max_length.cpython-311.pyc index a6cd5c04a2df3cd844e9be3012e60df7b9e2720d..5cb0366eba78c0abc743b4b04abc4809b86d0585 100644 GIT binary patch delta 20 acmcc1c9)HNIWI340}yOowRDEyNCjg6 delta 20 acmbQhK7pNkIWI340}$lg-?ovvl^FmsZUssJ diff --git a/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0004_alter_user_username_opts.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0004_alter_user_username_opts.cpython-311.pyc index 17932f70b577ccbc07ab879f9a924804d06e36f0..6f4203b54f4896491ba3b693af926d6128a1b80b 100644 GIT binary patch delta 20 acmX@ed61KPIWI340}yOowRd4ZFAIWI340}yOowRd4ZFAIWI340}$lg-?owaC<_2Qw+0UY diff --git a/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0009_alter_user_last_name_max_length.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0009_alter_user_last_name_max_length.cpython-311.pyc index 473fa1841ac2a03d6e61c489aae9a94141d97f56..e2ff853dde1e00797cb2405e06069c23305a59cf 100644 GIT binary patch delta 20 acmbQpK9QY!IWI340}yOowR6a`}d diff --git a/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0012_alter_user_first_name_max_length.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/0012_alter_user_first_name_max_length.cpython-311.pyc index 5989ff79392bc9561e1009ebc7c16438dced0d06..3b392e9a0d15a9344d7626b0d9556aad09e86151 100644 GIT binary patch delta 20 acmeBU?_=j)&dbZi00diC?cT`U%nSfB_yt`6 delta 20 acmeBU?_=j)&dbZi00cSrw{7HZW(EK<9tA`I diff --git a/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/auth/migrations/__pycache__/__init__.cpython-311.pyc index e71566c069095ecd4ab10e3399e8ee6ff2242f39..bc7f9ed7d720bd3fd7cb969f632159e2135d0338 100644 GIT binary patch delta 19 ZcmX@Zc!rUCIWI340}yOowRK>#&n1?T_( delta 19 ZcmX@Zc!rUCIWI340}$lg-!_r^AOJL^1NdPvD1^@s6 delta 19 Zcmcb@c!iOBIWI340}$lg-!_r^Bmgzc1?K<& diff --git a/lib/python3.11/site-packages/django/contrib/sessions/migrations/__pycache__/0001_initial.cpython-311.pyc b/lib/python3.11/site-packages/django/contrib/sessions/migrations/__pycache__/0001_initial.cpython-311.pyc index c18566df9418249e87b367c83ada1dff2454e36b..19f2d777a21e8a4d04b72765b0a18a2d25309203 100644 GIT binary patch delta 20 acmdnNy@Q*3IWI340}yOowRc!807IWI340}yOowRQ2;gh1@r&_ delta 19 Zcmcb>c!807IWI340}$li-!_r^C;&A+1>67t diff --git a/lib/python3.11/site-packages/django/core/cache/backends/__pycache__/locmem.cpython-311.pyc b/lib/python3.11/site-packages/django/core/cache/backends/__pycache__/locmem.cpython-311.pyc index 7942144d55412acfa0dce9b8f57b350fcd8dae0f..14f5b8d39d33134e1167ca402193abc3fdd17b51 100644 GIT binary patch delta 20 acmX@GzO6X diff --git a/lib/python3.11/site-packages/django/core/mail/backends/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/django/core/mail/backends/__pycache__/__init__.cpython-311.pyc index e479e39963c4a0a1ab42d38b32fb05ad504e0a71..7c88da0a1b424dbae0078302d549b512760eee0a 100644 GIT binary patch delta 19 ZcmX@kc$|@YIWI340}yOowR9so3~1=#=q delta 19 ZcmX@kc$|@YIWI340}$li-!_qZ4*)aq1;GFS diff --git a/lib/python3.11/site-packages/django/core/mail/backends/__pycache__/base.cpython-311.pyc b/lib/python3.11/site-packages/django/core/mail/backends/__pycache__/base.cpython-311.pyc index 67ca205550730bf057ed8de7a24a84060f287b90..f6abebb00ae53d9294a6ea5203dbf7a1a869bcc9 100644 GIT binary patch delta 20 acmZ1_wn~h9IWI340}yOowR0RS~X1?2z$ delta 19 ZcmX@jc$$%WIWI340}$li-!_r^001pbyA9ZIWI340}yOowRpbyA9ZIWI340}$li-?ow4ju!wu69uLK diff --git a/lib/python3.11/site-packages/django/db/backends/postgresql/__pycache__/creation.cpython-311.pyc b/lib/python3.11/site-packages/django/db/backends/postgresql/__pycache__/creation.cpython-311.pyc index 41920b1b6e39fc0b64220bac3bfa6c3f240bc3b4..faf9c5ae322e704a251d89fa77dc9c547c74e154 100644 GIT binary patch delta 20 acmX@7eNLNuIWI340}yOowR0Z^g`CjbBd delta 22 ccmZ3om~qKsM(*Xjyj%=Gkb8gIM(&w`08h^c4*&oF diff --git a/lib/python3.11/site-packages/django/db/backends/postgresql/__pycache__/psycopg_any.cpython-311.pyc b/lib/python3.11/site-packages/django/db/backends/postgresql/__pycache__/psycopg_any.cpython-311.pyc index 71144c792d23d69b9749fb9810804c4f06a00455..869dffec198b87cb30398b6b401e14907d532eef 100644 GIT binary patch delta 20 acmeA->^J0I&dbZi00diC?cT`UA^`w79R^J0I&dbZi00g=Bw{7HZkpKWVN(He1 diff --git a/lib/python3.11/site-packages/django/db/backends/postgresql/__pycache__/schema.cpython-311.pyc b/lib/python3.11/site-packages/django/db/backends/postgresql/__pycache__/schema.cpython-311.pyc index 282deaf0b5b564f88f819f696f869674319a8b23..1e49bfff4e0efbcdf1816663401d69a373176e0a 100644 GIT binary patch delta 20 acmbPVI=_^AIWI340}yOowRPx# delta 22 ccmdltk8$5TM(*Xjyj%=Gkb8gIMs8z&08(fM(EtDd diff --git a/lib/python3.11/site-packages/django/db/migrations/__pycache__/graph.cpython-311.pyc b/lib/python3.11/site-packages/django/db/migrations/__pycache__/graph.cpython-311.pyc index bf5a9b0b645e1407fd364835491d3ff85ec475b9..b566f61484fd51715a0874149ad11fdafa2612ea 100644 GIT binary patch delta 22 ccmeC1$=ElOk$X8WFBbz4Y+bc`BX_e8083>C%m4rY delta 22 ccmeC1$=ElOk$X8WFBbz4$neo_UM(*Xjyj%=Guyxh$joiCE0aM@yWdHyG delta 22 ccmX>$neo_UM(*Xjyj%=Gkb8gIM(*9708 int: diff --git a/lib/python3.11/site-packages/pip/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/__pycache__/__init__.cpython-311.pyc index 7cb920c54c5792fc5c510a8369130f307bc489f9..9f2ee967ad65d542c9238b2e3ddff57f9ecb19f6 100644 GIT binary patch delta 39 tcmeyv`j3@&IWI340}zCoA4o}^$Xm_MW@M~qq-VIXSC@%VZ1QdaX diff --git a/lib/python3.11/site-packages/pip/__pycache__/__pip-runner__.cpython-311.pyc b/lib/python3.11/site-packages/pip/__pycache__/__pip-runner__.cpython-311.pyc index c2b35e132cc1a3af7e345414dc50fa10143c8832..454f25b14ad2ba20b7e251efae35f0bf7cd18b42 100644 GIT binary patch delta 20 acmX>ud|a4&IWI340}zCoAK1vfhZ6ueT?JSG delta 20 acmX>ud|a4&IWI340}xc+-?ou^4<`UU7X}&t diff --git a/lib/python3.11/site-packages/pip/_internal/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/__pycache__/__init__.cpython-311.pyc index 5748dc2b6c8b546b7ea7803744c5127e8fa43e3c..e438f9d8bdd2e4d0949ccdda4d74b6d189af343c 100644 GIT binary patch delta 20 acmdnWzLlMOIWI340}zCoAK1vfiWvYi*98Os delta 20 acmdnWzLlMOIWI340}xc+-?ou^6*B-hkp;#8 diff --git a/lib/python3.11/site-packages/pip/_internal/__pycache__/build_env.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/__pycache__/build_env.cpython-311.pyc index 81f75bcd7c4414b06eac9cf2f9001b331525f4b2..631f1113ad6d3e672992d533f04779f6b5e45f4d 100644 GIT binary patch delta 20 acmX?Fd$g8&IWI340}zCoAK1vf%MJiXDh68s delta 20 acmX?Fd$g8&IWI340}xc+-?ou^mmL600% diff --git a/lib/python3.11/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-311.pyc index da3a88445e44be42b47ebe287fc4df573e26f12d..f5199c827a0e0ee9b14234fe3b985af3ffe1e1fd 100644 GIT binary patch delta 20 acmdlUu|0x&IWI340}zCoAK1vPqXPgwv;|cF delta 20 acmdlUu|0x&IWI340}xc+-?oukM+X2yZUz?s diff --git a/lib/python3.11/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-311.pyc index 1aee2375cd2fdd9b63ca08b7dc2dc6bcded7680d..a995d8a43ba178d541182b9c33f0b9310a3818e1 100644 GIT binary patch delta 20 acmbPQKDC^CIWI340}zCoAK1v3_MIWI340}zCoAK1t($Or%~IRq^L delta 20 acmbQkG>3_MIWI340}xc+-?oukkP!ef^91hz diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-311.pyc index ee2de183d89401535068859747b84aae930dacad..db414562cf90b56eaa88a4173bde5d4fff0f4840 100644 GIT binary patch delta 20 acmccRcgv4^IWI340}zCoAK1w4uMPl0zXhcL delta 20 acmccRcgv4^IWI340}xc+-?ow4UmXBPc?M?y diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-311.pyc index c025b5327c8f0d43aa54f6806308ac8e1a655018..fc7978c766935dd415b09d1831baae139d29c958 100644 GIT binary patch delta 20 acmX>Wb1a5?IWI340}zCoAK1uktp@->o&}5m delta 20 acmX>Wb1a5?IWI340}xc+-?ow4S`Pq5SO!i2 diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-311.pyc index 49dec06fb54e112ccc1343346ef8eddc4894fe8d..73b113c29b6c181031120822d6b1d5842ca6871f 100644 GIT binary patch delta 22 ccmccE&UCSziF-LOFBbz4gqk1N$bGCC08a}B+yDRo delta 22 ccmccE&UCSziF-LOFBbz4RNmjVk^5LP08_;Wo&W#< diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-311.pyc index c749bee1d2e9cee571f35f3a05b12eae545878ad..c9e8e0a79724dcf394049e99e1bc511006ccfeed 100644 GIT binary patch delta 20 acmdlbuuFh@IWI340}zCoAK1vP&jA25=me?& delta 20 acmdlbuuFh@IWI340}xc+-?oukp926nq6KUK diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/main.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/main.cpython-311.pyc index ce8273f82a94ff168ef7a47a572ea025b154aef9..78b84e9e7cd00641ef0be32a9152e504c948246d 100644 GIT binary patch delta 20 acmbOrGC_oUIWI340}zCoAK1vv$^`%}>I60b delta 20 acmbOrGC_oUIWI340}xc+-?ovPl?wnfqy+c? diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-311.pyc index b0417d258ed736f6e90c198c1f9cb71e87dcd03d..7e835d27b5cd30dd507c1aeee8e2d007415caad7 100644 GIT binary patch delta 20 acmbQBJwcm$IWI340}zCoAK1v>jkj@ diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/parser.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/parser.cpython-311.pyc index 00d42ea0a971e1ed5a1f888cca242246de790e86..dc1b4356051163c8042e95f136fa624a4b71b8f2 100644 GIT binary patch delta 22 ccmey{!uYp^k$X8WFBbz4gqk1N$X(xSFBL+O%aRl&LKONtK}*sCPXqbz+`!u?=`4&J207MliR<8ZK%_<}4JKTcq$$ZwnZ|8|OtQH-8i_vx zrh-kh=4#P<+61db`>74wp&@&k??{|%ZR>B552 z^tDQ-T048C3AWs0W!Mg7#VvV1nVlnwm-s?&y?d5TxhXzxnJ?aaQrmo^Jj@g~8htxQ z52svS(3iA1QtqJQ;RSA;Fl-DT_X}%IYtKpv=__tyXYd=P2)cT!6KHD) z^-X+3`wo|5&GZwj#YX5oXg|;;PT?~CfKmp+gIGiu5pKjP;xi%(@dK;}$A`-F?1M0T zbml913=AaGsTk2r#JNk!K;uZJTQQ?qh~2AL(QL%&R(Ldls2b-$LfvVU{g6UtYW*4@HfwMdZAOri&oR-v2PQI>*T6bd2e zq4WtO9V>@#v&PsVL>pKk3Dq$*#}?jFz4g@&;S4DaAqboNv9{N z^|8ew5k9W2B_b0?=dDM|B^wV#KL51C>GA@&WzB=kMq5o>ib)aSf`HYmG$O`?^SWak zC2=_>v-}YwM(F{!5AK00MyGk8Bw~om5fL&f6gW|DgVu^}mmD+Cn5Ha*O!Ju@oy2E` zM8!#vD_3bNY*rqo7AW(N!lJ){X2EZNlP6_oeZzwnqkXI=+RM)M4verTym>f_15Q=- zcsIC=5v`CE`Iif8ljefYw!KMPRr-OIs!k!l2x_a(I<*3;UD_fX+X#(V)u+{$1+U6C zV0RICxptq-o?~zyF$?u|HMuWP=MeLVmxu+3)!i_@;+onI59{)vSn(X%X$)b_EMgL| z+Yb7<3z%I*JcGE>L0i;%0t@u5 zdb7bq?XR)93E@Vl@F*ChA7L#Rrk`M6sFZ$y^A@a diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-311.pyc index daf50e829fb83c6fd534bd5d6072ddfa2196bb1c..78062b92282ec731d6c338ed52d587235c0e4b21 100644 GIT binary patch delta 20 acmZp4ZFJ>c&dbZi00g1t2R3q-DFFa9js*h% delta 20 acmZp4ZFJ>c&dbZi00foyw{7GuQvv`vNCm|J diff --git a/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-311.pyc index f9bb35448e8bc3f9814389a68a55dca5291a3162..10f035f9f3c039f723e2037dd703b5f73c7e0015 100644 GIT binary patch delta 20 acmeyu^o5CgIWI340}zCoAK1v9$p`>D`2{rq delta 20 acmeyu^o5CgIWI340}xc+-?ouElMw(wvjz76 diff --git a/lib/python3.11/site-packages/pip/_internal/cli/req_command.py b/lib/python3.11/site-packages/pip/_internal/cli/req_command.py index c2f4e38..86070f1 100644 --- a/lib/python3.11/site-packages/pip/_internal/cli/req_command.py +++ b/lib/python3.11/site-packages/pip/_internal/cli/req_command.py @@ -287,6 +287,7 @@ class RequirementCommand(IndexGroupCommand): """ temp_build_dir_path = temp_build_dir.path assert temp_build_dir_path is not None + legacy_resolver = False resolver_variant = cls.determine_resolver_variant(options) if resolver_variant == "2020-resolver": @@ -300,6 +301,7 @@ class RequirementCommand(IndexGroupCommand): "production." ) else: + legacy_resolver = True lazy_wheel = False if "fast-deps" in options.features_enabled: logger.warning( @@ -320,6 +322,7 @@ class RequirementCommand(IndexGroupCommand): use_user_site=use_user_site, lazy_wheel=lazy_wheel, verbosity=verbosity, + legacy_resolver=legacy_resolver, ) @classmethod diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pyc index 3af42026e6c090528c92fc99a88629ef762ddbda..78707757ffe8cf757765017bce8e78aeeefdae8d 100644 GIT binary patch delta 20 acmaE&^hAk!IWI340}zCoAK1tpDF^^Q2?bRE delta 20 acmaE&^hAk!IWI340}xc+-?ouEQV;+_!v+@s diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pyc index dfcc1354c8382d4a7cbc9f084cd3bafbedcccc87..26618bbf7f0b30b5681b8c998a0bb42a4a277b90 100644 GIT binary patch delta 20 acmdlUv^|J>IWI340}zCoAK1vPqX_^#*#$-b delta 20 acmdlUv^|J>IWI340}xc+-?oukM-u=-lLiO? diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pyc index 1b636ef8fbccfb65a942e6b293f2d75ce7aded37..271e56e20efa903cf77ec3ec787345c3cef57f11 100644 GIT binary patch delta 20 acmaDZ^jwI0IWI340}zCoAK1tp!wCR9IR!QV delta 20 acmaDZ^jwI0IWI340}xc+-?ouEh7$ll^9A?- diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pyc index 298f73628aecba1d8044479a49e3b6d3b73a032c..4b97f5e7f018a2c1ebc8af507c05ba99fda3469f 100644 GIT binary patch delta 20 acmX@Ac~p~oIWI340}zCoAK1vfO9TKrFa?PK delta 20 acmX@Ac~p~oIWI340}xc+-?ou^mk0nq>IO>y diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pyc index d92549895141fa3542e6acd91df3403eb644e7da..3b5b9afc74c428456d337fc80d8969b7e75e9aa2 100644 GIT binary patch delta 20 acmZ2mvbKbKIWI340}zCoAK1vPWCZ|0A_aW_ delta 20 acmZ2mvbKbKIWI340}xc+-?ouk$qE2P+y*}Y diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pyc index eaf0ae5f71830ded63b8588fa064f07c4e853dc0..cf809b8ff55da4710929cca3be0fa832a5aed284 100644 GIT binary patch delta 20 acmaDD`!JS!IWI340}zCoAK1u!O%DJ@`UYPB delta 20 acmaDD`!JS!IWI340}xc+-?owanjQd4vmE!;{^i% delta 20 acmZ3-zmA`KIWI340}xc+-?ou^F*^V_odv}J diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pyc index e4403bf0ad646669bb3c4f299fc124271ecda0d1..feb097ea623bbc4c4bee478ad0b7a0da79c8f65f 100644 GIT binary patch delta 20 acmaEB^VWuYIWI340}zCoAK1v9BnJRPCIzto delta 20 acmaEB^VWuYIWI340}xc+-?ouENe%!<;0AL5 diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pyc index dd8efdf98edfe7343ee7fb4170213135f3b82ccb..569cefe0734184d1f65922e9c140e699b4b3002f 100644 GIT binary patch delta 20 acmcbmbW4eQIWI340}zCoAK1w4F9-lUc?CBB delta 20 acmcbmbW4eQIWI340}xc+-?ow4Ul0I6GX?no diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pyc index 19048499a29f190747fad93bf1f6439b9791e019..3b47ae2f28685de26c83b5ba61d651c2735aeeed 100644 GIT binary patch delta 22 ccmaF-nep*wM(*Xjyj%=G5Ndv4BlnF;0Af}L-T(jq delta 22 ccmaF-nep*wM(*Xjyj%=GP diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pyc index 7838bf03bed256c9185faa4e31f68e6e293cabdb..89436137a38d43a404ed1ff7ae8125d7eeeaa1e9 100644 GIT binary patch delta 22 ccmdnf#<-`Ak$X8WFBbz4gqk1N$ZhBh07>`-*#H0l delta 22 ccmdnf#<-`Ak$X8WFBbz4RNmjVk=xK208X+7n*aa+ diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pyc index 3842f3ba05d67dc9f9cc3f1ccf8df6c2b9b292a6..395748868384508a66bfb4e44b742de438766049 100644 GIT binary patch delta 20 acmez3`o)!dIWI340}zCoAK1wKQV9S?h6Y>! delta 20 acmez3`o)!dIWI340}xc+-?owar4j&3KnETG diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pyc index 627fd626929a15049c2c8b129c1aad3433fe6953..6dcee456735341cc2cff956522dacf0fdeb5d08a 100644 GIT binary patch delta 20 acmbOoF*|~LIWI340}zCoAK1t(paTFpR0RP5 delta 20 acmbOoF*|~LIWI340}xc+-?oukKnDOn4h6#i diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pyc index 5991b7ee1ef17059831173eb75d0b054f994367e..b8b1725067a49f8839bba9df73d3591c19be9454 100644 GIT binary patch delta 20 acmbQHF-?PeIWI340}zCoAK1vvEdl^Cv;=wp delta 20 acmbQHF-?PeIWI340}xc+-?ovPTLb_%ZUsC5 diff --git a/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pyc index 2959e89383d01c4d8f2fbd986ecaa646a6be9129..8399e07332d92ad5a9b7110701fa07d7d05c841b 100644 GIT binary patch delta 20 acmdnyxy_S%IWI340}zCoAK1vfS_J?-Xa%eQ delta 20 acmdnyxy_S%IWI340}xc+-?ou^wF&@2A_i^% diff --git a/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-311.pyc index 427134f94db4a117ebd548bec41734e5b7801b61..0bdd8478b974436025eda6c54bad25bcb932ab34 100644 GIT binary patch delta 20 acmeC;=;GjB&dbZi00g1t2R3s5X9fT+Lj?r@ delta 20 acmeC;=;GjB&dbZi00foyw{7J9&kO)E{RPJW diff --git a/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/base.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/base.cpython-311.pyc index 5aaf91f0891185147b9e53d9cb98b329186b86f3..353d4b41e2dde42274b08d49260188ed351350e2 100644 GIT binary patch delta 20 acmaDR^h}6*IWI340}zCoAK1tp%?SWJ5d|{< delta 20 acmaDR^h}6*IWI340}xc+-?ouEniBv(%LVlS diff --git a/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-311.pyc index c72cd5f0210b434a0d71eeaef0167c895368ce77..3f49964c2a09b875cf52182a4e0ea1ca55bd82eb 100644 GIT binary patch delta 20 acmZqYY3Jcy&dbZi00g1t2R3s5VFds#T?GaJ delta 20 acmZqYY3Jcy&dbZi00foyw{7J9!wLX17X`=w diff --git a/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-311.pyc index b912ed14e297ec392d9e2ce94ab49b97a04c7fac..43ce343d43f0504805032d1085d64e219e4f3f82 100644 GIT binary patch delta 20 acmez9`q7npIWI340}zCoAK1wKObGx+4hB;I delta 20 acmez9`q7npIWI340}xc+-?owanGyg>$Ojbw diff --git a/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-311.pyc index eafff0d9e0a6bfba7f20f29acf9ee5ca71b80a0d..de2bc85145a4b7d61bf2ce7154713883751404ea 100644 GIT binary patch delta 20 acmca9a8rPLIWI340}zCoAK1w4#{mF2zy${Y delta 20 acmca9a8rPLIWI340}xc+-?ow4j{^WcdIiY< diff --git a/lib/python3.11/site-packages/pip/_internal/index/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/index/__pycache__/__init__.cpython-311.pyc index 6cab8c639274f853ed94bdb1bed49c2517ac6329..f0c4545508934c566b452c0ab11a346bd8855aa7 100644 GIT binary patch delta 19 ZcmaFI_>Pf#IWI340}zCoADGDf7yvco1%Lnm delta 19 ZcmaFI_>Pf#IWI340}xc+-!_r^F#tK-20{P; diff --git a/lib/python3.11/site-packages/pip/_internal/index/__pycache__/collector.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/index/__pycache__/collector.cpython-311.pyc index 44cc7065598d5f56702193546ece1f5ed3cc18ae..c134ae72e7f921599c207d4fd6a2f5e785e8feac 100644 GIT binary patch delta 22 ccmaE`pYg$dM(*Xjyj%=G5Ndv4Blp#K09nrmQvd(} delta 22 ccmaE`pYg$dM(*Xjyj%=GPj~pt&dbZi00g1t2R3puY6Ac_vjooo delta 20 acmeAP>j~pt&dbZi00foyw{7HR)CK@NZ3U44 diff --git a/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-311.pyc index 7e8f89044fd7ef9641dc2229836f7cf2c21f4c41..e68d9888dee03560914b02cfe97b50713fc03466 100644 GIT binary patch delta 22 ccmZqZV{GVSoRa({IL07D-JH~;_u delta 22 ccmZqZV{GVSNMhB&dbZi00g1t2R3s5lK=oT7zJwp delta 20 acmeA)>NMhB&dbZi00foyw{7J9CjkIB(grO6 diff --git a/lib/python3.11/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-311.pyc index 34414ff1ca494414f45e7956024cc4887ed7d5f8..17aa5832776517c3561ff6c9020bb674e506b8ed 100644 GIT binary patch delta 20 acmaDY{aTuPIWI340}zCoAK1wKfENHiAqCg~ delta 20 acmaDY{aTuPIWI340}xc+-?owa0WSbU+Xk8d diff --git a/lib/python3.11/site-packages/pip/_internal/metadata/__pycache__/base.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/metadata/__pycache__/base.cpython-311.pyc index 9476d9eaad49b82a31baafc8129e8b7b7df9f5cc..0e1b308095a803902119e0874b334aab09c8c7d6 100644 GIT binary patch delta 22 ccmeydg6YQ!Chq0Dyj%=G5Ndv4BX{l;09mjHBme*a delta 22 ccmeydg6YQ!Chq0Dyj%=GPo#07l- diff --git a/lib/python3.11/site-packages/pip/_internal/models/__pycache__/index.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/models/__pycache__/index.cpython-311.pyc index 9325083b6a4c386cc0e198761954df06867c909b..3fec879206a1215b0553a53f29b6c0a0eeafa576 100644 GIT binary patch delta 20 acmaFK_mYo$IWI340}zCoAK1tp#|{8H_XRQl delta 20 acmaFK_mYo$IWI340}xc+-?ouEjvW9%u?6%1 diff --git a/lib/python3.11/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-311.pyc index 123547e7382813ddc843bf140404169e9b1c6f4e..3470524d0b2d6f0becf4ff39d89f872f8d886d4a 100644 GIT binary patch delta 20 acmZn=X%OLF&dbZi00g1t2R3qlIQiL diff --git a/lib/python3.11/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-311.pyc index b3edff2f3c21d0ae93d8594238dabffde0deff34..00aed3c5c4b7df803d05f1d551b2cd94c56125fd 100644 GIT binary patch delta 20 acmX@4dq|giIWI340}zCoAK1vfT?_y_N(G7l delta 20 acmX@4dq|giIWI340}xc+-?ou^yBGjK1O`k1 diff --git a/lib/python3.11/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-311.pyc index 9e6ed07dd6d2847dbf04c953be303b66d993d35b..1a594b68076e59ae2c36cd9f58e5acd133153825 100644 GIT binary patch delta 20 acmX@be~O=bIWI340}zCoAK1vfpB(@=Lj_j= delta 20 acmX@be~O=bIWI340}xc+-?ou^KRW>fB1%?0s diff --git a/lib/python3.11/site-packages/pip/_internal/network/__pycache__/auth.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/network/__pycache__/auth.cpython-311.pyc index 6b8ec75169657a39af311e1931b572ddfc3996d1..4d8703264ced0294dbf5a30ad8bc5ccb52e86aea 100644 GIT binary patch delta 22 ccmdnIn{o4QM(*Xjyj%=G5Ndv4Bln6}08yd_!TPegJ diff --git a/lib/python3.11/site-packages/pip/_internal/network/__pycache__/session.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/network/__pycache__/session.cpython-311.pyc index c6d10d503b3ffdc764fffb44fa14de06827a65ea..19c8304e4658c291404f415c01b178038762d94a 100644 GIT binary patch delta 910 zcma)3TSydP6rMBgjPA~?m<aYrzP%5>+;#*wpex+(FouX6_*(c>`GRPA7B@ruT zh(gL%;In)kyPZiZRd>4^Y&-on;%DWt|F3TSXLY>XV})X4P4BV5%^7zHP0NZT3R6j0 z5k}6P5#odk(Zob-T9kxv$({-$rCTs8Q;L#ufx*fXQ&L>o01t|jU0ha!jU^)y2^p4X zVls&YVl-@{;n=j)k5Ce!ucmq*l78Abp5_FZL=O+1K0!{9Lz7WkQi^~y% zBaLNAykrjdi=>iBk85S$MamB&h35gXwsX9 zSC0@NFY5^993h<#<@x&ijXKw!3FQv->zw)We07d*TjSktd3R=f#jSUo%JTjk@7H-h z{_Z^w4cb_55MV`1A8WT%R+B*u7RjktR6#ZP-N}6nBDbP2=W7NBcKKezOKshkrlAAh z^B<=v8n5{cuEyN2!Q9l1Ukn_AkJ|bGfWL(qg#u+_zP7$lR#aMD8Rz5XO%fO^DIcu% z0<#@m%GtydfICmWfhJ4`d!b(I3$D_Q9&^mf$!JWG(6um1L=zDixy}9uaof-^1hnfz dF^exy2HpboXPn=it7-jIbbkIz2i6M&9MTyj%=GP}lNVZ6D%G;qu+}hSF@xklpp3Cd3Youv zWwN8bs3_|)Mh1q}Knwwl3^fc3SSL4fi)fYb!UP!@Y8X>k*RU;P0xAV!2uNYC0y2O` zvQG}=5u5zMij@(pk*S1t@&RjUP84Y|puwyu9Fj2248>8zTf~XaB4tLf{hNPTvoO}* zV#z2eDbQrR#a5i0k(!(Oi&4KQ1ZZbbE|AdVxW$%}pPrstbc-c3FD<`F0VMMcNZeve zEGS6LODXyV5|IZHKY@fMThVq9`yYs40)|o1S0L*ab8d0^EzXSm;*$7+{GyU#HlUya z7)(BBtHbC%`JJt|p@_l)k&7Z~S47l0IB#%^%y79PV{(BTgl_N%T;Wl<&ZB*aM|*|m zMIN&&JZ2Yo%qCB>i)59UA=p#1`GcJ|BjdKsHV&#Re0)G_Z?P2>7vyA?6!A~acTwZH z#TAyAQ<~~pRFq#dd6tVTqrl`HE=L%5Z?1J+#>A*SS;fPF=^x|dG>=={{2)h5ft;^3 z+1t~Q@%iRjPew*JS=KPd4-6pkhKTqFW-vohbA|E}St!TT7s7bJ$@_s7p&FtGO4?06 z>UD-uYVss+J4VsX7rjp~N$Y_e%a@j!Q<7R#o>-KZnU`K%qz$rOck&j$U`CJ49R4{h dF7C{XwjUUIWI340}zCoAK1tp#|Z#Di3L0W delta 20 acmaDU^iqg>IWI340}xc+-?ouEjuQYuLk0c- diff --git a/lib/python3.11/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-311.pyc index aec0cf7365fcbc37e2d88bf7669508eb513ec39c..5591197e7af680ec7fb0dd3e2fb7862e65ec87fd 100644 GIT binary patch delta 20 acmew&@kN4rIWI340}zCoAK1v9$pZjC90hCu delta 20 acmew&@kN4rIWI340}xc+-?ouElLr7p)&?#B diff --git a/lib/python3.11/site-packages/pip/_internal/network/session.py b/lib/python3.11/site-packages/pip/_internal/network/session.py index 6c40ade..887dc14 100644 --- a/lib/python3.11/site-packages/pip/_internal/network/session.py +++ b/lib/python3.11/site-packages/pip/_internal/network/session.py @@ -419,15 +419,17 @@ class PipSession(requests.Session): msg += f" (from {source})" logger.info(msg) - host_port = parse_netloc(host) - if host_port not in self.pip_trusted_origins: - self.pip_trusted_origins.append(host_port) + parsed_host, parsed_port = parse_netloc(host) + if parsed_host is None: + raise ValueError(f"Trusted host URL must include a host part: {host!r}") + if (parsed_host, parsed_port) not in self.pip_trusted_origins: + self.pip_trusted_origins.append((parsed_host, parsed_port)) self.mount( build_url_from_netloc(host, scheme="http") + "/", self._trusted_host_adapter ) self.mount(build_url_from_netloc(host) + "/", self._trusted_host_adapter) - if not host_port[1]: + if not parsed_port: self.mount( build_url_from_netloc(host, scheme="http") + ":", self._trusted_host_adapter, diff --git a/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-311.pyc index 22cc562d2a67fb10cca781e6cff9396de2ab292e..c6a6139feb1769e387a98e2174dcd55a4cf0e93e 100644 GIT binary patch delta 19 ZcmX@cc#M&IIWI340}zCoADGC!8vrmI1qc8D delta 19 ZcmX@cc#M&IIWI340}xc+-!_qZHvlvg1UH8?&dbZi00g1t2R3puDFOgB0R*4` delta 20 acmeBm>UH8?&dbZi00foyw{7HRQUm}wy9HtZ diff --git a/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-311.pyc index d9b50ccfff4601678dbc2a393cfd561a26d1cd02..2acda6ccb6df314384cdebe2f1831f6db4b4313a 100644 GIT binary patch delta 20 acmX>Vbt;N`IWI340}zCoAK1ukuL}S{^#zjv delta 20 acmX>Vbt;N`IWI340}xc+-?ow4UKapHuLe~B diff --git a/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-311.pyc index ecf094f3c38c9a4dbeee42965c26adef9a7310fb..83f2c59515d6908389d092a564e0f5f774e4c081 100644 GIT binary patch delta 2037 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 diff --git a/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-311.pyc index e12fc677d2e0db0f7ffef08502da3db1e39a126b..a6171741a8808d534fb898613eb318fe45d22ea8 100644 GIT binary patch delta 20 acmdmQzu%sFIWI340}zCoAK1vfMIHb>V+F1N delta 20 acmdmQzu%sFIWI340}xc+-?ou^i#z~A9R_d! diff --git a/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-311.pyc index 6b451317095b6433dbf3e840598479e4bfc8a8b6..1ddcddd7456365178c2769ba97bda6f3fce753e6 100644 GIT binary patch delta 20 acmaDX_*js8IWI340}zCoAK1u!g989ObOomX delta 20 acmaDX_*js8IWI340}xc+-?owa1_uB^E(U1; diff --git a/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-311.pyc index 26799b414b7825d4bbfb3277f6f13d5bff18f790..269ab537b8e9792a1c9e4b9770f35f15f4b6e8b5 100644 GIT binary patch delta 20 acmZn{Y8T>O&dbZi00g1t2R3s5;Q#O&dbZi00foyw{7J9!vO#@@&(rb diff --git a/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-311.pyc index 7284f374327bd64e61c1739450dd33e25c739028..a14b17b6cfaf9fd68cb91a198a6b1e7712be7565 100644 GIT binary patch delta 20 acmew_^IwL0IWI340}zCoAK1uU!Uq6BW(Ai3 delta 20 acmew_^IwL0IWI340}xc+-?ovvgbx5lAO=|g diff --git a/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-311.pyc index 3255ee8d5df90c1cd1dd0a85d1f5c56a40d46d90..74596cc6eb7e77d4ee002bf354ecf83309e92788 100644 GIT binary patch delta 20 acmbQrKb4<*IWI340}zCoAK1v<#SQ>3`vkZE delta 20 acmbQrKb4<*IWI340}xc+-?ovviyZ(owFP=fi)&dbZi00g1t2R3roaR2}=WCWQ2 delta 20 acmeAa>=fi)&dbZi00foyw{7IE;{X6N9tB$f diff --git a/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-311.pyc index 1630350bdb2e7951f5365374344d3b01c37bfc01..978b3a60e3e0c338f48b5b55f91b3b24fdab444a 100644 GIT binary patch delta 22 ccmZ3ti)r01Chq0Dyj%=G5Ndv4Be(Kg08j}Aa{vGU delta 22 ccmZ3ti)r01Chq0Dyj%=GP None: super().__init__() @@ -259,6 +260,9 @@ class RequirementPreparer: # How verbose should underlying tooling be? self.verbosity = verbosity + # Are we using the legacy resolver? + self.legacy_resolver = legacy_resolver + # Memoized downloaded files, as mapping of url: path. self._downloaded: Dict[str, str] = {} @@ -365,6 +369,11 @@ class RequirementPreparer: self, req: InstallRequirement, ) -> Optional[BaseDistribution]: + if self.legacy_resolver: + logger.debug( + "Metadata-only fetching is not used in the legacy resolver", + ) + return None if self.require_hashes: logger.debug( "Metadata-only fetching is not used as hash checking is required", diff --git a/lib/python3.11/site-packages/pip/_internal/req/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/req/__pycache__/__init__.cpython-311.pyc index 4d03449b233ab5bd5b9851de8bb7ae9fc0345cf9..3010097322a94b8b79937111d73997fff5ab5e7c 100644 GIT binary patch delta 20 acmZ3av`C42IWI340}zCoAK1t(E(icKxde{@ delta 20 acmZ3av`C42IWI340}xc+-?oukTo3>_a|KZV diff --git a/lib/python3.11/site-packages/pip/_internal/req/__pycache__/constructors.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/req/__pycache__/constructors.cpython-311.pyc index 314f78477826637879f608c62f35122553c48b89..b835bc0c958358a7937c217a713f7042231cdeb9 100644 GIT binary patch delta 22 ccmcb$knz?+M(*Xjyj%=G5Ndv4Blr0L08}gn_5c6? delta 22 ccmcb$knz?+M(*Xjyj%=GP09I57!vFvP diff --git a/lib/python3.11/site-packages/pip/_internal/req/__pycache__/req_set.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/req/__pycache__/req_set.cpython-311.pyc index 550ea0fc9cfd60a9db7d1ebed066fb66945ff5ff..5d1f2cec10a1790e9b72a4e0b06f133013ebcd79 100644 GIT binary patch delta 20 acmbPaH_48BIWI340}zCoAK1vvE)M`THw2{s delta 20 acmbPaH_48BIWI340}xc+-?ovPT^;~A@dal9 diff --git a/lib/python3.11/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-311.pyc index d2897853680ab9499b29ba57d0164421d43ac250..044ff25cb8a8268d4733f60352bf09f0be0291dc 100644 GIT binary patch delta 22 ccmaE{gz3c+Chq0Dyj%=G5Ndv4BX{g109IlK>Hq)$ delta 22 ccmaE{gz3c+Chq0Dyj%=GPXPw diff --git a/lib/python3.11/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-311.pyc index c864a28597bbbfb5331a4d1f64563a5f88033885..ee3e52d5fa88e1a9b27b7c5e147e7409468ac83e 100644 GIT binary patch delta 22 ccmeyolkxLTM(*Xjyj%=G5Ndv4Bln9K09+FXeEK1IWI340}zCoAK1vIWI340}xc+-?ovvO9%ir*afiw diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/_log.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/_log.cpython-311.pyc index d3e26aad1da2c9f46403ca6558b90eb2ef460e18..61521d95352e6be0a653b28d68330a1713ea2296 100644 GIT binary patch delta 20 acmcb|e~+JgIWI340}zCoAK1u!nH>N-V+E4{ delta 20 acmcb|e~+JgIWI340}xc+-?owaGCKf39R^hZ diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-311.pyc index aab63c72d37539afe7ce00b1ce44d1afe0162313..54d8af1df0ef7320fd1bec9aaae42128b0e555e5 100644 GIT binary patch delta 20 acmew%{6m;~IWI340}zCoAK1wKmJ delta 20 acmew%{6m;~IWI340}xc+-?owaEhhj(zXq)U diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/compat.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/compat.cpython-311.pyc index 7dfe6cc85b53edeb1d816f21a5c8e760319f4cca..43246c76a1a195efa1bdb2a6feb075c21de0f753 100644 GIT binary patch delta 20 acmca2ctwzVIWI340}zCoAK1u!k^=xb90hs+ delta 20 acmca2ctwzVIWI340}xc+-?owaBnJRK)&@KP diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-311.pyc index 20e8d7e32afa9683c98842cb5ccfa55c1466028a..51a59a673c46dcc50eafcafb0eb08dcba692af8b 100644 GIT binary patch delta 20 acmaE0^1y_9IWI340}zCoAK1tpDg^*P`UQ3X delta 20 acmaE0^1y_9IWI340}xc+-?ouER0;q@v<5f; diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-311.pyc index 7d83db15301188e09718d0c388223442ef9cc2dd..718081f27539edd2549e10c6213524dfa5767afe 100644 GIT binary patch delta 20 acmX@cdW@BOIWI340}zCoAK1vfn+X6mHU%;O delta 20 acmX@cdW@BOIWI340}xc+-?ou^HxmFl@CEb$ diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-311.pyc index 37281d658509982aa2b4bd53443d08a7a75213bf..ac9add80dd442e44023a454eec5a6a66ae1347a9 100644 GIT binary patch delta 20 acmX@Ea$JRbIWI340}zCoAK1ukBLo0B$^`=e delta 20 acmX@Ea$JRbIWI340}xc+-?ow4MhE~tgayR_ diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-311.pyc index 88889de7768bb41e777ddbb255f775e0db042a18..3ab1bc022e503767186a2a3d5674cb0f5cffce51 100644 GIT binary patch delta 20 acmZpXZIR_(&dbZi00g1t2R3q7@&N!ZQUs^~ delta 20 acmZpXZIR_(&dbZi00foyw{7IEJj2z&dbZi00g1t2R3puasmJ@0R$xg delta 20 acmeAX>Jj2z&dbZi00foyw{7HR{H}k&dbZi00g1t2R3py3jhEybOg`< delta 20 acmeBE>{H}k&dbZi00foyw{7HZ761S?E(MYR diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-311.pyc index 0c1606cb22f87a9eb363219a6b1f98a56dfa15d9..13e550906a10e1d3363a98d1d7d3b1bc8699a69a 100644 GIT binary patch delta 20 acmbR5FyDcDIWI340}zCoAK1t(q5uFlhy>99 delta 20 acmbR5FyDcDIWI340}xc+-?oukL;(OiLIslm diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-311.pyc index 42cba51d926215639facf7a4056854b698ae6d7c..90657c7b1ee8d6b10d4c7d004df93daa66c0b582 100644 GIT binary patch delta 20 acmbQsHJ6KfIWI340}zCoAK1t(#0mf}g#<(Z delta 20 acmbQsHJ6KfIWI340}xc+-?oukh!p@dKLrK= diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-311.pyc index af6f4f1af15f17da1ca342c41e1ce2697499106a..cc9bf3fa540c9e543eb514859e450f16d179fca5 100644 GIT binary patch delta 20 acmZ20vQ~t9IWI340}zCoAK1vP#03B|as-V4 delta 20 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 Jac19D_%Fx0v+)1` diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/models.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/models.cpython-311.pyc index 019697921af802f06155de59323472ec91cc0dd5..902bb56ba7e40b839087e8d7e8b3634cf39c09a6 100644 GIT binary patch delta 20 acmew=_En5~IWI340}zCoAK1v9#SH*H`vqzM delta 20 acmew=_En5~IWI340}xc+-?ouEiyHt#wFWEz diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-311.pyc index 4e0c523754d39de45a2f11080605029542a2b1b6..966b01616e51e1fc5ac45560e26b9b0eb4e15db0 100644 GIT binary patch delta 20 acmew$`azU?IWI340}zCoAK1wKlnVeq4h7f% delta 20 acmew$`azU?IWI340}xc+-?owaDHi}k$Of7K diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-311.pyc index 474b97f885e65314a646f893bb5c62d917fb062f..642b196016cc126d524a19c166b66d1cd32fc1e3 100644 GIT binary patch delta 20 acmZovYgFT2&dbZi00g1t2R3ql69ND+A_X-7 delta 20 acmZovYgFT2&dbZi00foyw{7J9CIkRA+y(al diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-311.pyc index 75a0ecefc4422fc19768e7ef6d88e65186937992..0936742e6c1d51ca478f8cd08073e7c9b7acadc3 100644 GIT binary patch delta 20 acmbR5JKvXkIWI340}zCoAK1t}MGXKtVg+#k delta 20 acmbR5JKvXkIWI340}xc+-?ou^iW&ev90oH0 diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-311.pyc index 970870bdeed4518c9bee3f3b0c2b7a1dbc6d434a..89ba264276943662e825fc5ddcaebd8f5b4bd51c 100644 GIT binary patch delta 20 acmbOhIW3ZVIWI340}zCoAK1veFek- diff --git a/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-311.pyc index acb561a99bb0e8f85f496a94eb4b0ca79d5ea686..77eaadbd33643c891b90bc270f8b776eb57d98d9 100644 GIT binary patch delta 20 acmdmQzTcdCIWI340}zCoAK1vfMH&D+KLwfq delta 20 acmdmQzTcdCIWI340}xc+-?ou^i!=a0`3777 diff --git a/lib/python3.11/site-packages/pip/_internal/utils/misc.py b/lib/python3.11/site-packages/pip/_internal/utils/misc.py index afcf170..bd191c4 100644 --- a/lib/python3.11/site-packages/pip/_internal/utils/misc.py +++ b/lib/python3.11/site-packages/pip/_internal/utils/misc.py @@ -1,6 +1,3 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - import contextlib import errno import getpass @@ -344,17 +341,18 @@ def write_output(msg: Any, *args: Any) -> None: class StreamWrapper(StringIO): - orig_stream: TextIO = None + orig_stream: TextIO @classmethod def from_stream(cls, orig_stream: TextIO) -> "StreamWrapper": - cls.orig_stream = orig_stream - return cls() + ret = cls() + ret.orig_stream = orig_stream + return ret # compileall.compile_dir() needs stdout.encoding to print to stdout - # https://github.com/python/mypy/issues/4125 + # type ignore is because TextIOBase.encoding is writeable @property - def encoding(self): # type: ignore + def encoding(self) -> str: # type: ignore return self.orig_stream.encoding @@ -422,7 +420,7 @@ def build_url_from_netloc(netloc: str, scheme: str = "https") -> str: return f"{scheme}://{netloc}" -def parse_netloc(netloc: str) -> Tuple[str, Optional[int]]: +def parse_netloc(netloc: str) -> Tuple[Optional[str], Optional[int]]: """ Return the host-port pair from a netloc. """ @@ -510,7 +508,9 @@ def _redact_netloc(netloc: str) -> Tuple[str]: return (redact_netloc(netloc),) -def split_auth_netloc_from_url(url: str) -> Tuple[str, str, Tuple[str, str]]: +def split_auth_netloc_from_url( + url: str, +) -> Tuple[str, str, Tuple[Optional[str], Optional[str]]]: """ Parse a url into separate netloc, auth, and url with no auth. diff --git a/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-311.pyc index 3bc53a9d33a8c036942dc70d028cd1c2a27a5dd9..08175c301e5479c4aa9e1ed6d75c351da6be6924 100644 GIT binary patch delta 20 acmeyu@`Z(aIWI340}zCoAK1v9$pipALIpYi delta 20 acmeyu@`Z(aIWI340}xc+-?ouElL-Jo`~~~~ diff --git a/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-311.pyc index 1326fbb3bc0f487c26ff7d641263ec39baa557c9..670ef09300861d93760c2b8482edb787a4d5a406 100644 GIT binary patch delta 20 acmcbsdsmlxIWI340}zCoAK1u!Nelo#f(6?E delta 20 acmcbsdsmlxIWI340}xc+-?owak{AF)JO-Tr diff --git a/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/git.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/git.cpython-311.pyc index bcbe6527e51370dcfd3c43c6aebd1a9e008e2ce0..d44fb4968654227da63cc22c560a7195f5200466 100644 GIT binary patch delta 22 ccmeBO!PvWkk$X8WFBbz4gqk1N$juZ207p^s9R&dbZi00g1t2R3s5R0IGu;RT5R delta 20 acmZp1X>s9R&dbZi00foyw{7J9sR#f%n+8h& diff --git a/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-311.pyc index cc8871346c289958d2b065c4732256495fda1a4f..22517de3806feff601041928760a48eab24ea973 100644 GIT binary patch delta 20 acmZoEYANDg&dbZi00g1t2R3s5v;Y7+a0UDT delta 20 acmZoEYANDg&dbZi00foyw{7J9X#oI1Dh9p) diff --git a/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-311.pyc b/lib/python3.11/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-311.pyc index 6fb95284986cd0471286e3b5bb0ed0b69dba14a6..247014d5268512d05d506d674d3d118bc0f484e9 100644 GIT binary patch delta 22 ccmezQgYoANM(*Xjyj%=G5Ndv4BX?d60A%<-$4gL^qIFBbz4gqj~{%<-$4gL^qIFBbz4RNmj#$lc1#xRsmfJtF{!zzDto diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-311.pyc index 9cd46d93052f6a5362443eac98fdac30163192b1..52466a763e9adfdfa9cffb4e27071883fa8c790c 100644 GIT binary patch delta 20 acmX@ic9@NOIWI340}zCoAK1uk!3+R2;{>b# delta 20 acmX@ic9@NOIWI340}xc+-?ow4f*Algods?H diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-311.pyc index e04abd97ba56f3e514dddfc6a2ab4dde727aa495..40273839c1368b64fab7735bfd19a34da9bef7f2 100644 GIT binary patch delta 20 acmZn?Z4%{P&dbZi00g1t2R3q-a{&M?-UN;S delta 20 acmZn?Z4%{P&dbZi00foyw{7Gu=K=sSm<3P( diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-311.pyc index 26825e17ca3a99ccb9ce91809cb410a58196ba45..4dac3747d9023de07bdeb195fe936af7205e52e0 100644 GIT binary patch delta 20 acmeyV^;3&`IWI340}zCoAK1v9Ckg;Ubp@yZ delta 20 acmeyV^;3&`IWI340}xc+-?ouEPZR)0F9vD= diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-311.pyc index aa4bd2271315d361051df439e1fd63934e0976c9..825212550531ffe707e4fa465311de9c908ce8fa 100644 GIT binary patch delta 20 acmdljyIYofIWI340}zCoAK1vffe!#T>IF>z delta 20 acmdljyIYofIWI340}xc+-?ou^10Mi9qy`TF diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-311.pyc index 11d2e849218c9ee62aef20923fdc84e06de95704..ab8fa5b25daa1c3c1a5c45ccfbc93865125143d4 100644 GIT binary patch delta 20 acmaFC@q&YUIWI340}zCoAK1tp%K`v8^aUUQ delta 20 acmaFC@q&YUIWI340}xc+-?ouEmIVMmt_9)% diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-311.pyc index b5b48bc129b6ad8de577ddb9218f10a47b31bdaa..b955b0974c2017cae2946350f6671a2b5e4d92e1 100644 GIT binary patch delta 22 ccmdnpz_`1Ck$X8WFBbz4gqk1N$Zg;N07&2k#{d8T delta 22 ccmdnpz_`1Ck$X8WFBbz4RNmjVk=wul08N?(i2wiq diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-311.pyc index 5865705ec150f39ce5054d8f9bc8e012aa2d0ae8..d53c7dddb4c5d675a68acfaaae9d877551e07c03 100644 GIT binary patch delta 20 acmZouY*XZ3&dbZi00g1t2R3q73jhExGz7Q+ delta 20 acmZouY*XZ3&dbZi00foyw{7IE761S=?ge@P diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-311.pyc index 57c0b5bfc98b445581d3f7649931ac8bcaed4bf2..7465273ea0ca7b57183345f94a0f04045185cc20 100644 GIT binary patch delta 20 acmbPiGTDTCIWI340}zCoAK1vvAq4<4@&u0n delta 20 acmbPiGTDTCIWI340}xc+-?ovPLka*mtOZd3 diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-311.pyc index 873aa63d8fb1f01b571b913cecfd0186387f75eb..53deba805418da0afdb553b567d81dcbf89dda1e 100644 GIT binary patch delta 20 acmX@+c+8P|IWI340}zCoAK1vfTLAz*#0AIz delta 20 acmX@+c+8P|IWI340}xc+-?ou^w*mk|eg=vF diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-311.pyc index 528c2caeaf3b3e8a422ec960aa394ca23a46bdf4..f3b28335564853b497a9b03350f00d59774e50ce 100644 GIT binary patch delta 20 acmdnPzK5NAIWI340}zCoAK1vfkr@Cq?*$nE delta 20 acmdnPzK5NAIWI340}xc+-?ou^BQpRwsRi2r diff --git a/lib/python3.11/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-311.pyc index e25358acb99d5b48a936bcccae3304c79a7acfe4..e4b135dc38dc6a10386bedf14ada9ef1d0810cf6 100644 GIT binary patch delta 20 acmbQmJd2roIWI340}zCoAK1v<&jjj7a diff --git a/lib/python3.11/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-311.pyc index ad13d9b330f09c6603f957b780cb0af258425fe5..3b9aa52ce13e53d6c73284738fc39a8b7c6fd3d2 100644 GIT binary patch delta 20 acmaFB`hb;tIWI340}zCoAK1u!l?ebkMg@QX delta 20 acmaFB`hb;tIWI340}xc+-?owaDiZ)d00u$; diff --git a/lib/python3.11/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-311.pyc index 80da25ce486d1612bff18fa0592a7ad684d7b09f..2db2cbb1aee95372dbbfb6444c5a061a3d778415 100644 GIT binary patch delta 20 acmbOyHBX9rIWI340}zCoAK1t(%nJZ9^#pGK delta 20 acmbOyHBX9rIWI340}xc+-?oukm=^#xuLUsx diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-311.pyc index c8c3e3d089ac8b9af30693a994c6c9e5e288bd23..013a7ac80e219c4a02674da728a43ce2b0d86c6b 100644 GIT binary patch delta 20 acmX@Dep;P-IWI340}zCoAK1u!Ko|f!*9DdU delta 20 acmX@Dep;P-IWI340}xc+-?owafG_|+kp@@* diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-311.pyc index 6d063aea5556ea27a52527f3beb8de3c9fb55744..7dc703f9e1b768552dbb97c24611229a5e9294f1 100644 GIT binary patch delta 22 ccmdmcg>ml{M(*Xjyj%=G5Ndv4Bezi&09Gspp8x;= delta 22 ccmdmcg>ml{M(*Xjyj%=GP?glyl diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-311.pyc index 254c88250d0b2c3c993673b4db37c04697fc9d69..b412e79d42182cdc095116be23a2de9d731b41c4 100644 GIT binary patch delta 20 acmZ3Yy+oUPIWI340}zCoAK1t}QxpI;Q3Wdi delta 20 acmZ3Yy+oUPIWI340}xc+-?ou^rYHbA3kB@} diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-311.pyc index 2c08f7a5f94524eea13c0105aeb3cc396e21e269..4f648cccd1bf28b64369f608887bf24100aff6f3 100644 GIT binary patch delta 20 acmbO(KV6=CIWI340}zCoAK1v5&Zv}Y( diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-311.pyc index 24a45fcc1a504a1b855d165fd148abcd23d56a82..e531304f8b9973f4611edf51a1078f6b28e9c94b 100644 GIT binary patch delta 20 acmZ3awn&Y8IWI340}zCoAK1t(E(`!PO9Yt! delta 20 acmZ3awn&Y8IWI340}xc+-?oukTo?d31qE9G diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-311.pyc index 24da8acf4c8521d1ef291e4ff616813688a0d97a..96db7f8ed5fe7dd297b0276bf8f8ebf7d9b6d3db 100644 GIT binary patch delta 20 acmcbcbT^56IWI340}zCoAK1tpWC#F85e47? delta 20 acmcbcbT^56IWI340}xc+-?ouE$PfTZ%LbwV diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-311.pyc index 9fddcce7f111d5592f465adca45c56222738a732..b6796f0b40eab0d90f45046e2cad7be5d5f87379 100644 GIT binary patch delta 20 acmeyO@j0Q{q diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-311.pyc index e0cecf2540e2bc71963fab7eb5a06c9242c476f0..c816d8afeed20ca57889b3c7ce6983d101801c33 100644 GIT binary patch delta 20 acmdlGw;_&uIWI340}zCoAK1vPst*7@cLh%X delta 20 acmdlGw;_&uIWI340}xc+-?oukRUZIDF$NI; diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-311.pyc index e0c1fb1726d59a6aac7ce8b3214a59c63661f6cc..9ed33fad8674af4362bd4427905291711195de8b 100644 GIT binary patch delta 20 acmeC=?d0WN&dbZi00g1t2R3rou>k-r(gcqH delta 20 acmeC=?d0WN&dbZi00foyw{7IEV*>y(j0I5u diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-311.pyc index 91da6f801b288a0ebc95ff932dd3e9b1f0f79f44..68c280874b1217d1603ce0f37c23cd57e26e3d77 100644 GIT binary patch delta 22 ccmX?fh4Ii8M(*Xjyj%=G5Ndv4Be!`L09OMBt^fc4 delta 22 ccmX?fh4Ii8M(*Xjyj%=GPk-r(gcqH delta 20 acmeC=?d0WN&dbZi00foyw{7IEV*>y(j0I5u diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-311.pyc index a15ce7bc5ffe8681df778b5277a07101afcab4d2..022112ac7157387a1c563ba46ba2cf72d1235349 100644 GIT binary patch delta 22 ccmdlom2t~dM(*Xjyj%=G5Ndv4Blk)#088)&W&i*H delta 22 ccmdlom2t~dM(*Xjyj%=GPdIWI340}zCoAK1v<%LV{2Dg?X$ delta 20 acmbQiJA;>dIWI340}xc+-?ovvmkj_kFApigX delta 22 ccmeBN%h diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-311.pyc index 6d8918c12bbc335ec667d90a8c5c1fa332d91f9c..ab12d1798b4be3bbdfae09123003367a292d26a7 100644 GIT binary patch delta 25 fcmX>;kM;OGR_^7zyj%=G5Ndv)k$WpQqm4fRW10rf delta 25 fcmX>;kM;OGR_^7zyj%=GP}~ diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-311.pyc index 9deb3c402b58d14ae1bf01d2cbd0a2766b549cd0..0f6916da1cd00706813ae298e94fa0a96380548e 100644 GIT binary patch delta 20 acmbQDFhzlTIWI340}zCoAK1vvDF6U5Km=d_ delta 20 acmbQDFhzlTIWI340}xc+-?ovPQvd)p`UN5Y diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-311.pyc index bd380a60681cb54295340e135d2fa81a1dcb1aab..de23c8041a2f063f6421bdf26a4b0e65152c639c 100644 GIT binary patch delta 20 acmX@ae~6!ZIWI340}zCoAK1vfogDx-0|h?- delta 20 acmX@ae~6!ZIWI340}xc+-?ou^J39b7y#@gQ diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-311.pyc index b496a2e82ad49705e8264f55bee3b82d6d50478b..71d8b4cd458930e07430bc235d29ca76532452b5 100644 GIT binary patch delta 22 ccmaF&o$=jwM(*Xjyj%=G5Ndv4BlqKK0A$Sw2><{9 delta 22 ccmaF&o$=jwM(*Xjyj%=GP?Pk delta 20 acmcZ@bTNo~IWI340}xc+-?ow4O%nh{qXt$0 diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-311.pyc index 8e54a968347153c6ad2b5edc0fe786864fe77b58..8bc8646a81d94400f781b9abca8a4d7f8374cf4f 100644 GIT binary patch delta 20 acmeB>?vUnQ&dbZi00g1t2R3ro@&W)asRXY8 delta 20 acmeB>?vUnQ&dbZi00foyw{7IEA delta 19 ZcmX@gc$ATQIWI340}xc+-!_qZ7XUNw1;+pY diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-311.pyc index 6b2664e0d5c2093be3316d5fd9dc41b6e95b2eaf..0b2e4529c6dced03cc9080f96d4c7251df6eedad 100644 GIT binary patch delta 20 acmeyM_(73-IWI340}zCoAK1wKQ~&@##0B;M delta 20 acmeyM_(73-IWI340}xc+-?owasQ>^)eg?Pz diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-311.pyc index 599a224d27228092bd140172f68d2111f21c169c..923c1352b6cd31a547d1116865f5db6158549189 100644 GIT binary patch delta 19 ZcmX@bc#4sGIWI340}zCoADGC!9{@101rz`P delta 19 ZcmX@bc#4sGIWI340}xc+-!_qZKL9kS1=aun diff --git a/lib/python3.11/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-311.pyc index 2f8d444957a49cbba1bcda1bfd5b48e2031bb055..a3a6a71eb0ec04d85bf961e1e4999f0d8d9ddaaa 100644 GIT binary patch delta 20 acmdlKvMGdnIWI340}zCoAK1vPt_1)+S_M1+ delta 20 acmdlKvMGdnIWI340}xc+-?oukT?+t06b1eO diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-311.pyc index 536ff65872b5e8817f4f6537b5049d46133944cc..22f1b45e02d587a00143c23ca774105746af68f1 100644 GIT binary patch delta 20 acmdnVvXg~-IWI340}zCoAK1vP#{>W~3IvG& delta 20 acmdnVvXg~-IWI340}xc+-?oukj|l)b#05(L diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-311.pyc index 4f5c45819e4bd974cc3a7abab766f8e891d2496b..dad33caa3b67ac89d846e3d2ac08895a2875633b 100644 GIT binary patch delta 20 acmcbvd|jD)IWI340}zCoAK1u!Mi2l!B?Yhm delta 20 acmcbvd|jD)IWI340}xc+-?owaj359(-v)93 diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-311.pyc index e0f2bb72f4e228112277a62212202fcd0474a2cc..d1ea2f164b478253881bd167b5679c9fd8a5c5ca 100644 GIT binary patch delta 20 acmcawceRdtIWI340}zCoAK1w4We)&I&jt% diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-311.pyc index 131ee38e7569d0923df4cd5937c79f473b239619..4a41e3dc21ba2d45773eb84e4b261c46a1b80afb 100644 GIT binary patch delta 20 acmaE7`_7hoIWI340}zCoAK1wKSPlS0at1a4 delta 20 acmaE7`_7hoIWI340}xc+-?owau^a$NEC%=h diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-311.pyc index eb9073c9c45877a1d0f1e1046e341d2d860a9d74..07d94d9794ba854f17c9066f2a5758c1905194db 100644 GIT binary patch delta 20 acmdntzQdh+IWI340}zCoAK1vfRv7?2Zw0LY delta 20 acmdntzQdh+IWI340}xc+-?ou^tug>YDF$x< diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-311.pyc index c60a7be2ef85fdd6189488a7adfc92374c6d5db7..a2aea0a000ef7c197157d0bf10dceeaf79f7e38a 100644 GIT binary patch delta 19 ZcmX@Xc!H68IWI340}zCoADGC!7XUD31r7iJ delta 19 ZcmX@Xc!H68IWI340}xc+-!_qZF90-N1<(Kh diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-311.pyc index 77c08c090f5cfadea026dc3d5f86cff825889c65..a40273503fbc9cccd0d048b70f0e53c9f29dc26c 100644 GIT binary patch delta 20 acmcbrdsUZvIWI340}zCoAK1u!N(=x#LIuMB delta 20 acmcbrdsUZvIWI340}xc+-?owalo$X){04;p diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-311.pyc index 9620b99995475e3ed3b72cdf2499c79785ce49d6..fedb827d5000d06e6d45a0029a477d5f86722445 100644 GIT binary patch delta 22 ccmeBJ!Pv2ak$X8WFBbz4gqk1N$o)4M07!ZUkpKVy delta 22 ccmeBJ!Pv2ak$X8WFBbz4RNmjVk^65j08KOpQvd(} diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-311.pyc index d5bc278b0a7f1d788ba58630ec587f9d9c77ba7c..99eb9754c8fa2aba97c79425e67e74b5dda9ff1f 100644 GIT binary patch delta 20 acmdm;w>yt}IWI340}zCoAK1ukU=9F6cLkUL delta 20 acmdm;w>yt}IWI340}xc+-?ow4z#ITaF$P)y diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-311.pyc index 1b825dcc240c10ebcdce6f3b83bee55c7d07fcf5..9b579642a73d9cd5ab87ac7615fbc9cc83e31ef8 100644 GIT binary patch delta 20 acmdmBvcZIVIWI340}zCoAK1vPDg^*IdIaVG delta 20 acmdmBvcZIVIWI340}xc+-?oukRSEz-GzF*t diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-311.pyc index 3fdd81a2fc42af0fef07014ae2e0da5b5b6350f9..7d6470be14206583e0abd9670a6fb335f830ae10 100644 GIT binary patch delta 20 acmdllwqJ~UIWI340}zCoAK1uk!VLg6iv-93 delta 20 acmdllwqJ~UIWI340}xc+-?ow4gc|@mMFolg diff --git a/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-311.pyc index b40a3c3bab0c4179249c055e90506bea19b06b55..06b268f03656b13c6f26738d036eca5c9095a7cd 100644 GIT binary patch delta 20 acmX?LalnFmIWI340}zCoAK1ukDgyvJj0GS7 delta 20 acmX?LalnFmIWI340}xc+-?ow4R0aS*Mg`&k diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-311.pyc index 4866f7e3d7c0d165aba1d146f21bb2e9e79261a8..7bd459f9e960a224126f0e48a3434c5f805f144a 100644 GIT binary patch delta 20 acmbQoJ&&7vIWI340}zCoAK1t}nH2yq(FDl= delta 20 acmbQoJ&&7vIWI340}xc+-?ou^GAjTziv^1S diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-311.pyc index e0f0de43c292fb391b54fe08f739ee339980261c..7b357ff9f222285b724aabe5c938452f18de4c73 100644 GIT binary patch delta 22 ccmcaGgZaV?X71&@yj%=G5Ndv4Be&}r08r%y#sB~S delta 22 ccmcaGgZaV?X71&@yj%=GP diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-311.pyc index d8999470053c65f75672f4ecb2788529f06d415e..51dcd5df69c4a4ed135358a8d2c32703b1690812 100644 GIT binary patch delta 25 fcmX@u#B#8Sg?l+KFBbz4gqj~{oRa+f**06@G2q5uE@ delta 22 ccmZo@Wo&3=pF diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-311.pyc index 25bdffaf9ccf72048dbbb34ce56322128ddfc1bf..61c9392fe13ece9daf5080d221e9ca5259060617 100644 GIT binary patch delta 20 acmaE0|G=JmIWI340}zCoAK1u!RUQCBiv|$@ delta 20 acmaE0|G=JmIWI340}xc+-?owasyqNkMF!IV diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-311.pyc index 6cadc1bedcbb3485dd7cde1d478b22ad7d509153..b68213f244cd066d92f053c21806f8c3086448ee 100644 GIT binary patch delta 22 ccmZqqz|``AiF-LOFBbz4gqk1N$o+FW08>u~djJ3c delta 22 ccmZqqz|``AiF-LOFBbz4RNmjVk^AR%09XkKJpcdz diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-311.pyc index 7b0fa15460105740d4fb9e77168bc3dff2e8e092..3f040da9fed387a728c8c0ab20beb8f623c72325 100644 GIT binary patch delta 22 ccmZ2Ig>m&1M(*Xjyj%=G5Ndv4Be#MV07*s#$p8QV delta 22 ccmZ2Ig>m&1M(*Xjyj%=GPpF diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-311.pyc index c716a6a63c95aa96641a5e14b6ea5cad3c02423a..b91eec9c9dea026ac0e1a02196dac21cba2a1c0f 100644 GIT binary patch delta 25 fcmZ4VlXcNgR_^7zyj%=G5Ndv)k$WpQA9 diff --git a/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-311.pyc index 69d9170f58d90e529f373b4d3953c44715442754..7ae60e6342a362d1567de7710f9261f942f92871 100644 GIT binary patch delta 22 ccmeC|W9sZ<;$F_n%f$c$q2>oRa{p@s07VA|l>h($ delta 22 ccmeC|W9sZ<;$F_n%f$c$mG`%8ibVP`IIWI340}zCoAK1uk$q4{9!350! delta 20 acmX>ibVP`IIWI340}xc+-?ow4k`n+sdj*dG diff --git a/lib/python3.11/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-311.pyc index 0c1a62d8a1c9f6cbc1d0c21a00cd1e04db0532de..41b64ed3fe7001c591f8c2730b5cdfe094cbd11b 100644 GIT binary patch delta 20 acmX@=e$<_NIWI340}zCoAK1vfOBnz^cLme{ delta 20 acmX@=e$<_NIWI340}xc+-?ou^moflEF$R_Z diff --git a/lib/python3.11/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-311.pyc index c0f169e8a5a73e226486f71e2a47e192968d8052..3924465f1fc1d91c0f0a215818dfe6eef7135102 100644 GIT binary patch delta 22 ccmZ4afobIjChq0Dyj%=G5Ndv4Be&cR09S_w>i_@% delta 22 ccmZ4afobIjChq0Dyj%=GPvX+H=IWI340}zCoAK1vP!~_5_DgvX+H=IWI340}xc+-?ouki3tEToRa@RNj06|LytpET3 delta 22 ccmZo~WNdF_VR|o)l^atAj delta 28 icmeBt%-Q*vlY2QYFBbz4RNmj#$lc1#xRsl!t`Go(ItZNr diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-311.pyc index 058313501b139f81a930b127ae3df39d5c516ba0..af99b3a61497b051c1c6f0b66a8beb4c96caacc2 100644 GIT binary patch delta 22 ccmccA!FZ{Ik$X8WFBbz4gqk1N$nEX|08RM@AOHXW delta 22 ccmccA!FZ{Ik$X8WFBbz4RNmjVk=xw`08+CC;s5{u diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-311.pyc index ded62bd37692804aea70e404d1ac0a261df1fdda..79f2b653b53387e065d37a24884233d3d53430a1 100644 GIT binary patch delta 20 acmca7cu$afIWI340}zCoAK1u!nF9bjtOb|= delta 20 acmca7cu$afIWI340}xc+-?owaG6w)aW(HaS diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-311.pyc index b64bfc9bd2385115272bfcb6287c9f9cb5d44d0f..e41a35d75b8d98379dc746bbdafda643ffae1ec6 100644 GIT binary patch delta 20 acmcZ+cq5Q|IWI340}zCoAK1u!Rs#S-+y*89 delta 20 acmcZ+cq5Q|IWI340}xc+-?owatOfu`mImkm diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-311.pyc index 838b0aeab4e5ab19b29a5b7587f3548989bbf86e..15a1cabf18bec45ddb599080f1706d5a2c91f384 100644 GIT binary patch delta 20 acmdlQv^9u(IWI340}zCoAK1vPr3nB%i3LCa delta 20 acmdlQv^9u(IWI340}xc+-?oukOA`P>Lk0o> diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-311.pyc index 637e1c57a6e747f9c63f9098b65cab0d1208b4c8..c7d2e963c6f45a632c1cf5b27f54368f5e7b4635 100644 GIT binary patch delta 20 acmZ3hzgC}nIWI340}zCoAK1vfNE`q-O9fB> delta 20 acmZ3hzgC}nIWI340}xc+-?ou^kvIT71qKoT diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-311.pyc index c89a016dcaee362f8eb28cba85d8e797bc212dc2..7aaafcebe5161dfbcd0296dcf2f521fb4629ccc6 100644 GIT binary patch delta 20 acmX?}eLS0cIWI340}zCoAK1vf#}oiW=>{|a delta 20 acmX?}eLS0cIWI340}xc+-?ou^k0}62qXzZ> diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-311.pyc index 585466bf5a8f6f26e764fb017b30a71f2c60c029..3a68b466005d0e54a5ab8112e9e98ecb6161c08c 100644 GIT binary patch delta 20 acmdnYw3&%}IWI340}zCoAK1vP!3Y2`(FAe; delta 20 acmdnYw3&%}IWI340}xc+-?oukgAo8Wiv=_Q diff --git a/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-311.pyc index 80e1580c58d61139d12c6505e6beab16534d7999..ea80f381635565311f63030d5f460d0d070c3ac4 100644 GIT binary patch delta 20 acmaE#^FD`rIWI340}zCoAK1v9Vg>+8P6jUk delta 20 acmaE#^FD`rIWI340}xc+-?ouE#S8#X2nO*0 diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-311.pyc index cf5fa04b5660befbc40dbf43072683e4f07c123b..28a3e968f3150fdb217cc06d80d86dbb792b8240 100644 GIT binary patch delta 20 acmew)`$?92IWI340}zCoAK1wKoDTp%f(7yb delta 20 acmew)`$?92IWI340}xc+-?owaIUfK;JO;D? diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-311.pyc index abb03ac93c2483e9c92786741346eb73b9246150..9a3830cbf91961774631d789ccd20205167aa420 100644 GIT binary patch delta 20 acmZo?YiHwL&dbZi00g1t2R3s5VFCaxf&}*f delta 20 acmZo?YiHwL&dbZi00foyw{7J9!vp{_JO#M` diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-311.pyc index e55761a68b468f1f2337a81164c14b1b0dad35ba..c3615199f4c13b5afeb31c41a6ce8da9a89f66ee 100644 GIT binary patch delta 22 ccmX^2hVk4RM(*Xjyj%=G5Ndv4Be!!I09?BV4gdfE delta 22 ccmX^2hVk4RM(*Xjyj%=GP delta 20 acmdnSyN#E7IWI340}xc+-?ou^H5&jqlm*xT diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-311.pyc index b1202d2cecb14b508e8a156cfc311c0c5495c849..3292d275bc225f18c33c29c118698f9f2575b379 100644 GIT binary patch delta 20 acmbO%J6V={IWI340}zCoAK1v;@nJ diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-311.pyc index 91b4a366917f4409c9260baf0923d2e526ed15c9..143b40028651379ad2122fd7f1f94ed146bafc7d 100644 GIT binary patch delta 22 ccmeA^%hY|AiF-LOFBbz4gqk1N$lb6E08SPLxc~qF delta 22 ccmeA^%hY|AiF-LOFBbz4RNmjVk-K3T08-EgdjJ3c diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-311.pyc index 8d370b1687915f50fb5f492353eb2e6928e6d9e9..df0c1e444e20ac65bc58ff3c638fb0b5ac784b5d 100644 GIT binary patch delta 22 ccmbPypKtW08!8eyZ`_I delta 22 ccmbPypKIWI340}zCoAK1vfUKId7Q3bsK delta 20 acmdnxy~~?>IWI340}xc+-?ou^y($1h3kH7x diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-311.pyc index f2c7c3778c4f8c5ede33448f81a98748f3b0a9ab..0740812ebe09ba01b9eb497570a687b17d408b5b 100644 GIT binary patch delta 20 acmbQLKUJT5IWI340}zCoAK1vMFq+L diff --git a/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-311.pyc index d26eab9de194dcee199330551e071cbae658dd47..57884c09394d4ed3009deef124018a3210b8fb80 100644 GIT binary patch delta 22 ccmbQ-z&N>qk$X8WFBbz4gqk1N$j#vZ0757QPXGV_ delta 22 ccmbQ-z&N>qk$X8WFBbz4RNmjVk(99 delta 20 acmbR5FyDcDIWI340}xc+-?oukL;(OiLIslm diff --git a/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc index 2191f71dec0b6aa312e66f04267d05e73d7a5534..41b62263f966542fdf6770fedfc8a8a492276415 100644 GIT binary patch delta 20 acmbQ`KFghZIWI340}zCoAK1vn~xm&pzTe+E9xtX_ev;1!a0G7)L=>Px# delta 34 ocmeBb5$b9Y;$F_n%f$c$mG`$ba<_6bwsJGIax-t`X8GR;0HmD>s{jB1 diff --git a/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc index 40baf59de900b326cfb1286f99912a2e2464ed9b..d7523002a23f240225cfeb4112470f7560c4e807 100644 GIT binary patch delta 20 acmZq8Zq4Ri&dbZi00g1t2R3q7nF0VhnFVeD delta 20 acmZq8Zq4Ri&dbZi00foyw{7IEG6euXQwA^q diff --git a/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc index 9ac3c7b3bdfce51b356e146342c56bad5c26317e..06871860925b97daa71afb6dee4aa052fbc1f534 100644 GIT binary patch delta 22 ccmaE{jQPbfX71&@yj%=G5Ndv4BX{g&09O_VF#rGn delta 22 ccmaE{jQPbfX71&@yj%=GPoRa@RNl0704svH$=8 delta 22 ccmZo~W^8X}bN~PV diff --git a/lib/python3.11/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc index e66c1a628d4ec665cf42994a7a9b74d2dab7b67d..16934da5fe312436a335969ea8dc58b9fb362417 100644 GIT binary patch delta 22 ccmaF=fbsnUM(*Xjyj%=G5Ndv4BX>#x0AOqfQvd(} delta 22 ccmaF=fbsnUM(*Xjyj%=GP(^b diff --git a/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-311.pyc index 8190eb752d5f650d5cfe48cfb4d3b4f013872d65..4f461e31224fe59383d117060a77b0307c10f019 100644 GIT binary patch delta 20 acmeC+?BL{H&dbZi00g1t2R3rovH$=r7zBa< delta 20 acmeC+?BL{H&dbZi00foyw{7IEWdQ&&(gj2S diff --git a/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-311.pyc index 9288661d893eaad2febffa2d230648d733cddbed..1ebdda950e0afe3f6642bc65b975655989aa3daa 100644 GIT binary patch delta 22 ccmaFV!1$IAI- delta 20 acmX@ga+HO8IWI340}xc+-?ow4iU|NYqy=vP diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-311.pyc index d388fc827033f711a62ddb3453adf8aba42f8602..f935b83dcfacee43335dcc21c5a82ed67664f92c 100644 GIT binary patch delta 20 acmaDT@KAtzIWI340}zCoAK1tp#sL6300kca delta 20 acmaDT@KAtzIWI340}xc+-?ouEi~|5ax&`3? diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-311.pyc index 808c42b747057aad33b2ea30004b668778479743..fac6462c6be98c0a76dd8451b0bbe927d454b839 100644 GIT binary patch delta 22 ccmbQYm2uuyM(*Xjyj%=G5Ndv4BlqMe08K6ibN~PV delta 22 ccmbQYm2uuyM(*Xjyj%=GPg diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-311.pyc index 0f5002aea8265da1b764c56c374753342769d2a9..54fc81cded7efe48e8fdff046dc20ecb809cda61 100644 GIT binary patch delta 20 acmZ2jw6KVKIWI340}zCoAK1t(W(fd3`2|z} delta 20 acmZ2jw6KVKIWI340}xc+-?ouk%n|@Yvj!Fb diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-311.pyc index 18760315530a431ce4d631a962718b5fa684f79a..88cb8e048092b76b60f6db6f17699f63ef80ce6a 100644 GIT binary patch delta 20 acmcb}evzGfIWI340}zCoAK1u!j2QqpHw9P# delta 20 acmcb}evzGfIWI340}xc+-?owa7&8Do@dg?I diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-311.pyc index e91438d4fc08f7ced66f6727e24c422c78e8ab56..0c468e087b79030b694d96d365b7ae53493b7c26 100644 GIT binary patch delta 19 ZcmeC?>*nKL&dbZi00g1t2NrU(0{|%o1PA~C delta 19 ZcmeC?>*nKL&dbZi00foyw=Lvm2LLSo1j+ya diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-311.pyc index 390aa44c076db2e22cc48a62560303d8186c94e0..2983a97466f5dd35743a40015704470b0cc67638 100644 GIT binary patch delta 22 ccmaEOnepLeM(*Xjyj%=G5Ndv4BlopT09_CVhyVZp delta 22 ccmaEOnepLeM(*Xjyj%=GPyIWI340}zCoAK1uks|Wx-IR#Mw delta 20 acmX@%bi#>yIWI340}xc+-?ow4RuKR~^9BUU diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-311.pyc index 01e5cf01973a49ecc3489fa16b3c77bb4d6aaa17..f9b9bba475aefa48fa4709e9ce71357d723347ff 100644 GIT binary patch delta 20 acmdnVwv&x}IWI340}zCoAK1vP#|!{7Qv{9x delta 20 acmdnVwv&x}IWI340}xc+-?oukj~M_s4FymD diff --git a/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-311.pyc index d96499ae341cc029a3d8fa0c29e45d87f0463b6a..38d11774580ce90f2711f25148d5a486a5df7ea9 100644 GIT binary patch delta 22 ccmezIobktVM(*Xjyj%=G5Ndv4Blp{40AvFP{{R30 delta 22 ccmezIobktVM(*Xjyj%=GPl5Q%&dbZi00g1t2R3pua{~Y_;{-JT delta 20 acmeAZ>l5Q%&dbZi00foyw{7HR<^}*Wodov) diff --git a/lib/python3.11/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-311.pyc index bb4a3d4c56e741d40a2ccfc2940222d25b611f60..f751c3c0655a4b93b4b0be4e26c456a816c839cb 100644 GIT binary patch delta 22 ccmZ4YgmK*yM(*Xjyj%=G5Ndv4Be!x909GFcng9R* delta 22 ccmZ4YgmK*yM(*Xjyj%=GPdc{-ANIWI340}zCoAK1u!KnDOq_y!XI delta 20 acmX>dc{-ANIWI340}xc+-?owafDQmhvIf-v diff --git a/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-311.pyc index a27733c5228c22a7be84ae57aa5a42310e504bdf..eba5f632d62ba07a0fd01be7430822b3940f56bb 100644 GIT binary patch delta 19 ZcmX@jc$$%WIWI340}zCoADGB}001!61s4DS delta 19 ZcmX@jc$$%WIWI340}xc+-!_r^001=21=#=q diff --git a/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-311.pyc index 4d7ffc0a3a4bccf63262c34ec45a88b2214462c1..e351c54a3ab98b2c22395479675cf4d9558f2114 100644 GIT binary patch delta 20 acmcb|e2$}u8w8X9 delta 20 acmeC=@8suR&dbZi00foyw{7IEV+Q~-)df}n diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-311.pyc index ae9b94ad600df8d3d94f493ab75ffe16cb25c970..4fbe6416e9dc39aa3c9a2695a4b7a2c1f1030ecb 100644 GIT binary patch delta 20 acmbOrG(m`aIWI340}zCoAK1vv$_W52p#(7i delta 20 acmbOrG(m`aIWI340}xc+-?ovPl@kCnTLkj} diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-311.pyc index 0bfb6326135c9996b808c50043e01e8cc8d0e47e..5bebb342030d7debad926f0ade53ca1de3031dda 100644 GIT binary patch delta 20 acmeyy@{NUiIWI340}zCoAK1v9%>)2Ek_A8j delta 20 acmeyy@{NUiIWI340}xc+-?ouEn+X6xOa=k~ diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-311.pyc index 63595ea4039f12848406b0d490616895039ac808..53cee77f3c220d185ddbb98c105a0641e8395132 100644 GIT binary patch delta 20 acmX@ZeukZUIWI340}zCoAK1u!kQo3sZv{yJ delta 20 acmX@ZeukZUIWI340}xc+-?owaATt0wDFzDw diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-311.pyc index 7b6902b3e19b891a8e52cd0e023245e34d5d2122..373ee554a933563c462b1f5f47981d36e825f73c 100644 GIT binary patch delta 20 acmaEs_biWlIWI340}zCoAK1tpZ4LlQF9sO^ delta 20 acmaEs_biWlIWI340}xc+-?ouE+8h8)=?2>X diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-311.pyc index 655c0156c3eb644fe7061d26cf0faeae8ccf7007..9282d19ff244ca1ccd316ce08fd3b20e6c67a259 100644 GIT binary patch delta 20 acmbQEI!BdzIWI340}zCoAK1t}Q3wDuHU$I# delta 20 acmbQEI!BdzIWI340}xc+-?ou^q7VQ$@CC*I diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-311.pyc index 6eb5cf5d15310acc2aa600029ab70205e6b22a58..2e5818e27c7d48e346d374aa4971589a0fc18701 100644 GIT binary patch delta 20 acmdlduup({IWI340}zCoAK1uk%mDy3hy=C( delta 20 acmdlduup({IWI340}xc+-?ow4m;(ShLIrpL diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-311.pyc index 4cdc6377993fc4e29e77adee57c248d9f80e3572..a58f0a500b6f7ec953e6a8187c2e8df0098d9746 100644 GIT binary patch delta 20 acmX@9a8iMLIWI340}zCoAK1ukCjbCBhy?!t delta 20 acmX@9a8iMLIWI340}xc+-?ow4P5=NtLIuG9 diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-311.pyc index 285f87350d49f6a452e10b94b8f1eaf1cf01f6f5..df1a293face4472c27e4e1d7c2f784f84ad6c0e6 100644 GIT binary patch delta 20 acmeyT@lS($IWI340}zCoAK1uUECK*R^aZj2 delta 20 acmeyT@lS($IWI340}xc+-?ovvSOfq^t_E}f diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-311.pyc index 1262b613498cea9442dd161164f8b0979b4d8865..7604c8da351a605950c3836334436a005ca816f0 100644 GIT binary patch delta 20 acmbQvHl2-oIWI340}zCoAK1vv!wdi}0|Y1l delta 20 acmbQvHl2-oIWI340}xc+-?ovPhZz7ey#(q2 diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-311.pyc index 8bb6cc975b60f4d9da2a4a27e0629b400eb1eb79..52800793c8e6409d3e4af4df50a8cc6d275bcb5b 100644 GIT binary patch delta 20 acmexq`_qlEW&&dbZi00g1t2R3s5;{pIM8U-Z) delta 20 acmeAa>lEW&&dbZi00foyw{7J9#{~d1)CK1N diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-311.pyc index e50ced52826ee22dea759de3ebf5621748fc6bcb..6bed99231e4ebb169a1e77e9e934c731ee4f9912 100644 GIT binary patch delta 20 acmdlWzd@dRIWI340}zCoAK1vflpg>#dj&B7 delta 20 acmdlWzd@dRIWI340}xc+-?ou^DL()^H3jnk diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-311.pyc index 2eac9836af1dd7df124f82134e3e958a83d715a7..5ddd71ba67cabcfc1581831dd944d55315e12113 100644 GIT binary patch delta 20 acmcaBdRLTtIWI340}zCoAK1u!i3N;c?F{Y diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-311.pyc index 82cd01cec82255e6542c7055afc5b86352afd361..dae04ac733143048aeb15c40506516308ce271f4 100644 GIT binary patch delta 20 acmbOjJTaJiIWI340}zCoAK1vxJO%*( diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/control.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/control.cpython-311.pyc index 975eadf2974fa528fa00d5b7e35e07a6dbb7e1d2..13dbb4c3a37dc58da4eda8cfd2fe644cf5b2f100 100644 GIT binary patch delta 20 acmews^DTyZIWI340}zCoAK1v9tp@-}9tIo$ delta 20 acmews^DTyZIWI340}xc+-?ouETMqzD*aqGJ diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-311.pyc index a6d18f34bc03360be61245312249ac404262a6aa..0065126451ba8d17c59874b8c075f525dc39b997 100644 GIT binary patch delta 20 acmdm*v^9x)IWI340}zCoAK1vPWe5O2(FJG# delta 20 acmdm*v^9x)IWI340}xc+-?ouk%MbuWiv}tH diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-311.pyc index 8d31031264b9357d0fbbf5dc7402f61a896c4e79..b78a028f6e4147a6d357a1119f8a048d637f5f94 100644 GIT binary patch delta 20 acmbQqHf-30mo delta 20 acmeA*?ltCK&dbZi00foyw{7HZk^}%amj%24 diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-311.pyc index 61a5f3cf49732ccc05f22155fb554b223e04df33..a37936445391a71d682c6ea491dbaf082d7f4264 100644 GIT binary patch delta 20 acmZoPYBb_r&dbZi00g1t2R3qllK=oR*acGn delta 20 acmZoPYBb_r&dbZi00foyw{7J9CIJ99k_Ht3 diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-311.pyc index 0cd9c45cc82b3a08590a6c752c54c574df8f3788..fe436d337054dec1683aa5bac302d3ad0c70f24a 100644 GIT binary patch delta 22 ccmeC##@Mrsk$X8WFBbz4gqk1N$julH07*~k diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/live.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/live.cpython-311.pyc index fd6b956a2b935205fd334e501cf81b3bc33c8d83..c2da438fdaad831e5e7167b5a5f378e7302e5b3a 100644 GIT binary patch delta 22 ccmZ3tjB(vEM(*Xjyj%=G5Ndv4Be!xe08EYr{{R30 delta 22 ccmZ3tjB(vEM(*Xjyj%=GPccsP)IIWI340}zCoAK1vfLjwRnlm+Ji delta 20 acmX>ccsP)IIWI340}xc+-?ou^hXw#eP6nv} diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-311.pyc index c4da0d0ce7b769dd3cc60089b0c020c7dba93e8e..88f5fa51b2d5837890df04d9bb1d8f207fcce068 100644 GIT binary patch delta 20 acmaE2@x+3AIWI340}zCoAK1tpDFXmOECq}J delta 20 acmaE2@x+3AIWI340}xc+-?ouEQU(A;<_1mx diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-311.pyc index a9a08aa732187e847f4791879a0fa31a3cb721fd..90780257e589a7b13ecca8fb300bfb2f062be1f6 100644 GIT binary patch delta 20 acmdmEwa1EkIWI340}zCoAK1ukC<_2PH3b;} delta 20 acmdmEwa1EkIWI340}xc+-?ow4P!<3`?*-cc diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-311.pyc index 1d291ff65c75363fe57db95e611c7074145fe9dd..cca118bed802ae3b64b9bdf2e34eaaa23c04f40c 100644 GIT binary patch delta 20 acmX>kcu0_YIWI340}zCoAK1vfodWkcu0_YIWI340}xc+-?ou^I|l$f1_lNI diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-311.pyc index 3c372f99bf831727333e91d280d1f031780485d6..62477d2623301fba11c0db91e7b3eb4fe98747fe 100644 GIT binary patch delta 20 acmcbvcU_NrIWI340}zCoAK1w4BMtyPw*^c9 delta 20 acmcbvcU_NrIWI340}xc+-?ow4M;rh`aRv?m diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-311.pyc index 7c0ac8b7a8f47e9da591f7f87f927747f92473a6..fa2d2c65e604e7ea7323828ce48b8526deb6739d 100644 GIT binary patch delta 20 acmdm;ygQkDIWI340}zCoAK1vf!4LpJz+uIWI340}zCoAK1wKUK#*JcLqxU delta 20 acmexm{>z+uIWI340}xc+-?oway)*zyF$WC* diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-311.pyc index 5b0faebaa3da10c7931f1e9c22222645a9f6c6b1..a5d7886d9ecf411472331b3b828ca65f810a500a 100644 GIT binary patch delta 20 acmeyP_(zd@IWI340}zCoAK1wKQ2+o!qy`!Q delta 20 acmeyP_(zd@IWI340}xc+-?owaqW}O$UIyF% diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-311.pyc index 9ecbe503e2c6ecca18e3272553fe25844640af5b..767731d930a59013c0273441df1f14bbcdfff7a1 100644 GIT binary patch delta 20 acmcaCdRdfvIWI340}zCoAK1u!f(rmTh6RBD delta 20 acmcaCdRdfvIWI340}xc+-?owa1Q!55Kn6nq diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-311.pyc index f9fa03c28e5ea151e401b53ae0757e55092be918..e4bfe390147be06288d4bfd72792f80cd9e86b6a 100644 GIT binary patch delta 22 ccmezPjq&3*M(*Xjyj%=G5Ndv4BX?Rg0AwczkN^Mx delta 22 ccmezPjq&3*M(*Xjyj%=GPde@YDIWI340}zCoAK1u!NeTc!rUmZ+ delta 20 acmca>de@YDIWI340}xc+-?owak`w?%Ub309MQf_5c6? delta 22 ccmex8iRt$wChq0Dyj%=GPZV~2Q&dbZi00g1t2R3q7asmJ?ZV~2Q&dbZi00foyw{7IE diff --git a/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-311.pyc index 2c963abdcfcaa759331fc51c7cba7a0eca648afd..d71360ba33a8c1b76752ad6a415ebdef78bbf497 100644 GIT binary patch delta 22 ccmbPsmTB5qChq0Dyj%=G5Ndv4BX{>Q08j4*+5i9m delta 22 ccmbPsmTB5qChq0Dyj%=GPoRa{p`t07Nhbh5!Hn delta 22 ccmZqaV`}MR;$F_n%f$c$mG`%8q20AXhbWB>pF delta 22 ccmezTi1G6yM(*Xjyj%=GPgZ delta 20 acmew_{9l-RIWI340}xc+-?owa3nu_Y*9O7> diff --git a/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-311.pyc index a3290cc5d1bfedb3de2dd207611e46c43728d9f8..c3f5e55b1aba7763d7c2ad93aca299125215c41b 100644 GIT binary patch delta 20 acmcb`dyAKQIWI340}zCoAK1u!o(%vxdIf?2 delta 20 acmcb`dyAKQIWI340}xc+-?owaJR1N%GzLTf diff --git a/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-311.pyc index 07c233edcddd5ab9c9e5d067337cc5aec625bfa8..6c8ff8febb666e5fd9c2242c2ce2624458f4d904 100644 GIT binary patch delta 20 acmdnOvxSFyIWI340}zCoAK1vP$p!#3W(1A^ delta 20 acmdnOvxSFyIWI340}xc+-?ouklMMhkAO%nW diff --git a/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-311.pyc index cdf70da437678e2a905411f2e75baa1dc83aadf5..415ddfb1d9e12ca3f84f92bb45ec7c129a4ec324 100644 GIT binary patch delta 20 acmX>sbXbUcIWI340}zCoAK1uk!3h91nFPuJ delta 20 acmX>sbXbUcIWI340}xc+-?ow4f)fBcQw59w diff --git a/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-311.pyc index 6c456e0b3ebf8c80ff8dadb74c0c247c510bf5f7..c7d04a1c6634edec6e40ea6a8e4c0195c4112b29 100644 GIT binary patch delta 20 acmbQmGmD3NIWI340}zCoAK1vv&jtW5Rs=u* delta 20 acmbQmGmD3NIWI340}xc+-?ovPpA7&s5CsAN diff --git a/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-311.pyc index 35e0ba02d96214d83ce8efbabaa2dcc63feed85e..d57578037efbaef22807b021ea8f8bd5d1bff525 100644 GIT binary patch delta 20 acmX?9bEt-UIWI340}zCoAK1ukZU+EGjs?&F delta 20 acmX?9bEt-UIWI340}xc+-?ow4+ztRrNCuJs diff --git a/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-311.pyc index 10e83afee0c7af77c487a156c025fd4a980cf87f..43b91ecd1ccd8f61c123d6fd28f21ae10e7f4bc9 100644 GIT binary patch delta 20 acmbPiIN6YUIWI340}zCoAK1vx$ delta 19 Zcmcc4c%6}ZIWI340}xc+-!_r^3;;HX1^oa3 diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-311.pyc index b9c51aa600408a60853891658c3e01748b3b6132..abd80c01c87f8a5e9bb078df32885d7959e18e08 100644 GIT binary patch delta 22 ccmZ3xhH>p0M(*Xjyj%=G5Ndv4Bezl*08LN^3jhEB delta 22 ccmZ3xhH>p0M(*Xjyj%=GPV!Z diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-311.pyc index a93e8130e8e050f80cab64a205ae430c8c71d664..0d9eb777218c25fbb5d96db9b71b71484812eb04 100644 GIT binary patch delta 22 ccmZo%&D6M>iF-LOFBbz4gqk1N$XzxS07oeXMgRZ+ delta 22 ccmZo%&D6M>iF-LOFBbz4RNmjVk-Kav088Ts2mk;8 diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-311.pyc index e91e7d5302d5d7831a73ed7f73b0ee1d15621863..9aa5a11c66f4f134817b7f3d047efbb6b648f856 100644 GIT binary patch delta 20 acmexf`@NQXIWI340}zCoAK1wK#tr~Z`Udd; delta 20 acmexf`@NQXIWI340}xc+-?owajU50}vdw09PCay8r+H delta 22 ccmaF8g7NhVM(*Xjyj%=GP`7X`2|$~ delta 20 acmZoLX)xhl&dbZi00foyw{7J9DhU8Lvj!Ic diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-311.pyc index 006c2a1ff3882bbefbae59718db2272379078eb2..bd1396a06dddd32fce841d609d331e3a4ccfca69 100644 GIT binary patch delta 22 ccmdlzmudH0Chq0Dyj%=G5Ndv4Blm_r08YLJ(EtDd delta 22 ccmdlzmudH0Chq0Dyj%=GPt<8 delta 22 ccmaDcpXtSXChq0Dyj%=GPOV diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-311.pyc index 965399d3270e09d6bc8856cb278842453a13a630..a63ebdf3f174430b08df6f77f01726a7ce1b57ba 100644 GIT binary patch delta 20 acmbPgKh>UlIWI340}zCoAK1vUlIWI340}xc+-?ovvOCA6_jRo=m diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-311.pyc index bd0c2dbf116723c8744c174634f4e83bf47b02c6..19b1d1602bdf5565ace2314a097d9de240755aa1 100644 GIT binary patch delta 19 Zcmcb`c#DyHIWI340}zCoADGB}9sn}{1w;S< delta 19 Zcmcb`c#DyHIWI340}xc+-!_r^JODQM1_l5C diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-311.pyc index 817fbcac3d7dcc4266ac0b9b6c834323df6051a8..bb1da8ce5c2a07d6905c9b3e36104a40d9855e83 100644 GIT binary patch delta 22 ccmX@w!g#cWk$X8WFBbz4gqk1N$Zh2W081b%7 diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-311.pyc index 33b552bcd194581ed5c240b65d262e7dfd0cd0d8..63ae4abfa3e650701d6c9b63f4e12695907ee43a 100644 GIT binary patch delta 20 acmexV`Kgk7IWI340}zCoAK1wK+y($mpa$3g delta 20 acmexV`Kgk7IWI340}xc+-?owaxeWkPS_hf{ diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-311.pyc index fc037b281a4fb2ed497aeb05053bf7b355d7c47d..a56b70de85700a0dd26a3ff14b55f0049871c0cf 100644 GIT binary patch delta 19 ZcmX@bc#4sGIWI340}zCoADGC!9{@101rz`P delta 19 ZcmX@bc#4sGIWI340}xc+-!_qZKL9kS1=aun diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-311.pyc index 41391ead4c022968d51616d00e5b13393945ba04..549421eeb163526588801cca2e9ad95beba80350 100644 GIT binary patch delta 22 ccmaF!is{WOChq0Dyj%=G5Ndv4BX{Cf0Abq)r2qf` delta 22 ccmaF!is{WOChq0Dyj%=GP83oD! diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-311.pyc index 1020cb1d05685250009113c9f211d282970ff6f1..e8794fde186e02a4593bd29cfc1eddbbc61bae87 100644 GIT binary patch delta 20 acmeyv^@odlIWI340}zCoAK1uU$O-^HT?JtP delta 20 acmeyv^@odlIWI340}xc+-?ovvkQD$!7X~8$ diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-311.pyc index 19b88cad5cfeb1ec309e988c4c2fe429a62ee340..4f9da5995186f9eb7f1850bc853cfb0c8e0807f3 100644 GIT binary patch delta 19 ZcmeCy=+@v~&dbZi00g1t2NrUR001n91W5n@ delta 19 ZcmeCy=+@v~&dbZi00foyw=Lur0RS+61q%QG diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-311.pyc index a89a317dde9f3dcfe5c16bd79cfa8f2f4b3d0b85..97a04cd1512773142a2c8890942cda69c155a6aa 100644 GIT binary patch delta 20 acmdnUyOEcBIWI340}zCoAK1vfj12%Z5(NhU delta 20 acmdnUyOEcBIWI340}xc+-?ou^85;mN%mv8+ diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-311.pyc index 7b9a0bf78d09a5c84385bb1491b15aae8b125049..75ce9ed86355b74bdb7d91f5e4c890a362875184 100644 GIT binary patch delta 20 acmcb?eS@2OIWI340}zCoAK1u!mK6Xw;RSa9 delta 20 acmcb?eS@2OIWI340}xc+-?owaEGqy$n+7=m diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-311.pyc index 99434ca11aa7118273d3fdd2fed524df5235b876..e4a92a5001d3a3d61b5cea58bd9c740b4d84b720 100644 GIT binary patch delta 20 acmeBB=}_Tb&dbZi00g1t2R3s56$Ah=@dZTy delta 20 acmeBB=}_Tb&dbZi00foyw{7J9D+mBKs|E)E diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-311.pyc index cca64e026678d7d12a34993c8ae71cafa93a045c..a53449afa59e40372c6da2ce6e30c2f218b5223b 100644 GIT binary patch delta 20 acmbO$Jy)80IWI340}zCoAK1t}i5CDe@dWMw delta 20 acmbO$Jy)80IWI340}xc+-?ou^5-$KZs|BzC diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-311.pyc index e01568ca3fe874fdd7e6f5c424bb27b97b9d5f1d..4acb1460e97b8ff9943fe6a75c2bc9e34c43b92a 100644 GIT binary patch delta 22 ccmaF3k@4Y1M(*Xjyj%=G5Ndv4Blook09VlmGXMYp delta 22 ccmaF3k@4Y1M(*Xjyj%=GP diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-311.pyc index 5d224a03c2e7bf3b1433c8dfd7c9e208175e9251..be898ca9362b845385890ae7e407a0a30749b4f8 100644 GIT binary patch delta 22 ccmdnc%($VMk$X8WFBbz4gqk1N$i37N07!iXEdT%j delta 22 ccmdnc%($VMk$X8WFBbz4RNmjVk$b5l08KXr?*IS* diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-311.pyc index 52452e7d53101ffd1b556da065c6fa0fd03d3484..2d8b482526797858eb2dda457627b27da09b2120 100644 GIT binary patch delta 20 acmZ3iyI7ZdIWI340}zCoAK1t}Lks{mas@2_ delta 20 acmZ3iyI7ZdIWI340}xc+-?ou^h8O@lECufX diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-311.pyc index 47400aed616d75ebfe1027d998a66a26c79646da..263bdd7edcb6023f1b3ecd0cf59742b387e384e5 100644 GIT binary patch delta 20 acmaD6^&*OUIWI340}zCoAK1tps|x@|r3LK( delta 20 acmaD6^&*OUIWI340}xc+-?ouERu=$EUk0xL diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-311.pyc index 81606248676a80f72620486af24452aed2de8fba..0ae20a0ab8c61e577a759981f2473af4cfc19849 100644 GIT binary patch delta 20 acmX>VaVmm)IWI340}zCoAK1ukuLA%VaVmm)IWI340}xc+-?ow4UIze1W(H6I diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-311.pyc index 34301c16babcd4c7d07526cfba5606644115db8b..f02df1f175af181ca6e3fa97b1b0030f6db020b7 100644 GIT binary patch delta 22 ccmZ48$+)_ck$X8WFBbz4gqk1N$i2V?07#PtEdT%j delta 22 ccmZ48$+)_ck$X8WFBbz4RNmjVk$Zs)08LE>?*IS* diff --git a/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-311.pyc index f2ac21e631f73e2336cbe40e59f986769206e8cc..3619d48d177e4376e380c68a5681754e47fa3986 100644 GIT binary patch delta 20 acmZouZ&T-9&dbZi00g1t2R3q73j+W#4+O^m delta 20 acmZouZ&T-9&dbZi00foyw{7IE76t${$pwi3 diff --git a/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-311.pyc index e02b988fc5f31d9569ad5e96c7812a69a274cce3..6ba28b9e75c957f7cde97b5c12116735dc4b1ca9 100644 GIT binary patch delta 20 acmX??axR5?IWI340}zCoAK1w4Yy<#A0tL7L delta 20 acmX??axR5?IWI340}xc+-?ow4*$4ngyasvz diff --git a/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-311.pyc index 16d811bf77df4ee5192c1163f13d3a13752d4a2a..b0b311fcd33a233bf61a9681607442f95a657898 100644 GIT binary patch delta 20 acmaE7@y>#KIWI340}zCoAK1v9ECT>SyalQN delta 20 acmaE7@y>#KIWI340}xc+-?ouESq1<{b_Q$! diff --git a/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-311.pyc index 163b64bb7892bca3e374543e64cf4bb6edc21d51..b87c0abbc97a29df2c556a6896511d97659beeec 100644 GIT binary patch delta 20 acmZpZY?I_(&dbZi00g1t2R3q7^8f%Z5Co(E delta 20 acmZpZY?I_(&dbZi00foyw{7IE<^cdR$^~Ws diff --git a/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-311.pyc index e3c1516c4ad9785b845143237e6c7fb0593f3e1a..8b0df7f52a12621f01a84e27a1ef75f6aab9bc0d 100644 GIT binary patch delta 20 acmdlGz9F1@IWI340}zCoAK1vfR2u+3cLluw delta 20 acmdlGz9F1@IWI340}xc+-?ou^sWt#ZF$RAC diff --git a/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-311.pyc b/lib/python3.11/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-311.pyc index d72f003725209c5b0192ca1ab549f0b1b149e75e..f08df3c3ff2ed244c0afc27d975b8cbe1f758986 100644 GIT binary patch delta 20 acmaDR{Y;vBIWI340}zCoAK1u!n->5+Sp~@e delta 20 acmaDR{Y;vBIWI340}xc+-?owaHZK4}69$U_ diff --git a/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/INSTALLER b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/LICENSE.txt b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/LICENSE.txt new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/LICENSE.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/METADATA b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/METADATA new file mode 100644 index 0000000..d4fecdb --- /dev/null +++ b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/METADATA @@ -0,0 +1,93 @@ +Metadata-Version: 2.1 +Name: psycopg +Version: 3.1.9 +Summary: PostgreSQL database adapter for Python +Home-page: https://psycopg.org/psycopg3/ +Author: Daniele Varrazzo +Author-email: daniele.varrazzo@gmail.com +License: GNU Lesser General Public License v3 (LGPLv3) +Project-URL: Homepage, https://psycopg.org/ +Project-URL: Documentation, https://psycopg.org/psycopg3/docs/ +Project-URL: Changes, https://psycopg.org/psycopg3/docs/news.html +Project-URL: Code, https://github.com/psycopg/psycopg +Project-URL: Issue Tracker, https://github.com/psycopg/psycopg/issues +Project-URL: Download, https://pypi.org/project/psycopg/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +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: Topic :: Database +Classifier: Topic :: Database :: Front-Ends +Classifier: Topic :: Software Development +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.txt +Requires-Dist: typing-extensions (>=4.1) +Requires-Dist: backports.zoneinfo (>=0.2.0) ; python_version < "3.9" +Requires-Dist: tzdata ; sys_platform == "win32" +Provides-Extra: binary +Requires-Dist: psycopg-binary (==3.1.9) ; extra == 'binary' +Provides-Extra: c +Requires-Dist: psycopg-c (==3.1.9) ; extra == 'c' +Provides-Extra: dev +Requires-Dist: black (>=23.1.0) ; extra == 'dev' +Requires-Dist: dnspython (>=2.1) ; extra == 'dev' +Requires-Dist: flake8 (>=4.0) ; extra == 'dev' +Requires-Dist: mypy (>=1.2) ; extra == 'dev' +Requires-Dist: types-setuptools (>=57.4) ; extra == 'dev' +Requires-Dist: wheel (>=0.37) ; extra == 'dev' +Provides-Extra: docs +Requires-Dist: Sphinx (>=5.0) ; extra == 'docs' +Requires-Dist: furo (==2022.6.21) ; extra == 'docs' +Requires-Dist: sphinx-autobuild (>=2021.3.14) ; extra == 'docs' +Requires-Dist: sphinx-autodoc-typehints (>=1.12) ; extra == 'docs' +Provides-Extra: pool +Requires-Dist: psycopg-pool ; extra == 'pool' +Provides-Extra: test +Requires-Dist: anyio (>=3.6.2) ; extra == 'test' +Requires-Dist: mypy (>=1.2) ; extra == 'test' +Requires-Dist: pproxy (>=2.7) ; extra == 'test' +Requires-Dist: pytest (>=6.2.5) ; extra == 'test' +Requires-Dist: pytest-cov (>=3.0) ; extra == 'test' +Requires-Dist: pytest-randomly (>=3.5) ; extra == 'test' + +Psycopg 3: PostgreSQL database adapter for Python +================================================= + +Psycopg 3 is a modern implementation of a PostgreSQL adapter for Python. + +This distribution contains the pure Python package ``psycopg``. + + +Installation +------------ + +In short, run the following:: + + pip install --upgrade pip # to upgrade pip + pip install "psycopg[binary,pool]" # to install package and dependencies + +If something goes wrong, and for more information about installation, please +check out the `Installation documentation`__. + +.. __: https://www.psycopg.org/psycopg3/docs/basic/install.html# + + +Hacking +------- + +For development information check out `the project readme`__. + +.. __: https://github.com/psycopg/psycopg#readme + + +Copyright (C) 2020 The Psycopg Team diff --git a/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/RECORD b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/RECORD new file mode 100644 index 0000000..2434333 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/RECORD @@ -0,0 +1,132 @@ +psycopg-3.1.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +psycopg-3.1.9.dist-info/LICENSE.txt,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652 +psycopg-3.1.9.dist-info/METADATA,sha256=G152cQnnElSmFSJEGnRFFsTI8MYV9OO0NFFXg76_aXw,3576 +psycopg-3.1.9.dist-info/RECORD,, +psycopg-3.1.9.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +psycopg-3.1.9.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92 +psycopg-3.1.9.dist-info/top_level.txt,sha256=npthKx2_OEoahttYqdsIPlRUgjS_bQBmfpDCVxQcPGo,8 +psycopg/__init__.py,sha256=IALSmAJ3hedCpA_mesbu-Df0jtdSj87uqkerLNmxpvA,3055 +psycopg/__pycache__/__init__.cpython-311.pyc,, +psycopg/__pycache__/_adapters_map.cpython-311.pyc,, +psycopg/__pycache__/_cmodule.cpython-311.pyc,, +psycopg/__pycache__/_column.cpython-311.pyc,, +psycopg/__pycache__/_compat.cpython-311.pyc,, +psycopg/__pycache__/_dns.cpython-311.pyc,, +psycopg/__pycache__/_encodings.cpython-311.pyc,, +psycopg/__pycache__/_enums.cpython-311.pyc,, +psycopg/__pycache__/_pipeline.cpython-311.pyc,, +psycopg/__pycache__/_preparing.cpython-311.pyc,, +psycopg/__pycache__/_queries.cpython-311.pyc,, +psycopg/__pycache__/_struct.cpython-311.pyc,, +psycopg/__pycache__/_tpc.cpython-311.pyc,, +psycopg/__pycache__/_transform.cpython-311.pyc,, +psycopg/__pycache__/_typeinfo.cpython-311.pyc,, +psycopg/__pycache__/_tz.cpython-311.pyc,, +psycopg/__pycache__/_wrappers.cpython-311.pyc,, +psycopg/__pycache__/abc.cpython-311.pyc,, +psycopg/__pycache__/adapt.cpython-311.pyc,, +psycopg/__pycache__/client_cursor.cpython-311.pyc,, +psycopg/__pycache__/connection.cpython-311.pyc,, +psycopg/__pycache__/connection_async.cpython-311.pyc,, +psycopg/__pycache__/conninfo.cpython-311.pyc,, +psycopg/__pycache__/copy.cpython-311.pyc,, +psycopg/__pycache__/cursor.cpython-311.pyc,, +psycopg/__pycache__/cursor_async.cpython-311.pyc,, +psycopg/__pycache__/dbapi20.cpython-311.pyc,, +psycopg/__pycache__/errors.cpython-311.pyc,, +psycopg/__pycache__/generators.cpython-311.pyc,, +psycopg/__pycache__/postgres.cpython-311.pyc,, +psycopg/__pycache__/rows.cpython-311.pyc,, +psycopg/__pycache__/server_cursor.cpython-311.pyc,, +psycopg/__pycache__/sql.cpython-311.pyc,, +psycopg/__pycache__/transaction.cpython-311.pyc,, +psycopg/__pycache__/version.cpython-311.pyc,, +psycopg/__pycache__/waiting.cpython-311.pyc,, +psycopg/_adapters_map.py,sha256=ZDS-g64MnEqkBzbKAhMdpGBNBfgSCaNAFtHpO5WpQew,10709 +psycopg/_cmodule.py,sha256=q6CxV-8shy72bscUFaeltbREcA8lUJ6IEFjuf4X8HfU,786 +psycopg/_column.py,sha256=TF_XEIpltbGMyXtLV2I1fL9Kgzi8KmQVOxWDedmb_nY,3803 +psycopg/_compat.py,sha256=7bA8L_rzgUZQ01_lJAs7kGj3ElgWFQtnbc4lKwUq2Lg,1763 +psycopg/_dns.py,sha256=tMxJCt1r-E-sSZjR1Yur66CaaCdUnaI4DHwSLES5Pzs,7316 +psycopg/_encodings.py,sha256=GTzriHVX0j1eDcR0gpeKp5zJaZkVe0I3a1vTiyVewXY,4518 +psycopg/_enums.py,sha256=GXJG0OqgQRaUOisysI3iWEvtGko8xrFJwAmnbehci-0,1678 +psycopg/_pipeline.py,sha256=1bFjypUcfewtmX7GVMhomNRz6rvsI2-O93HX3skMhkw,10223 +psycopg/_preparing.py,sha256=6jxCx5urk9JMsjp2PBYuq9pkSUL0aq3Z0CkhR08Mku8,6323 +psycopg/_queries.py,sha256=1Rt1E7ouEqA09kMjrVejunk85iZQMS8qCljCu4DAAhs,11627 +psycopg/_struct.py,sha256=jgJpHymLt899gaIPDlTUBkx3T6yTKBCr92DXR23loNY,2014 +psycopg/_tpc.py,sha256=3cWUSpUg0RgI_PEXCKmsr-ubHIKcqfsWX6MxOtKhUns,3583 +psycopg/_transform.py,sha256=Iz54c91djEfXWPHyAei1Z9-6ngGRGa6JCsGdtS0L318,11452 +psycopg/_typeinfo.py,sha256=PN_3o68sFGsk605wbQcy6Q1B1KzHT58ZFzqZmAAYTSw,14726 +psycopg/_tz.py,sha256=2O-tdDIVg1ckvbZ2W5gWX7O2O-RkotGEtCggn-NIT8U,1200 +psycopg/_wrappers.py,sha256=wKZt_ar8QuRgEKC6tuwamYXCwB1P7IZQsmgYdVOlAhU,3126 +psycopg/abc.py,sha256=kQ62n9TnSfZZjYrZN71CMNk9oRBIKKcWXIl-tLIInfk,7725 +psycopg/adapt.py,sha256=hnWdPy1ylx8gLMTBq99vevqmOhOyQJcDPnKuQ3SV3Vk,5307 +psycopg/client_cursor.py,sha256=F0yIS7YMDegIEtSIvzTxJ0naR6k00PWnevsxRcPoOcU,2815 +psycopg/connection.py,sha256=A5cYcH5pG5jJLSH7ddWXJXe5Ts801zDXc3BMrUNOuvs,33949 +psycopg/connection_async.py,sha256=bNL8Ic1IYHp4f2i20waPliiGWn7oySKCsvcDt6ykLGc,14051 +psycopg/conninfo.py,sha256=wbul7hMsnk38e1WBOEZ2LyYbcBXLQOyT9fAqABxiVeU,11906 +psycopg/copy.py,sha256=59LlWCNyosQgEr6F7xyWcRQbqQk6Nwhu313m58Ew0c8,29148 +psycopg/crdb/__init__.py,sha256=kyfsUIGuFvQTpLuXJcQ6gMpOB5WXeWtBa2wQjaqE3-g,396 +psycopg/crdb/__pycache__/__init__.cpython-311.pyc,, +psycopg/crdb/__pycache__/_types.cpython-311.pyc,, +psycopg/crdb/__pycache__/connection.cpython-311.pyc,, +psycopg/crdb/_types.py,sha256=ELUBFTS3UD_P2cIR68IVRZQ3Gv2CzJQvdbqt2LMB5Z4,5891 +psycopg/crdb/connection.py,sha256=qxXG1DqIro6ezbxyifOE55ZwKdWFMrtJyK05LNaIGSo,5394 +psycopg/cursor.py,sha256=16pdVsSeeBhtNftJUXho-nfGX68W6EiEyVv-mIuXnsw,30765 +psycopg/cursor_async.py,sha256=lQ7KsJHgCb_NnCOWnBq5tCv7drR4UP7_Q-FmMi6Z4KY,7924 +psycopg/dbapi20.py,sha256=-kzMT8Rn9-U2IMctFAEjVNlWFDvAHH_Q13B3k6T6TEo,3175 +psycopg/errors.py,sha256=vyKbMqtSqsE_c3UD2efvIjpn5zgOcwszpkf-CTv2J54,40714 +psycopg/generators.py,sha256=FVBEYg_9E_L-Gs2yoCk3MWJbHUvKLABQ4hEtL4fyRiM,9209 +psycopg/postgres.py,sha256=TN02kIF3l4wl5EFEHN-GoMSkcT_uBPaqlpFIY5xP634,4986 +psycopg/pq/__init__.py,sha256=1zGPgm9Zf31MfBaX7jz-t_F8YA1lRJNQx1rDJ1cnGAI,3880 +psycopg/pq/__pycache__/__init__.cpython-311.pyc,, +psycopg/pq/__pycache__/_debug.cpython-311.pyc,, +psycopg/pq/__pycache__/_enums.cpython-311.pyc,, +psycopg/pq/__pycache__/_pq_ctypes.cpython-311.pyc,, +psycopg/pq/__pycache__/abc.cpython-311.pyc,, +psycopg/pq/__pycache__/misc.cpython-311.pyc,, +psycopg/pq/__pycache__/pq_ctypes.cpython-311.pyc,, +psycopg/pq/_debug.py,sha256=jfIsSITc43a1AlNdaOd0r7UhbV6wc2ed1zBJ8n3Y4BA,3051 +psycopg/pq/_enums.py,sha256=a5crxkDrP6NMBcdYuGnoL-QExEg-qqe0QtNc9SFXt1U,5660 +psycopg/pq/_pq_ctypes.py,sha256=tr9BeMMEOnjCC8t4uZIxlyZJc-zKgztQ63hvGs0FcT4,20061 +psycopg/pq/abc.py,sha256=PGhs5_MOfYhyo23r8PLZxozK9bVH2ACe8c8TnewYPmw,7767 +psycopg/pq/misc.py,sha256=1VCWIvzebWNG1Ej7KJI5NpWsPFJReaJRGoM1VODpMJ0,3957 +psycopg/pq/pq_ctypes.py,sha256=oU085qsovMe453T-QM848j_ODetxeLagNpcTDpoL8RI,35791 +psycopg/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +psycopg/rows.py,sha256=2jh1xNMl5OQxVGxudP2H9iO9epDU0tNxe9qqufCRrq8,7449 +psycopg/server_cursor.py,sha256=fkOaZ_sTKmqVm1R190rKu1IcC3DcE7VI0Er0rsx4l68,15006 +psycopg/sql.py,sha256=1VlZ5esUXJYTU-h796FfnHJCnsiYPDcvrzjJfC_qlxo,15925 +psycopg/transaction.py,sha256=VYFmPcL9TV4OlNc3KpxC8f0CakG3wIVGYXnPc7G5O70,9426 +psycopg/types/__init__.py,sha256=JPAkV4EfkXwdsr76_U1DsQV19c8aQNSB6kgud4bhXeM,181 +psycopg/types/__pycache__/__init__.cpython-311.pyc,, +psycopg/types/__pycache__/array.cpython-311.pyc,, +psycopg/types/__pycache__/bool.cpython-311.pyc,, +psycopg/types/__pycache__/composite.cpython-311.pyc,, +psycopg/types/__pycache__/datetime.cpython-311.pyc,, +psycopg/types/__pycache__/enum.cpython-311.pyc,, +psycopg/types/__pycache__/hstore.cpython-311.pyc,, +psycopg/types/__pycache__/json.cpython-311.pyc,, +psycopg/types/__pycache__/multirange.cpython-311.pyc,, +psycopg/types/__pycache__/net.cpython-311.pyc,, +psycopg/types/__pycache__/none.cpython-311.pyc,, +psycopg/types/__pycache__/numeric.cpython-311.pyc,, +psycopg/types/__pycache__/range.cpython-311.pyc,, +psycopg/types/__pycache__/shapely.cpython-311.pyc,, +psycopg/types/__pycache__/string.cpython-311.pyc,, +psycopg/types/__pycache__/uuid.cpython-311.pyc,, +psycopg/types/array.py,sha256=e4gnMAWpjGaZ3-8N65Wm3JziPfwloKrI2dJYiqBc7lA,14643 +psycopg/types/bool.py,sha256=yLbDw8HCl26j7MFB3xlkaTdSK0pBrk2NKe5NuY4lc_w,1137 +psycopg/types/composite.py,sha256=nXzwxQUuTTXnlLRh7KZGwZb10fRo8f9q9_w8u14bKmc,9444 +psycopg/types/datetime.py,sha256=yoViTWpRkkdBImVebjwSjFufHLu9BBV_YIAuHRINzZ8,24788 +psycopg/types/enum.py,sha256=bAG0v03mUo2ts7Zb67mTY3eWta10nPOKNdczsQpytV4,5149 +psycopg/types/hstore.py,sha256=ZseqKnuB5w59JSw4bsshLSlwSVFJGiyGj-SE0yRc2gg,3718 +psycopg/types/json.py,sha256=Ru73V1w8q84Ojv769K3sI8e70YxfCGUbnkz5GPEiANM,6958 +psycopg/types/multirange.py,sha256=lMauuSHckhCSolt6HPs39CMHv515Rc6IbHK3eTmCxJs,16390 +psycopg/types/net.py,sha256=JIU0Odz8yJ_lbGanYoQ-kSrSF5k0lHYNn12wwn4uVho,6941 +psycopg/types/none.py,sha256=4b96Aw0WSW6Jpo_HMIvKUkivAxkxvHJzvzy-Q6Uf-60,613 +psycopg/types/numeric.py,sha256=RpeY0CfipDcR4t15sc3ZbytK90lFCLCJEOIhicMkpuk,13703 +psycopg/types/range.py,sha256=JshuZE2QKbDg6VBUIhmKAy3fAYDRWW3kcXctHn643Z4,20483 +psycopg/types/shapely.py,sha256=LkBsLkq_uJuzY6JzKR4vjJCGbaqRepAOjL_rSCiCvpM,2096 +psycopg/types/string.py,sha256=hWqmXSkX1da7Bg7JSuu-5f4ea6Ho3Aklz8lO89rfGzE,7662 +psycopg/types/uuid.py,sha256=5xqkVcZ22jX7a2oU9PXz_71y6VKpO5EYj8AITiSQNBE,1616 +psycopg/version.py,sha256=Li_I4PXX5XHaj8jiJpD4-vrNDBlq0PyZ3xJ2Ir_5USc,375 +psycopg/waiting.py,sha256=ki6TLORe7n9cNwpZWLjDA2kmoh9cOpckb-M7gRLAvKc,10011 diff --git a/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/REQUESTED b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/WHEEL b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/WHEEL new file mode 100644 index 0000000..1f37c02 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg-3.1.9.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/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/top_level.txt b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/top_level.txt new file mode 100644 index 0000000..296ca87 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg-3.1.9.dist-info/top_level.txt @@ -0,0 +1 @@ +psycopg diff --git a/lib/python3.11/site-packages/psycopg/__init__.py b/lib/python3.11/site-packages/psycopg/__init__.py new file mode 100644 index 0000000..baadf30 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/__init__.py @@ -0,0 +1,110 @@ +""" +psycopg -- PostgreSQL database adapter for Python +""" + +# Copyright (C) 2020 The Psycopg Team + +import logging + +from . import pq # noqa: F401 import early to stabilize side effects +from . import types +from . import postgres +from ._tpc import Xid +from .copy import Copy, AsyncCopy +from ._enums import IsolationLevel +from .cursor import Cursor +from .errors import Warning, Error, InterfaceError, DatabaseError +from .errors import DataError, OperationalError, IntegrityError +from .errors import InternalError, ProgrammingError, NotSupportedError +from ._column import Column +from .conninfo import ConnectionInfo +from ._pipeline import Pipeline, AsyncPipeline +from .connection import BaseConnection, Connection, Notify +from .transaction import Rollback, Transaction, AsyncTransaction +from .cursor_async import AsyncCursor +from .server_cursor import AsyncServerCursor, ServerCursor +from .client_cursor import AsyncClientCursor, ClientCursor +from .connection_async import AsyncConnection + +from . import dbapi20 +from .dbapi20 import BINARY, DATETIME, NUMBER, ROWID, STRING +from .dbapi20 import Binary, Date, DateFromTicks, Time, TimeFromTicks +from .dbapi20 import Timestamp, TimestampFromTicks + +from .version import __version__ as __version__ # noqa: F401 + +# Set the logger to a quiet default, can be enabled if needed +logger = logging.getLogger("psycopg") +if logger.level == logging.NOTSET: + logger.setLevel(logging.WARNING) + +# DBAPI compliance +connect = Connection.connect +apilevel = "2.0" +threadsafety = 2 +paramstyle = "pyformat" + +# register default adapters for PostgreSQL +adapters = postgres.adapters # exposed by the package +postgres.register_default_adapters(adapters) + +# After the default ones, because these can deal with the bytea oid better +dbapi20.register_dbapi20_adapters(adapters) + +# Must come after all the types have been registered +types.array.register_all_arrays(adapters) + +# Note: defining the exported methods helps both Sphynx in documenting that +# this is the canonical place to obtain them and should be used by MyPy too, +# so that function signatures are consistent with the documentation. +__all__ = [ + "AsyncClientCursor", + "AsyncConnection", + "AsyncCopy", + "AsyncCursor", + "AsyncPipeline", + "AsyncServerCursor", + "AsyncTransaction", + "BaseConnection", + "ClientCursor", + "Column", + "Connection", + "ConnectionInfo", + "Copy", + "Cursor", + "IsolationLevel", + "Notify", + "Pipeline", + "Rollback", + "ServerCursor", + "Transaction", + "Xid", + # DBAPI exports + "connect", + "apilevel", + "threadsafety", + "paramstyle", + "Warning", + "Error", + "InterfaceError", + "DatabaseError", + "DataError", + "OperationalError", + "IntegrityError", + "InternalError", + "ProgrammingError", + "NotSupportedError", + # DBAPI type constructors and singletons + "Binary", + "Date", + "DateFromTicks", + "Time", + "TimeFromTicks", + "Timestamp", + "TimestampFromTicks", + "BINARY", + "DATETIME", + "NUMBER", + "ROWID", + "STRING", +] diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48077b509d87447424a137262afc8d3c59fbadf6 GIT binary patch literal 3191 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 gQLQCzVFVo^E;s5{u literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_cmodule.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_cmodule.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c35d9beb5e712a04729966d477d1c674d11d1f69 GIT binary patch literal 896 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 B9GL(B literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_compat.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_compat.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0bc597f58603b7f6b1d820b1f0eb4edfd9a4bbb GIT binary patch literal 2444 zcmb7EO>7fK6rTODcl{GPecE@3p{V}s^ zf+G&D#DPN(9H`(JRTTxbhaNd{?4gGZ^1)iEk|j>LSwg*V>YH(F>_88lef##!yf<&& z``(-Vb!aG#U|c!>!gv)$=oOuGhjb*o{(?v75xRj4q#%Pcc#Bgw_T?2GzJev#q9WQ6 zC1OXFs4XdyEi1AeQ(|^piF0(1XeI2VlH?HPwuib07?GU_m5BrvQSg#dQXF!kY?kQE zc!cAI^n^p`H+VZkN#mFy<0uvl9;eGfwyQumg41tj{TgK$C-I08y8yQDjUk2k?a{6y zWfWqFTVwXPG7b@)i6LXwNZ{dq??w_!IP>;2W5|%pQ6qIP!gi;v6ZV8M0oe~@8Bg}x z;mNXSjNB8I@qtK2kI=}#*<)7Lo>Hb5cH`hFr{tKNv8L@AWyYRW<{+*-Se^jf=*k>j zf%ybj=aoE@$E=ebFMwj+;D4VyhGTBv{A^z}roijGGJjN!DX1Qs4cO=U?5DxLpcIbm zr@@}hwvaLNGpC#~_%&3V+dCiEUAvAuA_#v&!wW1UX7oA!dySS^FzP4%MFt&;vOf=smq5MsSy3(vrUc!Az`6!LZA`mXL;A-BFaqIoq(H{Ip0tA3T> z@7BK$rH;4`recM-MkwkoaYND3Y#c@j20KTGd(s=!IelL*0egh}UiTuj-IMR4!HTS* zXWX?SA4*37gbAHs&Bv;*c{@d(jDRmfyVRpc<@0Y=OSd&r+TGnP*)`9{#Kew4G+QfK z=4PqFU|d-~cdq1_K0aH~^c`&rd!>q3)7{EeN$r$lxl$t&)H7wX)O!Y49sLtU!xN44 z{Qk!W>BUBRF_0HugMz{Z85>nVSn%*Iy_XK?=!Ir!e+t52+I}BA+dcU%H0=}E@f+R6 z2DA!)?T|Vx3SwTd=nZv zIZYY;KawJ4Cn=k!jFpF_NlQ~)plBGbuBuRhnn!5LVbrfxz#*YP5|J`m3_6=HFx$ zfKYrA#@MBHUCU#&Beb7Fc@IElK6@!aYrB?(JNLf>!6|wa!{GzEX>=3%wc--rTkdUV zuuzmJ0Gb8u@C>o4vPO6#U$9-HYT?hxXJA7+#M_5XYYQC5wRxTs+o;Eqh)dMt^l740 zojpx-J^26Bjw5a{Kp*x~ONcgvu?M$b3NwK)(-h}|cc>*U1%uQQ6ZO^mmwvcP$#$jPiKSqW+G0Gxw^5hXCHk-q F{uf&}Vk7_n literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_dns.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_dns.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..edd48a5c8795f1f24fed8aa6c568b8964f49c88d GIT binary patch literal 12473 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 VGjb(dd7n4#H!}ZbY}nt%{U5rI3TglV literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_encodings.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_encodings.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5dfbdc7a5becf4ed8ac9b2d1de42203b1f004c17 GIT binary patch literal 7523 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 GrT+$nB4!Ez literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_enums.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_enums.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3da5c6da7433ca6f6c3e05113d2d964f2fa0a6b3 GIT binary patch literal 2673 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_preparing.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_preparing.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e02768e7387b7f9a63790a9da30221609a31f33a GIT binary patch literal 8938 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 Wk+|Y^0UsSszhn8|Kc$p0+5Z7F2j_JF literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_queries.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_queries.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed71167c3e2101e164ce9fbd5da615b5bed72951 GIT binary patch literal 16899 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_tpc.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_tpc.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abd5724bb68d047f8aac6e189b1b766919832628 GIT binary patch literal 6341 zcmcH-TW=Fr`pk^ScVauvtqqqU+?o*VQXsIXh2_?kP)s4POVf*)cqWO#_LwshLcE4` zD;`pWR8~SFZCTY16-z}Q`mnpIR{PK&un%KoiD;xqNUJ{Z=8CO^`m+0dXKcsgzzVIj z$K&tZzVn^$eDmGT{AtxHKY?;=_YcayR}u10>@$j zpcXQ&tT--a-Q#W!=Uo|3);sRa`o?{%FJ}DNz<3}V91n7YCn|Ry_OXlNzRMAEAO3b3 z?|}J$;`!F=9OubfMDblCivKPT`0%&OU8wFiI%GVg1k_M6+!#>!F)|n|4EXcPR>~3 znH)3_Rgn!jm63Jb@=!IOkyC1+_oG)nP__;xUwQwdyutpKze++iK4 zcb@zWL~xs^1O!XQ`7T%4wa8wb;y|B`Ep1oFF z?!a-^aRPwjT*>0;8pXyQk3Yl~%forZd(RV0*)icQ}!D}vf4SrRG_9|$H zl@3*eenb^vwKyp(a|3ijfYGV8QVy@69EEw_DGNmaS}rG_j5DtiS+TyW&RHky)eW?4 zKBFt}dSI>#=(<~Fr+8q*3x7PfU+G@4s#g&~$$Bi|Y+5PYIIvR13@YbzIfdFIr4==2 zq$krVjrsi&l+)9yq)nVxQ-+k1bCR6VHEBYXW^#EsbwO1mS(jvK$F{VgW+h`LpHZb( z&P{4GD;vqQa&A~UH)T+4FkF3!lAbAxr-mamCvi44yY8AihL=0Ra)sw$SK&E`~U zc~O@qz%VRMx7<`UW@s+ev@*~kH~a- zI3P$J269vN)7#Qb>rz&plP2YKMgnO_x_U{aaz>)6tZO+vCLPUz4@gae^nt8>ZlsPc z05(!2c&jlcT%?y66s%QAHj}hBvwTM`r&Q(|DB3c(1tFEuX(zOGJhdeKayWiTrt#U? z*?4wNH&mKda|)HSay*lsi09{wX)U)SwtahChqt^9-@81e>hZeEiYJYHDwdzK0(i{& zu7wb?)iNOAb_oC_QVR;c&5O~VhtZ7>q8rO6E72|0=oT}$<>^wWuSPiE=4G%H?YU_z zoGiO4(M{FpCNo%nY674=efm@n0?ALhddcnnUBaKaT|%nqs9^$+$5dhn8n>UT5Kcca zM!w+^;0!%USx*{i1t+DN6HfI0|;|?&SbI>z+=`sTVX~=&t4*nq3CDD>%~v6 z-neRd*F1qS;$RF(F~(47A!>18pnT#n4t+!D8mQWK%c!~K-B>4vNFD&VTX_B=m7r~j z>71focGv|HWqXZ41BGxNYP&$YDK2O?ZD3L;a?4I|jL?3-9~3AGn_^_79XP<#wbb4DK}5h7{R*T#;@>2UJp5K+UW&8;S7{!y%hPftI=+)72dhZ*}Ebb zjc^Hzo=Zb;u5$Lus1hrRQ$?@1UT7beld`k-Li>o|LtCV>%vMn-x{9LHBZ3Z#i9*MO z%zP3$GYA5Y@%21L&7uPU2EAZAR83w^gJXy3)U@UQjhvZLk5H;nOGxJohy+xd$y1cS z<+jrs%gx%uHL|;!YUWzXVVsKL(?p z9lw5jVSOdIx*A+P&w)Lm2Z}Fst~S?ft8~VyoiQ^Q`?0Hcf&0qyg{RDY?!V*z!--ob z=6y@ymloE4wdIQ~<@KKr-5IKcH&w%%9)^b>goi8PST!7*7heEnG1U3l)$3Om()YT* z6Dy&SYG}mtj@Wk4s)tQGc#YXXk^9&v3Z;3v}p|3L`xJbw&|@RUSPb@kb_2BzT8Hm&3>Lk!_$6-Tx7*L+w$)= z`{jx}@C#>Kj@Y1|zC>X-Jy};x$WJ7QzIt9wVZx&fODy-0vNO7YDUP9O6csnqkPuG_ z@n*u(M3beQmfMz7r(`32NtJfIwrv8^c2Hz>N~Mo~4Fn3CorH6mA!W22OhZxtp?qYg zl$wTMUf9fXpeE(#;;lGCLd&V`?Bf`oVbEpyPS53S3!~eBA4`A;VkZMG+m@V;UB}nD zY(eO;3mwgP&WvzBjOl*?0O8zAg5737S`2l~Us>u|XG)1m&xvZ!2{U|RG1|4@Govwh z9xzxQwQGB9sYf!`pQ`kXReQ$F@YqtQ^X9Hk3pWZ22e1Er{`YM5Xr*Vg+B0f~NB{e5 zO(5ZQH8<&q&VRVn*>A2Mt#lr%b{;c>$9@E|zgkesXDXqs)zDVcyVW+V7Na3e!y1B7 zXOR5Z(;6mA*lPyLG2#dsEi=y!A5J&!RPu6*sexeY#kt~&Gf1_B@Bh<&Je;<{3i*H%>BbaQ$4{1m`EQ!c;MZmjk~eVhRz;nvY{JtPLU~GPI3y&&EOTq zPQ_!=Z{h9&i8RZ`&2_oiRY7w;FJF@PQ}xmt+heaa*CZ@12_cqw1kCd6d=Fiq<+eXN&{v@Y*&rr= zFlOJ|+$!^NIwFGWV2L1I4V`+5Z0FLaU_k#A0Jx1l5)9wiX9m`nPk%jbZrc4Q+IwrS z8C>(Tn{@Us?7Xx0VgK-h{^3f0tlA%|MB>#*{9$C|L1d&7*;9?|nRhQmUVag@N1Z*l zVrFP3JmnF)zW1hGo8Fx(T>-iUJjD~tB$~N-;q|d2?;JUFTAE5jplDo9hb4A79hMrG zQ|Zl9Cyq<`sbm8qc^NL&I^6)Y207+zTQmDkOq3xXVlO3maYm(cg&vlxtQemL3c43S zi98A&H$%r6=avBcq*^@(a?RNP02=>Osw_H!zKDUe==zqs3sK=d{O!UnET9A-=u*7& z&f4mfcw0gS&rU9*Bomg%8Ls8R?sS+tB~fQ~*4phSN563Cjg z>)Jx9(lJo&7?>B9LOnP2^4ags{BYI`B`TprHIy*D2_~t*KFga-=D_5WNz0#1W;JCd zgY94v1TSamGjOw0v{W)lQKl3xSym{SlyeY^nThJKLV&v;JB-CE2Kz7px1FrIECwsU zKDuR9xH&7fFxDZtjR^1s(JcrtHKiC`nW4}(uyp_dY71l9HX|ld1Sn^HD@31C%dh4V zMQ@ED=pf;~1>wdO)3q9&ifi>^prbTe8vS^5F%Z3Z=*AnSs}G)vt8a1hQ0eXY>6`S{ z@2VXeOxF-R71z*W|GLtV`8_u3I@7hT;##-3c7UPkH?pQ{0G^6#;E@=v@m_KB!l4?0 zs(gf1%it%0xFgrzXE?PkPF%YXg^XHU+Ya2E7_p}!IMoVZYJZun+JCS6p8nmT@4N0@ ztq$%(y#4LK4cp;nyBAW(#O|`ns%6l^(C%6n!w!qXi+xf#dS_Klz;)2j+zK_HPQf0IykVgOWcLrL)8w3*%q9b;L1CY*#y@Ln^f3@&AdxI!7X-n*96vB zzv1itdUMyFdgJh0c7t(+ST(W?n}gw%PEf0LF&O>OXTXBe~>mh78_4pU>>$cJD zqbFe&{jB~70DQ~gxEjxMt{OoQB%HtG!`~w5HXF|(*^N`KJiXtUaq(qT=Sd>blEL+ygulQ{zvSj%YTXx$@CZXdnw5lXa;X|&X z{LoNoB`~(Btbx#3WzFeUrkNfmtsogdSY&oQKn8GndKUSyz>-E`O%O1k#cY7-U&|n~ zSfl^!o^y*VR#9@ggDsU#-Ma64>zwbNbMEDD?e=O4u9x>e629)EsDHti(!~`6Kcr}i zx=+1A36!4_Xu%Ys!zRBe%=now>u1B9p9`D)=5Uq2ipF#X(k*^V*y^{EcQ#ZVuJPB9 zFc-3g?S4Ci%|cbEHtg^_NZ0~lr{77!RtVSm>q)pedPu5cW}sB*%wQ?x9~2vPZ#zxYNlIwELkUfy=QD<)zJP!A^6wIwFHt=$ z^F!6A#L%oL@zJX@;zW#(MfsQ%jL4HwDa_vphUP?>zbeLVieiMna65J_8sUQxfxi%y zV^flN>1SuF|A002nDfj~7*l;uw6K_GkF5Di4 z(FJ39>&RRf#{RN+J8v0_Mnr4|`o>(0-ppHooD04!O4!-cW3LXKJv|aQe|jWu89(vb zIEJ86$L!QZG!hBG*rLL8WD4?{)jIQLY#mC&U`XqtB%ce;Vy7>hltdYZ4&mD4L0N=; zMPTY-s-#vJ9ZU`B)o^g)nwYOWKP~9qB`?XL)=hFuK!kQ#i=iLhf-ila5-C3oa%TeR zqy3Cvf;T43YPofR&mjDT_U`9Ivsfis1Xj;~WiA%20!O&eELMv(GqzH}a*lEc@|rQP zPz522T1v1Q(yK|V1=4Fs&Rv2X+P9bUOqzt+JDk5(bX2AY4uP6v1?L^MVgydHPH>23 zq0UfC{f2z?B%cdfaBWCyfVAC0!-jZwv2NWcpuBrSK9ArLY(nFT3FObLAG6RbHVQ2; z#!crA#$=nc2wU!${Y?TVHj9?>7@(A{49RI0TJNy_mOm?}7jkY9+Mv!>U7col_v+pq z@NO2{$}#28q*-W(I@$$ZY=!ydVeUKNy@R~Bh+gPXC*<)#TqmSkU|zZ)>=U*EH&yl> zb9O^&m#_^|x5IyrxK->fw+1y->)&Bkc0m4ZLhq(|&4#>Yp%3zI7y6$+8mPYt#$n)c z7|{Tf>)Eu&gV5uhkh(*#0ebGq*Nm62Qj~&c0Gq0LxP~GcnqCXW_=zB3CIS#IPEJlw zOpB3N==P6;>OeKAX#ASUho&b*e&Y5-NaUlFd<-Bo@(3#Uj3hY5dLUP>7F2 zVIbFnktuP2hi;MTiXFKYydgs4GB3x1F%f%0MhkGr%Ocbt43!p=;sE4eSma}XwPb3p z7Au3rB0MdNLUHW#_F4J%M09p)fYdhs3273i7fZ@KE>OXkIxdV2VAuHo$qZxS1GBI` zAA3&J^JQt{2besxk8OR&1h~$D4 zt!$i@n&b2gmMx`exDW9q?Tmsl=2D(WQ>?ZWrl`%!3WgGKil$<96!yg3-YEyqL&AVQFW;ox9s`s&~;(Yp2w z?AkRbPsham+2F+6!6{K5EXv1VKvUQTWD9@an@ROkCf0NR6~m{ez`s z4Bd6CH*dinCE)J|=p~gmOJZzJiWtNKS(%8%CI-n@5Y`AEjrE+K==yNr72 zWl-&}Oz37AB)IqmQ1b4>jLyJQy)IFo(_=lfv=d%Gr=^4NkTE+?dM=@{GVjrM7)DWC zbFdN_abl5Lcew7(XDrR6KZd69!;_Cc2?1l%au;+&>*fLtDA*9wunw7{jA}*(h|mN_ zphopF4hRrso|}tJ_8;hBr2~+Ij6&K1p}bi&0eVbiqsP4TB+9T&#_)mtt>YXU`x( z?i>fHsFB5(hQelby+x?N1z$RcImdu#pn(v;!aw1gCK&NAs9(^(;OXJ%e?VOP?F!HQu{LFR=Pr<0jdJW#g=D-B@Fs zS#&SaX>DaL)s9c00=gn}oOz#1a0xm=O@fVg#}d=lM&NkX$mb)}XHZAk(yJUx4>Km= za19by1raXz{~-kABj!GZ>+zMH3-l73hM0}l5|h^EPoG)|yGte`K+kA1eb01v7XS&> z!{n={v`?MqCUHH@v$)3gaCy_f&OAMxXC}ij={z)~f(=eO&o3@668ZaM^^p*GBPOEZ z*<ZPo0mxA}c0%OQd*tW+)G!j^#Ba_o&NRTlULwATQ?SoeGRmC?56f;y! z7CD;(Gh<5ZF_QtRL)Dl(Z;DJxuVG)2U*38P)}oh+i-dlJ#zjJ(vVdj(8<1zuaHO?V z3oO}pYu6p_0>xTgxxW644fTL?sgad)IY&!@qV3yqUEN7madzZv^@-8-rnZ$@T-bA7 z-^!aAOK-xI7{7aEo#cfYNFGNWLYphccP2&@o0mj_R?xL0eJnBgLFD~N>Sx*7cBQsG zQ`^3FBf%6*hB+)xJ_$X2>BOU}-&lWdB~$%9ex83rLbM53H?*Zg6IB?X1_AHG3qXMB zJ_S7m)l;DFSmN|1!U6fzE2gVw0~_lgV#zc`$53F3S7qLL;7$-a4KNS{V0kgf8-7P3 zZ-{muK_`j4HG#Y_>0-6UN1U#dB#ZPBv(yNe`XCO?V zQWYKS7K)C#RKE^y^E)d=rdSVAY&R2|kD(ONIe?imtryk%(WTV*6YrkK-aTu>4?S7$ zON#d;Em0K@PI>`*#1WAodV8J;i4mf_f6l0!-wioPcV+w>Z}D%bjP68s*7s|^^~ZX> zf;~J11o=Hz>Z016Z%@E8+j>!Hy+~N;skg3kta0m48*AJ;qoHrSN*zDMSxODZEyX!`HHHvdyy8_AGe-rq(L)I; zfL;M|;Y_MJv`xAOF$Avwe?uu|KW+X_^b zwTFxc4VUbM7toFMoJB z?asQlDei5F;Uv8@nrrkf&nHeKJC;u6wsfoyG+FH9;x( z8dqmD%L3-CtX7;N5CN=?u^X-*b4@Im;-)k%8XK-k1!94To61%!zzi$>KF&zLi!%aU zh7ZB?HmObe&v7=UF+WAUO@KrC!ipw4z?6E$*>cGRF7h9IR7~^4QB)Tt{W}`-Yl2l4 zr?jD>xa)IKa3T_%X@L|8y$g8@>~fyKEm8@s{GxsZP?cvR;EspwQ{2K7 zB~**@RgySG3@vL=l7d8GlwQOH?&@vWOX#Umk?Jq8qT3j6l5UXp@)j%>kgtdGrr5NM z3}e8e>YyA5ffEz<1dKkQa{NC-8TmLtp*12~n?p;Y!&IJ~c zwa%AoY)OrOIG>zf_icT!|F_3}b8M~atNyI-CB^qr%965R^r0udy^no+*T%oPlJyNM zzTuPwi(Op_J#O5QY21-(;?pOgro#|`owyb+FY5LC5oa+2o%sRRhM;D}9w>$-elYL8v_Tk;kKkcG{l5J*#l7mPVgIHPo?HGG3a?E*EcvgRsK6qq>* z+{4@@ij1MEJcdiuh7s^E0`58L%!b;*^TR<8tFVW0Zo>3B7B`{tVYaKL(}rnC$8Sd zuHMz*HBZ)cKye)aPiSX%x+^WOj(jrsU@&9b1ls+G z)C*YDu&o&BgkEUNBT)d{#*MxiZP~AMN4`gwm>c(6&~fg@lQo2cVY?Z(ktd^b5dpMa zv=H;PL!~Whb#dAbkz_rSJQ(^p60(vZf9Gj95OW&#Jfz9sgh&b${q9l%lJ#zPNrDKY zvTIPxX#hI;-$Neoc$pY$9Xj0MQ+EJIco9s&SyduAn=>&|VBi&b%*m%D~+)Hk;Fp{lmIsy?9jx5Bk@l(?`;LsX4xO9-oNqb;AbYLmqE3#V2xk{J~@lm>m&PLvz;kqT<5MB813KZ>=?CJNGG_`!cqDl_0qv zdCdkOnXt{R0J#niZDqdcqJidF*v;Na=&rma42R!vdwYU~oTUpfgP_-choKpn z4owlcLGLFmyYn}qgaCW76Q*0Hx1k=G;Tm91O(iJCHAYM{6={H+rXSBKw?#mlpVKlZ z4CR`CMSW~C8WZo)Q=mA+G(5vi!b$}J{4?@`nfP{eMicS!R2fR@QjM)Z4SNax)l*Bt|kTaERD0z;10-Q5d{2`=3mE~tyC^l}*MpsBktRDgQe zvH9BK(HVqm@U4<9q4_Rg2AL1z?)6nT@DrH`%?WVOsB}7XCpj3}V^z;x{72}4bRWrO zBnvxf$pPnj;fY2{ud^=mGBX;Tvp> zM?-lAYTDH6VMTu+vadYv*2}0C-GQ=+$7;X@Tw8xP0v3d$9;Nez5>D^Q*6&s7_hxK+ z*PV6A@r-i^+>Z%Ojjvo$LuxG0)$3~`nZeU=KPL3y$k*r8kQ%Gjnsbh>#lBj|I7i|B zo-w&Nu( zE-MfL3|V!X6E@c?r5$psm+BIbS(IV)eHZ0STWnNss$oxsDkF=Lhl!kV@#h?J1;LT6KFTdz3UEVayaAI2KQq^Q(Y_lYDkS$ zb9p;bqv`PnSF)|U6K2AUE8eVYo8sDrXGRVY0?b(NzTf|0f0{{O%GUQN^*s;;F0!BJ z+V-XdrEPGHQQG#dUCOo{RN4+E%}M!Q&9ik!W8zlIoOQG-j`oa2J!?V+ZE&X{evvf> zPVvLuiP0Qg(jD+HetY97AY)q5?R7}+y)Lf`0{vrUe?xPWN(2+m*l%16Sc(5K)QPA)kIh&;ro06 z|LO%tXsB1I`yj=4J5i2_ms|=%A{?4|6&}QcO*oraqQ$KyUfpc`qxHy?7!hyHN)@~G zgt<#Y)a^Eva-Tz{N8k9ff2IBvI3M`a4LkKf{)f|(q?3CJ4AncZI+(F{B*wvIl)A3i zJJR4k>Q?OC8GHA`Sb-^(D3>jV2<(A8U&9gXLxM|N-g!Zaf?XXB!!cLYa+$(ts~CaP zw-TI#Eg2>#)5I`&OSPl(cEgB_CW;|x6i2oO#h)!wPitxuF;E|~H62P#$ETN8J)c~D zaQSh~&P>ftva)m)Omy8#^xy7Tz47_sFAu{)25%~T+R&I{;aFa_VTaPN18fd0MNR*n zVQ?7&0;9Iqf&uRYKi9@N`L4wWi$hDV($ZVtAo+XD1La7_i6JLWyj69RlV2(rRtgq| zLgcy+23BeL>P-?omu+Hq z{R^yY!P-{U)@cTjwHgN1`{0JyR5HoiSY{?S%?dvt~PnE+IiD z7U5Q+i1l!)14uJ)^3}+0q7*={k68`NxD4`msYVXgv(f3J=Dmpg`4wc)nb1em9>ukN z)up)b(1>cilBHLNjlf;U1@vL zy!&zU?!PdX5Xe>#%n&p}4 zNG$IN1PE#e@uxnRj&m)cpCxY|C8yaX7sedMn3{Jqai7Xm7wcgLdKFJNKo#i1|)b~Tbf7m3nb_QQT;9GFp&f# zO-RreA$^JjH45o(kr1xJ)k4(;4`FC)iF86h{ugLyQTJCcSvX69LefChcPySMuxy>} z|5zw{{re}DPToCPuu@zt*rc|GAXw9&AXW7=AqcK&jID8ov?=0&BMPzYoaqQi(0?Tu-RS6_*S#4GLeI#5-Mrg`h zS1?&QK7C;Itl~QePJWJm7$%Q0`JRDncP^8R1rKGe1;piAQl~Oo4=Jq(xE!90DiX|G zd*?Nh1uT5b%yMlhADHnRY+#m%mJK6p#X2FK#!Nu8bc|4|flz9D`jFBxP|mh7Z!P8R z$aU{1)Ob0-&$B z{`9p~`2oxh1Rq}f`gIccb}xBUl4_d!8C}YcVYL8;umnCgq2_kZmGiWvQfWg>-w}v9+l+S7Wi_I10Jgf$m1b! zDZEvZLp4y9T%h1lNm}YSPx?}Ug2!6tSFj-sfk#jaJSs`Ii)+N@;IRtbg~vn7BiGk< z68yI7Tlv32afq!XJ8C&THC&+Jv3g)__{*at`0%wy6JK8;!AincbJgintFNt1D*Z>5 zu44rXA|Ac)t?S!~Z<~JqB6+POO*YPhorA~f?k|D)A@C43oZ#_XqRKyt{#eg$3D-{ecFaI9GKrCU|v1#j|>hBj8Ce&W*1gAjFp?t5`-*jVy^Rm{P6%Bts?#xyh!O z`twSToO)J&yI56M3uk&zJBH9gdZ@tQT=k}d<7TH{N{oVe>s)9Mr(jZQo(`4WGB<0_plTM`V F{{fdwiLU?v literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_typeinfo.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_typeinfo.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef95ff3fcb00662ecd28e1ea738c7afc031d0b7a GIT binary patch literal 23797 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/_wrappers.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/_wrappers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a04b64543fa39dac91079912dc30dad4a151264c GIT binary patch literal 7299 zcmdT|TW=dh6rS}xj#IZuTPRSnNiQT2Y_*L_R7&Z+4NVgu6oenxY`q)T#kbC`YhqQZ zg^CCW2_8VLgpl%7WEEa{<|njOq*g2O#2+v+4=7KZZ+3l2oU}@$y3Qv1?aZ9<>^W!7 zcV=dP?db_Jx-Pu+r*=5R*x#tsF0WIlKBU5Jrm+~)q?qJl=a}ZY#Wc6>y6a}_9^Lj8 za|@Y=WZo8;N6366^S8*nLKYxdSBuOiWI>X3>;4t*3kX?=WIZjiE+N}OvT)0oL2c_a z8{Ssj9sGo=xtz`oc{a=COg^piWL!4qa=H--7I)-~xp+30h}aE|I9@XsPmfcnenf?@ z$xAwmN#rRPdCIMOsO*Y)$x}Yfqp?}fJe!p?@2ybGuX*&qtV`5=RPSo4`>7tBXJ1IM zZqhPfdB!v5!Q#cBOxM{gkL$9QPv?@EgsjT%&zV=U8F^+PnK5T%)j(6$FcVy#{$N5r zVq8ldnK9C8Dn;@r-3MnPVw^Iw+$v94KCYX2o{760JMe%_nA7Tcf}f<@%#^6$TzBbt zuU26TO_F*eyTNWqcWK0X^--r;S(+@nEU%F#Z(Dvv$>;?|DZ4FqJY{f1n$@K!@sw&9 zieljHvRqmkk6u@Kv`{ES({qMNbE9W8uBO#!DtS4Y6Q&=E95@g)lBWJd_dg8xKL`&jh6nBk2KY9TE;FS*&l*W!$_;jvO7?ZNZuHN@ zdb5@bNVwd91vsPSTHc37aQ)(;7;sN6NkdE0aM>g5g1H$rt&`EPo^J>2AZRvNv=)1u znX|p~3iYW*3CP;Vy*q!5EcOoH51*j_-_MlK{dVrr$kB%*M<0wFTO2uNw*vzwgb&Ig z{wn>{3MxuEtL0PldMl(T*Yax0Rt7HCvTk z$wj;mFKeM80$t=BXeM&b8|e4qs+z&4B1>viXh&+{FF}vpfELY>Rzw1U=5_*!pkqG( zPUSLSn80YF>j)YFG77H)L}xTTm%tw@Uf6KpUrr_{<`MT}ogMdMwYWb5hj&ukLo*Tg z??AK76!*~Fj{DZGmQyY$cXXhT(^mvjs!=1~3 z-iEm~9!y{sI)w+z^%HEEf_|HY4Smb}Yjfg581NKM97Z3&X}XQ|Z{0@L-nC(CS84Co z4TiLx$-c9xtZI%v?HoIcUTd9Xg>W>=^-kvS7TeGoe?LR$bP9hPx(V*8&~3ADH(d9t z&0B0O8@zQ+b$kG=gMdANy?}iLmRAIiIJxoH&{{vaak0f-x&3<^eE=WRy`IzBKEd^c z^BqNb81kGbKUVzo$qTobm?u(xEUIPmms7f&i<>53dBy(c_paX89-|$<_@QszT3u?xFZQhR KjwZi}Wc)u`TK3og literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/abc.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/abc.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e37656fc4daf734a9a33dcf27d11e5dc19af9202 GIT binary patch literal 12508 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/connection.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/connection.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29ac0ada4967314f6a2eb23c456ca4a678ef8499 GIT binary patch literal 53152 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 W%J6OimSc^9Pl)%gt00kn{eJ)-vX-O( literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/conninfo.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/conninfo.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58fb2baf061394ee4bb1086017e027c58187307a GIT binary patch literal 19267 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/copy.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/copy.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e00c0d114e8ee87c42961179f7ec29c70cb01c17 GIT binary patch literal 44159 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
^5!etyC&!Z_^Vfh6D<5A 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 Oq-{aU0|ptj2>%JPI_J^= literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/postgres.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/postgres.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66175fb1f9beafff7f7665dafa9553510be6fb10 GIT binary patch literal 8241 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

Anmeldung

-
+

Essensanmeldung

{% csrf_token %} @@ -59,7 +59,7 @@

Hinweise

-
    +
    1. Bei überschreiten der maximalen Sitzanzahl von 7 pro Veranstaltung wird Ihre gesamte Reservierung ungültig gemacht.
    2. Gerne können Sie den Rechnungsbetrag für Ihr Ticket auch überweisen. Die Kontodaten finden Sie unter Unterstützen. Bitte geben Sie Ihren Namen und einen Hinweis auf die Reservierung im Verwendungszweck mit an.
    3. Für Reservierungen werden die Hälfte aller Plätze bereitgestellt. Weitere Plätze sind, solange der Vorrat reicht, an der Kasse verfügbar.
    4. diff --git a/templates/datenschutz.html b/templates/datenschutz.html index 4362629..85db537 100644 --- a/templates/datenschutz.html +++ b/templates/datenschutz.html @@ -1,58 +1,9 @@ {% extends 'base.html' %} {% block title %}Datenschutz{% endblock title %} {% block content %} -
      -

      Datenschutzhinweise der Christengemeinschaft

      -

      Für unsere Mitglieder, Nutzer der Internetseite und sonstige Betroffene

      -

      I. Allgemeine Hinweise und Zuständigkeiten

      -

      1. Die Datenspeicherung und -verarbeitung innerhalb der Christengemeinschaft dient nur der Erfüllung ihres kirchlichen Auftrags. Jedermann darf darauf vertrauen, dass die Christengemeinschaft Daten nur für eigene Zwecke erhebt und nicht ohne Zustimmung der Betroffenen oder gesetzliche Verpflichtung an Dritte weitergibt. Innerhalb der Christengemeinschaft ist der Zugang zu persönlichen Daten auf die Personen beschränkt, die diese Daten zur Erfüllung ihrer Aufgaben benötigen.
      Aufzeichnungen, die in Wahrnehmung eines Seelsorgeauftrages erstellt werden, sind Dritten nicht zugänglich. Die besonderen Bestimmungen über den Schutz des Beicht- und Seelsorgegeheimnisses bleiben gewahrt.
      Die staatlichen Gesetze über den Datenschutz sind innerhalb der Christengemeinschaft nicht unmittelbar anzuwenden. Die Christengemeinschaft hat vielmehr entsprechend Artikel 91 der Europäischen Datenschutz-Grundverordnung (DSGVO) die eigene Datenschutzordnung entsprechend den rechtlichen Vorgaben angepasst.
      Die aktuelle Datenschutzordnung der Christengemeinschaft (DSO) kann hier eingesehen werden. Über die demnach geltenden Bestimmungen und Grundsätze informieren wir nachfolgend.

      -

      2. Die Datenschutzhinweise gelten für die Datenverarbeitung durch die Christengemeinschaft in Deutschland – Körperschaftsverband KdöR, Pfeifferstr. 4, 34121 Kassel, verantwortlich für die Datenverarbeitung: Stefan Illemann, 0561 8 10 46 34, kv.deutschland@christengemeinschaft.org, sowie alle angeschlossenen Regionalkörperschaften und sonstigen rechtlich selbständigen Einrichtungen der Christengemeinschaft , die sie mit den jeweiligen Kontaktdaten und Verantwortlichen hier finden.
      Die Hinweise gelten außerdem für alle den Regionalkörperschaften angeschlossenen Gemeinden, die sie hier finden.

      -

      3. Datenschutzbeauftragte für den gesamten zuvor genannten Bereich der Christengemeinschaft sind:

      -
        -
      • Dorothea Humérez (Koordinatorin der Region Bayern), Telefon: 0931 – 7 20 88 52
      • -
      -

      und als Stellvertreter

      -
        -
      • Thomas Nayda (Koordinator der Region Norddeutschland), Telefon: 040 – 44 40 54 22
      • -
      -

      Postanschrift:
      Die Christengemeinschaft in Deutschland, Körperschaftsverband KdöR
      Pfeifferstraße 4, 34121 Kassel
      E-Mail: datenschutz@christengemeinschaft.org

      -

      4. Über die Einhaltung der Datenschutzordnung in der Christengemeinschaft wacht eine unabhängige Aufsichtsstelle der Christengemeinschaft für den Datenschutz, die geleitet wird von

      - -

      II. Datenschutzhinweise für die Mitglieder der Christengemeinschaft und sonstige Betroffene.

      -

      1. Personenbezogene Daten werden in der Christengemeinschaft nach den Grundsätzen verarbeitet, die in § 4 DSO definiert sind: Rechtmäßigkeit, Zweckbindung, Datenminimierung, Richtigkeit, Speicherbegren-zung, Integrität und Vertraulichkeit.
      Jedermann hat das Recht, sich darüber zu informieren, welche Daten innerhalb der Christengemeinschaft über ihn gespeichert werden, er kann dem widersprechen und besitzt weitere in der DSO aufgeführte Be-troffenenrechte.

      -

      2. Wenn Sie Mitglied der Christengemeinschaft sind oder werden, Informationen anfordern oder als Liefe-rant oder Dienstleister für die Christengemeinschaft tätig werden wollen, waren oder sind, erheben wir folgende Informationen:

      -
        -
      • Anrede, Vorname, Nachname,
      • -
      • E-Mail-Adresse,
      • -
      • Anschrift,
      • -
      • Telefonnummer (Festnetz und/oder Mobilfunk),
      • -
      • Ggf. Geburtsdatum,
      • -
      • Kontoverbindung,
      • -
      • Informationen über ihre Beziehung zur Christengemeinschaft und im Falle der Mitgliedschaft der Familienverhältnisse und empfangene Sakramente.
      • -
      -

      Die Erhebung dieser Daten erfolgt,

      -
        -
      • um Sie als Mitglied, Interessent, Dienstleister oder Lieferant identifizieren zu können;
      • -
      • zur Korrespondenz mit Ihnen;
      • -
      • zur Rechnungsstellung, bzw. Beitragserhebung;
      • -
      • Im Falle der Mitgliedschaft zur Führung der Kirchenbücher.
      • -
      -

      3. Die Datenverarbeitung erfolgt auf Basis von §§ 6,9 DSO und ist zur angemessenen Bearbeitung des Mitgliedschafts-, Vertrags- oder Interessentenverhältnisses erforderlich.
      Die von uns erhobenen personenbezogenen Daten werden spätestens nach 10 Jahren gelöscht, es sei denn ihre Kenntnis ist nur für eine kürzere oder längere Zeit entsprechend § 13 DSO erforderlich.

      -

      4. Eine Offenlegung ihrer Daten innerhalb der Christengemeinschaft ist im Rahmen des § 7 DSO zulässig, sofern dies zur Erfüllung der Aufgaben der Christengemeinschaft erforderlich ist.
      Eine Übermittlung Ihrer persönlichen Daten an Dritte erfolgt durch die Christengemeinschaft nur auf Basis von gesetzlichen Verpflichtungen z.B. an die Steuerverwaltung oder im Rahmen der Auftragsverarbeitung z.B. durch einen Steuerberater.

      -

      III. Betroffenenrechte für die Mitglieder der Christengemeinschaft und sonstige Betroffene.

      -
        -
      • Sie haben das Recht:
        gemäß § 8 DSO eine einmal erteilte Einwilligung jederzeit gegenüber uns (Christengemeinschaft in Deutschland – Körperschaftsverband KdöR, Pfeifferstr. 4, 34121 Kassel) zu widerrufen. Dies hat zur Folge, dass wir die Datenverarbeitung, die auf dieser Einwilligung beruhte, für die Zukunft nicht mehr fortführen dürfen;
      • -
      • gemäß § 11 DSO Auskunft über Ihre von uns verarbeiteten personenbezogenen Daten zu verlangen. Insbesondere können Sie Auskunft über die Verarbeitungszwecke, die Kategorie der personenbezogenen Daten, die Kategorien von Empfängern, gegenüber denen Ihre Daten offengelegt wurden oder werden, die geplante Speicherdauer, das Bestehen eines Rechts auf Berichtigung, Löschung, Einschränkung der Verarbeitung oder Widerspruch, das Bestehen eines Beschwerderechts verlangen;
      • -
      • gemäß § 12 DSO unverzüglich die Berichtigung unrichtiger oder Vervollständigung Ihrer bei uns gespeicherten personenbezogenen Daten zu verlangen;
      • -
      • gemäß § 13 DSO die Löschung Ihrer bei uns gespeicherten personenbezogenen Daten zu verlangen, soweit nicht die Verarbeitung zur Ausübung des Rechts auf freie Meinungsäußerung und Information, zur Erfüllung einer rechtlichen Verpflichtung, aus Gründen des öffentlichen Interesses oder zur Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen erforderlich ist;
      • -
      • gemäß § 14 DSO die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen, soweit die Richtigkeit der Daten von Ihnen bestritten wird;
      • -
      • gemäß § 15 DSO Ihre personenbezogenen Daten, die Sie uns bereitgestellt haben, in einem strukturierten, gängigen und maschinenlesebaren Format zu erhalten oder die Übermittlung an einen anderen Verantwortlichen zu verlangen;
      • -
      • gemäß § 16 DSO Widerspruch gegen die Verarbeitung ihrer personenbezogenen Daten unter folgender Anschrift zu erheben:
        Christengemeinschaft in Deutschland – Körperschaftsverband KdöR, Pfeifferstr. 4, 34121 Kassel;
        es genügt eine E-Mail an: kv.deutschland@christengemeinschaft.org;
      • -
      • gemäß § 31 sich bei der unabhängigen Aufsichtsstelle der Christengemeinschaft zu beschweren. Dietmar Schwarz, Christengemeinschaft, Mittelweg 13, 20148 Hamburg, Tel: 040 – 41 33 02 72 / E-Mail: d.schwarz@cg-sozialwerke.de
      • -
      -

      IV. Datenschutzhinweise für Besucher dieser Website

      -

      1. Durch den Besuch unserer Website können Informationen über Ihren Zugriff (insbesondere Datum, Uhrzeit, aufgerufene Seite, genutzter Webbrowser, IP-Adresse) auf dem Server gespeichert werden. Diese Daten können nicht bestimmten Personen zugeordnet werden. Die Speicherung dient technischen und statistischen Zwecken. Unsere Website verwendet außerdem Cookies. Ein Cookie ist eine Textdatei, die auf Ihrer Festplatte zwischengespeichert wird. Wird der Server unserer Website erneut aufgerufen, sendet der Webbrowser den zuvor empfangenen Cookie wieder zurück an den Server. Durch Cookies kann insbe-sondere das Navigieren auf einer Internetseite erleichtert werden. Wenn Sie die Speicherung von Cookies unterbinden möchten, können Sie dies durch die Anpassung der Einstellungen Ihres Webbrowsers errei-chen. Allerdings wird hierdurch ggf. die Funktionalität der Website eingeschränkt.

      +
      +

      Datenschutzhinweise

      +
      Wir verarbeiten Ihre Daten nur zum Zwecke der Bereitstellung auf der Website angebotener Dienstleistungen. +
      {% endblock content %} diff --git a/templates/drama.html b/templates/drama.html index 0ed7c1c..2774cfc 100644 --- a/templates/drama.html +++ b/templates/drama.html @@ -10,6 +10,6 @@
      -

      Rudolf Steiner begann die Mysteriendramen zu schreiben mit dem Ziel, insgesamt die Textbücher für 12 Dramen fertigzustellen. Heute darf unsere Gesellschaft sich glücklich schätzen, die ersten vier Dramen zu kennen. Die Dramen sind Beispiele für die Verwandlung der Menschen auf dem Weg der inneren Schulung. Sie berichten von der geistigen und seelischen Entwicklung der Menschen.
      Im ersten Drama, der „Pforte der Einweihung“, geht es um Johannes Thomasius, welcher sich, aufgrund einer Erkenntnis, die er nach einem Vortragsbesuch hatte, in einer tiefen Lebenskrise befindet. Er versucht nun verzweifelt, seinen innersten Wesenskern zu finden, doch je genauer und kritischer er sich selbst betrachtet, desto mehr verschwindet sein Ich aus seinem Selbstbild. Außerdem empfindet er, ohne sich davon distanzieren zu können, alles, was seine Mitmenschen berichten oder erleiden, nach. Er widersteht jedoch den Versuchungen, sich in eine andere, der Realität fernen, Welt zu träumen und wird so schließlich von seinem Lehrer für bereit erklärt, sich auf den Entwicklungsweg zu begeben.
      Im Laufe des Stückes geht er dann durch eine ganz bestimmte Verwandlung, beeinflusst von guten und bösen Wesen und Geistern der Natur. Dabei macht nicht nur Johannes Thomasius eine Entwicklung durch, sondern auch alle, welche sich eng mit ihm verbunden hatten.
      Siehe hier für weitere Informationen: Die Mysteriendramen Rudolf Steiners | Anthrowiki

      +

      Rudolf Steiner begann die Mysteriendramen zu schreiben mit dem Ziel, insgesamt die Textbücher für 12 Dramen fertigzustellen. Heute darf unsere Gesellschaft sich glücklich schätzen, die ersten vier Dramen zu kennen. Die Dramen sind Beispiele für die Verwandlung der Menschen auf dem Weg der inneren Schulung. Sie berichten von der geistigen und seelischen Entwicklung der Menschen.
      Im ersten Drama, der „Pforte der Einweihung“, geht es um Johannes Thomasius, welcher sich, aufgrund einer Erkenntnis, die er nach einem Vortragsbesuch hatte, in einer tiefen Lebenskrise befindet. Er versucht nun verzweifelt, seinen innersten Wesenskern zu finden, doch je genauer und kritischer er sich selbst betrachtet, desto mehr verschwindet sein Ich aus seinem Selbstbild. Außerdem empfindet er, ohne sich davon distanzieren zu können, alles, was seine Mitmenschen berichten oder erleiden, nach. Er widersteht jedoch den Versuchungen, sich in eine andere, der Realität fernen, Welt zu träumen und wird so schließlich von seinem Lehrer für bereit erklärt, sich auf den Entwicklungsweg zu begeben.
      Im Laufe des Stückes geht er dann durch eine ganz bestimmte Verwandlung, beeinflusst von guten und bösen Wesen und Geistern der Natur. Dabei macht nicht nur Johannes Thomasius eine Entwicklung durch, sondern auch alle, welche sich eng mit ihm verbunden hatten.

      {% endblock content %} diff --git a/templates/footer.html b/templates/footer.html index 1f21dac..0f46b46 100644 --- a/templates/footer.html +++ b/templates/footer.html @@ -1,9 +1,6 @@
      -
      + -
      -
      ©2023 Die Christengemeinschaft in Bayern KdöR, Gemeinde Nürnberg
      -
      diff --git a/templates/impressum.html b/templates/impressum.html index db0cf60..60242f8 100644 --- a/templates/impressum.html +++ b/templates/impressum.html @@ -4,12 +4,12 @@

      Impressum

      Angaben gemäß § 5 TMG

      -

      Die Christengemeinschaft – Gemeinde Nürnberg (KdöR)

      -

      Krelingstr. 26 90408 Nürnberg Vertreten durch: Daniel Hafner (Pfarrer)

      +

      Daniel Hafner

      +

      Kaulbachstraße 11 90408 Nürnberg

      Kontakt:
      Telefon: +49-911-93207882
      Email: dhafner1964@hotmail.com

      -

      Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV: Daniel Hafner (Pfarrer)

      +

      Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV: Daniel Hafner

      Haftungsausschluss (Disclaimer)

      Haftung für Inhalte Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen. Haftung für Links Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen. Urheberrecht Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.

      diff --git a/templates/ueber.html b/templates/ueber.html index 68bcacd..cbb043f 100644 --- a/templates/ueber.html +++ b/templates/ueber.html @@ -3,8 +3,6 @@ {% block title %}Über uns{% endblock title %} {% block content %}
      -
      -
      diff --git a/website/__pycache__/views.cpython-311.pyc b/website/__pycache__/views.cpython-311.pyc index 6d6a6c1564c55608c820be7687d0f9a00e5d3e80..1dadaecb2e06eb6468d1309a90c030833e8d6cd4 100644 GIT binary patch delta 2183 zcmb7EO>7%Q6yDj5f3uDg|EBr##&szriPOp{C247!v}p@XNg7+UYUq#So!V~fO&G61 zF*d$%NUI78+e5gZNK~b$l}Ht-Cy+q7ATI1$fkcsVL>y320)+$Oz#F@Tnj#=oIAevWNkCdtKFS#4vZEms*acta6gK9?WsFWu0aiQ7;;@ zYz7F?SVU8n6U}0EloR=TmfJem1bV35(e7_~zm4~(+oGzMbOHl!nSU4eLsWoE_;usO4 z7*NKYL`Z)K4(;Yx9Ft^R7LxN1A~7%&-i;ICwU`7m5qf{o9|+QfiLiC|QJj+JZ^`kf z@`v7=7eY9k1TP}Io{nNkjFR-k1Qt$BresXwK#*`UOj>E2JCd8o!*J9Xmckv8aVeEf z$Z;v^kBlcXZZQ_VEMc;z`{k~~v2i&Wjwk5CG2*4W)Rgn|$K<5)yTh6%dtrg>qtFeI zJ`M0cl7!fUaXB-Q2+J9QQ<%I1<)L*fXNo1inb3bO-3U-Jh7x435SN6$q4@`+35Xs` zJwk@{o6`+X8l9n4A#ym;Bc$t}TppPJdK5>-V39so%HR5y=PPW+HM}w4vhd5?@&3@R zYO(`%D_$V-BAwBvj=Vr&Ck39u00sJ65);5O7nkH+W>PCsrudYWFB*A?a>b`~bHSJS zB;3hx6ki-27bjEn-4@D?&?jx#R920I;QIvh)UT|PaGuN?OeuDWcYQQ?ZBXNz7x-qC zZ(g!D+&r*o-(Ik9pE;)4+ZOC?Q%5V3E4)*6?NI|KzVFfkgR2Y|MD1$~*VVqNXZ%A* z9ez_in_p#^K6ZqKVHlmKLy{%zs)4hl*tHNthet&OcbNZWWbB@g{Wtwnh83&xMpX55 z&bl>g_ky)sHFhr>+Ep-kG=pd6_^p9OUsu7`H9MmDdKY}X-(D#Ag4!pp*8Cb{ zF&*KS_~u34Tj0GK?_1z~D(|b9MrG37ax=T=-dS+(ykpkffdzM9>crA>l6f#~+&$Z+ zHSU9i_lMXuhG`11Qv)kj+l^PQ=C0?a-!51M)hf)itAQakIHCnc)C&0$gzDK43;At1P}PAh$Uvl*78h^lvA#6oNaK=NC$;Z c3dOq~QatVkH1c_m8#T3}o>k^aAa=0+4;ms-g8%>k delta 656 zcmeCOzh=OrI}^EX9~LdA*P|qtE2mLjJ5GHH-^bCl?BfOjckK5G&yYs)B+Vh7^`%ObiUGnI>C` z$T1axbQyEAW&?$Q=KGZJPkt+;%FI;5H2DIz3R{s#4HLp33+x8Lj1Fd~VaS4U7*g1v zX3CccPF56_n0!*0&je(94f8Uft5<_u4hF#tDGb33n(Tf>GC=+<&b0iZ-1w5pg4A2A zsl~;qd6Tb8$kpFsc6SZYHO!QC diff --git a/website/views.py b/website/views.py index 060becb..a24b93e 100644 --- a/website/views.py +++ b/website/views.py @@ -74,12 +74,32 @@ def anmeldung(request): essen_form = EssenForm(request.POST) if essen_form.is_valid(): essen_form.save() - return render(request, 'anmeldung.html') + name = request.POST.get('name') + mail = request.POST.get('mail') + send_mail('Essensanmeldung erhalten!', '''Sehr geehrte/r ''' + name + ''', +hiermit möchten wir Ihnen den Erhalt Ihrer Essensanmeldung bestätigen. +Mit freundlichen Grüßen, +Ihr Team der Jugendgruppe Mysteriendrama''', 'webmailer@denkena-consulting.com', [mail, 'mysteriendrama@denkena-consulting.com', 'dhafner1964@hotmail.com',], fail_silently=False) + context = init_context() + return render(request, 'anmeldung.html', context) if request.method == 'POST' and request.POST.get("form_type") == "reservierung": reservierung_form = ReservierungForm(request.POST) if reservierung_form.is_valid(): reservierung_form.save() - return render(request, 'anmeldung.html') + name = request.POST.get('name') + mail = request.POST.get('mail') + anzahl_b = request.POST.get('anzahl_b') + anzahl_w = request.POST.get('anzahl_w') + anzahl_l = request.POST.get('anzahl_l') + message_body = '''Sehr geehrte/r ''' + name + ''',\nhiermit möchten wir Ihnen den Erhalt Ihrer Sitzplatzreservierung bestätigen.\n''' + if int(anzahl_b) > 0: message_body += ('Sitzplätze in Böblingen: ' + anzahl_b + '.\n') + if int(anzahl_w) > 0: message_body += ('Sitzplätze in Wuppertal: ' + anzahl_w + '.\n') + if int(anzahl_l) > 0: message_body += ('Sitzplätze in Lübeck: ' + anzahl_l + '.\n') + message_body += ('''Mit freundlichen Grüßen, +Ihr Team der Jugendgruppe Mysteriendrama''') + send_mail('Reservierung erhalten!', message_body, 'webmailer@denkena-consulting.com', [mail, 'mysteriendrama@denkena-consulting.com', 'dhafner1964@hotmail.com'], fail_silently=False) + context = init_context() + return render(request, 'anmeldung.html', context) if request.method == 'GET': context = init_context() return render(request, 'anmeldung.html', context)

__)sBmh|zo5%f!pF-&kI2Pk{e|s#f3-F=vvbAXJcO*fA-D%N1y3L7Yc^ zAW!1D`mrG9Xu9b~MSfjR&(9GnR+grh_kv*b}|@)x4eKj z$68u9J}xH`Sc+P0gR4LLAtjzba8saxQXc%U*toaUxOZI;>-(OBx36AYJyi^Mm%`n7 zr5Jvu5O{_s8!I+OOO4TW!CfD5B>VWvBk#l6;@;;pnXF9K>=cxCAJ{PO&Ri}{|9-n{>2As8(LhaO)1#T$=% zezotj{-J_@sJf}NJTS?E*bE6vd7P_{$^{`{QmLp8A$iS8XCNtc8K1N)svW8-j2$^CwgC8?WU(MRt7%7*G8E{ z^8SZAO43ovEAseRcCvym-AH!pPg%nC9YOEme8_8NhmMU$ z2;Kud8i4zCi0fl+#iMwwWnS?mT*r_u;Z^{;t>;s&C1DE6&s%}9`h-_$P#Uc`0PX;X z;sDq_rP-bz06YQjAOJPgq6q=%8W`YiR9XPSTc>Oyh8|CVJiH`a7suKlbTl&(l`moL zGU4Nd0SgI)8}JwqE5Sr^S<-Z^9*LF?>C;sHSmL$@R0<-8cpO(bTH`3y@t%n%f!?5r z;sQ1VeOmKRXJ-|tyhuSrvTat=lB9zofX_0NWU~$g9Zl4(O)K%_)EuE$E-Tw>ZD3kp z3Ik4RgQRu?QkcUdMapDzX1=@|SQH^=RxP0CSyi5%hP)5-jymWHq6xhZhOf&cQV$MV z*x~r` zLxNN5v?$uwEN5KaT%VAIc~mlg=>5U|W3EvL?Dio&DF-&j5Zn_kV=cK9bruFGiYG(s2^0&ifdf@)g>M>;rJzcuAv`|c zV^E5zRv0*z$^vt0$8ljK`w?=}NbtHT6q+ya-*4O>Ud@L;zFKTQSZY652%cQhmb72a zKGyzf;jb6WRE(#gB3`I&6qPMKsAq(#c#Z;Er!^WNNxI2bk#5`=3nUaQhPLA-B|L)Q zYpjs04!_Y*O0oGusrkZ^`-#8lcHMH_=l+h*{2i;|qJL+}zq4TcIABIb|KDIbmfxh=NKyjQ@@ABKS~zRS=nwacSEk zguOhTRUfx2Q0fnad!i^TcM{EU!B}K#Hv0B8ylqn++xzyL`eUS@zdo%VpWkB+yn(N6 z18=1IhsaCYkKpUS6aJ0{f9py79(Av}|5@PA1NlEGcJ!Az`uS6PXpFjtrYslW`Y9{w zcWHu;Gs#xAaW-mki_-NWpm7eizJLABb$iZ_+kUkT_rdVkSS+;ONFK3obP zE(8wO#%7do%fq_jj{U{(fl~NDA#lKs$$U%$t(M(bXdFXCyq6780T&g7^fb;LdK%YW z6f@C^p&(Mw59d&5VY`|M3R;n=Wh)d%?-J{<LnNZdB(Xr6NhLI0FtQ0ay;Iq2Z%lfoQt;`WlvO;J zx+PgM=+P|N$drpgJZmPHM0@+B-q_|c5xp2eiIF}jf&wCz=r;eXQ3}r}W{QoH(NkQV zrjgnh?e3En{R0GhM4nx(&w23@yPWJg_5amSVoi zQHLK>8d9i3)w)9nw69D(h!-0prA7iu_03PVbgZ_2@aEk&mrgC6deX9e_0-2Fi!ISo z3sfNKcjFAeqX%EQ-Qni11O(8TG&Qd`2%+}(Z``@DdgT5K#b8g# zg1WIS4AZKlbyH7MFhT(_8LsyUfG}AZ;4#1QEfBOs)1fZi3TMEblU)K4Q7*Bf`1^ozLrK42$+6<<6ZoOgO5| zVEqAfpRiU6Zmu&hII6+2F$=Yt#Crbe7@dy@2kEF#G;(41%<##J(v1U)(y7UuQ$sYXkEZ=x24` ze1+3nVqfHVlXOi2?=>a|R@uu%|%_vSET&Z zkIm&P2JhXY^K5E!YOP$K`NFJDATL;)F5<-3B4)B+tFuf|I{u|j*bM&$KpQ6X{r5;Ru=L&&ySd|gaQ*j1f8yZtj zgYyX+1ZkX31GN{CS{Y{xMYx1u#s8%!P1e?mgtdb<`3FV7YH9js`FuuX-r0;h06 zx|&5OK-4xnG1%<|PH`4#ZAd6j`BWX1)?TKunfK1*ruv_Ua-G>058y2(F_nGH|4%Un zjCIm;h}9JqdSe-oWdmkl*#Amt$i0D76cfPJ99V)gSF0~$BI>|cX z^Wg5!g1htXVsK9>xToOX!@8yHf$k9Y%eQ9f>`))nA>$zaH%ZnjZ0B!gyQdHv+*jyLfdE{Ds~8aZ5%)2Xq_>Z=_sD7t?D(d!@yArLBn-rzsSmVf4g zhRe)MdJ=L=LW)jIV9}c(|F#J%dJ_{d2qk6>C_@<@F#V47EEV%+yOK>o7~$Snw!-;z zd0O$P6)&5Fo~Pu;U3|IQ&kXq&leEKeF8G=$8!rVOfN#vC*xN5E+d z`;o9^x%_C!G`wITnK31};p;mA^k)bJrg+FJ#&Mxpk})WTpBxMjHM_8{#weJX=%WFN z12zE?O{t?2+=o!_bvAZJ|MhVdfZ^{ga}x#|Ki!#*325jOLwR5hsiWVhsJE24*{lk% z&N~q=nAM`L=QYV@$WhlY-PrOV7jtI2&^U2*sRnr+7(8~6Xw5QF7-ksLqtHgk@Bx-h zbw&mCn;ua57@1uT`P9%_FnQb>e>omUn^@yXM22W-E{c}8&peMwux7p;#?TvnWfq-t z|EoR{wT=~ z5Ya0cNhTt!npVT<9ZTljtd+URl+jS4O5|~aO^DyqT)g(u=1ry?UW%OSeJwkqz6I0U zCSCV`-(0<_z2|!MGJ36cGheIuXeP_B9bBHdkrV!h%s<|oDCB|&f|>8JQli&kMb(H& zRwf&rKMGSG89X(xNzgjvBHU->CEbqS|WKlnNwdy2HdZro*Sx2u2SDZ zP18ce?uzm`w+0< zO?FBYq{xzMtt+xrx9%7A?)&NZ=RJd;^$b2f@~an$J;SA*;dNn0J(Oz*ih-`BlPhg2 zxz&phA0bvYofV(7ONFjii|uDh?Pm(1Gy3ya`18}n_K{NiNFg)=a|)&3vleQ-SO4Ss z2i>djkD~XZ#ZY%C)LjU5e-R8XEv$t)aDIQ`&cf|?mfwLot0}q`h6{wdrTt0gp0$qi zU%Fk}+rJVJK!>%ZecdOtgekk#JrA_}k&ou?&)wf&4DBn0_7y_=);f2s)UDKgv1Qx3 zP|tE&dHMHcvpRdfzZi;^LeWAfx)$2Hdhmk)Wnz`IH{W)@uNdkrg?bC@_gi={xo$5k zFBJUSIiMlqq61o(2-A;FXHv7v2`ij(-J-i*Sa8*rqaDbyLY8vo0_oKa*}4zX`6hW) z?hV2lo29I9?u7ZTKNIQ}?8tVHpt?oj4I$&16|TGA5N1U?wygnvM0qPfgt^GR0*w^b zKD#%AT?n+Tk-D&llw1-~xQ8#3_DC;L=?2Xbnr428Qidx4TVE|M^g0wWHYtlQfW4Zb zio&X^DI{C!j@M?f-QAyZ zG+a4|J0e%Oi*UKk)+bL{GD#1GHNsd;Z2B9sx>SgQY zr}W8mZF=!02e_ThoPHc6tOnl`RUK zOX|M0G~-m2lDd+)vY4#&tR)@$yq`EA(Z_boLhT+Nf&c9hnnO#jCrvFY-M8OZeq+hC z?y9TbxfW=Cf8@@{hl$lgA6&V6r5M;<3hXWfc7sEl6^m=k`+SI5kc|0s%8c>jnv0x7gxEI&+P>w89|KMg|EA`h>=gf@dp!MbFl? zmadidQcG8{rMuM9ee;!dkK21*T!mqR&c7#Y5WU+>r#f7dQyor~fzRXZF^w3wCL0D$ zl|kT?=-ol?addtN*E~8udY+$agy&s5k=~#0EOqp)3%Gs+Qo!k31bkhfE~CCQ508Ge zaRnE(Efp57wt3fiZFY$|c+}xO;e+kKpQx+Y=;mb`-N+6RV0MKj;BCk!meebEqY`Y^ zoiJDxM;)e$nIt29t69=io0AS-#>U26zrhkA>FeHeI#;sFuw3QLOc|VFn(>4TtuJkU z)43yo-$BYZ+ZlEQDav<}5+^3*d?GtTHVw9Gk(3YSwi7Z%rxe3z0q3^y@j>ZIE;p?W z?x#(X0|2B{Nn)j0_40oBziRuj<%a4-n<4wPIqXEc-k(yg(-xb7E4g&4n>Zpn(6s&w zZ;W0%@x%U+q2bYsBd11&U%SAUsTypaIBxEs&fu+1k23CRN%1V%p&H3199X); z)#K3APRrC?Y=YR4nzi_TOLGa&VL&fjx0vV!3>c;pRwJ&IuG5_X z96Djrjnay-@gETUaqK4xq87AEx`~P%A>?ra*>)ecQ&GwKvEbT#8x$-pB!%lo!nNRn zCyV<*g#`Vsxcm&WwRlG7JFU4yav8x$_{PErnwy*7=VU*mafEKA!ee4Hi;Rp)SWXkr z{72})y9mmn#*H$xFn|PZ+Po6OR&`9{%q0?J=tV5OzjZhvZY}z|O8zcvQ~M$atR&VC zGKy|>>DE|R_ zZEXei+KP8vEv@TrBwBYHS@0FEYU?NYOt|sCv4Fs7#jzaWXzORfReR%`eSGbs>+mdc z**Cm7Q4sQWvu&iFQMCtk_{P;Ise5q&$CX~3xJ*T2PT8H7r^_DVBaGP97#=c-N4K@? z!~MK-7%1`hIJHDOiddLj%*~{uh2ZGJp?^K{vyorM|LvY%d;Ye*c=VOh(N~Inua^2= zMWp`okMgb~1CIkVQn#_L`|r4T&-0$Q=8i%EmM0e`3#HVL>d9g!{RP)mGp)0$?s%UD z*zS0iJWC{Ka4%GIGF5t^!XV_XZ7!+YM+i{_(<~~}Hdo_Y41hMcR5VS7?*O44i|QRb zhh{z5FgGR;eCX1>oA)h>x7~R>sXpMLhEb|MDxF)MT>=m1XABQ#SGk2NGRLizLQNt^ z%;48>Qg2Z}COYiz)8ZPR!#DLgd;!nrd#%iI0xlb8SU%3oZ0sQvTwPt(QFky7Z0nTXNS2DNk`R;My+VwS1}3l0Fn^kwR5ZfWeI z$3*v-2#f(S3nNi+*+bQ5Em4HMQ1-Mvw4?k+WV!=2i(o6%^#-U*3cC2>^@o-PGX zFL{vT`*U~ZR@>~ZuGsbwMI9>Lw;Jdf13!~=)lC6SX&W@M08yMG5(pRr(A)hZdPu>G z)Xq%a$qJQN%k8u3Ys<$e?Pta}>0t$C=-aN0cR6usv}z6a?X^SG)AeRba5 zCa}RZ0UMmYMZkFs)ty>q9z>&bY|xNen|q9}Y1lX8z#WRdgy8{{0OY{j^)Wwx`6Do2 zCLw$a{J=aH$ikGWfab;C41Tvp*y-|PCG8v05MvoRRohcVu;nOsODXZjj0kdd*0 zx#)2J2v#TZrFn<%b+>)h!qlhmZ?0U?H{wv4*m*-+di0b21sIl)LhXfMB` z4wMDSse~Swo`%b(x;#k+H!eV-0Q!gz1XS8n-(@M)VPoS+hCcm4n|0urm68TkWomGO zef@>$KDb0iAB~ZYk$q3=x8jboT`Eo^j^Pfwi9o9v=s|ZgBIwYYt-u7DfgOxQM-Dl` zfM$ROBLR?|55 zT56Li4|C!4-fDt+#K*o0gzx@fBci`*BO>v)dQz3th-*R|Z9Z&fYLp=OUt_uPJQ>@$ zU0SXOFMTQtv|F*6Xv5i-<*Z=nO}MF_nady!>6S41vXl9JEBMG)+QoI<#l%EUl;UC< zoEsRMFrQ4q1a1F1lr1;Qe(tCwSBD@2duEi4ji2cN92Eu6(_Kc*oCzgSE0bVU{G&OR zzalrg0eEvpZJ6tw&|9nAW=L%#clw%|Xg=pjQXvNOw!zg<3+INz^xQZDzEbqYVodtM zi8HScUtrgpJ3rRao&zpKoyv0fHc@BUY1pv_4qL=|5J{cLuZn|F!RozPI(C+4(g)?$95%W29jTr>lO#4`7ZMvz?A^e<_R{tYq&N^!dGwiW%mO8#Bg8%VCZdp>q^|4-5ro#L*$Lyw0FJLp$z z9WJ#F7XrgyG&Zm7S$c8lMF!rEK1>vL9>uTN`dq1%ePpCDxZLsQIQ~wcCb3IrC6F!-tRb8T|A5lQmSoWNF{o*;!$(*_}eLoj-Zpmqm9bE*e z=PT%utI7Ty(c`;_hHfC#y5wDJ3@*PwG`DXp(DMG7J7*rWttRd#KiYkNcQFtv1!9Fj zjM5x?aQ*&bp|KA?Jz-(n(fpC09xHVp!4-bRz;mSl5#bl6`t9XH@MW%kd!!Wmj+Oe3 z;er11zsxDAO65jym{HOhTx_PTbh>)0O>9KLrTBp!C*88}z?1QSZ_*WgoEC~MS5K66 z_%~t?Bz@}SvX?=~YT+MWiApF=@xKG<=eO9Wxd|HoBlRokozSoFZePH6p`aPrH}DI5 z((Ys-xOZjfEQ(|w-ns_d9eSpVE@B-F?gsHJXG-WFJ#3+HNh3*?mwY=GZj=LU3F7X zp@O1uwi)K*belk6*F*hNdPu(Is@>9VD$n! zJ)C)T;c@iQrP6-(RT>^=rLtW`>b&1!8Yw!Ho~a^ibu1iC>xPC;op}AsMNSqGzCrT{;?;L3kz1aOt3+As14CsW zlq4|OayJKJx!l8n1O%@AYoIF{ld^02ZKf<`z7l0G)2lG>&N*To(0h7X&athV@bfc1 z(yVc%DjVBQ%8Y#ogLzaiM~NTNGXl75+|<9ItA9a(6JUSiKgPeJbX@%zVllkf%Ym5* zKM_$}cez9lx)nh{5Swo{(chZDPIS>-sP$VDUM>9Lzb}N2g7dc~>?}BcYeKY8>$fIE z3eMk}&{J^!)_qMPc~qXdZ9X4K^5@yD=X@|F2Ub;Q(HRvqZ_ww-1Mw9G%a;6C2tQb58SMy IKQ?Lp4}O`b>i_@% literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/transaction.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/transaction.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc37514878927187a400ed625c7d9367676c2560 GIT binary patch literal 15556 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 RAVP$JU#x)}1dCXK(f}~)Nwxq0 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/__pycache__/waiting.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/__pycache__/waiting.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac862f6c735fd1e7313c654d0b78b11e467826bb GIT binary patch literal 13346 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 L%Ifqe-Sz(m?(k+i literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/_adapters_map.py b/lib/python3.11/site-packages/psycopg/_adapters_map.py new file mode 100644 index 0000000..70bf4cc --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_adapters_map.py @@ -0,0 +1,295 @@ +""" +Mapping from types/oids to Dumpers/Loaders +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Any, Dict, List, Optional, Type, TypeVar, Union +from typing import cast, TYPE_CHECKING + +from . import pq +from . import errors as e +from .abc import Dumper, Loader +from ._enums import PyFormat as PyFormat +from ._cmodule import _psycopg +from ._typeinfo import TypesRegistry + +if TYPE_CHECKING: + from .connection import BaseConnection + +RV = TypeVar("RV") + + +class AdaptersMap: + r""" + Establish how types should be converted between Python and PostgreSQL in + an `~psycopg.abc.AdaptContext`. + + `!AdaptersMap` maps Python types to `~psycopg.adapt.Dumper` classes to + define how Python types are converted to PostgreSQL, and maps OIDs to + `~psycopg.adapt.Loader` classes to establish how query results are + converted to Python. + + Every `!AdaptContext` object has an underlying `!AdaptersMap` defining how + types are converted in that context, exposed as the + `~psycopg.abc.AdaptContext.adapters` attribute: changing such map allows + to customise adaptation in a context without changing separated contexts. + + When a context is created from another context (for instance when a + `~psycopg.Cursor` is created from a `~psycopg.Connection`), the parent's + `!adapters` are used as template for the child's `!adapters`, so that every + cursor created from the same connection use the connection's types + configuration, but separate connections have independent mappings. + + Once created, `!AdaptersMap` are independent. This means that objects + already created are not affected if a wider scope (e.g. the global one) is + changed. + + The connections adapters are initialised using a global `!AdptersMap` + template, exposed as `psycopg.adapters`: changing such mapping allows to + customise the type mapping for every connections created afterwards. + + The object can start empty or copy from another object of the same class. + Copies are copy-on-write: if the maps are updated make a copy. This way + extending e.g. global map by a connection or a connection map from a cursor + is cheap: a copy is only made on customisation. + """ + + __module__ = "psycopg.adapt" + + types: TypesRegistry + + _dumpers: Dict[PyFormat, Dict[Union[type, str], Type[Dumper]]] + _dumpers_by_oid: List[Dict[int, Type[Dumper]]] + _loaders: List[Dict[int, Type[Loader]]] + + # Record if a dumper or loader has an optimised version. + _optimised: Dict[type, type] = {} + + def __init__( + self, + template: Optional["AdaptersMap"] = None, + types: Optional[TypesRegistry] = None, + ): + if template: + self._dumpers = template._dumpers.copy() + self._own_dumpers = _dumpers_shared.copy() + template._own_dumpers = _dumpers_shared.copy() + + self._dumpers_by_oid = template._dumpers_by_oid[:] + self._own_dumpers_by_oid = [False, False] + template._own_dumpers_by_oid = [False, False] + + self._loaders = template._loaders[:] + self._own_loaders = [False, False] + template._own_loaders = [False, False] + + self.types = TypesRegistry(template.types) + + else: + self._dumpers = {fmt: {} for fmt in PyFormat} + self._own_dumpers = _dumpers_owned.copy() + + self._dumpers_by_oid = [{}, {}] + self._own_dumpers_by_oid = [True, True] + + self._loaders = [{}, {}] + self._own_loaders = [True, True] + + self.types = types or TypesRegistry() + + # implement the AdaptContext protocol too + @property + def adapters(self) -> "AdaptersMap": + return self + + @property + def connection(self) -> Optional["BaseConnection[Any]"]: + return None + + def register_dumper( + self, cls: Union[type, str, None], dumper: Type[Dumper] + ) -> None: + """ + Configure the context to use `!dumper` to convert objects of type `!cls`. + + If two dumpers with different `~Dumper.format` are registered for the + same type, the last one registered will be chosen when the query + doesn't specify a format (i.e. when the value is used with a ``%s`` + "`~PyFormat.AUTO`" placeholder). + + :param cls: The type to manage. + :param dumper: The dumper to register for `!cls`. + + If `!cls` is specified as string it will be lazy-loaded, so that it + will be possible to register it without importing it before. In this + case it should be the fully qualified name of the object (e.g. + ``"uuid.UUID"``). + + If `!cls` is None, only use the dumper when looking up using + `get_dumper_by_oid()`, which happens when we know the Postgres type to + adapt to, but not the Python type that will be adapted (e.g. in COPY + after using `~psycopg.Copy.set_types()`). + + """ + if not (cls is None or isinstance(cls, (str, type))): + raise TypeError( + f"dumpers should be registered on classes, got {cls} instead" + ) + + if _psycopg: + dumper = self._get_optimised(dumper) + + # Register the dumper both as its format and as auto + # so that the last dumper registered is used in auto (%s) format + if cls: + for fmt in (PyFormat.from_pq(dumper.format), PyFormat.AUTO): + if not self._own_dumpers[fmt]: + self._dumpers[fmt] = self._dumpers[fmt].copy() + self._own_dumpers[fmt] = True + + self._dumpers[fmt][cls] = dumper + + # Register the dumper by oid, if the oid of the dumper is fixed + if dumper.oid: + if not self._own_dumpers_by_oid[dumper.format]: + self._dumpers_by_oid[dumper.format] = self._dumpers_by_oid[ + dumper.format + ].copy() + self._own_dumpers_by_oid[dumper.format] = True + + self._dumpers_by_oid[dumper.format][dumper.oid] = dumper + + def register_loader(self, oid: Union[int, str], loader: Type["Loader"]) -> None: + """ + Configure the context to use `!loader` to convert data of oid `!oid`. + + :param oid: The PostgreSQL OID or type name to manage. + :param loader: The loar to register for `!oid`. + + If `oid` is specified as string, it refers to a type name, which is + looked up in the `types` registry. ` + + """ + if isinstance(oid, str): + oid = self.types[oid].oid + if not isinstance(oid, int): + raise TypeError(f"loaders should be registered on oid, got {oid} instead") + + if _psycopg: + loader = self._get_optimised(loader) + + fmt = loader.format + if not self._own_loaders[fmt]: + self._loaders[fmt] = self._loaders[fmt].copy() + self._own_loaders[fmt] = True + + self._loaders[fmt][oid] = loader + + def get_dumper(self, cls: type, format: PyFormat) -> Type["Dumper"]: + """ + Return the dumper class for the given type and format. + + Raise `~psycopg.ProgrammingError` if a class is not available. + + :param cls: The class to adapt. + :param format: The format to dump to. If `~psycopg.adapt.PyFormat.AUTO`, + use the last one of the dumpers registered on `!cls`. + """ + try: + # Fast path: the class has a known dumper. + return self._dumpers[format][cls] + except KeyError: + if format not in self._dumpers: + raise ValueError(f"bad dumper format: {format}") + + # If the KeyError was caused by cls missing from dmap, let's + # look for different cases. + dmap = self._dumpers[format] + + # Look for the right class, including looking at superclasses + for scls in cls.__mro__: + if scls in dmap: + return dmap[scls] + + # If the adapter is not found, look for its name as a string + fqn = scls.__module__ + "." + scls.__qualname__ + if fqn in dmap: + # Replace the class name with the class itself + d = dmap[scls] = dmap.pop(fqn) + return d + + raise e.ProgrammingError( + f"cannot adapt type {cls.__name__!r} using placeholder '%{format}'" + f" (format: {PyFormat(format).name})" + ) + + def get_dumper_by_oid(self, oid: int, format: pq.Format) -> Type["Dumper"]: + """ + Return the dumper class for the given oid and format. + + Raise `~psycopg.ProgrammingError` if a class is not available. + + :param oid: The oid of the type to dump to. + :param format: The format to dump to. + """ + try: + dmap = self._dumpers_by_oid[format] + except KeyError: + raise ValueError(f"bad dumper format: {format}") + + try: + return dmap[oid] + except KeyError: + info = self.types.get(oid) + if info: + msg = ( + f"cannot find a dumper for type {info.name} (oid {oid})" + f" format {pq.Format(format).name}" + ) + else: + msg = ( + f"cannot find a dumper for unknown type with oid {oid}" + f" format {pq.Format(format).name}" + ) + raise e.ProgrammingError(msg) + + def get_loader(self, oid: int, format: pq.Format) -> Optional[Type["Loader"]]: + """ + Return the loader class for the given oid and format. + + Return `!None` if not found. + + :param oid: The oid of the type to load. + :param format: The format to load from. + """ + return self._loaders[format].get(oid) + + @classmethod + def _get_optimised(self, cls: Type[RV]) -> Type[RV]: + """Return the optimised version of a Dumper or Loader class. + + Return the input class itself if there is no optimised version. + """ + try: + return self._optimised[cls] + except KeyError: + pass + + # Check if the class comes from psycopg.types and there is a class + # with the same name in psycopg_c._psycopg. + from psycopg import types + + if cls.__module__.startswith(types.__name__): + new = cast(Type[RV], getattr(_psycopg, cls.__name__, None)) + if new: + self._optimised[cls] = new + return new + + self._optimised[cls] = cls + return cls + + +# Micro-optimization: copying these objects is faster than creating new dicts +_dumpers_owned = dict.fromkeys(PyFormat, True) +_dumpers_shared = dict.fromkeys(PyFormat, False) diff --git a/lib/python3.11/site-packages/psycopg/_cmodule.py b/lib/python3.11/site-packages/psycopg/_cmodule.py new file mode 100644 index 0000000..288ef1b --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_cmodule.py @@ -0,0 +1,24 @@ +""" +Simplify access to the _psycopg module +""" + +# Copyright (C) 2021 The Psycopg Team + +from typing import Optional + +from . import pq + +__version__: Optional[str] = None + +# Note: "c" must the first attempt so that mypy associates the variable the +# right module interface. It will not result Optional, but hey. +if pq.__impl__ == "c": + from psycopg_c import _psycopg as _psycopg + from psycopg_c import __version__ as __version__ # noqa: F401 +elif pq.__impl__ == "binary": + from psycopg_binary import _psycopg as _psycopg # type: ignore + from psycopg_binary import __version__ as __version__ # type: ignore # noqa: F401 +elif pq.__impl__ == "python": + _psycopg = None # type: ignore +else: + raise ImportError(f"can't find _psycopg optimised module in {pq.__impl__!r}") diff --git a/lib/python3.11/site-packages/psycopg/_column.py b/lib/python3.11/site-packages/psycopg/_column.py new file mode 100644 index 0000000..50577e6 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_column.py @@ -0,0 +1,142 @@ +""" +The Column object in Cursor.description +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Any, NamedTuple, Optional, Sequence, TYPE_CHECKING +from operator import attrgetter + +if TYPE_CHECKING: + from .cursor import BaseCursor + + +class ColumnData(NamedTuple): + ftype: int + fmod: int + fsize: int + + +class Column(Sequence[Any]): + __module__ = "psycopg" + + def __init__(self, cursor: "BaseCursor[Any, Any]", index: int): + res = cursor.pgresult + assert res + + fname = res.fname(index) + if fname: + self._name = fname.decode(cursor._encoding) + else: + # COPY_OUT results have columns but no name + self._name = f"column_{index + 1}" + + self._data = ColumnData( + ftype=res.ftype(index), + fmod=res.fmod(index), + fsize=res.fsize(index), + ) + self._type = cursor.adapters.types.get(self._data.ftype) + + _attrs = tuple( + attrgetter(attr) + for attr in """ + name type_code display_size internal_size precision scale null_ok + """.split() + ) + + def __repr__(self) -> str: + return ( + f"" + ) + + def __len__(self) -> int: + return 7 + + def _type_display(self) -> str: + parts = [] + parts.append(self._type.name if self._type else str(self.type_code)) + + mod1 = self.precision + if mod1 is None: + mod1 = self.display_size + if mod1: + parts.append(f"({mod1}") + if self.scale: + parts.append(f", {self.scale}") + parts.append(")") + + if self._type and self.type_code == self._type.array_oid: + parts.append("[]") + + return "".join(parts) + + def __getitem__(self, index: Any) -> Any: + if isinstance(index, slice): + return tuple(getter(self) for getter in self._attrs[index]) + else: + return self._attrs[index](self) + + @property + def name(self) -> str: + """The name of the column.""" + return self._name + + @property + def type_code(self) -> int: + """The numeric OID of the column.""" + return self._data.ftype + + @property + def display_size(self) -> Optional[int]: + """The field size, for :sql:`varchar(n)`, None otherwise.""" + if not self._type: + return None + + if self._type.name in ("varchar", "char"): + fmod = self._data.fmod + if fmod >= 0: + return fmod - 4 + + return None + + @property + def internal_size(self) -> Optional[int]: + """The internal field size for fixed-size types, None otherwise.""" + fsize = self._data.fsize + return fsize if fsize >= 0 else None + + @property + def precision(self) -> Optional[int]: + """The number of digits for fixed precision types.""" + if not self._type: + return None + + dttypes = ("time", "timetz", "timestamp", "timestamptz", "interval") + if self._type.name == "numeric": + fmod = self._data.fmod + if fmod >= 0: + return fmod >> 16 + + elif self._type.name in dttypes: + fmod = self._data.fmod + if fmod >= 0: + return fmod & 0xFFFF + + return None + + @property + def scale(self) -> Optional[int]: + """The number of digits after the decimal point if available.""" + if self._type and self._type.name == "numeric": + fmod = self._data.fmod - 4 + if fmod >= 0: + return fmod & 0xFFFF + + return None + + @property + def null_ok(self) -> Optional[bool]: + """Always `!None`""" + return None diff --git a/lib/python3.11/site-packages/psycopg/_compat.py b/lib/python3.11/site-packages/psycopg/_compat.py new file mode 100644 index 0000000..7dbae79 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_compat.py @@ -0,0 +1,72 @@ +""" +compatibility functions for different Python versions +""" + +# Copyright (C) 2021 The Psycopg Team + +import sys +import asyncio +from typing import Any, Awaitable, Generator, Optional, Sequence, Union, TypeVar + +# NOTE: TypeAlias cannot be exported by this module, as pyright special-cases it. +# For this raisin it must be imported directly from typing_extension where used. +# See https://github.com/microsoft/pyright/issues/4197 +from typing_extensions import TypeAlias + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from typing_extensions import Protocol + +T = TypeVar("T") +FutureT: TypeAlias = Union["asyncio.Future[T]", Generator[Any, None, T], Awaitable[T]] + +if sys.version_info >= (3, 8): + create_task = asyncio.create_task + from math import prod + +else: + + def create_task( + coro: FutureT[T], name: Optional[str] = None + ) -> "asyncio.Future[T]": + return asyncio.create_task(coro) + + from functools import reduce + + def prod(seq: Sequence[int]) -> int: + return reduce(int.__mul__, seq, 1) + + +if sys.version_info >= (3, 9): + from zoneinfo import ZoneInfo + from functools import cache + from collections import Counter, deque as Deque +else: + from typing import Counter, Deque + from functools import lru_cache + from backports.zoneinfo import ZoneInfo + + cache = lru_cache(maxsize=None) + +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: + from typing_extensions import TypeGuard + +if sys.version_info >= (3, 11): + from typing import LiteralString +else: + from typing_extensions import LiteralString + +__all__ = [ + "Counter", + "Deque", + "LiteralString", + "Protocol", + "TypeGuard", + "ZoneInfo", + "cache", + "create_task", + "prod", +] diff --git a/lib/python3.11/site-packages/psycopg/_dns.py b/lib/python3.11/site-packages/psycopg/_dns.py new file mode 100644 index 0000000..1e146ba --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_dns.py @@ -0,0 +1,223 @@ +# type: ignore # dnspython is currently optional and mypy fails if missing +""" +DNS query support +""" + +# Copyright (C) 2021 The Psycopg Team + +import os +import re +import warnings +from random import randint +from typing import Any, DefaultDict, Dict, List, NamedTuple, Optional, Sequence +from typing import TYPE_CHECKING +from collections import defaultdict + +try: + from dns.resolver import Resolver, Cache + from dns.asyncresolver import Resolver as AsyncResolver + from dns.exception import DNSException +except ImportError: + raise ImportError( + "the module psycopg._dns requires the package 'dnspython' installed" + ) + +from . import errors as e +from .conninfo import resolve_hostaddr_async as resolve_hostaddr_async_ + +if TYPE_CHECKING: + from dns.rdtypes.IN.SRV import SRV + +resolver = Resolver() +resolver.cache = Cache() + +async_resolver = AsyncResolver() +async_resolver.cache = Cache() + + +async def resolve_hostaddr_async(params: Dict[str, Any]) -> Dict[str, Any]: + """ + Perform async DNS lookup of the hosts and return a new params dict. + + .. deprecated:: 3.1 + The use of this function is not necessary anymore, because + `psycopg.AsyncConnection.connect()` performs non-blocking name + resolution automatically. + """ + warnings.warn( + "from psycopg 3.1, resolve_hostaddr_async() is not needed anymore", + DeprecationWarning, + ) + return await resolve_hostaddr_async_(params) + + +def resolve_srv(params: Dict[str, Any]) -> Dict[str, Any]: + """Apply SRV DNS lookup as defined in :RFC:`2782`.""" + return Rfc2782Resolver().resolve(params) + + +async def resolve_srv_async(params: Dict[str, Any]) -> Dict[str, Any]: + """Async equivalent of `resolve_srv()`.""" + return await Rfc2782Resolver().resolve_async(params) + + +class HostPort(NamedTuple): + host: str + port: str + totry: bool = False + target: Optional[str] = None + + +class Rfc2782Resolver: + """Implement SRV RR Resolution as per RFC 2782 + + The class is organised to minimise code duplication between the sync and + the async paths. + """ + + re_srv_rr = re.compile(r"^(?P_[^\.]+)\.(?P_[^\.]+)\.(?P.+)") + + def resolve(self, params: Dict[str, Any]) -> Dict[str, Any]: + """Update the parameters host and port after SRV lookup.""" + attempts = self._get_attempts(params) + if not attempts: + return params + + hps = [] + for hp in attempts: + if hp.totry: + hps.extend(self._resolve_srv(hp)) + else: + hps.append(hp) + + return self._return_params(params, hps) + + async def resolve_async(self, params: Dict[str, Any]) -> Dict[str, Any]: + """Update the parameters host and port after SRV lookup.""" + attempts = self._get_attempts(params) + if not attempts: + return params + + hps = [] + for hp in attempts: + if hp.totry: + hps.extend(await self._resolve_srv_async(hp)) + else: + hps.append(hp) + + return self._return_params(params, hps) + + def _get_attempts(self, params: Dict[str, Any]) -> List[HostPort]: + """ + Return the list of host, and for each host if SRV lookup must be tried. + + Return an empty list if no lookup is requested. + """ + # If hostaddr is defined don't do any resolution. + if params.get("hostaddr", os.environ.get("PGHOSTADDR", "")): + return [] + + host_arg: str = params.get("host", os.environ.get("PGHOST", "")) + hosts_in = host_arg.split(",") + port_arg: str = str(params.get("port", os.environ.get("PGPORT", ""))) + ports_in = port_arg.split(",") + + if len(ports_in) == 1: + # If only one port is specified, it applies to all the hosts. + ports_in *= len(hosts_in) + if len(ports_in) != len(hosts_in): + # ProgrammingError would have been more appropriate, but this is + # what the raise if the libpq fails connect in the same case. + raise e.OperationalError( + f"cannot match {len(hosts_in)} hosts with {len(ports_in)} port numbers" + ) + + out = [] + srv_found = False + for host, port in zip(hosts_in, ports_in): + m = self.re_srv_rr.match(host) + if m or port.lower() == "srv": + srv_found = True + target = m.group("target") if m else None + hp = HostPort(host=host, port=port, totry=True, target=target) + else: + hp = HostPort(host=host, port=port) + out.append(hp) + + return out if srv_found else [] + + def _resolve_srv(self, hp: HostPort) -> List[HostPort]: + try: + ans = resolver.resolve(hp.host, "SRV") + except DNSException: + ans = () + return self._get_solved_entries(hp, ans) + + async def _resolve_srv_async(self, hp: HostPort) -> List[HostPort]: + try: + ans = await async_resolver.resolve(hp.host, "SRV") + except DNSException: + ans = () + return self._get_solved_entries(hp, ans) + + def _get_solved_entries( + self, hp: HostPort, entries: "Sequence[SRV]" + ) -> List[HostPort]: + if not entries: + # No SRV entry found. Delegate the libpq a QNAME=target lookup + if hp.target and hp.port.lower() != "srv": + return [HostPort(host=hp.target, port=hp.port)] + else: + return [] + + # If there is precisely one SRV RR, and its Target is "." (the root + # domain), abort. + if len(entries) == 1 and str(entries[0].target) == ".": + return [] + + return [ + HostPort(host=str(entry.target).rstrip("."), port=str(entry.port)) + for entry in self.sort_rfc2782(entries) + ] + + def _return_params( + self, params: Dict[str, Any], hps: List[HostPort] + ) -> Dict[str, Any]: + if not hps: + # Nothing found, we ended up with an empty list + raise e.OperationalError("no host found after SRV RR lookup") + + out = params.copy() + out["host"] = ",".join(hp.host for hp in hps) + out["port"] = ",".join(str(hp.port) for hp in hps) + return out + + def sort_rfc2782(self, ans: "Sequence[SRV]") -> "List[SRV]": + """ + Implement the priority/weight ordering defined in RFC 2782. + """ + # Divide the entries by priority: + priorities: DefaultDict[int, "List[SRV]"] = defaultdict(list) + out: "List[SRV]" = [] + for entry in ans: + priorities[entry.priority].append(entry) + + for pri, entries in sorted(priorities.items()): + if len(entries) == 1: + out.append(entries[0]) + continue + + entries.sort(key=lambda ent: ent.weight) + total_weight = sum(ent.weight for ent in entries) + while entries: + r = randint(0, total_weight) + csum = 0 + for i, ent in enumerate(entries): + csum += ent.weight + if csum >= r: + break + out.append(ent) + total_weight -= ent.weight + del entries[i] + + return out diff --git a/lib/python3.11/site-packages/psycopg/_encodings.py b/lib/python3.11/site-packages/psycopg/_encodings.py new file mode 100644 index 0000000..876acb9 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_encodings.py @@ -0,0 +1,170 @@ +""" +Mappings between PostgreSQL and Python encodings. +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +import string +import codecs +from typing import Any, Dict, Optional, TYPE_CHECKING + +from .pq._enums import ConnStatus +from .errors import NotSupportedError +from ._compat import cache + +if TYPE_CHECKING: + from .pq.abc import PGconn + from .connection import BaseConnection + +OK = ConnStatus.OK + + +_py_codecs = { + "BIG5": "big5", + "EUC_CN": "gb2312", + "EUC_JIS_2004": "euc_jis_2004", + "EUC_JP": "euc_jp", + "EUC_KR": "euc_kr", + # "EUC_TW": not available in Python + "GB18030": "gb18030", + "GBK": "gbk", + "ISO_8859_5": "iso8859-5", + "ISO_8859_6": "iso8859-6", + "ISO_8859_7": "iso8859-7", + "ISO_8859_8": "iso8859-8", + "JOHAB": "johab", + "KOI8R": "koi8-r", + "KOI8U": "koi8-u", + "LATIN1": "iso8859-1", + "LATIN10": "iso8859-16", + "LATIN2": "iso8859-2", + "LATIN3": "iso8859-3", + "LATIN4": "iso8859-4", + "LATIN5": "iso8859-9", + "LATIN6": "iso8859-10", + "LATIN7": "iso8859-13", + "LATIN8": "iso8859-14", + "LATIN9": "iso8859-15", + # "MULE_INTERNAL": not available in Python + "SHIFT_JIS_2004": "shift_jis_2004", + "SJIS": "shift_jis", + # this actually means no encoding, see PostgreSQL docs + # it is special-cased by the text loader. + "SQL_ASCII": "ascii", + "UHC": "cp949", + "UTF8": "utf-8", + "WIN1250": "cp1250", + "WIN1251": "cp1251", + "WIN1252": "cp1252", + "WIN1253": "cp1253", + "WIN1254": "cp1254", + "WIN1255": "cp1255", + "WIN1256": "cp1256", + "WIN1257": "cp1257", + "WIN1258": "cp1258", + "WIN866": "cp866", + "WIN874": "cp874", +} + +py_codecs: Dict[bytes, str] = {} +py_codecs.update((k.encode(), v) for k, v in _py_codecs.items()) + +# Add an alias without underscore, for lenient lookups +py_codecs.update( + (k.replace("_", "").encode(), v) for k, v in _py_codecs.items() if "_" in k +) + +pg_codecs = {v: k.encode() for k, v in _py_codecs.items()} + + +def conn_encoding(conn: "Optional[BaseConnection[Any]]") -> str: + """ + Return the Python encoding name of a psycopg connection. + + Default to utf8 if the connection has no encoding info. + """ + if not conn or conn.closed: + return "utf-8" + + pgenc = conn.pgconn.parameter_status(b"client_encoding") or b"UTF8" + return pg2pyenc(pgenc) + + +def pgconn_encoding(pgconn: "PGconn") -> str: + """ + Return the Python encoding name of a libpq connection. + + Default to utf8 if the connection has no encoding info. + """ + if pgconn.status != OK: + return "utf-8" + + pgenc = pgconn.parameter_status(b"client_encoding") or b"UTF8" + return pg2pyenc(pgenc) + + +def conninfo_encoding(conninfo: str) -> str: + """ + Return the Python encoding name passed in a conninfo string. Default to utf8. + + Because the input is likely to come from the user and not normalised by the + server, be somewhat lenient (non-case-sensitive lookup, ignore noise chars). + """ + from .conninfo import conninfo_to_dict + + params = conninfo_to_dict(conninfo) + pgenc = params.get("client_encoding") + if pgenc: + try: + return pg2pyenc(pgenc.encode()) + except NotSupportedError: + pass + + return "utf-8" + + +@cache +def py2pgenc(name: str) -> bytes: + """Convert a Python encoding name to PostgreSQL encoding name. + + Raise LookupError if the Python encoding is unknown. + """ + return pg_codecs[codecs.lookup(name).name] + + +@cache +def pg2pyenc(name: bytes) -> str: + """Convert a PostgreSQL encoding name to Python encoding name. + + Raise NotSupportedError if the PostgreSQL encoding is not supported by + Python. + """ + try: + return py_codecs[name.replace(b"-", b"").replace(b"_", b"").upper()] + except KeyError: + sname = name.decode("utf8", "replace") + raise NotSupportedError(f"codec not available in Python: {sname!r}") + + +def _as_python_identifier(s: str, prefix: str = "f") -> str: + """ + Reduce a string to a valid Python identifier. + + Replace all non-valid chars with '_' and prefix the value with `!prefix` if + the first letter is an '_'. + """ + if not s.isidentifier(): + if s[0] in "1234567890": + s = prefix + s + if not s.isidentifier(): + s = _re_clean.sub("_", s) + # namedtuple fields cannot start with underscore. So... + if s[0] == "_": + s = prefix + s + return s + + +_re_clean = re.compile( + f"[^{string.ascii_lowercase}{string.ascii_uppercase}{string.digits}_]" +) diff --git a/lib/python3.11/site-packages/psycopg/_enums.py b/lib/python3.11/site-packages/psycopg/_enums.py new file mode 100644 index 0000000..a7cb78d --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_enums.py @@ -0,0 +1,79 @@ +""" +Enum values for psycopg + +These values are defined by us and are not necessarily dependent on +libpq-defined enums. +""" + +# Copyright (C) 2020 The Psycopg Team + +from enum import Enum, IntEnum +from selectors import EVENT_READ, EVENT_WRITE + +from . import pq + + +class Wait(IntEnum): + R = EVENT_READ + W = EVENT_WRITE + RW = EVENT_READ | EVENT_WRITE + + +class Ready(IntEnum): + R = EVENT_READ + W = EVENT_WRITE + RW = EVENT_READ | EVENT_WRITE + + +class PyFormat(str, Enum): + """ + Enum representing the format wanted for a query argument. + + The value `AUTO` allows psycopg to choose the best format for a certain + parameter. + """ + + __module__ = "psycopg.adapt" + + AUTO = "s" + """Automatically chosen (``%s`` placeholder).""" + TEXT = "t" + """Text parameter (``%t`` placeholder).""" + BINARY = "b" + """Binary parameter (``%b`` placeholder).""" + + @classmethod + def from_pq(cls, fmt: pq.Format) -> "PyFormat": + return _pg2py[fmt] + + @classmethod + def as_pq(cls, fmt: "PyFormat") -> pq.Format: + return _py2pg[fmt] + + +class IsolationLevel(IntEnum): + """ + Enum representing the isolation level for a transaction. + """ + + __module__ = "psycopg" + + READ_UNCOMMITTED = 1 + """:sql:`READ UNCOMMITTED` isolation level.""" + READ_COMMITTED = 2 + """:sql:`READ COMMITTED` isolation level.""" + REPEATABLE_READ = 3 + """:sql:`REPEATABLE READ` isolation level.""" + SERIALIZABLE = 4 + """:sql:`SERIALIZABLE` isolation level.""" + + +_py2pg = { + PyFormat.TEXT: pq.Format.TEXT, + PyFormat.BINARY: pq.Format.BINARY, +} + +_pg2py = { + pq.Format.TEXT: PyFormat.TEXT, + pq.Format.BINARY: PyFormat.BINARY, +} diff --git a/lib/python3.11/site-packages/psycopg/_pipeline.py b/lib/python3.11/site-packages/psycopg/_pipeline.py new file mode 100644 index 0000000..ecd6f06 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_pipeline.py @@ -0,0 +1,287 @@ +""" +commands pipeline management +""" + +# Copyright (C) 2021 The Psycopg Team + +import logging +from types import TracebackType +from typing import Any, List, Optional, Union, Tuple, Type, TypeVar, TYPE_CHECKING +from typing_extensions import TypeAlias + +from . import pq +from . import errors as e +from .abc import PipelineCommand, PQGen +from ._compat import Deque +from ._encodings import pgconn_encoding +from ._preparing import Key, Prepare +from .generators import pipeline_communicate, fetch_many, send + +if TYPE_CHECKING: + from .pq.abc import PGresult + from .cursor import BaseCursor + from .connection import BaseConnection, Connection + from .connection_async import AsyncConnection + + +PendingResult: TypeAlias = Union[ + None, Tuple["BaseCursor[Any, Any]", Optional[Tuple[Key, Prepare, bytes]]] +] + +FATAL_ERROR = pq.ExecStatus.FATAL_ERROR +PIPELINE_ABORTED = pq.ExecStatus.PIPELINE_ABORTED +BAD = pq.ConnStatus.BAD + +ACTIVE = pq.TransactionStatus.ACTIVE + +logger = logging.getLogger("psycopg") + + +class BasePipeline: + command_queue: Deque[PipelineCommand] + result_queue: Deque[PendingResult] + _is_supported: Optional[bool] = None + + def __init__(self, conn: "BaseConnection[Any]") -> None: + self._conn = conn + self.pgconn = conn.pgconn + self.command_queue = Deque[PipelineCommand]() + self.result_queue = Deque[PendingResult]() + self.level = 0 + + def __repr__(self) -> str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + info = pq.misc.connection_summary(self._conn.pgconn) + return f"<{cls} {info} at 0x{id(self):x}>" + + @property + def status(self) -> pq.PipelineStatus: + return pq.PipelineStatus(self.pgconn.pipeline_status) + + @classmethod + def is_supported(cls) -> bool: + """Return `!True` if the psycopg libpq wrapper supports pipeline mode.""" + if BasePipeline._is_supported is None: + BasePipeline._is_supported = not cls._not_supported_reason() + return BasePipeline._is_supported + + @classmethod + def _not_supported_reason(cls) -> str: + """Return the reason why the pipeline mode is not supported. + + Return an empty string if pipeline mode is supported. + """ + # Support only depends on the libpq functions available in the pq + # wrapper, not on the database version. + if pq.version() < 140000: + return ( + f"libpq too old {pq.version()};" + " v14 or greater required for pipeline mode" + ) + + if pq.__build_version__ < 140000: + return ( + f"libpq too old: module built for {pq.__build_version__};" + " v14 or greater required for pipeline mode" + ) + + return "" + + def _enter_gen(self) -> PQGen[None]: + if not self.is_supported(): + raise e.NotSupportedError( + f"pipeline mode not supported: {self._not_supported_reason()}" + ) + if self.level == 0: + self.pgconn.enter_pipeline_mode() + elif self.command_queue or self.pgconn.transaction_status == ACTIVE: + # Nested pipeline case. + # Transaction might be ACTIVE when the pipeline uses an "implicit + # transaction", typically in autocommit mode. But when entering a + # Psycopg transaction(), we expect the IDLE state. By sync()-ing, + # we make sure all previous commands are completed and the + # transaction gets back to IDLE. + yield from self._sync_gen() + self.level += 1 + + def _exit(self, exc: Optional[BaseException]) -> None: + self.level -= 1 + if self.level == 0 and self.pgconn.status != BAD: + try: + self.pgconn.exit_pipeline_mode() + except e.OperationalError as exc2: + # Notice that this error might be pretty irrecoverable. It + # happens on COPY, for instance: even if sync succeeds, exiting + # fails with "cannot exit pipeline mode with uncollected results" + if exc: + logger.warning("error ignored exiting %r: %s", self, exc2) + else: + raise exc2.with_traceback(None) + + def _sync_gen(self) -> PQGen[None]: + self._enqueue_sync() + yield from self._communicate_gen() + yield from self._fetch_gen(flush=False) + + def _exit_gen(self) -> PQGen[None]: + """ + Exit current pipeline by sending a Sync and fetch back all remaining results. + """ + try: + self._enqueue_sync() + yield from self._communicate_gen() + finally: + # No need to force flush since we emitted a sync just before. + yield from self._fetch_gen(flush=False) + + def _communicate_gen(self) -> PQGen[None]: + """Communicate with pipeline to send commands and possibly fetch + results, which are then processed. + """ + fetched = yield from pipeline_communicate(self.pgconn, self.command_queue) + to_process = [(self.result_queue.popleft(), results) for results in fetched] + for queued, results in to_process: + self._process_results(queued, results) + + def _fetch_gen(self, *, flush: bool) -> PQGen[None]: + """Fetch available results from the connection and process them with + pipeline queued items. + + If 'flush' is True, a PQsendFlushRequest() is issued in order to make + sure results can be fetched. Otherwise, the caller may emit a + PQpipelineSync() call to ensure the output buffer gets flushed before + fetching. + """ + if not self.result_queue: + return + + if flush: + self.pgconn.send_flush_request() + yield from send(self.pgconn) + + to_process = [] + while self.result_queue: + results = yield from fetch_many(self.pgconn) + if not results: + # No more results to fetch, but there may still be pending + # commands. + break + queued = self.result_queue.popleft() + to_process.append((queued, results)) + + for queued, results in to_process: + self._process_results(queued, results) + + def _process_results( + self, queued: PendingResult, results: List["PGresult"] + ) -> None: + """Process a results set fetched from the current pipeline. + + This matches 'results' with its respective element in the pipeline + queue. For commands (None value in the pipeline queue), results are + checked directly. For prepare statement creation requests, update the + cache. Otherwise, results are attached to their respective cursor. + """ + if queued is None: + (result,) = results + if result.status == FATAL_ERROR: + raise e.error_from_result(result, encoding=pgconn_encoding(self.pgconn)) + elif result.status == PIPELINE_ABORTED: + raise e.PipelineAborted("pipeline aborted") + else: + cursor, prepinfo = queued + cursor._set_results_from_pipeline(results) + if prepinfo: + key, prep, name = prepinfo + # Update the prepare state of the query. + cursor._conn._prepared.validate(key, prep, name, results) + + def _enqueue_sync(self) -> None: + """Enqueue a PQpipelineSync() command.""" + self.command_queue.append(self.pgconn.pipeline_sync) + self.result_queue.append(None) + + +class Pipeline(BasePipeline): + """Handler for connection in pipeline mode.""" + + __module__ = "psycopg" + _conn: "Connection[Any]" + _Self = TypeVar("_Self", bound="Pipeline") + + def __init__(self, conn: "Connection[Any]") -> None: + super().__init__(conn) + + def sync(self) -> None: + """Sync the pipeline, send any pending command and receive and process + all available results. + """ + try: + with self._conn.lock: + self._conn.wait(self._sync_gen()) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + def __enter__(self: _Self) -> _Self: + with self._conn.lock: + self._conn.wait(self._enter_gen()) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + try: + with self._conn.lock: + self._conn.wait(self._exit_gen()) + except Exception as exc2: + # Don't clobber an exception raised in the block with this one + if exc_val: + logger.warning("error ignored terminating %r: %s", self, exc2) + else: + raise exc2.with_traceback(None) + finally: + self._exit(exc_val) + + +class AsyncPipeline(BasePipeline): + """Handler for async connection in pipeline mode.""" + + __module__ = "psycopg" + _conn: "AsyncConnection[Any]" + _Self = TypeVar("_Self", bound="AsyncPipeline") + + def __init__(self, conn: "AsyncConnection[Any]") -> None: + super().__init__(conn) + + async def sync(self) -> None: + try: + async with self._conn.lock: + await self._conn.wait(self._sync_gen()) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + async def __aenter__(self: _Self) -> _Self: + async with self._conn.lock: + await self._conn.wait(self._enter_gen()) + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + try: + async with self._conn.lock: + await self._conn.wait(self._exit_gen()) + except Exception as exc2: + # Don't clobber an exception raised in the block with this one + if exc_val: + logger.warning("error ignored terminating %r: %s", self, exc2) + else: + raise exc2.with_traceback(None) + finally: + self._exit(exc_val) diff --git a/lib/python3.11/site-packages/psycopg/_preparing.py b/lib/python3.11/site-packages/psycopg/_preparing.py new file mode 100644 index 0000000..f60c0cb --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_preparing.py @@ -0,0 +1,198 @@ +""" +Support for prepared statements +""" + +# Copyright (C) 2020 The Psycopg Team + +from enum import IntEnum, auto +from typing import Iterator, Optional, Sequence, Tuple, TYPE_CHECKING +from collections import OrderedDict +from typing_extensions import TypeAlias + +from . import pq +from ._compat import Deque +from ._queries import PostgresQuery + +if TYPE_CHECKING: + from .pq.abc import PGresult + +Key: TypeAlias = Tuple[bytes, Tuple[int, ...]] + +COMMAND_OK = pq.ExecStatus.COMMAND_OK +TUPLES_OK = pq.ExecStatus.TUPLES_OK + + +class Prepare(IntEnum): + NO = auto() + YES = auto() + SHOULD = auto() + + +class PrepareManager: + # Number of times a query is executed before it is prepared. + prepare_threshold: Optional[int] = 5 + + # Maximum number of prepared statements on the connection. + prepared_max: int = 100 + + def __init__(self) -> None: + # Map (query, types) to the number of times the query was seen. + self._counts: OrderedDict[Key, int] = OrderedDict() + + # Map (query, types) to the name of the statement if prepared. + self._names: OrderedDict[Key, bytes] = OrderedDict() + + # Counter to generate prepared statements names + self._prepared_idx = 0 + + self._maint_commands = Deque[bytes]() + + @staticmethod + def key(query: PostgresQuery) -> Key: + return (query.query, query.types) + + def get( + self, query: PostgresQuery, prepare: Optional[bool] = None + ) -> Tuple[Prepare, bytes]: + """ + Check if a query is prepared, tell back whether to prepare it. + """ + if prepare is False or self.prepare_threshold is None: + # The user doesn't want this query to be prepared + return Prepare.NO, b"" + + key = self.key(query) + name = self._names.get(key) + if name: + # The query was already prepared in this session + return Prepare.YES, name + + count = self._counts.get(key, 0) + if count >= self.prepare_threshold or prepare: + # The query has been executed enough times and needs to be prepared + name = f"_pg3_{self._prepared_idx}".encode() + self._prepared_idx += 1 + return Prepare.SHOULD, name + else: + # The query is not to be prepared yet + return Prepare.NO, b"" + + def _should_discard(self, prep: Prepare, results: Sequence["PGresult"]) -> bool: + """Check if we need to discard our entire state: it should happen on + rollback or on dropping objects, because the same object may get + recreated and postgres would fail internal lookups. + """ + if self._names or prep == Prepare.SHOULD: + for result in results: + if result.status != COMMAND_OK: + continue + cmdstat = result.command_status + if cmdstat and (cmdstat.startswith(b"DROP ") or cmdstat == b"ROLLBACK"): + return self.clear() + return False + + @staticmethod + def _check_results(results: Sequence["PGresult"]) -> bool: + """Return False if 'results' are invalid for prepared statement cache.""" + if len(results) != 1: + # We cannot prepare a multiple statement + return False + + status = results[0].status + if COMMAND_OK != status != TUPLES_OK: + # We don't prepare failed queries or other weird results + return False + + return True + + def _rotate(self) -> None: + """Evict an old value from the cache. + + If it was prepared, deallocate it. Do it only once: if the cache was + resized, deallocate gradually. + """ + if len(self._counts) > self.prepared_max: + self._counts.popitem(last=False) + + if len(self._names) > self.prepared_max: + name = self._names.popitem(last=False)[1] + self._maint_commands.append(b"DEALLOCATE " + name) + + def maybe_add_to_cache( + self, query: PostgresQuery, prep: Prepare, name: bytes + ) -> Optional[Key]: + """Handle 'query' for possible addition to the cache. + + If a new entry has been added, return its key. Return None otherwise + (meaning the query is already in cache or cache is not enabled). + + Note: This method is only called in pipeline mode. + """ + # don't do anything if prepared statements are disabled + if self.prepare_threshold is None: + return None + + key = self.key(query) + if key in self._counts: + if prep is Prepare.SHOULD: + del self._counts[key] + self._names[key] = name + else: + self._counts[key] += 1 + self._counts.move_to_end(key) + return None + + elif key in self._names: + self._names.move_to_end(key) + return None + + else: + if prep is Prepare.SHOULD: + self._names[key] = name + else: + self._counts[key] = 1 + return key + + def validate( + self, + key: Key, + prep: Prepare, + name: bytes, + results: Sequence["PGresult"], + ) -> None: + """Validate cached entry with 'key' by checking query 'results'. + + Possibly return a command to perform maintenance on database side. + + Note: this method is only called in pipeline mode. + """ + if self._should_discard(prep, results): + return + + if not self._check_results(results): + self._names.pop(key, None) + self._counts.pop(key, None) + else: + self._rotate() + + def clear(self) -> bool: + """Clear the cache of the maintenance commands. + + Clear the internal state and prepare a command to clear the state of + the server. + """ + self._counts.clear() + if self._names: + self._names.clear() + self._maint_commands.clear() + self._maint_commands.append(b"DEALLOCATE ALL") + return True + else: + return False + + def get_maintenance_commands(self) -> Iterator[bytes]: + """ + Iterate over the commands needed to align the server state to our state + """ + while self._maint_commands: + yield self._maint_commands.popleft() diff --git a/lib/python3.11/site-packages/psycopg/_queries.py b/lib/python3.11/site-packages/psycopg/_queries.py new file mode 100644 index 0000000..2a7554c --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_queries.py @@ -0,0 +1,375 @@ +""" +Utility module to manipulate queries +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +from typing import Any, Dict, List, Mapping, Match, NamedTuple, Optional +from typing import Sequence, Tuple, Union, TYPE_CHECKING +from functools import lru_cache + +from . import pq +from . import errors as e +from .sql import Composable +from .abc import Buffer, Query, Params +from ._enums import PyFormat +from ._encodings import conn_encoding + +if TYPE_CHECKING: + from .abc import Transformer + + +class QueryPart(NamedTuple): + pre: bytes + item: Union[int, str] + format: PyFormat + + +class PostgresQuery: + """ + Helper to convert a Python query and parameters into Postgres format. + """ + + __slots__ = """ + query params types formats + _tx _want_formats _parts _encoding _order + """.split() + + def __init__(self, transformer: "Transformer"): + self._tx = transformer + + self.params: Optional[Sequence[Optional[Buffer]]] = None + # these are tuples so they can be used as keys e.g. in prepared stmts + self.types: Tuple[int, ...] = () + + # The format requested by the user and the ones to really pass Postgres + self._want_formats: Optional[List[PyFormat]] = None + self.formats: Optional[Sequence[pq.Format]] = None + + self._encoding = conn_encoding(transformer.connection) + self._parts: List[QueryPart] + self.query = b"" + self._order: Optional[List[str]] = None + + def convert(self, query: Query, vars: Optional[Params]) -> None: + """ + Set up the query and parameters to convert. + + The results of this function can be obtained accessing the object + attributes (`query`, `params`, `types`, `formats`). + """ + if isinstance(query, str): + bquery = query.encode(self._encoding) + elif isinstance(query, Composable): + bquery = query.as_bytes(self._tx) + else: + bquery = query + + if vars is not None: + ( + self.query, + self._want_formats, + self._order, + self._parts, + ) = _query2pg(bquery, self._encoding) + else: + self.query = bquery + self._want_formats = self._order = None + + self.dump(vars) + + def dump(self, vars: Optional[Params]) -> None: + """ + Process a new set of variables on the query processed by `convert()`. + + This method updates `params` and `types`. + """ + if vars is not None: + params = _validate_and_reorder_params(self._parts, vars, self._order) + assert self._want_formats is not None + self.params = self._tx.dump_sequence(params, self._want_formats) + self.types = self._tx.types or () + self.formats = self._tx.formats + else: + self.params = None + self.types = () + self.formats = None + + +class PostgresClientQuery(PostgresQuery): + """ + PostgresQuery subclass merging query and arguments client-side. + """ + + __slots__ = ("template",) + + def convert(self, query: Query, vars: Optional[Params]) -> None: + """ + Set up the query and parameters to convert. + + The results of this function can be obtained accessing the object + attributes (`query`, `params`, `types`, `formats`). + """ + if isinstance(query, str): + bquery = query.encode(self._encoding) + elif isinstance(query, Composable): + bquery = query.as_bytes(self._tx) + else: + bquery = query + + if vars is not None: + (self.template, self._order, self._parts) = _query2pg_client( + bquery, self._encoding + ) + else: + self.query = bquery + self._order = None + + self.dump(vars) + + def dump(self, vars: Optional[Params]) -> None: + """ + Process a new set of variables on the query processed by `convert()`. + + This method updates `params` and `types`. + """ + if vars is not None: + params = _validate_and_reorder_params(self._parts, vars, self._order) + self.params = tuple( + self._tx.as_literal(p) if p is not None else b"NULL" for p in params + ) + self.query = self.template % self.params + else: + self.params = None + + +@lru_cache() +def _query2pg( + query: bytes, encoding: str +) -> Tuple[bytes, List[PyFormat], Optional[List[str]], List[QueryPart]]: + """ + Convert Python query and params into something Postgres understands. + + - Convert Python placeholders (``%s``, ``%(name)s``) into Postgres + format (``$1``, ``$2``) + - placeholders can be %s, %t, or %b (auto, text or binary) + - return ``query`` (bytes), ``formats`` (list of formats) ``order`` + (sequence of names used in the query, in the position they appear) + ``parts`` (splits of queries and placeholders). + """ + parts = _split_query(query, encoding) + order: Optional[List[str]] = None + chunks: List[bytes] = [] + formats = [] + + if isinstance(parts[0].item, int): + for part in parts[:-1]: + assert isinstance(part.item, int) + chunks.append(part.pre) + chunks.append(b"$%d" % (part.item + 1)) + formats.append(part.format) + + elif isinstance(parts[0].item, str): + seen: Dict[str, Tuple[bytes, PyFormat]] = {} + order = [] + for part in parts[:-1]: + assert isinstance(part.item, str) + chunks.append(part.pre) + if part.item not in seen: + ph = b"$%d" % (len(seen) + 1) + seen[part.item] = (ph, part.format) + order.append(part.item) + chunks.append(ph) + formats.append(part.format) + else: + if seen[part.item][1] != part.format: + raise e.ProgrammingError( + f"placeholder '{part.item}' cannot have different formats" + ) + chunks.append(seen[part.item][0]) + + # last part + chunks.append(parts[-1].pre) + + return b"".join(chunks), formats, order, parts + + +@lru_cache() +def _query2pg_client( + query: bytes, encoding: str +) -> Tuple[bytes, Optional[List[str]], List[QueryPart]]: + """ + Convert Python query and params into a template to perform client-side binding + """ + parts = _split_query(query, encoding, collapse_double_percent=False) + order: Optional[List[str]] = None + chunks: List[bytes] = [] + + if isinstance(parts[0].item, int): + for part in parts[:-1]: + assert isinstance(part.item, int) + chunks.append(part.pre) + chunks.append(b"%s") + + elif isinstance(parts[0].item, str): + seen: Dict[str, Tuple[bytes, PyFormat]] = {} + order = [] + for part in parts[:-1]: + assert isinstance(part.item, str) + chunks.append(part.pre) + if part.item not in seen: + ph = b"%s" + seen[part.item] = (ph, part.format) + order.append(part.item) + chunks.append(ph) + else: + chunks.append(seen[part.item][0]) + order.append(part.item) + + # last part + chunks.append(parts[-1].pre) + + return b"".join(chunks), order, parts + + +def _validate_and_reorder_params( + parts: List[QueryPart], vars: Params, order: Optional[List[str]] +) -> Sequence[Any]: + """ + Verify the compatibility between a query and a set of params. + """ + # Try concrete types, then abstract types + t = type(vars) + if t is list or t is tuple: + sequence = True + elif t is dict: + sequence = False + elif isinstance(vars, Sequence) and not isinstance(vars, (bytes, str)): + sequence = True + elif isinstance(vars, Mapping): + sequence = False + else: + raise TypeError( + "query parameters should be a sequence or a mapping," + f" got {type(vars).__name__}" + ) + + if sequence: + if len(vars) != len(parts) - 1: + raise e.ProgrammingError( + f"the query has {len(parts) - 1} placeholders but" + f" {len(vars)} parameters were passed" + ) + if vars and not isinstance(parts[0].item, int): + raise TypeError("named placeholders require a mapping of parameters") + return vars # type: ignore[return-value] + + else: + if vars and len(parts) > 1 and not isinstance(parts[0][1], str): + raise TypeError( + "positional placeholders (%s) require a sequence of parameters" + ) + try: + return [vars[item] for item in order or ()] # type: ignore[call-overload] + except KeyError: + raise e.ProgrammingError( + "query parameter missing:" + f" {', '.join(sorted(i for i in order or () if i not in vars))}" + ) + + +_re_placeholder = re.compile( + rb"""(?x) + % # a literal % + (?: + (?: + \( ([^)]+) \) # or a name in (braces) + . # followed by a format + ) + | + (?:.) # or any char, really + ) + """ +) + + +def _split_query( + query: bytes, encoding: str = "ascii", collapse_double_percent: bool = True +) -> List[QueryPart]: + parts: List[Tuple[bytes, Optional[Match[bytes]]]] = [] + cur = 0 + + # pairs [(fragment, match], with the last match None + m = None + for m in _re_placeholder.finditer(query): + pre = query[cur : m.span(0)[0]] + parts.append((pre, m)) + cur = m.span(0)[1] + if m: + parts.append((query[cur:], None)) + else: + parts.append((query, None)) + + rv = [] + + # drop the "%%", validate + i = 0 + phtype = None + while i < len(parts): + pre, m = parts[i] + if m is None: + # last part + rv.append(QueryPart(pre, 0, PyFormat.AUTO)) + break + + ph = m.group(0) + if ph == b"%%": + # unescape '%%' to '%' if necessary, then merge the parts + if collapse_double_percent: + ph = b"%" + pre1, m1 = parts[i + 1] + parts[i + 1] = (pre + ph + pre1, m1) + del parts[i] + continue + + if ph == b"%(": + raise e.ProgrammingError( + "incomplete placeholder:" + f" '{query[m.span(0)[0]:].split()[0].decode(encoding)}'" + ) + elif ph == b"% ": + # explicit messasge for a typical error + raise e.ProgrammingError( + "incomplete placeholder: '%'; if you want to use '%' as an" + " operator you can double it up, i.e. use '%%'" + ) + elif ph[-1:] not in b"sbt": + raise e.ProgrammingError( + "only '%s', '%b', '%t' are allowed as placeholders, got" + f" '{m.group(0).decode(encoding)}'" + ) + + # Index or name + item: Union[int, str] + item = m.group(1).decode(encoding) if m.group(1) else i + + if not phtype: + phtype = type(item) + elif phtype is not type(item): + raise e.ProgrammingError( + "positional and named placeholders cannot be mixed" + ) + + format = _ph_to_fmt[ph[-1:]] + rv.append(QueryPart(pre, item, format)) + i += 1 + + return rv + + +_ph_to_fmt = { + b"s": PyFormat.AUTO, + b"t": PyFormat.TEXT, + b"b": PyFormat.BINARY, +} diff --git a/lib/python3.11/site-packages/psycopg/_struct.py b/lib/python3.11/site-packages/psycopg/_struct.py new file mode 100644 index 0000000..28a6084 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_struct.py @@ -0,0 +1,57 @@ +""" +Utility functions to deal with binary structs. +""" + +# Copyright (C) 2020 The Psycopg Team + +import struct +from typing import Callable, cast, Optional, Tuple +from typing_extensions import TypeAlias + +from .abc import Buffer +from . import errors as e +from ._compat import Protocol + +PackInt: TypeAlias = Callable[[int], bytes] +UnpackInt: TypeAlias = Callable[[Buffer], Tuple[int]] +PackFloat: TypeAlias = Callable[[float], bytes] +UnpackFloat: TypeAlias = Callable[[Buffer], Tuple[float]] + + +class UnpackLen(Protocol): + def __call__(self, data: Buffer, start: Optional[int]) -> Tuple[int]: + ... + + +pack_int2 = cast(PackInt, struct.Struct("!h").pack) +pack_uint2 = cast(PackInt, struct.Struct("!H").pack) +pack_int4 = cast(PackInt, struct.Struct("!i").pack) +pack_uint4 = cast(PackInt, struct.Struct("!I").pack) +pack_int8 = cast(PackInt, struct.Struct("!q").pack) +pack_float4 = cast(PackFloat, struct.Struct("!f").pack) +pack_float8 = cast(PackFloat, struct.Struct("!d").pack) + +unpack_int2 = cast(UnpackInt, struct.Struct("!h").unpack) +unpack_uint2 = cast(UnpackInt, struct.Struct("!H").unpack) +unpack_int4 = cast(UnpackInt, struct.Struct("!i").unpack) +unpack_uint4 = cast(UnpackInt, struct.Struct("!I").unpack) +unpack_int8 = cast(UnpackInt, struct.Struct("!q").unpack) +unpack_float4 = cast(UnpackFloat, struct.Struct("!f").unpack) +unpack_float8 = cast(UnpackFloat, struct.Struct("!d").unpack) + +_struct_len = struct.Struct("!i") +pack_len = cast(Callable[[int], bytes], _struct_len.pack) +unpack_len = cast(UnpackLen, _struct_len.unpack_from) + + +def pack_float4_bug_304(x: float) -> bytes: + raise e.InterfaceError( + "cannot dump Float4: Python affected by bug #304. Note that the psycopg-c" + " and psycopg-binary packages are not affected by this issue." + " See https://github.com/psycopg/psycopg/issues/304" + ) + + +# If issue #304 is detected, raise an error instead of dumping wrong data. +if struct.Struct("!f").pack(1.0) != bytes.fromhex("3f800000"): + pack_float4 = pack_float4_bug_304 diff --git a/lib/python3.11/site-packages/psycopg/_tpc.py b/lib/python3.11/site-packages/psycopg/_tpc.py new file mode 100644 index 0000000..3528188 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_tpc.py @@ -0,0 +1,116 @@ +""" +psycopg two-phase commit support +""" + +# Copyright (C) 2021 The Psycopg Team + +import re +import datetime as dt +from base64 import b64encode, b64decode +from typing import Optional, Union +from dataclasses import dataclass, replace + +_re_xid = re.compile(r"^(\d+)_([^_]*)_([^_]*)$") + + +@dataclass(frozen=True) +class Xid: + """A two-phase commit transaction identifier. + + The object can also be unpacked as a 3-item tuple (`format_id`, `gtrid`, + `bqual`). + + """ + + format_id: Optional[int] + gtrid: str + bqual: Optional[str] + prepared: Optional[dt.datetime] = None + owner: Optional[str] = None + database: Optional[str] = None + + @classmethod + def from_string(cls, s: str) -> "Xid": + """Try to parse an XA triple from the string. + + This may fail for several reasons. In such case return an unparsed Xid. + """ + try: + return cls._parse_string(s) + except Exception: + return Xid(None, s, None) + + def __str__(self) -> str: + return self._as_tid() + + def __len__(self) -> int: + return 3 + + def __getitem__(self, index: int) -> Union[int, str, None]: + return (self.format_id, self.gtrid, self.bqual)[index] + + @classmethod + def _parse_string(cls, s: str) -> "Xid": + m = _re_xid.match(s) + if not m: + raise ValueError("bad Xid format") + + format_id = int(m.group(1)) + gtrid = b64decode(m.group(2)).decode() + bqual = b64decode(m.group(3)).decode() + return cls.from_parts(format_id, gtrid, bqual) + + @classmethod + def from_parts( + cls, format_id: Optional[int], gtrid: str, bqual: Optional[str] + ) -> "Xid": + if format_id is not None: + if bqual is None: + raise TypeError("if format_id is specified, bqual must be too") + if not 0 <= format_id < 0x80000000: + raise ValueError("format_id must be a non-negative 32-bit integer") + if len(bqual) > 64: + raise ValueError("bqual must be not longer than 64 chars") + if len(gtrid) > 64: + raise ValueError("gtrid must be not longer than 64 chars") + + elif bqual is None: + raise TypeError("if format_id is None, bqual must be None too") + + return Xid(format_id, gtrid, bqual) + + def _as_tid(self) -> str: + """ + Return the PostgreSQL transaction_id for this XA xid. + + PostgreSQL wants just a string, while the DBAPI supports the XA + standard and thus a triple. We use the same conversion algorithm + implemented by JDBC in order to allow some form of interoperation. + + see also: the pgjdbc implementation + http://cvs.pgfoundry.org/cgi-bin/cvsweb.cgi/jdbc/pgjdbc/org/ + postgresql/xa/RecoveredXid.java?rev=1.2 + """ + if self.format_id is None or self.bqual is None: + # Unparsed xid: return the gtrid. + return self.gtrid + + # XA xid: mash together the components. + egtrid = b64encode(self.gtrid.encode()).decode() + ebqual = b64encode(self.bqual.encode()).decode() + + return f"{self.format_id}_{egtrid}_{ebqual}" + + @classmethod + def _get_recover_query(cls) -> str: + return "SELECT gid, prepared, owner, database FROM pg_prepared_xacts" + + @classmethod + def _from_record( + cls, gid: str, prepared: dt.datetime, owner: str, database: str + ) -> "Xid": + xid = Xid.from_string(gid) + return replace(xid, prepared=prepared, owner=owner, database=database) + + +Xid.__module__ = "psycopg" diff --git a/lib/python3.11/site-packages/psycopg/_transform.py b/lib/python3.11/site-packages/psycopg/_transform.py new file mode 100644 index 0000000..19bd6ae --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_transform.py @@ -0,0 +1,350 @@ +""" +Helper object to transform values between Python and PostgreSQL +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Any, Dict, List, Optional, Sequence, Tuple +from typing import DefaultDict, TYPE_CHECKING +from collections import defaultdict +from typing_extensions import TypeAlias + +from . import pq +from . import postgres +from . import errors as e +from .abc import Buffer, LoadFunc, AdaptContext, PyFormat, DumperKey, NoneType +from .rows import Row, RowMaker +from .postgres import INVALID_OID, TEXT_OID +from ._encodings import pgconn_encoding + +if TYPE_CHECKING: + from .abc import Dumper, Loader + from .adapt import AdaptersMap + from .pq.abc import PGresult + from .connection import BaseConnection + +DumperCache: TypeAlias = Dict[DumperKey, "Dumper"] +OidDumperCache: TypeAlias = Dict[int, "Dumper"] +LoaderCache: TypeAlias = Dict[int, "Loader"] + +TEXT = pq.Format.TEXT +PY_TEXT = PyFormat.TEXT + + +class Transformer(AdaptContext): + """ + An object that can adapt efficiently between Python and PostgreSQL. + + The life cycle of the object is the query, so it is assumed that attributes + such as the server version or the connection encoding will not change. The + object have its state so adapting several values of the same type can be + optimised. + + """ + + __module__ = "psycopg.adapt" + + __slots__ = """ + types formats + _conn _adapters _pgresult _dumpers _loaders _encoding _none_oid + _oid_dumpers _oid_types _row_dumpers _row_loaders + """.split() + + types: Optional[Tuple[int, ...]] + formats: Optional[List[pq.Format]] + + _adapters: "AdaptersMap" + _pgresult: Optional["PGresult"] + _none_oid: int + + def __init__(self, context: Optional[AdaptContext] = None): + self._pgresult = self.types = self.formats = None + + # WARNING: don't store context, or you'll create a loop with the Cursor + if context: + self._adapters = context.adapters + self._conn = context.connection + else: + self._adapters = postgres.adapters + self._conn = None + + # mapping fmt, class -> Dumper instance + self._dumpers: DefaultDict[PyFormat, DumperCache] + self._dumpers = defaultdict(dict) + + # mapping fmt, oid -> Dumper instance + # Not often used, so create it only if needed. + self._oid_dumpers: Optional[Tuple[OidDumperCache, OidDumperCache]] + self._oid_dumpers = None + + # mapping fmt, oid -> Loader instance + self._loaders: Tuple[LoaderCache, LoaderCache] = ({}, {}) + + self._row_dumpers: Optional[List["Dumper"]] = None + + # sequence of load functions from value to python + # the length of the result columns + self._row_loaders: List[LoadFunc] = [] + + # mapping oid -> type sql representation + self._oid_types: Dict[int, bytes] = {} + + self._encoding = "" + + @classmethod + def from_context(cls, context: Optional[AdaptContext]) -> "Transformer": + """ + Return a Transformer from an AdaptContext. + + If the context is a Transformer instance, just return it. + """ + if isinstance(context, Transformer): + return context + else: + return cls(context) + + @property + def connection(self) -> Optional["BaseConnection[Any]"]: + return self._conn + + @property + def encoding(self) -> str: + if not self._encoding: + conn = self.connection + self._encoding = pgconn_encoding(conn.pgconn) if conn else "utf-8" + return self._encoding + + @property + def adapters(self) -> "AdaptersMap": + return self._adapters + + @property + def pgresult(self) -> Optional["PGresult"]: + return self._pgresult + + def set_pgresult( + self, + result: Optional["PGresult"], + *, + set_loaders: bool = True, + format: Optional[pq.Format] = None, + ) -> None: + self._pgresult = result + + if not result: + self._nfields = self._ntuples = 0 + if set_loaders: + self._row_loaders = [] + return + + self._ntuples = result.ntuples + nf = self._nfields = result.nfields + + if not set_loaders: + return + + if not nf: + self._row_loaders = [] + return + + fmt: pq.Format + fmt = result.fformat(0) if format is None else format # type: ignore + self._row_loaders = [ + self.get_loader(result.ftype(i), fmt).load for i in range(nf) + ] + + def set_dumper_types(self, types: Sequence[int], format: pq.Format) -> None: + self._row_dumpers = [self.get_dumper_by_oid(oid, format) for oid in types] + self.types = tuple(types) + self.formats = [format] * len(types) + + def set_loader_types(self, types: Sequence[int], format: pq.Format) -> None: + self._row_loaders = [self.get_loader(oid, format).load for oid in types] + + def dump_sequence( + self, params: Sequence[Any], formats: Sequence[PyFormat] + ) -> Sequence[Optional[Buffer]]: + nparams = len(params) + out: List[Optional[Buffer]] = [None] * nparams + + # If we have dumpers, it means set_dumper_types had been called, in + # which case self.types and self.formats are set to sequences of the + # right size. + if self._row_dumpers: + for i in range(nparams): + param = params[i] + if param is not None: + out[i] = self._row_dumpers[i].dump(param) + return out + + types = [self._get_none_oid()] * nparams + pqformats = [TEXT] * nparams + + for i in range(nparams): + param = params[i] + if param is None: + continue + dumper = self.get_dumper(param, formats[i]) + out[i] = dumper.dump(param) + types[i] = dumper.oid + pqformats[i] = dumper.format + + self.types = tuple(types) + self.formats = pqformats + + return out + + def as_literal(self, obj: Any) -> bytes: + dumper = self.get_dumper(obj, PY_TEXT) + rv = dumper.quote(obj) + # If the result is quoted, and the oid not unknown or text, + # add an explicit type cast. + # Check the last char because the first one might be 'E'. + oid = dumper.oid + if oid and rv and rv[-1] == b"'"[0] and oid != TEXT_OID: + try: + type_sql = self._oid_types[oid] + except KeyError: + ti = self.adapters.types.get(oid) + if ti: + if oid < 8192: + # builtin: prefer "timestamptz" to "timestamp with time zone" + type_sql = ti.name.encode(self.encoding) + else: + type_sql = ti.regtype.encode(self.encoding) + if oid == ti.array_oid: + type_sql += b"[]" + else: + type_sql = b"" + self._oid_types[oid] = type_sql + + if type_sql: + rv = b"%s::%s" % (rv, type_sql) + + if not isinstance(rv, bytes): + rv = bytes(rv) + return rv + + def get_dumper(self, obj: Any, format: PyFormat) -> "Dumper": + """ + Return a Dumper instance to dump `!obj`. + """ + # Normally, the type of the object dictates how to dump it + key = type(obj) + + # Reuse an existing Dumper class for objects of the same type + cache = self._dumpers[format] + try: + dumper = cache[key] + except KeyError: + # If it's the first time we see this type, look for a dumper + # configured for it. + dcls = self.adapters.get_dumper(key, format) + cache[key] = dumper = dcls(key, self) + + # Check if the dumper requires an upgrade to handle this specific value + key1 = dumper.get_key(obj, format) + if key1 is key: + return dumper + + # If it does, ask the dumper to create its own upgraded version + try: + return cache[key1] + except KeyError: + dumper = cache[key1] = dumper.upgrade(obj, format) + return dumper + + def _get_none_oid(self) -> int: + try: + return self._none_oid + except AttributeError: + pass + + try: + rv = self._none_oid = self._adapters.get_dumper(NoneType, PY_TEXT).oid + except KeyError: + raise e.InterfaceError("None dumper not found") + + return rv + + def get_dumper_by_oid(self, oid: int, format: pq.Format) -> "Dumper": + """ + Return a Dumper to dump an object to the type with given oid. + """ + if not self._oid_dumpers: + self._oid_dumpers = ({}, {}) + + # Reuse an existing Dumper class for objects of the same type + cache = self._oid_dumpers[format] + try: + return cache[oid] + except KeyError: + # If it's the first time we see this type, look for a dumper + # configured for it. + dcls = self.adapters.get_dumper_by_oid(oid, format) + cache[oid] = dumper = dcls(NoneType, self) + + return dumper + + def load_rows(self, row0: int, row1: int, make_row: RowMaker[Row]) -> List[Row]: + res = self._pgresult + if not res: + raise e.InterfaceError("result not set") + + if not (0 <= row0 <= self._ntuples and 0 <= row1 <= self._ntuples): + raise e.InterfaceError( + f"rows must be included between 0 and {self._ntuples}" + ) + + records = [] + for row in range(row0, row1): + record: List[Any] = [None] * self._nfields + for col in range(self._nfields): + val = res.get_value(row, col) + if val is not None: + record[col] = self._row_loaders[col](val) + records.append(make_row(record)) + + return records + + def load_row(self, row: int, make_row: RowMaker[Row]) -> Optional[Row]: + res = self._pgresult + if not res: + return None + + if not 0 <= row < self._ntuples: + return None + + record: List[Any] = [None] * self._nfields + for col in range(self._nfields): + val = res.get_value(row, col) + if val is not None: + record[col] = self._row_loaders[col](val) + + return make_row(record) + + def load_sequence(self, record: Sequence[Optional[Buffer]]) -> Tuple[Any, ...]: + if len(self._row_loaders) != len(record): + raise e.ProgrammingError( + f"cannot load sequence of {len(record)} items:" + f" {len(self._row_loaders)} loaders registered" + ) + + return tuple( + (self._row_loaders[i](val) if val is not None else None) + for i, val in enumerate(record) + ) + + def get_loader(self, oid: int, format: pq.Format) -> "Loader": + try: + return self._loaders[format][oid] + except KeyError: + pass + + loader_cls = self._adapters.get_loader(oid, format) + if not loader_cls: + loader_cls = self._adapters.get_loader(INVALID_OID, format) + if not loader_cls: + raise e.InterfaceError("unknown oid loader not found") + loader = self._loaders[format][oid] = loader_cls(oid, self) + return loader diff --git a/lib/python3.11/site-packages/psycopg/_typeinfo.py b/lib/python3.11/site-packages/psycopg/_typeinfo.py new file mode 100644 index 0000000..08c5e65 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_typeinfo.py @@ -0,0 +1,500 @@ +""" +Information about PostgreSQL types + +These types allow to read information from the system catalog and provide +information to the adapters if needed. +""" + +# Copyright (C) 2020 The Psycopg Team +from enum import Enum +from typing import Any, Dict, Iterator, Optional, overload +from typing import Sequence, Tuple, Type, TypeVar, Union, TYPE_CHECKING +from typing_extensions import TypeAlias + +from . import errors as e +from .abc import AdaptContext, Query +from .rows import dict_row +from ._encodings import conn_encoding + +if TYPE_CHECKING: + from .connection import BaseConnection, Connection + from .connection_async import AsyncConnection + from .sql import Identifier, SQL + +T = TypeVar("T", bound="TypeInfo") +RegistryKey: TypeAlias = Union[str, int, Tuple[type, int]] + + +class TypeInfo: + """ + Hold information about a PostgreSQL base type. + """ + + __module__ = "psycopg.types" + + def __init__( + self, + name: str, + oid: int, + array_oid: int, + *, + regtype: str = "", + delimiter: str = ",", + ): + self.name = name + self.oid = oid + self.array_oid = array_oid + self.regtype = regtype or name + self.delimiter = delimiter + + def __repr__(self) -> str: + return ( + f"<{self.__class__.__qualname__}:" + f" {self.name} (oid: {self.oid}, array oid: {self.array_oid})>" + ) + + @overload + @classmethod + def fetch( + cls: Type[T], conn: "Connection[Any]", name: Union[str, "Identifier"] + ) -> Optional[T]: + ... + + @overload + @classmethod + async def fetch( + cls: Type[T], conn: "AsyncConnection[Any]", name: Union[str, "Identifier"] + ) -> Optional[T]: + ... + + @classmethod + def fetch( + cls: Type[T], conn: "BaseConnection[Any]", name: Union[str, "Identifier"] + ) -> Any: + """Query a system catalog to read information about a type.""" + from .sql import Composable + from .connection import Connection + from .connection_async import AsyncConnection + + if isinstance(name, Composable): + name = name.as_string(conn) + + if isinstance(conn, Connection): + return cls._fetch(conn, name) + elif isinstance(conn, AsyncConnection): + return cls._fetch_async(conn, name) + else: + raise TypeError( + f"expected Connection or AsyncConnection, got {type(conn).__name__}" + ) + + @classmethod + def _fetch(cls: Type[T], conn: "Connection[Any]", name: str) -> Optional[T]: + # This might result in a nested transaction. What we want is to leave + # the function with the connection in the state we found (either idle + # or intrans) + try: + with conn.transaction(): + if conn_encoding(conn) == "ascii": + conn.execute("set local client_encoding to utf8") + with conn.cursor(row_factory=dict_row) as cur: + cur.execute(cls._get_info_query(conn), {"name": name}) + recs = cur.fetchall() + except e.UndefinedObject: + return None + + return cls._from_records(name, recs) + + @classmethod + async def _fetch_async( + cls: Type[T], conn: "AsyncConnection[Any]", name: str + ) -> Optional[T]: + try: + async with conn.transaction(): + if conn_encoding(conn) == "ascii": + await conn.execute("set local client_encoding to utf8") + async with conn.cursor(row_factory=dict_row) as cur: + await cur.execute(cls._get_info_query(conn), {"name": name}) + recs = await cur.fetchall() + except e.UndefinedObject: + return None + + return cls._from_records(name, recs) + + @classmethod + def _from_records( + cls: Type[T], name: str, recs: Sequence[Dict[str, Any]] + ) -> Optional[T]: + if len(recs) == 1: + return cls(**recs[0]) + elif not recs: + return None + else: + raise e.ProgrammingError(f"found {len(recs)} different types named {name}") + + def register(self, context: Optional[AdaptContext] = None) -> None: + """ + Register the type information, globally or in the specified `!context`. + """ + if context: + types = context.adapters.types + else: + from . import postgres + + types = postgres.types + + types.add(self) + + if self.array_oid: + from .types.array import register_array + + register_array(self, context) + + @classmethod + def _get_info_query(cls, conn: "BaseConnection[Any]") -> Query: + from .sql import SQL + + return SQL( + """\ +SELECT + typname AS name, oid, typarray AS array_oid, + oid::regtype::text AS regtype, typdelim AS delimiter +FROM pg_type t +WHERE t.oid = {regtype} +ORDER BY t.oid +""" + ).format(regtype=cls._to_regtype(conn)) + + @classmethod + def _has_to_regtype_function(cls, conn: "BaseConnection[Any]") -> bool: + # to_regtype() introduced in PostgreSQL 9.4 and CockroachDB 22.2 + info = conn.info + if info.vendor == "PostgreSQL": + return info.server_version >= 90400 + elif info.vendor == "CockroachDB": + return info.server_version >= 220200 + else: + return False + + @classmethod + def _to_regtype(cls, conn: "BaseConnection[Any]") -> "SQL": + # `to_regtype()` returns the type oid or NULL, unlike the :: operator, + # which returns the type or raises an exception, which requires + # a transaction rollback and leaves traces in the server logs. + + from .sql import SQL + + if cls._has_to_regtype_function(conn): + return SQL("to_regtype(%(name)s)") + else: + return SQL("%(name)s::regtype") + + def _added(self, registry: "TypesRegistry") -> None: + """Method called by the `!registry` when the object is added there.""" + pass + + +class RangeInfo(TypeInfo): + """Manage information about a range type.""" + + __module__ = "psycopg.types.range" + + def __init__( + self, + name: str, + oid: int, + array_oid: int, + *, + regtype: str = "", + subtype_oid: int, + ): + super().__init__(name, oid, array_oid, regtype=regtype) + self.subtype_oid = subtype_oid + + @classmethod + def _get_info_query(cls, conn: "BaseConnection[Any]") -> Query: + from .sql import SQL + + return SQL( + """\ +SELECT t.typname AS name, t.oid AS oid, t.typarray AS array_oid, + t.oid::regtype::text AS regtype, + r.rngsubtype AS subtype_oid +FROM pg_type t +JOIN pg_range r ON t.oid = r.rngtypid +WHERE t.oid = {regtype} +""" + ).format(regtype=cls._to_regtype(conn)) + + def _added(self, registry: "TypesRegistry") -> None: + # Map ranges subtypes to info + registry._registry[RangeInfo, self.subtype_oid] = self + + +class MultirangeInfo(TypeInfo): + """Manage information about a multirange type.""" + + __module__ = "psycopg.types.multirange" + + def __init__( + self, + name: str, + oid: int, + array_oid: int, + *, + regtype: str = "", + range_oid: int, + subtype_oid: int, + ): + super().__init__(name, oid, array_oid, regtype=regtype) + self.range_oid = range_oid + self.subtype_oid = subtype_oid + + @classmethod + def _get_info_query(cls, conn: "BaseConnection[Any]") -> Query: + from .sql import SQL + + if conn.info.server_version < 140000: + raise e.NotSupportedError( + "multirange types are only available from PostgreSQL 14" + ) + + return SQL( + """\ +SELECT t.typname AS name, t.oid AS oid, t.typarray AS array_oid, + t.oid::regtype::text AS regtype, + r.rngtypid AS range_oid, r.rngsubtype AS subtype_oid +FROM pg_type t +JOIN pg_range r ON t.oid = r.rngmultitypid +WHERE t.oid = {regtype} +""" + ).format(regtype=cls._to_regtype(conn)) + + def _added(self, registry: "TypesRegistry") -> None: + # Map multiranges ranges and subtypes to info + registry._registry[MultirangeInfo, self.range_oid] = self + registry._registry[MultirangeInfo, self.subtype_oid] = self + + +class CompositeInfo(TypeInfo): + """Manage information about a composite type.""" + + __module__ = "psycopg.types.composite" + + def __init__( + self, + name: str, + oid: int, + array_oid: int, + *, + regtype: str = "", + field_names: Sequence[str], + field_types: Sequence[int], + ): + super().__init__(name, oid, array_oid, regtype=regtype) + self.field_names = field_names + self.field_types = field_types + # Will be set by register() if the `factory` is a type + self.python_type: Optional[type] = None + + @classmethod + def _get_info_query(cls, conn: "BaseConnection[Any]") -> Query: + from .sql import SQL + + return SQL( + """\ +SELECT + t.typname AS name, t.oid AS oid, t.typarray AS array_oid, + t.oid::regtype::text AS regtype, + coalesce(a.fnames, '{{}}') AS field_names, + coalesce(a.ftypes, '{{}}') AS field_types +FROM pg_type t +LEFT JOIN ( + SELECT + attrelid, + array_agg(attname) AS fnames, + array_agg(atttypid) AS ftypes + FROM ( + SELECT a.attrelid, a.attname, a.atttypid + FROM pg_attribute a + JOIN pg_type t ON t.typrelid = a.attrelid + WHERE t.oid = {regtype} + AND a.attnum > 0 + AND NOT a.attisdropped + ORDER BY a.attnum + ) x + GROUP BY attrelid +) a ON a.attrelid = t.typrelid +WHERE t.oid = {regtype} +""" + ).format(regtype=cls._to_regtype(conn)) + + +class EnumInfo(TypeInfo): + """Manage information about an enum type.""" + + __module__ = "psycopg.types.enum" + + def __init__( + self, + name: str, + oid: int, + array_oid: int, + labels: Sequence[str], + ): + super().__init__(name, oid, array_oid) + self.labels = labels + # Will be set by register_enum() + self.enum: Optional[Type[Enum]] = None + + @classmethod + def _get_info_query(cls, conn: "BaseConnection[Any]") -> Query: + from .sql import SQL + + return SQL( + """\ +SELECT name, oid, array_oid, array_agg(label) AS labels +FROM ( + SELECT + t.typname AS name, t.oid AS oid, t.typarray AS array_oid, + e.enumlabel AS label + FROM pg_type t + LEFT JOIN pg_enum e + ON e.enumtypid = t.oid + WHERE t.oid = {regtype} + ORDER BY e.enumsortorder +) x +GROUP BY name, oid, array_oid +""" + ).format(regtype=cls._to_regtype(conn)) + + +class TypesRegistry: + """ + Container for the information about types in a database. + """ + + __module__ = "psycopg.types" + + def __init__(self, template: Optional["TypesRegistry"] = None): + self._registry: Dict[RegistryKey, TypeInfo] + + # Make a shallow copy: it will become a proper copy if the registry + # is edited. + if template: + self._registry = template._registry + self._own_state = False + template._own_state = False + else: + self.clear() + + def clear(self) -> None: + self._registry = {} + self._own_state = True + + def add(self, info: TypeInfo) -> None: + self._ensure_own_state() + if info.oid: + self._registry[info.oid] = info + if info.array_oid: + self._registry[info.array_oid] = info + self._registry[info.name] = info + + if info.regtype and info.regtype not in self._registry: + self._registry[info.regtype] = info + + # Allow info to customise further their relation with the registry + info._added(self) + + def __iter__(self) -> Iterator[TypeInfo]: + seen = set() + for t in self._registry.values(): + if id(t) not in seen: + seen.add(id(t)) + yield t + + @overload + def __getitem__(self, key: Union[str, int]) -> TypeInfo: + ... + + @overload + def __getitem__(self, key: Tuple[Type[T], int]) -> T: + ... + + def __getitem__(self, key: RegistryKey) -> TypeInfo: + """ + Return info about a type, specified by name or oid + + :param key: the name or oid of the type to look for. + + Raise KeyError if not found. + """ + if isinstance(key, str): + if key.endswith("[]"): + key = key[:-2] + elif not isinstance(key, (int, tuple)): + raise TypeError(f"the key must be an oid or a name, got {type(key)}") + try: + return self._registry[key] + except KeyError: + raise KeyError(f"couldn't find the type {key!r} in the types registry") + + @overload + def get(self, key: Union[str, int]) -> Optional[TypeInfo]: + ... + + @overload + def get(self, key: Tuple[Type[T], int]) -> Optional[T]: + ... + + def get(self, key: RegistryKey) -> Optional[TypeInfo]: + """ + Return info about a type, specified by name or oid + + :param key: the name or oid of the type to look for. + + Unlike `__getitem__`, return None if not found. + """ + try: + return self[key] + except KeyError: + return None + + def get_oid(self, name: str) -> int: + """ + Return the oid of a PostgreSQL type by name. + + :param key: the name of the type to look for. + + Return the array oid if the type ends with "``[]``" + + Raise KeyError if the name is unknown. + """ + t = self[name] + if name.endswith("[]"): + return t.array_oid + else: + return t.oid + + def get_by_subtype(self, cls: Type[T], subtype: Union[int, str]) -> Optional[T]: + """ + Return info about a `TypeInfo` subclass by its element name or oid. + + :param cls: the subtype of `!TypeInfo` to look for. Currently + supported are `~psycopg.types.range.RangeInfo` and + `~psycopg.types.multirange.MultirangeInfo`. + :param subtype: The name or OID of the subtype of the element to look for. + :return: The `!TypeInfo` object of class `!cls` whose subtype is + `!subtype`. `!None` if the element or its range are not found. + """ + try: + info = self[subtype] + except KeyError: + return None + return self.get((cls, info.oid)) + + def _ensure_own_state(self) -> None: + # Time to write! so, copy. + if not self._own_state: + self._registry = self._registry.copy() + self._own_state = True diff --git a/lib/python3.11/site-packages/psycopg/_tz.py b/lib/python3.11/site-packages/psycopg/_tz.py new file mode 100644 index 0000000..813ed62 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_tz.py @@ -0,0 +1,44 @@ +""" +Timezone utility functions. +""" + +# Copyright (C) 2020 The Psycopg Team + +import logging +from typing import Dict, Optional, Union +from datetime import timezone, tzinfo + +from .pq.abc import PGconn +from ._compat import ZoneInfo + +logger = logging.getLogger("psycopg") + +_timezones: Dict[Union[None, bytes], tzinfo] = { + None: timezone.utc, + b"UTC": timezone.utc, +} + + +def get_tzinfo(pgconn: Optional[PGconn]) -> tzinfo: + """Return the Python timezone info of the connection's timezone.""" + tzname = pgconn.parameter_status(b"TimeZone") if pgconn else None + try: + return _timezones[tzname] + except KeyError: + sname = tzname.decode() if tzname else "UTC" + try: + zi: tzinfo = ZoneInfo(sname) + except (KeyError, OSError): + logger.warning("unknown PostgreSQL timezone: %r; will use UTC", sname) + zi = timezone.utc + except Exception as ex: + logger.warning( + "error handling PostgreSQL timezone: %r; will use UTC (%s - %s)", + sname, + type(ex).__name__, + ex, + ) + zi = timezone.utc + + _timezones[tzname] = zi + return zi diff --git a/lib/python3.11/site-packages/psycopg/_wrappers.py b/lib/python3.11/site-packages/psycopg/_wrappers.py new file mode 100644 index 0000000..f861741 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/_wrappers.py @@ -0,0 +1,137 @@ +""" +Wrappers for numeric types. +""" + +# Copyright (C) 2020 The Psycopg Team + +# Wrappers to force numbers to be cast as specific PostgreSQL types + +# These types are implemented here but exposed by `psycopg.types.numeric`. +# They are defined here to avoid a circular import. +_MODULE = "psycopg.types.numeric" + + +class Int2(int): + """ + Force dumping a Python `!int` as a PostgreSQL :sql:`smallint/int2`. + """ + + __module__ = _MODULE + __slots__ = () + + def __new__(cls, arg: int) -> "Int2": + return super().__new__(cls, arg) + + def __str__(self) -> str: + return super().__repr__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + +class Int4(int): + """ + Force dumping a Python `!int` as a PostgreSQL :sql:`integer/int4`. + """ + + __module__ = _MODULE + __slots__ = () + + def __new__(cls, arg: int) -> "Int4": + return super().__new__(cls, arg) + + def __str__(self) -> str: + return super().__repr__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + +class Int8(int): + """ + Force dumping a Python `!int` as a PostgreSQL :sql:`bigint/int8`. + """ + + __module__ = _MODULE + __slots__ = () + + def __new__(cls, arg: int) -> "Int8": + return super().__new__(cls, arg) + + def __str__(self) -> str: + return super().__repr__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + +class IntNumeric(int): + """ + Force dumping a Python `!int` as a PostgreSQL :sql:`numeric/decimal`. + """ + + __module__ = _MODULE + __slots__ = () + + def __new__(cls, arg: int) -> "IntNumeric": + return super().__new__(cls, arg) + + def __str__(self) -> str: + return super().__repr__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + +class Float4(float): + """ + Force dumping a Python `!float` as a PostgreSQL :sql:`float4/real`. + """ + + __module__ = _MODULE + __slots__ = () + + def __new__(cls, arg: float) -> "Float4": + return super().__new__(cls, arg) + + def __str__(self) -> str: + return super().__repr__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + +class Float8(float): + """ + Force dumping a Python `!float` as a PostgreSQL :sql:`float8/double precision`. + """ + + __module__ = _MODULE + __slots__ = () + + def __new__(cls, arg: float) -> "Float8": + return super().__new__(cls, arg) + + def __str__(self) -> str: + return super().__repr__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" + + +class Oid(int): + """ + Force dumping a Python `!int` as a PostgreSQL :sql:`oid`. + """ + + __module__ = _MODULE + __slots__ = () + + def __new__(cls, arg: int) -> "Oid": + return super().__new__(cls, arg) + + def __str__(self) -> str: + return super().__repr__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({super().__repr__()})" diff --git a/lib/python3.11/site-packages/psycopg/abc.py b/lib/python3.11/site-packages/psycopg/abc.py new file mode 100644 index 0000000..0cf1a75 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/abc.py @@ -0,0 +1,265 @@ +""" +Protocol objects representing different implementations of the same classes. +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Any, Callable, Generator, Mapping +from typing import List, Optional, Sequence, Tuple, TypeVar, Union +from typing import TYPE_CHECKING +from typing_extensions import TypeAlias + +from . import pq +from ._enums import PyFormat as PyFormat +from ._compat import Protocol, LiteralString + +if TYPE_CHECKING: + from . import sql + from .rows import Row, RowMaker + from .pq.abc import PGresult + from .waiting import Wait, Ready + from .connection import BaseConnection + from ._adapters_map import AdaptersMap + +NoneType: type = type(None) + +# An object implementing the buffer protocol +Buffer: TypeAlias = Union[bytes, bytearray, memoryview] + +Query: TypeAlias = Union[LiteralString, bytes, "sql.SQL", "sql.Composed"] +Params: TypeAlias = Union[Sequence[Any], Mapping[str, Any]] +ConnectionType = TypeVar("ConnectionType", bound="BaseConnection[Any]") +PipelineCommand: TypeAlias = Callable[[], None] +DumperKey: TypeAlias = Union[type, Tuple["DumperKey", ...]] + +# Waiting protocol types + +RV = TypeVar("RV") + +PQGenConn: TypeAlias = Generator[Tuple[int, "Wait"], "Ready", RV] +"""Generator for processes where the connection file number can change. + +This can happen in connection and reset, but not in normal querying. +""" + +PQGen: TypeAlias = Generator["Wait", "Ready", RV] +"""Generator for processes where the connection file number won't change. +""" + + +class WaitFunc(Protocol): + """ + Wait on the connection which generated `PQgen` and return its final result. + """ + + def __call__( + self, gen: PQGen[RV], fileno: int, timeout: Optional[float] = None + ) -> RV: + ... + + +# Adaptation types + +DumpFunc: TypeAlias = Callable[[Any], Buffer] +LoadFunc: TypeAlias = Callable[[Buffer], Any] + + +class AdaptContext(Protocol): + """ + A context describing how types are adapted. + + Example of `~AdaptContext` are `~psycopg.Connection`, `~psycopg.Cursor`, + `~psycopg.adapt.Transformer`, `~psycopg.adapt.AdaptersMap`. + + Note that this is a `~typing.Protocol`, so objects implementing + `!AdaptContext` don't need to explicitly inherit from this class. + + """ + + @property + def adapters(self) -> "AdaptersMap": + """The adapters configuration that this object uses.""" + ... + + @property + def connection(self) -> Optional["BaseConnection[Any]"]: + """The connection used by this object, if available. + + :rtype: `~psycopg.Connection` or `~psycopg.AsyncConnection` or `!None` + """ + ... + + +class Dumper(Protocol): + """ + Convert Python objects of type `!cls` to PostgreSQL representation. + """ + + format: pq.Format + """ + The format that this class `dump()` method produces, + `~psycopg.pq.Format.TEXT` or `~psycopg.pq.Format.BINARY`. + + This is a class attribute. + """ + + oid: int + """The oid to pass to the server, if known; 0 otherwise (class attribute).""" + + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + ... + + def dump(self, obj: Any) -> Buffer: + """Convert the object `!obj` to PostgreSQL representation. + + :param obj: the object to convert. + """ + ... + + def quote(self, obj: Any) -> Buffer: + """Convert the object `!obj` to escaped representation. + + :param obj: the object to convert. + """ + ... + + def get_key(self, obj: Any, format: PyFormat) -> DumperKey: + """Return an alternative key to upgrade the dumper to represent `!obj`. + + :param obj: The object to convert + :param format: The format to convert to + + Normally the type of the object is all it takes to define how to dump + the object to the database. For instance, a Python `~datetime.date` can + be simply converted into a PostgreSQL :sql:`date`. + + In a few cases, just the type is not enough. For example: + + - A Python `~datetime.datetime` could be represented as a + :sql:`timestamptz` or a :sql:`timestamp`, according to whether it + specifies a `!tzinfo` or not. + + - A Python int could be stored as several Postgres types: int2, int4, + int8, numeric. If a type too small is used, it may result in an + overflow. If a type too large is used, PostgreSQL may not want to + cast it to a smaller type. + + - Python lists should be dumped according to the type they contain to + convert them to e.g. array of strings, array of ints (and which + size of int?...) + + In these cases, a dumper can implement `!get_key()` and return a new + class, or sequence of classes, that can be used to identify the same + dumper again. If the mechanism is not needed, the method should return + the same `!cls` object passed in the constructor. + + If a dumper implements `get_key()` it should also implement + `upgrade()`. + + """ + ... + + def upgrade(self, obj: Any, format: PyFormat) -> "Dumper": + """Return a new dumper to manage `!obj`. + + :param obj: The object to convert + :param format: The format to convert to + + Once `Transformer.get_dumper()` has been notified by `get_key()` that + this Dumper class cannot handle `!obj` itself, it will invoke + `!upgrade()`, which should return a new `Dumper` instance, which will + be reused for every objects for which `!get_key()` returns the same + result. + """ + ... + + +class Loader(Protocol): + """ + Convert PostgreSQL values with type OID `!oid` to Python objects. + """ + + format: pq.Format + """ + The format that this class `load()` method can convert, + `~psycopg.pq.Format.TEXT` or `~psycopg.pq.Format.BINARY`. + + This is a class attribute. + """ + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + ... + + def load(self, data: Buffer) -> Any: + """ + Convert the data returned by the database into a Python object. + + :param data: the data to convert. + """ + ... + + +class Transformer(Protocol): + types: Optional[Tuple[int, ...]] + formats: Optional[List[pq.Format]] + + def __init__(self, context: Optional[AdaptContext] = None): + ... + + @classmethod + def from_context(cls, context: Optional[AdaptContext]) -> "Transformer": + ... + + @property + def connection(self) -> Optional["BaseConnection[Any]"]: + ... + + @property + def encoding(self) -> str: + ... + + @property + def adapters(self) -> "AdaptersMap": + ... + + @property + def pgresult(self) -> Optional["PGresult"]: + ... + + def set_pgresult( + self, + result: Optional["PGresult"], + *, + set_loaders: bool = True, + format: Optional[pq.Format] = None + ) -> None: + ... + + def set_dumper_types(self, types: Sequence[int], format: pq.Format) -> None: + ... + + def set_loader_types(self, types: Sequence[int], format: pq.Format) -> None: + ... + + def dump_sequence( + self, params: Sequence[Any], formats: Sequence[PyFormat] + ) -> Sequence[Optional[Buffer]]: + ... + + def as_literal(self, obj: Any) -> bytes: + ... + + def get_dumper(self, obj: Any, format: PyFormat) -> Dumper: + ... + + def load_rows(self, row0: int, row1: int, make_row: "RowMaker[Row]") -> List["Row"]: + ... + + def load_row(self, row: int, make_row: "RowMaker[Row]") -> Optional["Row"]: + ... + + def load_sequence(self, record: Sequence[Optional[Buffer]]) -> Tuple[Any, ...]: + ... + + def get_loader(self, oid: int, format: pq.Format) -> Loader: + ... diff --git a/lib/python3.11/site-packages/psycopg/adapt.py b/lib/python3.11/site-packages/psycopg/adapt.py new file mode 100644 index 0000000..7ec4a55 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/adapt.py @@ -0,0 +1,162 @@ +""" +Entry point into the adaptation system. +""" + +# Copyright (C) 2020 The Psycopg Team + +from abc import ABC, abstractmethod +from typing import Any, Optional, Type, TYPE_CHECKING + +from . import pq, abc +from . import _adapters_map +from ._enums import PyFormat as PyFormat +from ._cmodule import _psycopg + +if TYPE_CHECKING: + from .connection import BaseConnection + +AdaptersMap = _adapters_map.AdaptersMap +Buffer = abc.Buffer + +ORD_BS = ord("\\") + + +class Dumper(abc.Dumper, ABC): + """ + Convert Python object of the type `!cls` to PostgreSQL representation. + """ + + oid: int = 0 + """The oid to pass to the server, if known.""" + + format: pq.Format = pq.Format.TEXT + """The format of the data dumped.""" + + def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None): + self.cls = cls + self.connection: Optional["BaseConnection[Any]"] = ( + context.connection if context else None + ) + + def __repr__(self) -> str: + return ( + f"<{type(self).__module__}.{type(self).__qualname__}" + f" (oid={self.oid}) at 0x{id(self):x}>" + ) + + @abstractmethod + def dump(self, obj: Any) -> Buffer: + ... + + def quote(self, obj: Any) -> Buffer: + """ + By default return the `dump()` value quoted and sanitised, so + that the result can be used to build a SQL string. This works well + for most types and you won't likely have to implement this method in a + subclass. + """ + value = self.dump(obj) + + if self.connection: + esc = pq.Escaping(self.connection.pgconn) + # escaping and quoting + return esc.escape_literal(value) + + # This path is taken when quote is asked without a connection, + # usually it means by psycopg.sql.quote() or by + # 'Composible.as_string(None)'. Most often than not this is done by + # someone generating a SQL file to consume elsewhere. + + # No quoting, only quote escaping, random bs escaping. See further. + esc = pq.Escaping() + out = esc.escape_string(value) + + # b"\\" in memoryview doesn't work so search for the ascii value + if ORD_BS not in out: + # If the string has no backslash, the result is correct and we + # don't need to bother with standard_conforming_strings. + return b"'" + out + b"'" + + # The libpq has a crazy behaviour: PQescapeString uses the last + # standard_conforming_strings setting seen on a connection. This + # means that backslashes might be escaped or might not. + # + # A syntax E'\\' works everywhere, whereas E'\' is an error. OTOH, + # if scs is off, '\\' raises a warning and '\' is an error. + # + # Check what the libpq does, and if it doesn't escape the backslash + # let's do it on our own. Never mind the race condition. + rv: bytes = b" E'" + out + b"'" + if esc.escape_string(b"\\") == b"\\": + rv = rv.replace(b"\\", b"\\\\") + return rv + + def get_key(self, obj: Any, format: PyFormat) -> abc.DumperKey: + """ + Implementation of the `~psycopg.abc.Dumper.get_key()` member of the + `~psycopg.abc.Dumper` protocol. Look at its definition for details. + + This implementation returns the `!cls` passed in the constructor. + Subclasses needing to specialise the PostgreSQL type according to the + *value* of the object dumped (not only according to to its type) + should override this class. + + """ + return self.cls + + def upgrade(self, obj: Any, format: PyFormat) -> "Dumper": + """ + Implementation of the `~psycopg.abc.Dumper.upgrade()` member of the + `~psycopg.abc.Dumper` protocol. Look at its definition for details. + + This implementation just returns `!self`. If a subclass implements + `get_key()` it should probably override `!upgrade()` too. + """ + return self + + +class Loader(abc.Loader, ABC): + """ + Convert PostgreSQL values with type OID `!oid` to Python objects. + """ + + format: pq.Format = pq.Format.TEXT + """The format of the data loaded.""" + + def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None): + self.oid = oid + self.connection: Optional["BaseConnection[Any]"] = ( + context.connection if context else None + ) + + @abstractmethod + def load(self, data: Buffer) -> Any: + """Convert a PostgreSQL value to a Python object.""" + ... + + +Transformer: Type["abc.Transformer"] + +# Override it with fast object if available +if _psycopg: + Transformer = _psycopg.Transformer +else: + from . import _transform + + Transformer = _transform.Transformer + + +class RecursiveDumper(Dumper): + """Dumper with a transformer to help dumping recursive types.""" + + def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None): + super().__init__(cls, context) + self._tx = Transformer.from_context(context) + + +class RecursiveLoader(Loader): + """Loader with a transformer to help loading recursive types.""" + + def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None): + super().__init__(oid, context) + self._tx = Transformer.from_context(context) diff --git a/lib/python3.11/site-packages/psycopg/client_cursor.py b/lib/python3.11/site-packages/psycopg/client_cursor.py new file mode 100644 index 0000000..6271ec5 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/client_cursor.py @@ -0,0 +1,95 @@ +""" +psycopg client-side binding cursors +""" + +# Copyright (C) 2022 The Psycopg Team + +from typing import Optional, Tuple, TYPE_CHECKING +from functools import partial + +from ._queries import PostgresQuery, PostgresClientQuery + +from . import pq +from . import adapt +from . import errors as e +from .abc import ConnectionType, Query, Params +from .rows import Row +from .cursor import BaseCursor, Cursor +from ._preparing import Prepare +from .cursor_async import AsyncCursor + +if TYPE_CHECKING: + from typing import Any # noqa: F401 + from .connection import Connection # noqa: F401 + from .connection_async import AsyncConnection # noqa: F401 + +TEXT = pq.Format.TEXT +BINARY = pq.Format.BINARY + + +class ClientCursorMixin(BaseCursor[ConnectionType, Row]): + def mogrify(self, query: Query, params: Optional[Params] = None) -> str: + """ + Return the query and parameters merged. + + Parameters are adapted and merged to the query the same way that + `!execute()` would do. + + """ + self._tx = adapt.Transformer(self) + pgq = self._convert_query(query, params) + return pgq.query.decode(self._tx.encoding) + + def _execute_send( + self, + query: PostgresQuery, + *, + force_extended: bool = False, + binary: Optional[bool] = None, + ) -> None: + if binary is None: + fmt = self.format + else: + fmt = BINARY if binary else TEXT + + if fmt == BINARY: + raise e.NotSupportedError( + "client-side cursors don't support binary results" + ) + + self._query = query + + if self._conn._pipeline: + # In pipeline mode always use PQsendQueryParams - see #314 + # Multiple statements in the same query are not allowed anyway. + self._conn._pipeline.command_queue.append( + partial(self._pgconn.send_query_params, query.query, None) + ) + elif force_extended: + self._pgconn.send_query_params(query.query, None) + else: + # If we can, let's use simple query protocol, + # as it can execute more than one statement in a single query. + self._pgconn.send_query(query.query) + + def _convert_query( + self, query: Query, params: Optional[Params] = None + ) -> PostgresQuery: + pgq = PostgresClientQuery(self._tx) + pgq.convert(query, params) + return pgq + + def _get_prepared( + self, pgq: PostgresQuery, prepare: Optional[bool] = None + ) -> Tuple[Prepare, bytes]: + return (Prepare.NO, b"") + + +class ClientCursor(ClientCursorMixin["Connection[Any]", Row], Cursor[Row]): + __module__ = "psycopg" + + +class AsyncClientCursor( + ClientCursorMixin["AsyncConnection[Any]", Row], AsyncCursor[Row] +): + __module__ = "psycopg" diff --git a/lib/python3.11/site-packages/psycopg/connection.py b/lib/python3.11/site-packages/psycopg/connection.py new file mode 100644 index 0000000..299c4f3 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/connection.py @@ -0,0 +1,1031 @@ +""" +psycopg connection objects +""" + +# Copyright (C) 2020 The Psycopg Team + +import logging +import threading +from types import TracebackType +from typing import Any, Callable, cast, Dict, Generator, Generic, Iterator +from typing import List, NamedTuple, Optional, Type, TypeVar, Tuple, Union +from typing import overload, TYPE_CHECKING +from weakref import ref, ReferenceType +from warnings import warn +from functools import partial +from contextlib import contextmanager +from typing_extensions import TypeAlias + +from . import pq +from . import errors as e +from . import waiting +from . import postgres +from .abc import AdaptContext, ConnectionType, Params, Query, RV +from .abc import PQGen, PQGenConn +from .sql import Composable, SQL +from ._tpc import Xid +from .rows import Row, RowFactory, tuple_row, TupleRow, args_row +from .adapt import AdaptersMap +from ._enums import IsolationLevel +from .cursor import Cursor +from ._compat import LiteralString +from .conninfo import make_conninfo, conninfo_to_dict, ConnectionInfo +from ._pipeline import BasePipeline, Pipeline +from .generators import notifies, connect, execute +from ._encodings import pgconn_encoding +from ._preparing import PrepareManager +from .transaction import Transaction +from .server_cursor import ServerCursor + +if TYPE_CHECKING: + from .pq.abc import PGconn, PGresult + from psycopg_pool.base import BasePool + + +# Row Type variable for Cursor (when it needs to be distinguished from the +# connection's one) +CursorRow = TypeVar("CursorRow") + +TEXT = pq.Format.TEXT +BINARY = pq.Format.BINARY + +OK = pq.ConnStatus.OK +BAD = pq.ConnStatus.BAD + +COMMAND_OK = pq.ExecStatus.COMMAND_OK +TUPLES_OK = pq.ExecStatus.TUPLES_OK +FATAL_ERROR = pq.ExecStatus.FATAL_ERROR + +IDLE = pq.TransactionStatus.IDLE +INTRANS = pq.TransactionStatus.INTRANS + +logger = logging.getLogger("psycopg") + + +class Notify(NamedTuple): + """An asynchronous notification received from the database.""" + + channel: str + """The name of the channel on which the notification was received.""" + + payload: str + """The message attached to the notification.""" + + pid: int + """The PID of the backend process which sent the notification.""" + + +Notify.__module__ = "psycopg" + +NoticeHandler: TypeAlias = Callable[[e.Diagnostic], None] +NotifyHandler: TypeAlias = Callable[[Notify], None] + + +class BaseConnection(Generic[Row]): + """ + Base class for different types of connections. + + Share common functionalities such as access to the wrapped PGconn, but + allow different interfaces (sync/async). + """ + + # DBAPI2 exposed exceptions + Warning = e.Warning + Error = e.Error + InterfaceError = e.InterfaceError + DatabaseError = e.DatabaseError + DataError = e.DataError + OperationalError = e.OperationalError + IntegrityError = e.IntegrityError + InternalError = e.InternalError + ProgrammingError = e.ProgrammingError + NotSupportedError = e.NotSupportedError + + # Enums useful for the connection + ConnStatus = pq.ConnStatus + TransactionStatus = pq.TransactionStatus + + def __init__(self, pgconn: "PGconn"): + self.pgconn = pgconn + self._autocommit = False + + # None, but set to a copy of the global adapters map as soon as requested. + self._adapters: Optional[AdaptersMap] = None + + self._notice_handlers: List[NoticeHandler] = [] + self._notify_handlers: List[NotifyHandler] = [] + + # Number of transaction blocks currently entered + self._num_transactions = 0 + + self._closed = False # closed by an explicit close() + self._prepared: PrepareManager = PrepareManager() + self._tpc: Optional[Tuple[Xid, bool]] = None # xid, prepared + + wself = ref(self) + pgconn.notice_handler = partial(BaseConnection._notice_handler, wself) + pgconn.notify_handler = partial(BaseConnection._notify_handler, wself) + + # Attribute is only set if the connection is from a pool so we can tell + # apart a connection in the pool too (when _pool = None) + self._pool: Optional["BasePool[Any]"] + + self._pipeline: Optional[BasePipeline] = None + + # Time after which the connection should be closed + self._expire_at: float + + self._isolation_level: Optional[IsolationLevel] = None + self._read_only: Optional[bool] = None + self._deferrable: Optional[bool] = None + self._begin_statement = b"" + + def __del__(self) -> None: + # If fails on connection we might not have this attribute yet + if not hasattr(self, "pgconn"): + return + + # Connection correctly closed + if self.closed: + return + + # Connection in a pool so terminating with the program is normal + if hasattr(self, "_pool"): + return + + warn( + f"connection {self} was deleted while still open." + " Please use 'with' or '.close()' to close the connection", + ResourceWarning, + ) + + def __repr__(self) -> str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + info = pq.misc.connection_summary(self.pgconn) + return f"<{cls} {info} at 0x{id(self):x}>" + + @property + def closed(self) -> bool: + """`!True` if the connection is closed.""" + return self.pgconn.status == BAD + + @property + def broken(self) -> bool: + """ + `!True` if the connection was interrupted. + + A broken connection is always `closed`, but wasn't closed in a clean + way, such as using `close()` or a `!with` block. + """ + return self.pgconn.status == BAD and not self._closed + + @property + def autocommit(self) -> bool: + """The autocommit state of the connection.""" + return self._autocommit + + @autocommit.setter + def autocommit(self, value: bool) -> None: + self._set_autocommit(value) + + def _set_autocommit(self, value: bool) -> None: + raise NotImplementedError + + def _set_autocommit_gen(self, value: bool) -> PQGen[None]: + yield from self._check_intrans_gen("autocommit") + self._autocommit = bool(value) + + @property + def isolation_level(self) -> Optional[IsolationLevel]: + """ + The isolation level of the new transactions started on the connection. + """ + return self._isolation_level + + @isolation_level.setter + def isolation_level(self, value: Optional[IsolationLevel]) -> None: + self._set_isolation_level(value) + + def _set_isolation_level(self, value: Optional[IsolationLevel]) -> None: + raise NotImplementedError + + def _set_isolation_level_gen(self, value: Optional[IsolationLevel]) -> PQGen[None]: + yield from self._check_intrans_gen("isolation_level") + self._isolation_level = IsolationLevel(value) if value is not None else None + self._begin_statement = b"" + + @property + def read_only(self) -> Optional[bool]: + """ + The read-only state of the new transactions started on the connection. + """ + return self._read_only + + @read_only.setter + def read_only(self, value: Optional[bool]) -> None: + self._set_read_only(value) + + def _set_read_only(self, value: Optional[bool]) -> None: + raise NotImplementedError + + def _set_read_only_gen(self, value: Optional[bool]) -> PQGen[None]: + yield from self._check_intrans_gen("read_only") + self._read_only = bool(value) + self._begin_statement = b"" + + @property + def deferrable(self) -> Optional[bool]: + """ + The deferrable state of the new transactions started on the connection. + """ + return self._deferrable + + @deferrable.setter + def deferrable(self, value: Optional[bool]) -> None: + self._set_deferrable(value) + + def _set_deferrable(self, value: Optional[bool]) -> None: + raise NotImplementedError + + def _set_deferrable_gen(self, value: Optional[bool]) -> PQGen[None]: + yield from self._check_intrans_gen("deferrable") + self._deferrable = bool(value) + self._begin_statement = b"" + + def _check_intrans_gen(self, attribute: str) -> PQGen[None]: + # Raise an exception if we are in a transaction + status = self.pgconn.transaction_status + if status == IDLE and self._pipeline: + yield from self._pipeline._sync_gen() + status = self.pgconn.transaction_status + if status != IDLE: + if self._num_transactions: + raise e.ProgrammingError( + f"can't change {attribute!r} now: " + "connection.transaction() context in progress" + ) + else: + raise e.ProgrammingError( + f"can't change {attribute!r} now: " + "connection in transaction status " + f"{pq.TransactionStatus(status).name}" + ) + + @property + def info(self) -> ConnectionInfo: + """A `ConnectionInfo` attribute to inspect connection properties.""" + return ConnectionInfo(self.pgconn) + + @property + def adapters(self) -> AdaptersMap: + if not self._adapters: + self._adapters = AdaptersMap(postgres.adapters) + + return self._adapters + + @property + def connection(self) -> "BaseConnection[Row]": + # implement the AdaptContext protocol + return self + + def fileno(self) -> int: + """Return the file descriptor of the connection. + + This function allows to use the connection as file-like object in + functions waiting for readiness, such as the ones defined in the + `selectors` module. + """ + return self.pgconn.socket + + def cancel(self) -> None: + """Cancel the current operation on the connection.""" + # No-op if the connection is closed + # this allows to use the method as callback handler without caring + # about its life. + if self.closed: + return + + if self._tpc and self._tpc[1]: + raise e.ProgrammingError( + "cancel() cannot be used with a prepared two-phase transaction" + ) + + c = self.pgconn.get_cancel() + c.cancel() + + def add_notice_handler(self, callback: NoticeHandler) -> None: + """ + Register a callable to be invoked when a notice message is received. + + :param callback: the callback to call upon message received. + :type callback: Callable[[~psycopg.errors.Diagnostic], None] + """ + self._notice_handlers.append(callback) + + def remove_notice_handler(self, callback: NoticeHandler) -> None: + """ + Unregister a notice message callable previously registered. + + :param callback: the callback to remove. + :type callback: Callable[[~psycopg.errors.Diagnostic], None] + """ + self._notice_handlers.remove(callback) + + @staticmethod + def _notice_handler( + wself: "ReferenceType[BaseConnection[Row]]", res: "PGresult" + ) -> None: + self = wself() + if not (self and self._notice_handlers): + return + + diag = e.Diagnostic(res, pgconn_encoding(self.pgconn)) + for cb in self._notice_handlers: + try: + cb(diag) + except Exception as ex: + logger.exception("error processing notice callback '%s': %s", cb, ex) + + def add_notify_handler(self, callback: NotifyHandler) -> None: + """ + Register a callable to be invoked whenever a notification is received. + + :param callback: the callback to call upon notification received. + :type callback: Callable[[~psycopg.Notify], None] + """ + self._notify_handlers.append(callback) + + def remove_notify_handler(self, callback: NotifyHandler) -> None: + """ + Unregister a notification callable previously registered. + + :param callback: the callback to remove. + :type callback: Callable[[~psycopg.Notify], None] + """ + self._notify_handlers.remove(callback) + + @staticmethod + def _notify_handler( + wself: "ReferenceType[BaseConnection[Row]]", pgn: pq.PGnotify + ) -> None: + self = wself() + if not (self and self._notify_handlers): + return + + enc = pgconn_encoding(self.pgconn) + n = Notify(pgn.relname.decode(enc), pgn.extra.decode(enc), pgn.be_pid) + for cb in self._notify_handlers: + cb(n) + + @property + def prepare_threshold(self) -> Optional[int]: + """ + Number of times a query is executed before it is prepared. + + - If it is set to 0, every query is prepared the first time it is + executed. + - If it is set to `!None`, prepared statements are disabled on the + connection. + + Default value: 5 + """ + return self._prepared.prepare_threshold + + @prepare_threshold.setter + def prepare_threshold(self, value: Optional[int]) -> None: + self._prepared.prepare_threshold = value + + @property + def prepared_max(self) -> int: + """ + Maximum number of prepared statements on the connection. + + Default value: 100 + """ + return self._prepared.prepared_max + + @prepared_max.setter + def prepared_max(self, value: int) -> None: + self._prepared.prepared_max = value + + # Generators to perform high-level operations on the connection + # + # These operations are expressed in terms of non-blocking generators + # and the task of waiting when needed (when the generators yield) is left + # to the connections subclass, which might wait either in blocking mode + # or through asyncio. + # + # All these generators assume exclusive access to the connection: subclasses + # should have a lock and hold it before calling and consuming them. + + @classmethod + def _connect_gen( + cls: Type[ConnectionType], + conninfo: str = "", + *, + autocommit: bool = False, + ) -> PQGenConn[ConnectionType]: + """Generator to connect to the database and create a new instance.""" + pgconn = yield from connect(conninfo) + conn = cls(pgconn) + conn._autocommit = bool(autocommit) + return conn + + def _exec_command( + self, command: Query, result_format: pq.Format = TEXT + ) -> PQGen[Optional["PGresult"]]: + """ + Generator to send a command and receive the result to the backend. + + Only used to implement internal commands such as "commit", with eventual + arguments bound client-side. The cursor can do more complex stuff. + """ + self._check_connection_ok() + + if isinstance(command, str): + command = command.encode(pgconn_encoding(self.pgconn)) + elif isinstance(command, Composable): + command = command.as_bytes(self) + + if self._pipeline: + cmd = partial( + self.pgconn.send_query_params, + command, + None, + result_format=result_format, + ) + self._pipeline.command_queue.append(cmd) + self._pipeline.result_queue.append(None) + return None + + self.pgconn.send_query_params(command, None, result_format=result_format) + + result = (yield from execute(self.pgconn))[-1] + if result.status != COMMAND_OK and result.status != TUPLES_OK: + if result.status == FATAL_ERROR: + raise e.error_from_result(result, encoding=pgconn_encoding(self.pgconn)) + else: + raise e.InterfaceError( + f"unexpected result {pq.ExecStatus(result.status).name}" + f" from command {command.decode()!r}" + ) + return result + + def _check_connection_ok(self) -> None: + if self.pgconn.status == OK: + return + + if self.pgconn.status == BAD: + raise e.OperationalError("the connection is closed") + raise e.InterfaceError( + "cannot execute operations: the connection is" + f" in status {self.pgconn.status}" + ) + + def _start_query(self) -> PQGen[None]: + """Generator to start a transaction if necessary.""" + if self._autocommit: + return + + if self.pgconn.transaction_status != IDLE: + return + + yield from self._exec_command(self._get_tx_start_command()) + if self._pipeline: + yield from self._pipeline._sync_gen() + + def _get_tx_start_command(self) -> bytes: + if self._begin_statement: + return self._begin_statement + + parts = [b"BEGIN"] + + if self.isolation_level is not None: + val = IsolationLevel(self.isolation_level) + parts.append(b"ISOLATION LEVEL") + parts.append(val.name.replace("_", " ").encode()) + + if self.read_only is not None: + parts.append(b"READ ONLY" if self.read_only else b"READ WRITE") + + if self.deferrable is not None: + parts.append(b"DEFERRABLE" if self.deferrable else b"NOT DEFERRABLE") + + self._begin_statement = b" ".join(parts) + return self._begin_statement + + def _commit_gen(self) -> PQGen[None]: + """Generator implementing `Connection.commit()`.""" + if self._num_transactions: + raise e.ProgrammingError( + "Explicit commit() forbidden within a Transaction " + "context. (Transaction will be automatically committed " + "on successful exit from context.)" + ) + if self._tpc: + raise e.ProgrammingError( + "commit() cannot be used during a two-phase transaction" + ) + if self.pgconn.transaction_status == IDLE: + return + + yield from self._exec_command(b"COMMIT") + + if self._pipeline: + yield from self._pipeline._sync_gen() + + def _rollback_gen(self) -> PQGen[None]: + """Generator implementing `Connection.rollback()`.""" + if self._num_transactions: + raise e.ProgrammingError( + "Explicit rollback() forbidden within a Transaction " + "context. (Either raise Rollback() or allow " + "an exception to propagate out of the context.)" + ) + if self._tpc: + raise e.ProgrammingError( + "rollback() cannot be used during a two-phase transaction" + ) + + # Get out of a "pipeline aborted" state + if self._pipeline: + yield from self._pipeline._sync_gen() + + if self.pgconn.transaction_status == IDLE: + return + + yield from self._exec_command(b"ROLLBACK") + self._prepared.clear() + for cmd in self._prepared.get_maintenance_commands(): + yield from self._exec_command(cmd) + + if self._pipeline: + yield from self._pipeline._sync_gen() + + def xid(self, format_id: int, gtrid: str, bqual: str) -> Xid: + """ + Returns a `Xid` to pass to the `!tpc_*()` methods of this connection. + + The argument types and constraints are explained in + :ref:`two-phase-commit`. + + The values passed to the method will be available on the returned + object as the members `~Xid.format_id`, `~Xid.gtrid`, `~Xid.bqual`. + """ + self._check_tpc() + return Xid.from_parts(format_id, gtrid, bqual) + + def _tpc_begin_gen(self, xid: Union[Xid, str]) -> PQGen[None]: + self._check_tpc() + + if not isinstance(xid, Xid): + xid = Xid.from_string(xid) + + if self.pgconn.transaction_status != IDLE: + raise e.ProgrammingError( + "can't start two-phase transaction: connection in status" + f" {pq.TransactionStatus(self.pgconn.transaction_status).name}" + ) + + if self._autocommit: + raise e.ProgrammingError( + "can't use two-phase transactions in autocommit mode" + ) + + self._tpc = (xid, False) + yield from self._exec_command(self._get_tx_start_command()) + + def _tpc_prepare_gen(self) -> PQGen[None]: + if not self._tpc: + raise e.ProgrammingError( + "'tpc_prepare()' must be called inside a two-phase transaction" + ) + if self._tpc[1]: + raise e.ProgrammingError( + "'tpc_prepare()' cannot be used during a prepared two-phase transaction" + ) + xid = self._tpc[0] + self._tpc = (xid, True) + yield from self._exec_command(SQL("PREPARE TRANSACTION {}").format(str(xid))) + if self._pipeline: + yield from self._pipeline._sync_gen() + + def _tpc_finish_gen( + self, action: LiteralString, xid: Union[Xid, str, None] + ) -> PQGen[None]: + fname = f"tpc_{action.lower()}()" + if xid is None: + if not self._tpc: + raise e.ProgrammingError( + f"{fname} without xid must must be" + " called inside a two-phase transaction" + ) + xid = self._tpc[0] + else: + if self._tpc: + raise e.ProgrammingError( + f"{fname} with xid must must be called" + " outside a two-phase transaction" + ) + if not isinstance(xid, Xid): + xid = Xid.from_string(xid) + + if self._tpc and not self._tpc[1]: + meth: Callable[[], PQGen[None]] + meth = getattr(self, f"_{action.lower()}_gen") + self._tpc = None + yield from meth() + else: + yield from self._exec_command( + SQL("{} PREPARED {}").format(SQL(action), str(xid)) + ) + self._tpc = None + + def _check_tpc(self) -> None: + """Raise NotSupportedError if TPC is not supported.""" + # TPC supported on every supported PostgreSQL version. + pass + + +class Connection(BaseConnection[Row]): + """ + Wrapper for a connection to the database. + """ + + __module__ = "psycopg" + + cursor_factory: Type[Cursor[Row]] + server_cursor_factory: Type[ServerCursor[Row]] + row_factory: RowFactory[Row] + _pipeline: Optional[Pipeline] + _Self = TypeVar("_Self", bound="Connection[Any]") + + def __init__( + self, + pgconn: "PGconn", + row_factory: RowFactory[Row] = cast(RowFactory[Row], tuple_row), + ): + super().__init__(pgconn) + self.row_factory = row_factory + self.lock = threading.Lock() + self.cursor_factory = Cursor + self.server_cursor_factory = ServerCursor + + @overload + @classmethod + def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + row_factory: RowFactory[Row], + prepare_threshold: Optional[int] = 5, + cursor_factory: Optional[Type[Cursor[Row]]] = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "Connection[Row]": + # TODO: returned type should be _Self. See #308. + ... + + @overload + @classmethod + def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + cursor_factory: Optional[Type[Cursor[Any]]] = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "Connection[TupleRow]": + ... + + @classmethod # type: ignore[misc] # https://github.com/python/mypy/issues/11004 + def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + row_factory: Optional[RowFactory[Row]] = None, + cursor_factory: Optional[Type[Cursor[Row]]] = None, + context: Optional[AdaptContext] = None, + **kwargs: Any, + ) -> "Connection[Any]": + """ + Connect to a database server and return a new `Connection` instance. + """ + params = cls._get_connection_params(conninfo, **kwargs) + conninfo = make_conninfo(**params) + + try: + rv = cls._wait_conn( + cls._connect_gen(conninfo, autocommit=autocommit), + timeout=params["connect_timeout"], + ) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + if row_factory: + rv.row_factory = row_factory + if cursor_factory: + rv.cursor_factory = cursor_factory + if context: + rv._adapters = AdaptersMap(context.adapters) + rv.prepare_threshold = prepare_threshold + return rv + + def __enter__(self: _Self) -> _Self: + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if self.closed: + return + + if exc_type: + # try to rollback, but if there are problems (connection in a bad + # state) just warn without clobbering the exception bubbling up. + try: + self.rollback() + except Exception as exc2: + logger.warning( + "error ignored in rollback on %s: %s", + self, + exc2, + ) + else: + self.commit() + + # Close the connection only if it doesn't belong to a pool. + if not getattr(self, "_pool", None): + self.close() + + @classmethod + def _get_connection_params(cls, conninfo: str, **kwargs: Any) -> Dict[str, Any]: + """Manipulate connection parameters before connecting. + + :param conninfo: Connection string as received by `~Connection.connect()`. + :param kwargs: Overriding connection arguments as received by `!connect()`. + :return: Connection arguments merged and eventually modified, in a + format similar to `~conninfo.conninfo_to_dict()`. + """ + params = conninfo_to_dict(conninfo, **kwargs) + + # Make sure there is an usable connect_timeout + if "connect_timeout" in params: + params["connect_timeout"] = int(params["connect_timeout"]) + else: + params["connect_timeout"] = None + + return params + + def close(self) -> None: + """Close the database connection.""" + if self.closed: + return + self._closed = True + self.pgconn.finish() + + @overload + def cursor(self, *, binary: bool = False) -> Cursor[Row]: + ... + + @overload + def cursor( + self, *, binary: bool = False, row_factory: RowFactory[CursorRow] + ) -> Cursor[CursorRow]: + ... + + @overload + def cursor( + self, + name: str, + *, + binary: bool = False, + scrollable: Optional[bool] = None, + withhold: bool = False, + ) -> ServerCursor[Row]: + ... + + @overload + def cursor( + self, + name: str, + *, + binary: bool = False, + row_factory: RowFactory[CursorRow], + scrollable: Optional[bool] = None, + withhold: bool = False, + ) -> ServerCursor[CursorRow]: + ... + + def cursor( + self, + name: str = "", + *, + binary: bool = False, + row_factory: Optional[RowFactory[Any]] = None, + scrollable: Optional[bool] = None, + withhold: bool = False, + ) -> Union[Cursor[Any], ServerCursor[Any]]: + """ + Return a new cursor to send commands and queries to the connection. + """ + self._check_connection_ok() + + if not row_factory: + row_factory = self.row_factory + + cur: Union[Cursor[Any], ServerCursor[Any]] + if name: + cur = self.server_cursor_factory( + self, + name=name, + row_factory=row_factory, + scrollable=scrollable, + withhold=withhold, + ) + else: + cur = self.cursor_factory(self, row_factory=row_factory) + + if binary: + cur.format = BINARY + + return cur + + def execute( + self, + query: Query, + params: Optional[Params] = None, + *, + prepare: Optional[bool] = None, + binary: bool = False, + ) -> Cursor[Row]: + """Execute a query and return a cursor to read its results.""" + try: + cur = self.cursor() + if binary: + cur.format = BINARY + + return cur.execute(query, params, prepare=prepare) + + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + def commit(self) -> None: + """Commit any pending transaction to the database.""" + with self.lock: + self.wait(self._commit_gen()) + + def rollback(self) -> None: + """Roll back to the start of any pending transaction.""" + with self.lock: + self.wait(self._rollback_gen()) + + @contextmanager + def transaction( + self, + savepoint_name: Optional[str] = None, + force_rollback: bool = False, + ) -> Iterator[Transaction]: + """ + Start a context block with a new transaction or nested transaction. + + :param savepoint_name: Name of the savepoint used to manage a nested + transaction. If `!None`, one will be chosen automatically. + :param force_rollback: Roll back the transaction at the end of the + block even if there were no error (e.g. to try a no-op process). + :rtype: Transaction + """ + tx = Transaction(self, savepoint_name, force_rollback) + if self._pipeline: + with self.pipeline(), tx, self.pipeline(): + yield tx + else: + with tx: + yield tx + + def notifies(self) -> Generator[Notify, None, None]: + """ + Yield `Notify` objects as soon as they are received from the database. + """ + while True: + with self.lock: + try: + ns = self.wait(notifies(self.pgconn)) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + enc = pgconn_encoding(self.pgconn) + for pgn in ns: + n = Notify(pgn.relname.decode(enc), pgn.extra.decode(enc), pgn.be_pid) + yield n + + @contextmanager + def pipeline(self) -> Iterator[Pipeline]: + """Switch the connection into pipeline mode.""" + with self.lock: + self._check_connection_ok() + + pipeline = self._pipeline + if pipeline is None: + # WARNING: reference loop, broken ahead. + pipeline = self._pipeline = Pipeline(self) + + try: + with pipeline: + yield pipeline + finally: + if pipeline.level == 0: + with self.lock: + assert pipeline is self._pipeline + self._pipeline = None + + def wait(self, gen: PQGen[RV], timeout: Optional[float] = 0.1) -> RV: + """ + Consume a generator operating on the connection. + + The function must be used on generators that don't change connection + fd (i.e. not on connect and reset). + """ + try: + return waiting.wait(gen, self.pgconn.socket, timeout=timeout) + except KeyboardInterrupt: + # On Ctrl-C, try to cancel the query in the server, otherwise + # the connection will remain stuck in ACTIVE state. + c = self.pgconn.get_cancel() + c.cancel() + try: + waiting.wait(gen, self.pgconn.socket, timeout=timeout) + except e.QueryCanceled: + pass # as expected + raise + + @classmethod + def _wait_conn(cls, gen: PQGenConn[RV], timeout: Optional[int]) -> RV: + """Consume a connection generator.""" + return waiting.wait_conn(gen, timeout=timeout) + + def _set_autocommit(self, value: bool) -> None: + with self.lock: + self.wait(self._set_autocommit_gen(value)) + + def _set_isolation_level(self, value: Optional[IsolationLevel]) -> None: + with self.lock: + self.wait(self._set_isolation_level_gen(value)) + + def _set_read_only(self, value: Optional[bool]) -> None: + with self.lock: + self.wait(self._set_read_only_gen(value)) + + def _set_deferrable(self, value: Optional[bool]) -> None: + with self.lock: + self.wait(self._set_deferrable_gen(value)) + + def tpc_begin(self, xid: Union[Xid, str]) -> None: + """ + Begin a TPC transaction with the given transaction ID `!xid`. + """ + with self.lock: + self.wait(self._tpc_begin_gen(xid)) + + def tpc_prepare(self) -> None: + """ + Perform the first phase of a transaction started with `tpc_begin()`. + """ + try: + with self.lock: + self.wait(self._tpc_prepare_gen()) + except e.ObjectNotInPrerequisiteState as ex: + raise e.NotSupportedError(str(ex)) from None + + def tpc_commit(self, xid: Union[Xid, str, None] = None) -> None: + """ + Commit a prepared two-phase transaction. + """ + with self.lock: + self.wait(self._tpc_finish_gen("COMMIT", xid)) + + def tpc_rollback(self, xid: Union[Xid, str, None] = None) -> None: + """ + Roll back a prepared two-phase transaction. + """ + with self.lock: + self.wait(self._tpc_finish_gen("ROLLBACK", xid)) + + def tpc_recover(self) -> List[Xid]: + self._check_tpc() + status = self.info.transaction_status + with self.cursor(row_factory=args_row(Xid._from_record)) as cur: + cur.execute(Xid._get_recover_query()) + res = cur.fetchall() + + if status == IDLE and self.info.transaction_status == INTRANS: + self.rollback() + + return res diff --git a/lib/python3.11/site-packages/psycopg/connection_async.py b/lib/python3.11/site-packages/psycopg/connection_async.py new file mode 100644 index 0000000..2490480 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/connection_async.py @@ -0,0 +1,431 @@ +""" +psycopg async connection objects +""" + +# Copyright (C) 2020 The Psycopg Team + +import sys +import asyncio +import logging +from types import TracebackType +from typing import Any, AsyncGenerator, AsyncIterator, Dict, List, Optional +from typing import Type, TypeVar, Union, cast, overload, TYPE_CHECKING +from contextlib import asynccontextmanager + +from . import pq +from . import errors as e +from . import waiting +from .abc import AdaptContext, Params, PQGen, PQGenConn, Query, RV +from ._tpc import Xid +from .rows import Row, AsyncRowFactory, tuple_row, TupleRow, args_row +from .adapt import AdaptersMap +from ._enums import IsolationLevel +from .conninfo import make_conninfo, conninfo_to_dict, resolve_hostaddr_async +from ._pipeline import AsyncPipeline +from ._encodings import pgconn_encoding +from .connection import BaseConnection, CursorRow, Notify +from .generators import notifies +from .transaction import AsyncTransaction +from .cursor_async import AsyncCursor +from .server_cursor import AsyncServerCursor + +if TYPE_CHECKING: + from .pq.abc import PGconn + +TEXT = pq.Format.TEXT +BINARY = pq.Format.BINARY + +IDLE = pq.TransactionStatus.IDLE +INTRANS = pq.TransactionStatus.INTRANS + +logger = logging.getLogger("psycopg") + + +class AsyncConnection(BaseConnection[Row]): + """ + Asynchronous wrapper for a connection to the database. + """ + + __module__ = "psycopg" + + cursor_factory: Type[AsyncCursor[Row]] + server_cursor_factory: Type[AsyncServerCursor[Row]] + row_factory: AsyncRowFactory[Row] + _pipeline: Optional[AsyncPipeline] + _Self = TypeVar("_Self", bound="AsyncConnection[Any]") + + def __init__( + self, + pgconn: "PGconn", + row_factory: AsyncRowFactory[Row] = cast(AsyncRowFactory[Row], tuple_row), + ): + super().__init__(pgconn) + self.row_factory = row_factory + self.lock = asyncio.Lock() + self.cursor_factory = AsyncCursor + self.server_cursor_factory = AsyncServerCursor + + @overload + @classmethod + async def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + row_factory: AsyncRowFactory[Row], + cursor_factory: Optional[Type[AsyncCursor[Row]]] = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "AsyncConnection[Row]": + # TODO: returned type should be _Self. See #308. + ... + + @overload + @classmethod + async def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + cursor_factory: Optional[Type[AsyncCursor[Any]]] = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "AsyncConnection[TupleRow]": + ... + + @classmethod # type: ignore[misc] # https://github.com/python/mypy/issues/11004 + async def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + context: Optional[AdaptContext] = None, + row_factory: Optional[AsyncRowFactory[Row]] = None, + cursor_factory: Optional[Type[AsyncCursor[Row]]] = None, + **kwargs: Any, + ) -> "AsyncConnection[Any]": + if sys.platform == "win32": + loop = asyncio.get_running_loop() + if isinstance(loop, asyncio.ProactorEventLoop): + raise e.InterfaceError( + "Psycopg cannot use the 'ProactorEventLoop' to run in async" + " mode. Please use a compatible event loop, for instance by" + " setting 'asyncio.set_event_loop_policy" + "(WindowsSelectorEventLoopPolicy())'" + ) + + params = await cls._get_connection_params(conninfo, **kwargs) + conninfo = make_conninfo(**params) + + try: + rv = await cls._wait_conn( + cls._connect_gen(conninfo, autocommit=autocommit), + timeout=params["connect_timeout"], + ) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + if row_factory: + rv.row_factory = row_factory + if cursor_factory: + rv.cursor_factory = cursor_factory + if context: + rv._adapters = AdaptersMap(context.adapters) + rv.prepare_threshold = prepare_threshold + return rv + + async def __aenter__(self: _Self) -> _Self: + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if self.closed: + return + + if exc_type: + # try to rollback, but if there are problems (connection in a bad + # state) just warn without clobbering the exception bubbling up. + try: + await self.rollback() + except Exception as exc2: + logger.warning( + "error ignored in rollback on %s: %s", + self, + exc2, + ) + else: + await self.commit() + + # Close the connection only if it doesn't belong to a pool. + if not getattr(self, "_pool", None): + await self.close() + + @classmethod + async def _get_connection_params( + cls, conninfo: str, **kwargs: Any + ) -> Dict[str, Any]: + """Manipulate connection parameters before connecting. + + .. versionchanged:: 3.1 + Unlike the sync counterpart, perform non-blocking address + resolution and populate the ``hostaddr`` connection parameter, + unless the user has provided one themselves. See + `~psycopg._dns.resolve_hostaddr_async()` for details. + + """ + params = conninfo_to_dict(conninfo, **kwargs) + + # Make sure there is an usable connect_timeout + if "connect_timeout" in params: + params["connect_timeout"] = int(params["connect_timeout"]) + else: + params["connect_timeout"] = None + + # Resolve host addresses in non-blocking way + params = await resolve_hostaddr_async(params) + + return params + + async def close(self) -> None: + if self.closed: + return + self._closed = True + self.pgconn.finish() + + @overload + def cursor(self, *, binary: bool = False) -> AsyncCursor[Row]: + ... + + @overload + def cursor( + self, *, binary: bool = False, row_factory: AsyncRowFactory[CursorRow] + ) -> AsyncCursor[CursorRow]: + ... + + @overload + def cursor( + self, + name: str, + *, + binary: bool = False, + scrollable: Optional[bool] = None, + withhold: bool = False, + ) -> AsyncServerCursor[Row]: + ... + + @overload + def cursor( + self, + name: str, + *, + binary: bool = False, + row_factory: AsyncRowFactory[CursorRow], + scrollable: Optional[bool] = None, + withhold: bool = False, + ) -> AsyncServerCursor[CursorRow]: + ... + + def cursor( + self, + name: str = "", + *, + binary: bool = False, + row_factory: Optional[AsyncRowFactory[Any]] = None, + scrollable: Optional[bool] = None, + withhold: bool = False, + ) -> Union[AsyncCursor[Any], AsyncServerCursor[Any]]: + """ + Return a new `AsyncCursor` to send commands and queries to the connection. + """ + self._check_connection_ok() + + if not row_factory: + row_factory = self.row_factory + + cur: Union[AsyncCursor[Any], AsyncServerCursor[Any]] + if name: + cur = self.server_cursor_factory( + self, + name=name, + row_factory=row_factory, + scrollable=scrollable, + withhold=withhold, + ) + else: + cur = self.cursor_factory(self, row_factory=row_factory) + + if binary: + cur.format = BINARY + + return cur + + async def execute( + self, + query: Query, + params: Optional[Params] = None, + *, + prepare: Optional[bool] = None, + binary: bool = False, + ) -> AsyncCursor[Row]: + try: + cur = self.cursor() + if binary: + cur.format = BINARY + + return await cur.execute(query, params, prepare=prepare) + + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + async def commit(self) -> None: + async with self.lock: + await self.wait(self._commit_gen()) + + async def rollback(self) -> None: + async with self.lock: + await self.wait(self._rollback_gen()) + + @asynccontextmanager + async def transaction( + self, + savepoint_name: Optional[str] = None, + force_rollback: bool = False, + ) -> AsyncIterator[AsyncTransaction]: + """ + Start a context block with a new transaction or nested transaction. + + :rtype: AsyncTransaction + """ + tx = AsyncTransaction(self, savepoint_name, force_rollback) + if self._pipeline: + async with self.pipeline(), tx, self.pipeline(): + yield tx + else: + async with tx: + yield tx + + async def notifies(self) -> AsyncGenerator[Notify, None]: + while True: + async with self.lock: + try: + ns = await self.wait(notifies(self.pgconn)) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + enc = pgconn_encoding(self.pgconn) + for pgn in ns: + n = Notify(pgn.relname.decode(enc), pgn.extra.decode(enc), pgn.be_pid) + yield n + + @asynccontextmanager + async def pipeline(self) -> AsyncIterator[AsyncPipeline]: + """Context manager to switch the connection into pipeline mode.""" + async with self.lock: + self._check_connection_ok() + + pipeline = self._pipeline + if pipeline is None: + # WARNING: reference loop, broken ahead. + pipeline = self._pipeline = AsyncPipeline(self) + + try: + async with pipeline: + yield pipeline + finally: + if pipeline.level == 0: + async with self.lock: + assert pipeline is self._pipeline + self._pipeline = None + + async def wait(self, gen: PQGen[RV]) -> RV: + try: + return await waiting.wait_async(gen, self.pgconn.socket) + except (asyncio.CancelledError, KeyboardInterrupt): + # On Ctrl-C, try to cancel the query in the server, otherwise + # the connection will remain stuck in ACTIVE state. + c = self.pgconn.get_cancel() + c.cancel() + try: + await waiting.wait_async(gen, self.pgconn.socket) + except e.QueryCanceled: + pass # as expected + raise + + @classmethod + async def _wait_conn(cls, gen: PQGenConn[RV], timeout: Optional[int]) -> RV: + return await waiting.wait_conn_async(gen, timeout) + + def _set_autocommit(self, value: bool) -> None: + self._no_set_async("autocommit") + + async def set_autocommit(self, value: bool) -> None: + """Async version of the `~Connection.autocommit` setter.""" + async with self.lock: + await self.wait(self._set_autocommit_gen(value)) + + def _set_isolation_level(self, value: Optional[IsolationLevel]) -> None: + self._no_set_async("isolation_level") + + async def set_isolation_level(self, value: Optional[IsolationLevel]) -> None: + """Async version of the `~Connection.isolation_level` setter.""" + async with self.lock: + await self.wait(self._set_isolation_level_gen(value)) + + def _set_read_only(self, value: Optional[bool]) -> None: + self._no_set_async("read_only") + + async def set_read_only(self, value: Optional[bool]) -> None: + """Async version of the `~Connection.read_only` setter.""" + async with self.lock: + await self.wait(self._set_read_only_gen(value)) + + def _set_deferrable(self, value: Optional[bool]) -> None: + self._no_set_async("deferrable") + + async def set_deferrable(self, value: Optional[bool]) -> None: + """Async version of the `~Connection.deferrable` setter.""" + async with self.lock: + await self.wait(self._set_deferrable_gen(value)) + + def _no_set_async(self, attribute: str) -> None: + raise AttributeError( + f"'the {attribute!r} property is read-only on async connections:" + f" please use 'await .set_{attribute}()' instead." + ) + + async def tpc_begin(self, xid: Union[Xid, str]) -> None: + async with self.lock: + await self.wait(self._tpc_begin_gen(xid)) + + async def tpc_prepare(self) -> None: + try: + async with self.lock: + await self.wait(self._tpc_prepare_gen()) + except e.ObjectNotInPrerequisiteState as ex: + raise e.NotSupportedError(str(ex)) from None + + async def tpc_commit(self, xid: Union[Xid, str, None] = None) -> None: + async with self.lock: + await self.wait(self._tpc_finish_gen("commit", xid)) + + async def tpc_rollback(self, xid: Union[Xid, str, None] = None) -> None: + async with self.lock: + await self.wait(self._tpc_finish_gen("rollback", xid)) + + async def tpc_recover(self) -> List[Xid]: + self._check_tpc() + status = self.info.transaction_status + async with self.cursor(row_factory=args_row(Xid._from_record)) as cur: + await cur.execute(Xid._get_recover_query()) + res = await cur.fetchall() + + if status == IDLE and self.info.transaction_status == INTRANS: + await self.rollback() + + return res diff --git a/lib/python3.11/site-packages/psycopg/conninfo.py b/lib/python3.11/site-packages/psycopg/conninfo.py new file mode 100644 index 0000000..3b21f83 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/conninfo.py @@ -0,0 +1,378 @@ +""" +Functions to manipulate conninfo strings +""" + +# Copyright (C) 2020 The Psycopg Team + +import os +import re +import socket +import asyncio +from typing import Any, Dict, List, Optional +from pathlib import Path +from datetime import tzinfo +from functools import lru_cache +from ipaddress import ip_address + +from . import pq +from . import errors as e +from ._tz import get_tzinfo +from ._encodings import pgconn_encoding + + +def make_conninfo(conninfo: str = "", **kwargs: Any) -> str: + """ + Merge a string and keyword params into a single conninfo string. + + :param conninfo: A `connection string`__ as accepted by PostgreSQL. + :param kwargs: Parameters overriding the ones specified in `!conninfo`. + :return: A connection string valid for PostgreSQL, with the `!kwargs` + parameters merged. + + Raise `~psycopg.ProgrammingError` if the input doesn't make a valid + conninfo string. + + .. __: https://www.postgresql.org/docs/current/libpq-connect.html + #LIBPQ-CONNSTRING + """ + if not conninfo and not kwargs: + return "" + + # If no kwarg specified don't mung the conninfo but check if it's correct. + # Make sure to return a string, not a subtype, to avoid making Liskov sad. + if not kwargs: + _parse_conninfo(conninfo) + return str(conninfo) + + # Override the conninfo with the parameters + # Drop the None arguments + kwargs = {k: v for (k, v) in kwargs.items() if v is not None} + + if conninfo: + tmp = conninfo_to_dict(conninfo) + tmp.update(kwargs) + kwargs = tmp + + conninfo = " ".join(f"{k}={_param_escape(str(v))}" for (k, v) in kwargs.items()) + + # Verify the result is valid + _parse_conninfo(conninfo) + + return conninfo + + +def conninfo_to_dict(conninfo: str = "", **kwargs: Any) -> Dict[str, Any]: + """ + Convert the `!conninfo` string into a dictionary of parameters. + + :param conninfo: A `connection string`__ as accepted by PostgreSQL. + :param kwargs: Parameters overriding the ones specified in `!conninfo`. + :return: Dictionary with the parameters parsed from `!conninfo` and + `!kwargs`. + + Raise `~psycopg.ProgrammingError` if `!conninfo` is not a a valid connection + string. + + .. __: https://www.postgresql.org/docs/current/libpq-connect.html + #LIBPQ-CONNSTRING + """ + opts = _parse_conninfo(conninfo) + rv = {opt.keyword.decode(): opt.val.decode() for opt in opts if opt.val is not None} + for k, v in kwargs.items(): + if v is not None: + rv[k] = v + return rv + + +def _parse_conninfo(conninfo: str) -> List[pq.ConninfoOption]: + """ + Verify that `!conninfo` is a valid connection string. + + Raise ProgrammingError if the string is not valid. + + Return the result of pq.Conninfo.parse() on success. + """ + try: + return pq.Conninfo.parse(conninfo.encode()) + except e.OperationalError as ex: + raise e.ProgrammingError(str(ex)) + + +re_escape = re.compile(r"([\\'])") +re_space = re.compile(r"\s") + + +def _param_escape(s: str) -> str: + """ + Apply the escaping rule required by PQconnectdb + """ + if not s: + return "''" + + s = re_escape.sub(r"\\\1", s) + if re_space.search(s): + s = "'" + s + "'" + + return s + + +class ConnectionInfo: + """Allow access to information about the connection.""" + + __module__ = "psycopg" + + def __init__(self, pgconn: pq.abc.PGconn): + self.pgconn = pgconn + + @property + def vendor(self) -> str: + """A string representing the database vendor connected to.""" + return "PostgreSQL" + + @property + def host(self) -> str: + """The server host name of the active connection. See :pq:`PQhost()`.""" + return self._get_pgconn_attr("host") + + @property + def hostaddr(self) -> str: + """The server IP address of the connection. See :pq:`PQhostaddr()`.""" + return self._get_pgconn_attr("hostaddr") + + @property + def port(self) -> int: + """The port of the active connection. See :pq:`PQport()`.""" + return int(self._get_pgconn_attr("port")) + + @property + def dbname(self) -> str: + """The database name of the connection. See :pq:`PQdb()`.""" + return self._get_pgconn_attr("db") + + @property + def user(self) -> str: + """The user name of the connection. See :pq:`PQuser()`.""" + return self._get_pgconn_attr("user") + + @property + def password(self) -> str: + """The password of the connection. See :pq:`PQpass()`.""" + return self._get_pgconn_attr("password") + + @property + def options(self) -> str: + """ + The command-line options passed in the connection request. + See :pq:`PQoptions`. + """ + return self._get_pgconn_attr("options") + + def get_parameters(self) -> Dict[str, str]: + """Return the connection parameters values. + + Return all the parameters set to a non-default value, which might come + either from the connection string and parameters passed to + `~Connection.connect()` or from environment variables. The password + is never returned (you can read it using the `password` attribute). + """ + pyenc = self.encoding + + # Get the known defaults to avoid reporting them + defaults = { + i.keyword: i.compiled + for i in pq.Conninfo.get_defaults() + if i.compiled is not None + } + # Not returned by the libq. Bug? Bet we're using SSH. + defaults.setdefault(b"channel_binding", b"prefer") + defaults[b"passfile"] = str(Path.home() / ".pgpass").encode() + + return { + i.keyword.decode(pyenc): i.val.decode(pyenc) + for i in self.pgconn.info + if i.val is not None + and i.keyword != b"password" + and i.val != defaults.get(i.keyword) + } + + @property + def dsn(self) -> str: + """Return the connection string to connect to the database. + + The string contains all the parameters set to a non-default value, + which might come either from the connection string and parameters + passed to `~Connection.connect()` or from environment variables. The + password is never returned (you can read it using the `password` + attribute). + """ + return make_conninfo(**self.get_parameters()) + + @property + def status(self) -> pq.ConnStatus: + """The status of the connection. See :pq:`PQstatus()`.""" + return pq.ConnStatus(self.pgconn.status) + + @property + def transaction_status(self) -> pq.TransactionStatus: + """ + The current in-transaction status of the session. + See :pq:`PQtransactionStatus()`. + """ + return pq.TransactionStatus(self.pgconn.transaction_status) + + @property + def pipeline_status(self) -> pq.PipelineStatus: + """ + The current pipeline status of the client. + See :pq:`PQpipelineStatus()`. + """ + return pq.PipelineStatus(self.pgconn.pipeline_status) + + def parameter_status(self, param_name: str) -> Optional[str]: + """ + Return a parameter setting of the connection. + + Return `None` is the parameter is unknown. + """ + res = self.pgconn.parameter_status(param_name.encode(self.encoding)) + return res.decode(self.encoding) if res is not None else None + + @property + def server_version(self) -> int: + """ + An integer representing the server version. See :pq:`PQserverVersion()`. + """ + return self.pgconn.server_version + + @property + def backend_pid(self) -> int: + """ + The process ID (PID) of the backend process handling this connection. + See :pq:`PQbackendPID()`. + """ + return self.pgconn.backend_pid + + @property + def error_message(self) -> str: + """ + The error message most recently generated by an operation on the connection. + See :pq:`PQerrorMessage()`. + """ + return self._get_pgconn_attr("error_message") + + @property + def timezone(self) -> tzinfo: + """The Python timezone info of the connection's timezone.""" + return get_tzinfo(self.pgconn) + + @property + def encoding(self) -> str: + """The Python codec name of the connection's client encoding.""" + return pgconn_encoding(self.pgconn) + + def _get_pgconn_attr(self, name: str) -> str: + value: bytes = getattr(self.pgconn, name) + return value.decode(self.encoding) + + +async def resolve_hostaddr_async(params: Dict[str, Any]) -> Dict[str, Any]: + """ + Perform async DNS lookup of the hosts and return a new params dict. + + :param params: The input parameters, for instance as returned by + `~psycopg.conninfo.conninfo_to_dict()`. + + If a ``host`` param is present but not ``hostname``, resolve the host + addresses dynamically. + + The function may change the input ``host``, ``hostname``, ``port`` to allow + connecting without further DNS lookups, eventually removing hosts that are + not resolved, keeping the lists of hosts and ports consistent. + + Raise `~psycopg.OperationalError` if connection is not possible (e.g. no + host resolve, inconsistent lists length). + """ + hostaddr_arg = params.get("hostaddr", os.environ.get("PGHOSTADDR", "")) + if hostaddr_arg: + # Already resolved + return params + + host_arg: str = params.get("host", os.environ.get("PGHOST", "")) + if not host_arg: + # Nothing to resolve + return params + + hosts_in = host_arg.split(",") + port_arg: str = str(params.get("port", os.environ.get("PGPORT", ""))) + ports_in = port_arg.split(",") if port_arg else [] + default_port = "5432" + + if len(ports_in) == 1: + # If only one port is specified, the libpq will apply it to all + # the hosts, so don't mangle it. + default_port = ports_in.pop() + + elif len(ports_in) > 1: + if len(ports_in) != len(hosts_in): + # ProgrammingError would have been more appropriate, but this is + # what the raise if the libpq fails connect in the same case. + raise e.OperationalError( + f"cannot match {len(hosts_in)} hosts with {len(ports_in)} port numbers" + ) + ports_out = [] + + hosts_out = [] + hostaddr_out = [] + loop = asyncio.get_running_loop() + for i, host in enumerate(hosts_in): + if not host or host.startswith("/") or host[1:2] == ":": + # Local path + hosts_out.append(host) + hostaddr_out.append("") + if ports_in: + ports_out.append(ports_in[i]) + continue + + # If the host is already an ip address don't try to resolve it + if is_ip_address(host): + hosts_out.append(host) + hostaddr_out.append(host) + if ports_in: + ports_out.append(ports_in[i]) + continue + + try: + port = ports_in[i] if ports_in else default_port + ans = await loop.getaddrinfo( + host, port, proto=socket.IPPROTO_TCP, type=socket.SOCK_STREAM + ) + except OSError as ex: + last_exc = ex + else: + for item in ans: + hosts_out.append(host) + hostaddr_out.append(item[4][0]) + if ports_in: + ports_out.append(ports_in[i]) + + # Throw an exception if no host could be resolved + if not hosts_out: + raise e.OperationalError(str(last_exc)) + + out = params.copy() + out["host"] = ",".join(hosts_out) + out["hostaddr"] = ",".join(hostaddr_out) + if ports_in: + out["port"] = ",".join(ports_out) + + return out + + +@lru_cache() +def is_ip_address(s: str) -> bool: + """Return True if the string represent a valid ip address.""" + try: + ip_address(s) + except ValueError: + return False + return True diff --git a/lib/python3.11/site-packages/psycopg/copy.py b/lib/python3.11/site-packages/psycopg/copy.py new file mode 100644 index 0000000..26a2d9e --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/copy.py @@ -0,0 +1,902 @@ +""" +psycopg copy support +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +import queue +import struct +import asyncio +import threading +from abc import ABC, abstractmethod +from types import TracebackType +from typing import Any, AsyncIterator, Dict, Generic, Iterator, List, Match, IO +from typing import Optional, Sequence, Tuple, Type, TypeVar, Union, TYPE_CHECKING + +from . import pq +from . import adapt +from . import errors as e +from .abc import Buffer, ConnectionType, PQGen, Transformer +from ._compat import create_task +from ._cmodule import _psycopg +from ._encodings import pgconn_encoding +from .generators import copy_from, copy_to, copy_end + +if TYPE_CHECKING: + from .cursor import BaseCursor, Cursor + from .cursor_async import AsyncCursor + from .connection import Connection # noqa: F401 + from .connection_async import AsyncConnection # noqa: F401 + +PY_TEXT = adapt.PyFormat.TEXT +PY_BINARY = adapt.PyFormat.BINARY + +TEXT = pq.Format.TEXT +BINARY = pq.Format.BINARY + +COPY_IN = pq.ExecStatus.COPY_IN +COPY_OUT = pq.ExecStatus.COPY_OUT + +ACTIVE = pq.TransactionStatus.ACTIVE + +# Size of data to accumulate before sending it down the network. We fill a +# buffer this size field by field, and when it passes the threshold size +# we ship it, so it may end up being bigger than this. +BUFFER_SIZE = 32 * 1024 + +# Maximum data size we want to queue to send to the libpq copy. Sending a +# buffer too big to be handled can cause an infinite loop in the libpq +# (#255) so we want to split it in more digestable chunks. +MAX_BUFFER_SIZE = 4 * BUFFER_SIZE +# Note: making this buffer too large, e.g. +# MAX_BUFFER_SIZE = 1024 * 1024 +# makes operations *way* slower! Probably triggering some quadraticity +# in the libpq memory management and data sending. + +# Max size of the write queue of buffers. More than that copy will block +# Each buffer should be around BUFFER_SIZE size. +QUEUE_SIZE = 1024 + + +class BaseCopy(Generic[ConnectionType]): + """ + Base implementation for the copy user interface. + + Two subclasses expose real methods with the sync/async differences. + + The difference between the text and binary format is managed by two + different `Formatter` subclasses. + + Writing (the I/O part) is implemented in the subclasses by a `Writer` or + `AsyncWriter` instance. Normally writing implies sending copy data to a + database, but a different writer might be chosen, e.g. to stream data into + a file for later use. + """ + + _Self = TypeVar("_Self", bound="BaseCopy[Any]") + + formatter: "Formatter" + + def __init__( + self, + cursor: "BaseCursor[ConnectionType, Any]", + *, + binary: Optional[bool] = None, + ): + self.cursor = cursor + self.connection = cursor.connection + self._pgconn = self.connection.pgconn + + result = cursor.pgresult + if result: + self._direction = result.status + if self._direction != COPY_IN and self._direction != COPY_OUT: + raise e.ProgrammingError( + "the cursor should have performed a COPY operation;" + f" its status is {pq.ExecStatus(self._direction).name} instead" + ) + else: + self._direction = COPY_IN + + if binary is None: + binary = bool(result and result.binary_tuples) + + tx: Transformer = getattr(cursor, "_tx", None) or adapt.Transformer(cursor) + if binary: + self.formatter = BinaryFormatter(tx) + else: + self.formatter = TextFormatter(tx, encoding=pgconn_encoding(self._pgconn)) + + self._finished = False + + def __repr__(self) -> str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + info = pq.misc.connection_summary(self._pgconn) + return f"<{cls} {info} at 0x{id(self):x}>" + + def _enter(self) -> None: + if self._finished: + raise TypeError("copy blocks can be used only once") + + def set_types(self, types: Sequence[Union[int, str]]) -> None: + """ + Set the types expected in a COPY operation. + + The types must be specified as a sequence of oid or PostgreSQL type + names (e.g. ``int4``, ``timestamptz[]``). + + This operation overcomes the lack of metadata returned by PostgreSQL + when a COPY operation begins: + + - On :sql:`COPY TO`, `!set_types()` allows to specify what types the + operation returns. If `!set_types()` is not used, the data will be + returned as unparsed strings or bytes instead of Python objects. + + - On :sql:`COPY FROM`, `!set_types()` allows to choose what type the + database expects. This is especially useful in binary copy, because + PostgreSQL will apply no cast rule. + + """ + registry = self.cursor.adapters.types + oids = [t if isinstance(t, int) else registry.get_oid(t) for t in types] + + if self._direction == COPY_IN: + self.formatter.transformer.set_dumper_types(oids, self.formatter.format) + else: + self.formatter.transformer.set_loader_types(oids, self.formatter.format) + + # High level copy protocol generators (state change of the Copy object) + + def _read_gen(self) -> PQGen[Buffer]: + if self._finished: + return memoryview(b"") + + res = yield from copy_from(self._pgconn) + if isinstance(res, memoryview): + return res + + # res is the final PGresult + self._finished = True + + # This result is a COMMAND_OK which has info about the number of rows + # returned, but not about the columns, which is instead an information + # that was received on the COPY_OUT result at the beginning of COPY. + # So, don't replace the results in the cursor, just update the rowcount. + nrows = res.command_tuples + self.cursor._rowcount = nrows if nrows is not None else -1 + return memoryview(b"") + + def _read_row_gen(self) -> PQGen[Optional[Tuple[Any, ...]]]: + data = yield from self._read_gen() + if not data: + return None + + row = self.formatter.parse_row(data) + if row is None: + # Get the final result to finish the copy operation + yield from self._read_gen() + self._finished = True + return None + + return row + + def _end_copy_out_gen(self, exc: Optional[BaseException]) -> PQGen[None]: + if not exc: + return + + if self._pgconn.transaction_status != ACTIVE: + # The server has already finished to send copy data. The connection + # is already in a good state. + return + + # Throw a cancel to the server, then consume the rest of the copy data + # (which might or might not have been already transferred entirely to + # the client, so we won't necessary see the exception associated with + # canceling). + self.connection.cancel() + try: + while (yield from self._read_gen()): + pass + except e.QueryCanceled: + pass + + +class Copy(BaseCopy["Connection[Any]"]): + """Manage a :sql:`COPY` operation. + + :param cursor: the cursor where the operation is performed. + :param binary: if `!True`, write binary format. + :param writer: the object to write to destination. If not specified, write + to the `!cursor` connection. + + Choosing `!binary` is not necessary if the cursor has executed a + :sql:`COPY` operation, because the operation result describes the format + too. The parameter is useful when a `!Copy` object is created manually and + no operation is performed on the cursor, such as when using ``writer=``\\ + `~psycopg.copy.FileWriter`. + + """ + + __module__ = "psycopg" + + writer: "Writer" + + def __init__( + self, + cursor: "Cursor[Any]", + *, + binary: Optional[bool] = None, + writer: Optional["Writer"] = None, + ): + super().__init__(cursor, binary=binary) + if not writer: + writer = LibpqWriter(cursor) + + self.writer = writer + self._write = writer.write + + def __enter__(self: BaseCopy._Self) -> BaseCopy._Self: + self._enter() + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.finish(exc_val) + + # End user sync interface + + def __iter__(self) -> Iterator[Buffer]: + """Implement block-by-block iteration on :sql:`COPY TO`.""" + while True: + data = self.read() + if not data: + break + yield data + + def read(self) -> Buffer: + """ + Read an unparsed row after a :sql:`COPY TO` operation. + + Return an empty string when the data is finished. + """ + return self.connection.wait(self._read_gen()) + + def rows(self) -> Iterator[Tuple[Any, ...]]: + """ + Iterate on the result of a :sql:`COPY TO` operation record by record. + + Note that the records returned will be tuples of unparsed strings or + bytes, unless data types are specified using `set_types()`. + """ + while True: + record = self.read_row() + if record is None: + break + yield record + + def read_row(self) -> Optional[Tuple[Any, ...]]: + """ + Read a parsed row of data from a table after a :sql:`COPY TO` operation. + + Return `!None` when the data is finished. + + Note that the records returned will be tuples of unparsed strings or + bytes, unless data types are specified using `set_types()`. + """ + return self.connection.wait(self._read_row_gen()) + + def write(self, buffer: Union[Buffer, str]) -> None: + """ + Write a block of data to a table after a :sql:`COPY FROM` operation. + + If the :sql:`COPY` is in binary format `!buffer` must be `!bytes`. In + text mode it can be either `!bytes` or `!str`. + """ + data = self.formatter.write(buffer) + if data: + self._write(data) + + def write_row(self, row: Sequence[Any]) -> None: + """Write a record to a table after a :sql:`COPY FROM` operation.""" + data = self.formatter.write_row(row) + if data: + self._write(data) + + def finish(self, exc: Optional[BaseException]) -> None: + """Terminate the copy operation and free the resources allocated. + + You shouldn't need to call this function yourself: it is usually called + by exit. It is available if, despite what is documented, you end up + using the `Copy` object outside a block. + """ + if self._direction == COPY_IN: + data = self.formatter.end() + if data: + self._write(data) + self.writer.finish(exc) + self._finished = True + else: + self.connection.wait(self._end_copy_out_gen(exc)) + + +class Writer(ABC): + """ + A class to write copy data somewhere. + """ + + @abstractmethod + def write(self, data: Buffer) -> None: + """ + Write some data to destination. + """ + ... + + def finish(self, exc: Optional[BaseException] = None) -> None: + """ + Called when write operations are finished. + + If operations finished with an error, it will be passed to ``exc``. + """ + pass + + +class LibpqWriter(Writer): + """ + A `Writer` to write copy data to a Postgres database. + """ + + def __init__(self, cursor: "Cursor[Any]"): + self.cursor = cursor + self.connection = cursor.connection + self._pgconn = self.connection.pgconn + + def write(self, data: Buffer) -> None: + if len(data) <= MAX_BUFFER_SIZE: + # Most used path: we don't need to split the buffer in smaller + # bits, so don't make a copy. + self.connection.wait(copy_to(self._pgconn, data)) + else: + # Copy a buffer too large in chunks to avoid causing a memory + # error in the libpq, which may cause an infinite loop (#255). + for i in range(0, len(data), MAX_BUFFER_SIZE): + self.connection.wait( + copy_to(self._pgconn, data[i : i + MAX_BUFFER_SIZE]) + ) + + def finish(self, exc: Optional[BaseException] = None) -> None: + bmsg: Optional[bytes] + if exc: + msg = f"error from Python: {type(exc).__qualname__} - {exc}" + bmsg = msg.encode(pgconn_encoding(self._pgconn), "replace") + else: + bmsg = None + + res = self.connection.wait(copy_end(self._pgconn, bmsg)) + self.cursor._results = [res] + + +class QueuedLibpqDriver(LibpqWriter): + """ + A writer using a buffer to queue data to write to a Postgres database. + + `write()` returns immediately, so that the main thread can be CPU-bound + formatting messages, while a worker thread can be IO-bound waiting to write + on the connection. + """ + + def __init__(self, cursor: "Cursor[Any]"): + super().__init__(cursor) + + self._queue: queue.Queue[Buffer] = queue.Queue(maxsize=QUEUE_SIZE) + self._worker: Optional[threading.Thread] = None + self._worker_error: Optional[BaseException] = None + + def worker(self) -> None: + """Push data to the server when available from the copy queue. + + Terminate reading when the queue receives a false-y value, or in case + of error. + + The function is designed to be run in a separate thread. + """ + try: + while True: + data = self._queue.get(block=True, timeout=24 * 60 * 60) + if not data: + break + self.connection.wait(copy_to(self._pgconn, data)) + except BaseException as ex: + # Propagate the error to the main thread. + self._worker_error = ex + + def write(self, data: Buffer) -> None: + if not self._worker: + # warning: reference loop, broken by _write_end + self._worker = threading.Thread(target=self.worker) + self._worker.daemon = True + self._worker.start() + + # If the worker thread raies an exception, re-raise it to the caller. + if self._worker_error: + raise self._worker_error + + if len(data) <= MAX_BUFFER_SIZE: + # Most used path: we don't need to split the buffer in smaller + # bits, so don't make a copy. + self._queue.put(data) + else: + # Copy a buffer too large in chunks to avoid causing a memory + # error in the libpq, which may cause an infinite loop (#255). + for i in range(0, len(data), MAX_BUFFER_SIZE): + self._queue.put(data[i : i + MAX_BUFFER_SIZE]) + + def finish(self, exc: Optional[BaseException] = None) -> None: + self._queue.put(b"") + + if self._worker: + self._worker.join() + self._worker = None # break the loop + + # Check if the worker thread raised any exception before terminating. + if self._worker_error: + raise self._worker_error + + super().finish(exc) + + +class FileWriter(Writer): + """ + A `Writer` to write copy data to a file-like object. + + :param file: the file where to write copy data. It must be open for writing + in binary mode. + """ + + def __init__(self, file: IO[bytes]): + self.file = file + + def write(self, data: Buffer) -> None: + self.file.write(data) + + +class AsyncCopy(BaseCopy["AsyncConnection[Any]"]): + """Manage an asynchronous :sql:`COPY` operation.""" + + __module__ = "psycopg" + + writer: "AsyncWriter" + + def __init__( + self, + cursor: "AsyncCursor[Any]", + *, + binary: Optional[bool] = None, + writer: Optional["AsyncWriter"] = None, + ): + super().__init__(cursor, binary=binary) + + if not writer: + writer = AsyncLibpqWriter(cursor) + + self.writer = writer + self._write = writer.write + + async def __aenter__(self: BaseCopy._Self) -> BaseCopy._Self: + self._enter() + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + await self.finish(exc_val) + + async def __aiter__(self) -> AsyncIterator[Buffer]: + while True: + data = await self.read() + if not data: + break + yield data + + async def read(self) -> Buffer: + return await self.connection.wait(self._read_gen()) + + async def rows(self) -> AsyncIterator[Tuple[Any, ...]]: + while True: + record = await self.read_row() + if record is None: + break + yield record + + async def read_row(self) -> Optional[Tuple[Any, ...]]: + return await self.connection.wait(self._read_row_gen()) + + async def write(self, buffer: Union[Buffer, str]) -> None: + data = self.formatter.write(buffer) + if data: + await self._write(data) + + async def write_row(self, row: Sequence[Any]) -> None: + data = self.formatter.write_row(row) + if data: + await self._write(data) + + async def finish(self, exc: Optional[BaseException]) -> None: + if self._direction == COPY_IN: + data = self.formatter.end() + if data: + await self._write(data) + await self.writer.finish(exc) + self._finished = True + else: + await self.connection.wait(self._end_copy_out_gen(exc)) + + +class AsyncWriter(ABC): + """ + A class to write copy data somewhere (for async connections). + """ + + @abstractmethod + async def write(self, data: Buffer) -> None: + ... + + async def finish(self, exc: Optional[BaseException] = None) -> None: + pass + + +class AsyncLibpqWriter(AsyncWriter): + """ + An `AsyncWriter` to write copy data to a Postgres database. + """ + + def __init__(self, cursor: "AsyncCursor[Any]"): + self.cursor = cursor + self.connection = cursor.connection + self._pgconn = self.connection.pgconn + + async def write(self, data: Buffer) -> None: + if len(data) <= MAX_BUFFER_SIZE: + # Most used path: we don't need to split the buffer in smaller + # bits, so don't make a copy. + await self.connection.wait(copy_to(self._pgconn, data)) + else: + # Copy a buffer too large in chunks to avoid causing a memory + # error in the libpq, which may cause an infinite loop (#255). + for i in range(0, len(data), MAX_BUFFER_SIZE): + await self.connection.wait( + copy_to(self._pgconn, data[i : i + MAX_BUFFER_SIZE]) + ) + + async def finish(self, exc: Optional[BaseException] = None) -> None: + bmsg: Optional[bytes] + if exc: + msg = f"error from Python: {type(exc).__qualname__} - {exc}" + bmsg = msg.encode(pgconn_encoding(self._pgconn), "replace") + else: + bmsg = None + + res = await self.connection.wait(copy_end(self._pgconn, bmsg)) + self.cursor._results = [res] + + +class AsyncQueuedLibpqWriter(AsyncLibpqWriter): + """ + An `AsyncWriter` using a buffer to queue data to write. + + `write()` returns immediately, so that the main thread can be CPU-bound + formatting messages, while a worker thread can be IO-bound waiting to write + on the connection. + """ + + def __init__(self, cursor: "AsyncCursor[Any]"): + super().__init__(cursor) + + self._queue: asyncio.Queue[Buffer] = asyncio.Queue(maxsize=QUEUE_SIZE) + self._worker: Optional[asyncio.Future[None]] = None + + async def worker(self) -> None: + """Push data to the server when available from the copy queue. + + Terminate reading when the queue receives a false-y value. + + The function is designed to be run in a separate task. + """ + while True: + data = await self._queue.get() + if not data: + break + await self.connection.wait(copy_to(self._pgconn, data)) + + async def write(self, data: Buffer) -> None: + if not self._worker: + self._worker = create_task(self.worker()) + + if len(data) <= MAX_BUFFER_SIZE: + # Most used path: we don't need to split the buffer in smaller + # bits, so don't make a copy. + await self._queue.put(data) + else: + # Copy a buffer too large in chunks to avoid causing a memory + # error in the libpq, which may cause an infinite loop (#255). + for i in range(0, len(data), MAX_BUFFER_SIZE): + await self._queue.put(data[i : i + MAX_BUFFER_SIZE]) + + async def finish(self, exc: Optional[BaseException] = None) -> None: + await self._queue.put(b"") + + if self._worker: + await asyncio.gather(self._worker) + self._worker = None # break reference loops if any + + await super().finish(exc) + + +class Formatter(ABC): + """ + A class which understand a copy format (text, binary). + """ + + format: pq.Format + + def __init__(self, transformer: Transformer): + self.transformer = transformer + self._write_buffer = bytearray() + self._row_mode = False # true if the user is using write_row() + + @abstractmethod + def parse_row(self, data: Buffer) -> Optional[Tuple[Any, ...]]: + ... + + @abstractmethod + def write(self, buffer: Union[Buffer, str]) -> Buffer: + ... + + @abstractmethod + def write_row(self, row: Sequence[Any]) -> Buffer: + ... + + @abstractmethod + def end(self) -> Buffer: + ... + + +class TextFormatter(Formatter): + format = TEXT + + def __init__(self, transformer: Transformer, encoding: str = "utf-8"): + super().__init__(transformer) + self._encoding = encoding + + def parse_row(self, data: Buffer) -> Optional[Tuple[Any, ...]]: + if data: + return parse_row_text(data, self.transformer) + else: + return None + + def write(self, buffer: Union[Buffer, str]) -> Buffer: + data = self._ensure_bytes(buffer) + self._signature_sent = True + return data + + def write_row(self, row: Sequence[Any]) -> Buffer: + # Note down that we are writing in row mode: it means we will have + # to take care of the end-of-copy marker too + self._row_mode = True + + format_row_text(row, self.transformer, self._write_buffer) + if len(self._write_buffer) > BUFFER_SIZE: + buffer, self._write_buffer = self._write_buffer, bytearray() + return buffer + else: + return b"" + + def end(self) -> Buffer: + buffer, self._write_buffer = self._write_buffer, bytearray() + return buffer + + def _ensure_bytes(self, data: Union[Buffer, str]) -> Buffer: + if isinstance(data, str): + return data.encode(self._encoding) + else: + # Assume, for simplicity, that the user is not passing stupid + # things to the write function. If that's the case, things + # will fail downstream. + return data + + +class BinaryFormatter(Formatter): + format = BINARY + + def __init__(self, transformer: Transformer): + super().__init__(transformer) + self._signature_sent = False + + def parse_row(self, data: Buffer) -> Optional[Tuple[Any, ...]]: + if not self._signature_sent: + if data[: len(_binary_signature)] != _binary_signature: + raise e.DataError( + "binary copy doesn't start with the expected signature" + ) + self._signature_sent = True + data = data[len(_binary_signature) :] + + elif data == _binary_trailer: + return None + + return parse_row_binary(data, self.transformer) + + def write(self, buffer: Union[Buffer, str]) -> Buffer: + data = self._ensure_bytes(buffer) + self._signature_sent = True + return data + + def write_row(self, row: Sequence[Any]) -> Buffer: + # Note down that we are writing in row mode: it means we will have + # to take care of the end-of-copy marker too + self._row_mode = True + + if not self._signature_sent: + self._write_buffer += _binary_signature + self._signature_sent = True + + format_row_binary(row, self.transformer, self._write_buffer) + if len(self._write_buffer) > BUFFER_SIZE: + buffer, self._write_buffer = self._write_buffer, bytearray() + return buffer + else: + return b"" + + def end(self) -> Buffer: + # If we have sent no data we need to send the signature + # and the trailer + if not self._signature_sent: + self._write_buffer += _binary_signature + self._write_buffer += _binary_trailer + + elif self._row_mode: + # if we have sent data already, we have sent the signature + # too (either with the first row, or we assume that in + # block mode the signature is included). + # Write the trailer only if we are sending rows (with the + # assumption that who is copying binary data is sending the + # whole format). + self._write_buffer += _binary_trailer + + buffer, self._write_buffer = self._write_buffer, bytearray() + return buffer + + def _ensure_bytes(self, data: Union[Buffer, str]) -> Buffer: + if isinstance(data, str): + raise TypeError("cannot copy str data in binary mode: use bytes instead") + else: + # Assume, for simplicity, that the user is not passing stupid + # things to the write function. If that's the case, things + # will fail downstream. + return data + + +def _format_row_text( + row: Sequence[Any], tx: Transformer, out: Optional[bytearray] = None +) -> bytearray: + """Convert a row of objects to the data to send for copy.""" + if out is None: + out = bytearray() + + if not row: + out += b"\n" + return out + + for item in row: + if item is not None: + dumper = tx.get_dumper(item, PY_TEXT) + b = dumper.dump(item) + out += _dump_re.sub(_dump_sub, b) + else: + out += rb"\N" + out += b"\t" + + out[-1:] = b"\n" + return out + + +def _format_row_binary( + row: Sequence[Any], tx: Transformer, out: Optional[bytearray] = None +) -> bytearray: + """Convert a row of objects to the data to send for binary copy.""" + if out is None: + out = bytearray() + + out += _pack_int2(len(row)) + adapted = tx.dump_sequence(row, [PY_BINARY] * len(row)) + for b in adapted: + if b is not None: + out += _pack_int4(len(b)) + out += b + else: + out += _binary_null + + return out + + +def _parse_row_text(data: Buffer, tx: Transformer) -> Tuple[Any, ...]: + if not isinstance(data, bytes): + data = bytes(data) + fields = data.split(b"\t") + fields[-1] = fields[-1][:-1] # drop \n + row = [None if f == b"\\N" else _load_re.sub(_load_sub, f) for f in fields] + return tx.load_sequence(row) + + +def _parse_row_binary(data: Buffer, tx: Transformer) -> Tuple[Any, ...]: + row: List[Optional[Buffer]] = [] + nfields = _unpack_int2(data, 0)[0] + pos = 2 + for i in range(nfields): + length = _unpack_int4(data, pos)[0] + pos += 4 + if length >= 0: + row.append(data[pos : pos + length]) + pos += length + else: + row.append(None) + + return tx.load_sequence(row) + + +_pack_int2 = struct.Struct("!h").pack +_pack_int4 = struct.Struct("!i").pack +_unpack_int2 = struct.Struct("!h").unpack_from +_unpack_int4 = struct.Struct("!i").unpack_from + +_binary_signature = ( + b"PGCOPY\n\xff\r\n\0" # Signature + b"\x00\x00\x00\x00" # flags + b"\x00\x00\x00\x00" # extra length +) +_binary_trailer = b"\xff\xff" +_binary_null = b"\xff\xff\xff\xff" + +_dump_re = re.compile(b"[\b\t\n\v\f\r\\\\]") +_dump_repl = { + b"\b": b"\\b", + b"\t": b"\\t", + b"\n": b"\\n", + b"\v": b"\\v", + b"\f": b"\\f", + b"\r": b"\\r", + b"\\": b"\\\\", +} + + +def _dump_sub(m: Match[bytes], __map: Dict[bytes, bytes] = _dump_repl) -> bytes: + return __map[m.group(0)] + + +_load_re = re.compile(b"\\\\[btnvfr\\\\]") +_load_repl = {v: k for k, v in _dump_repl.items()} + + +def _load_sub(m: Match[bytes], __map: Dict[bytes, bytes] = _load_repl) -> bytes: + return __map[m.group(0)] + + +# Override functions with fast versions if available +if _psycopg: + format_row_text = _psycopg.format_row_text + format_row_binary = _psycopg.format_row_binary + parse_row_text = _psycopg.parse_row_text + parse_row_binary = _psycopg.parse_row_binary + +else: + format_row_text = _format_row_text + format_row_binary = _format_row_binary + parse_row_text = _parse_row_text + parse_row_binary = _parse_row_binary diff --git a/lib/python3.11/site-packages/psycopg/crdb/__init__.py b/lib/python3.11/site-packages/psycopg/crdb/__init__.py new file mode 100644 index 0000000..323903a --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/crdb/__init__.py @@ -0,0 +1,19 @@ +""" +CockroachDB support package. +""" + +# Copyright (C) 2022 The Psycopg Team + +from . import _types +from .connection import CrdbConnection, AsyncCrdbConnection, CrdbConnectionInfo + +adapters = _types.adapters # exposed by the package +connect = CrdbConnection.connect + +_types.register_crdb_adapters(adapters) + +__all__ = [ + "AsyncCrdbConnection", + "CrdbConnection", + "CrdbConnectionInfo", +] diff --git a/lib/python3.11/site-packages/psycopg/crdb/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/crdb/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e1a7986c4bb0584d272dba0dcd847d652d62238 GIT binary patch literal 610 zcmZ`#zi-qq6n;)}Nyt%9`6ZU3+fErct72fOKyWMw0RvkW%Z<%l+Qg3Rlxvvo59kgv z0|@a?@FyJ74V9-#Ol*<5b;721<%h)c^QZScfA2lppEfoUu=ec!S9XK|zB{rue-)ex z8@vMs88F1W5>;O2As73lUj!Riq|srRnPWPfrHS(i?nYdLYT}6F`(Qxm?Xbwd@lS| z;?yRljMfcT+C(dnxuy7|&^AYMdnfW+KnN{MLO#Q(t%S4Z_zhKfHk;w9b@GA>rf5ZR zS?uDvZKhJ(8*Oi6T{Qge>ggKSy3J)h!LBzZq!2|z$f$15;+;yegOWc`o3^|AAbn_| z^ASRw=b@kj2bTfeT)>S#{TN;@{_iLK&7+6&_&B+}Oa}Al1h(ek61Lt?zrk<`!vzex RAn1D?tYIFxrLNlHKLNcdrvm^0 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/crdb/__pycache__/_types.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/crdb/__pycache__/_types.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9851d4c4242897c3bc4e441ea3f0cae9674502d9 GIT binary patch literal 9698 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 KQ?vwl&iTLJESkdr literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/crdb/__pycache__/connection.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/crdb/__pycache__/connection.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0bc42a07dd87a17a58a5daeda97c29d1542e60e GIT binary patch literal 9138 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 ig}wCLsfSqmO`YXkZXbuX- None: + # Same adapters used by PostgreSQL, or a good starting point for customization + + from ..types import array, bool, composite, datetime + from ..types import numeric, string, uuid + + array.register_default_adapters(context) + bool.register_default_adapters(context) + composite.register_default_adapters(context) + datetime.register_default_adapters(context) + numeric.register_default_adapters(context) + string.register_default_adapters(context) + uuid.register_default_adapters(context) + + +def register_crdb_adapters(context: AdaptContext) -> None: + from .. import dbapi20 + from ..types import array + + register_postgres_adapters(context) + + # String must come after enum to map text oid -> string dumper + register_crdb_enum_adapters(context) + register_crdb_string_adapters(context) + register_crdb_json_adapters(context) + register_crdb_net_adapters(context) + register_crdb_none_adapters(context) + + dbapi20.register_dbapi20_adapters(adapters) + + array.register_all_arrays(adapters) + + +def register_crdb_string_adapters(context: AdaptContext) -> None: + from ..types import string + + # Dump strings with text oid instead of unknown. + # Unlike PostgreSQL, CRDB seems able to cast text to most types. + context.adapters.register_dumper(str, string.StrDumper) + context.adapters.register_dumper(str, string.StrBinaryDumper) + + +def register_crdb_enum_adapters(context: AdaptContext) -> None: + context.adapters.register_dumper(Enum, CrdbEnumBinaryDumper) + context.adapters.register_dumper(Enum, CrdbEnumDumper) + + +def register_crdb_json_adapters(context: AdaptContext) -> None: + from ..types import json + + adapters = context.adapters + + # CRDB doesn't have json/jsonb: both names map to the jsonb oid + adapters.register_dumper(json.Json, json.JsonbBinaryDumper) + adapters.register_dumper(json.Json, json.JsonbDumper) + + adapters.register_dumper(json.Jsonb, json.JsonbBinaryDumper) + adapters.register_dumper(json.Jsonb, json.JsonbDumper) + + adapters.register_loader("json", json.JsonLoader) + adapters.register_loader("jsonb", json.JsonbLoader) + adapters.register_loader("json", json.JsonBinaryLoader) + adapters.register_loader("jsonb", json.JsonbBinaryLoader) + + +def register_crdb_net_adapters(context: AdaptContext) -> None: + from ..types import net + + adapters = context.adapters + + adapters.register_dumper("ipaddress.IPv4Address", net.InterfaceDumper) + adapters.register_dumper("ipaddress.IPv6Address", net.InterfaceDumper) + adapters.register_dumper("ipaddress.IPv4Interface", net.InterfaceDumper) + adapters.register_dumper("ipaddress.IPv6Interface", net.InterfaceDumper) + adapters.register_dumper("ipaddress.IPv4Address", net.AddressBinaryDumper) + adapters.register_dumper("ipaddress.IPv6Address", net.AddressBinaryDumper) + adapters.register_dumper("ipaddress.IPv4Interface", net.InterfaceBinaryDumper) + adapters.register_dumper("ipaddress.IPv6Interface", net.InterfaceBinaryDumper) + adapters.register_dumper(None, net.InetBinaryDumper) + adapters.register_loader("inet", net.InetLoader) + adapters.register_loader("inet", net.InetBinaryLoader) + + +def register_crdb_none_adapters(context: AdaptContext) -> None: + context.adapters.register_dumper(NoneType, CrdbNoneDumper) + + +for t in [ + TypeInfo("json", 3802, 3807, regtype="jsonb"), # Alias json -> jsonb. + TypeInfo("int8", 20, 1016, regtype="integer"), # Alias integer -> int8 + TypeInfo('"char"', 18, 1002), # special case, not generated + # autogenerated: start + # Generated from CockroachDB 22.1.0 + TypeInfo("bit", 1560, 1561), + TypeInfo("bool", 16, 1000, regtype="boolean"), + TypeInfo("bpchar", 1042, 1014, regtype="character"), + TypeInfo("bytea", 17, 1001), + TypeInfo("date", 1082, 1182), + TypeInfo("float4", 700, 1021, regtype="real"), + TypeInfo("float8", 701, 1022, regtype="double precision"), + TypeInfo("inet", 869, 1041), + TypeInfo("int2", 21, 1005, regtype="smallint"), + TypeInfo("int2vector", 22, 1006), + TypeInfo("int4", 23, 1007), + TypeInfo("int8", 20, 1016, regtype="bigint"), + TypeInfo("interval", 1186, 1187), + TypeInfo("jsonb", 3802, 3807), + TypeInfo("name", 19, 1003), + TypeInfo("numeric", 1700, 1231), + TypeInfo("oid", 26, 1028), + TypeInfo("oidvector", 30, 1013), + TypeInfo("record", 2249, 2287), + TypeInfo("regclass", 2205, 2210), + TypeInfo("regnamespace", 4089, 4090), + TypeInfo("regproc", 24, 1008), + TypeInfo("regprocedure", 2202, 2207), + TypeInfo("regrole", 4096, 4097), + TypeInfo("regtype", 2206, 2211), + TypeInfo("text", 25, 1009), + TypeInfo("time", 1083, 1183, regtype="time without time zone"), + TypeInfo("timestamp", 1114, 1115, regtype="timestamp without time zone"), + TypeInfo("timestamptz", 1184, 1185, regtype="timestamp with time zone"), + TypeInfo("timetz", 1266, 1270, regtype="time with time zone"), + TypeInfo("unknown", 705, 0), + TypeInfo("uuid", 2950, 2951), + TypeInfo("varbit", 1562, 1563, regtype="bit varying"), + TypeInfo("varchar", 1043, 1015, regtype="character varying"), + # autogenerated: end +]: + types.add(t) diff --git a/lib/python3.11/site-packages/psycopg/crdb/connection.py b/lib/python3.11/site-packages/psycopg/crdb/connection.py new file mode 100644 index 0000000..451474b --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/crdb/connection.py @@ -0,0 +1,185 @@ +""" +CockroachDB-specific connections. +""" + +# Copyright (C) 2022 The Psycopg Team + +import re +from typing import Any, Optional, Type, Union, overload, TYPE_CHECKING + +from .. import errors as e +from ..abc import AdaptContext +from ..rows import Row, RowFactory, AsyncRowFactory, TupleRow +from ..conninfo import ConnectionInfo +from ..connection import Connection +from .._adapters_map import AdaptersMap +from ..connection_async import AsyncConnection +from ._types import adapters + +if TYPE_CHECKING: + from ..pq.abc import PGconn + from ..cursor import Cursor + from ..cursor_async import AsyncCursor + + +class _CrdbConnectionMixin: + _adapters: Optional[AdaptersMap] + pgconn: "PGconn" + + @classmethod + def is_crdb( + cls, conn: Union[Connection[Any], AsyncConnection[Any], "PGconn"] + ) -> bool: + """ + Return `!True` if the server connected to `!conn` is CockroachDB. + """ + if isinstance(conn, (Connection, AsyncConnection)): + conn = conn.pgconn + + return bool(conn.parameter_status(b"crdb_version")) + + @property + def adapters(self) -> AdaptersMap: + if not self._adapters: + # By default, use CockroachDB adapters map + self._adapters = AdaptersMap(adapters) + + return self._adapters + + @property + def info(self) -> "CrdbConnectionInfo": + return CrdbConnectionInfo(self.pgconn) + + def _check_tpc(self) -> None: + if self.is_crdb(self.pgconn): + raise e.NotSupportedError("CockroachDB doesn't support prepared statements") + + +class CrdbConnection(_CrdbConnectionMixin, Connection[Row]): + """ + Wrapper for a connection to a CockroachDB database. + """ + + __module__ = "psycopg.crdb" + + # TODO: this method shouldn't require re-definition if the base class + # implements a generic self. + # https://github.com/psycopg/psycopg/issues/308 + @overload + @classmethod + def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + row_factory: RowFactory[Row], + prepare_threshold: Optional[int] = 5, + cursor_factory: "Optional[Type[Cursor[Row]]]" = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "CrdbConnection[Row]": + ... + + @overload + @classmethod + def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + cursor_factory: "Optional[Type[Cursor[Any]]]" = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "CrdbConnection[TupleRow]": + ... + + @classmethod + def connect(cls, conninfo: str = "", **kwargs: Any) -> "CrdbConnection[Any]": + """ + Connect to a database server and return a new `CrdbConnection` instance. + """ + return super().connect(conninfo, **kwargs) # type: ignore[return-value] + + +class AsyncCrdbConnection(_CrdbConnectionMixin, AsyncConnection[Row]): + """ + Wrapper for an async connection to a CockroachDB database. + """ + + __module__ = "psycopg.crdb" + + # TODO: this method shouldn't require re-definition if the base class + # implements a generic self. + # https://github.com/psycopg/psycopg/issues/308 + @overload + @classmethod + async def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + row_factory: AsyncRowFactory[Row], + cursor_factory: "Optional[Type[AsyncCursor[Row]]]" = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "AsyncCrdbConnection[Row]": + ... + + @overload + @classmethod + async def connect( + cls, + conninfo: str = "", + *, + autocommit: bool = False, + prepare_threshold: Optional[int] = 5, + cursor_factory: "Optional[Type[AsyncCursor[Any]]]" = None, + context: Optional[AdaptContext] = None, + **kwargs: Union[None, int, str], + ) -> "AsyncCrdbConnection[TupleRow]": + ... + + @classmethod + async def connect( + cls, conninfo: str = "", **kwargs: Any + ) -> "AsyncCrdbConnection[Any]": + return await super().connect(conninfo, **kwargs) # type: ignore [no-any-return] + + +class CrdbConnectionInfo(ConnectionInfo): + """ + `~psycopg.ConnectionInfo` subclass to get info about a CockroachDB database. + """ + + __module__ = "psycopg.crdb" + + @property + def vendor(self) -> str: + return "CockroachDB" + + @property + def server_version(self) -> int: + """ + Return the CockroachDB server version connected. + + Return a number in the PostgreSQL format (e.g. 21.2.10 -> 210210). + """ + sver = self.parameter_status("crdb_version") + if not sver: + raise e.InternalError("'crdb_version' parameter status not set") + + ver = self.parse_crdb_version(sver) + if ver is None: + raise e.InterfaceError(f"couldn't parse CockroachDB version from: {sver!r}") + + return ver + + @classmethod + def parse_crdb_version(self, sver: str) -> Optional[int]: + m = re.search(r"\bv(\d+)\.(\d+)\.(\d+)", sver) + if not m: + return None + + return int(m.group(1)) * 10000 + int(m.group(2)) * 100 + int(m.group(3)) diff --git a/lib/python3.11/site-packages/psycopg/cursor.py b/lib/python3.11/site-packages/psycopg/cursor.py new file mode 100644 index 0000000..148ea10 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/cursor.py @@ -0,0 +1,915 @@ +""" +psycopg cursor objects +""" + +# Copyright (C) 2020 The Psycopg Team + +from functools import partial +from types import TracebackType +from typing import Any, Generic, Iterable, Iterator, List +from typing import Optional, NoReturn, Sequence, Tuple, Type, TypeVar +from typing import overload, TYPE_CHECKING +from contextlib import contextmanager + +from . import pq +from . import adapt +from . import errors as e +from .abc import ConnectionType, Query, Params, PQGen +from .copy import Copy, Writer as CopyWriter +from .rows import Row, RowMaker, RowFactory +from ._column import Column +from ._queries import PostgresQuery, PostgresClientQuery +from ._pipeline import Pipeline +from ._encodings import pgconn_encoding +from ._preparing import Prepare +from .generators import execute, fetch, send + +if TYPE_CHECKING: + from .abc import Transformer + from .pq.abc import PGconn, PGresult + from .connection import Connection + +TEXT = pq.Format.TEXT +BINARY = pq.Format.BINARY + +EMPTY_QUERY = pq.ExecStatus.EMPTY_QUERY +COMMAND_OK = pq.ExecStatus.COMMAND_OK +TUPLES_OK = pq.ExecStatus.TUPLES_OK +COPY_OUT = pq.ExecStatus.COPY_OUT +COPY_IN = pq.ExecStatus.COPY_IN +COPY_BOTH = pq.ExecStatus.COPY_BOTH +FATAL_ERROR = pq.ExecStatus.FATAL_ERROR +SINGLE_TUPLE = pq.ExecStatus.SINGLE_TUPLE +PIPELINE_ABORTED = pq.ExecStatus.PIPELINE_ABORTED + +ACTIVE = pq.TransactionStatus.ACTIVE + + +class BaseCursor(Generic[ConnectionType, Row]): + __slots__ = """ + _conn format _adapters arraysize _closed _results pgresult _pos + _iresult _rowcount _query _tx _last_query _row_factory _make_row + _pgconn _execmany_returning + __weakref__ + """.split() + + ExecStatus = pq.ExecStatus + + _tx: "Transformer" + _make_row: RowMaker[Row] + _pgconn: "PGconn" + + def __init__(self, connection: ConnectionType): + self._conn = connection + self.format = TEXT + self._pgconn = connection.pgconn + self._adapters = adapt.AdaptersMap(connection.adapters) + self.arraysize = 1 + self._closed = False + self._last_query: Optional[Query] = None + self._reset() + + def _reset(self, reset_query: bool = True) -> None: + self._results: List["PGresult"] = [] + self.pgresult: Optional["PGresult"] = None + self._pos = 0 + self._iresult = 0 + self._rowcount = -1 + self._query: Optional[PostgresQuery] + # None if executemany() not executing, True/False according to returning state + self._execmany_returning: Optional[bool] = None + if reset_query: + self._query = None + + def __repr__(self) -> str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + info = pq.misc.connection_summary(self._pgconn) + if self._closed: + status = "closed" + elif self.pgresult: + status = pq.ExecStatus(self.pgresult.status).name + else: + status = "no result" + return f"<{cls} [{status}] {info} at 0x{id(self):x}>" + + @property + def connection(self) -> ConnectionType: + """The connection this cursor is using.""" + return self._conn + + @property + def adapters(self) -> adapt.AdaptersMap: + return self._adapters + + @property + def closed(self) -> bool: + """`True` if the cursor is closed.""" + return self._closed + + @property + def description(self) -> Optional[List[Column]]: + """ + A list of `Column` objects describing the current resultset. + + `!None` if the current resultset didn't return tuples. + """ + res = self.pgresult + + # We return columns if we have nfields, but also if we don't but + # the query said we got tuples (mostly to handle the super useful + # query "SELECT ;" + if res and ( + res.nfields or res.status == TUPLES_OK or res.status == SINGLE_TUPLE + ): + return [Column(self, i) for i in range(res.nfields)] + else: + return None + + @property + def rowcount(self) -> int: + """Number of records affected by the precedent operation.""" + return self._rowcount + + @property + def rownumber(self) -> Optional[int]: + """Index of the next row to fetch in the current result. + + `!None` if there is no result to fetch. + """ + tuples = self.pgresult and self.pgresult.status == TUPLES_OK + return self._pos if tuples else None + + def setinputsizes(self, sizes: Sequence[Any]) -> None: + # no-op + pass + + def setoutputsize(self, size: Any, column: Optional[int] = None) -> None: + # no-op + pass + + def nextset(self) -> Optional[bool]: + """ + Move to the result set of the next query executed through `executemany()` + or to the next result set if `execute()` returned more than one. + + Return `!True` if a new result is available, which will be the one + methods `!fetch*()` will operate on. + """ + if self._iresult < len(self._results) - 1: + self._select_current_result(self._iresult + 1) + return True + else: + return None + + @property + def statusmessage(self) -> Optional[str]: + """ + The command status tag from the last SQL command executed. + + `!None` if the cursor doesn't have a result available. + """ + msg = self.pgresult.command_status if self.pgresult else None + return msg.decode() if msg else None + + def _make_row_maker(self) -> RowMaker[Row]: + raise NotImplementedError + + # + # Generators for the high level operations on the cursor + # + # Like for sync/async connections, these are implemented as generators + # so that different concurrency strategies (threads,asyncio) can use their + # own way of waiting (or better, `connection.wait()`). + # + + def _execute_gen( + self, + query: Query, + params: Optional[Params] = None, + *, + prepare: Optional[bool] = None, + binary: Optional[bool] = None, + ) -> PQGen[None]: + """Generator implementing `Cursor.execute()`.""" + yield from self._start_query(query) + pgq = self._convert_query(query, params) + results = yield from self._maybe_prepare_gen( + pgq, prepare=prepare, binary=binary + ) + if self._conn._pipeline: + yield from self._conn._pipeline._communicate_gen() + else: + assert results is not None + self._check_results(results) + self._results = results + self._select_current_result(0) + + self._last_query = query + + for cmd in self._conn._prepared.get_maintenance_commands(): + yield from self._conn._exec_command(cmd) + + def _executemany_gen_pipeline( + self, query: Query, params_seq: Iterable[Params], returning: bool + ) -> PQGen[None]: + """ + Generator implementing `Cursor.executemany()` with pipelines available. + """ + pipeline = self._conn._pipeline + assert pipeline + + yield from self._start_query(query) + if not returning: + self._rowcount = 0 + + assert self._execmany_returning is None + self._execmany_returning = returning + + first = True + for params in params_seq: + if first: + pgq = self._convert_query(query, params) + self._query = pgq + first = False + else: + pgq.dump(params) + + yield from self._maybe_prepare_gen(pgq, prepare=True) + yield from pipeline._communicate_gen() + + self._last_query = query + + if returning: + yield from pipeline._fetch_gen(flush=True) + + for cmd in self._conn._prepared.get_maintenance_commands(): + yield from self._conn._exec_command(cmd) + + def _executemany_gen_no_pipeline( + self, query: Query, params_seq: Iterable[Params], returning: bool + ) -> PQGen[None]: + """ + Generator implementing `Cursor.executemany()` with pipelines not available. + """ + yield from self._start_query(query) + if not returning: + self._rowcount = 0 + first = True + for params in params_seq: + if first: + pgq = self._convert_query(query, params) + self._query = pgq + first = False + else: + pgq.dump(params) + + results = yield from self._maybe_prepare_gen(pgq, prepare=True) + assert results is not None + self._check_results(results) + if returning: + self._results.extend(results) + else: + # In non-returning case, set rowcount to the cumulated number + # of rows of executed queries. + for res in results: + self._rowcount += res.command_tuples or 0 + + if self._results: + self._select_current_result(0) + + self._last_query = query + + for cmd in self._conn._prepared.get_maintenance_commands(): + yield from self._conn._exec_command(cmd) + + def _maybe_prepare_gen( + self, + pgq: PostgresQuery, + *, + prepare: Optional[bool] = None, + binary: Optional[bool] = None, + ) -> PQGen[Optional[List["PGresult"]]]: + # Check if the query is prepared or needs preparing + prep, name = self._get_prepared(pgq, prepare) + if prep is Prepare.NO: + # The query must be executed without preparing + self._execute_send(pgq, binary=binary) + else: + # If the query is not already prepared, prepare it. + if prep is Prepare.SHOULD: + self._send_prepare(name, pgq) + if not self._conn._pipeline: + (result,) = yield from execute(self._pgconn) + if result.status == FATAL_ERROR: + raise e.error_from_result(result, encoding=self._encoding) + # Then execute it. + self._send_query_prepared(name, pgq, binary=binary) + + # Update the prepare state of the query. + # If an operation requires to flush our prepared statements cache, + # it will be added to the maintenance commands to execute later. + key = self._conn._prepared.maybe_add_to_cache(pgq, prep, name) + + if self._conn._pipeline: + queued = None + if key is not None: + queued = (key, prep, name) + self._conn._pipeline.result_queue.append((self, queued)) + return None + + # run the query + results = yield from execute(self._pgconn) + + if key is not None: + self._conn._prepared.validate(key, prep, name, results) + + return results + + def _get_prepared( + self, pgq: PostgresQuery, prepare: Optional[bool] = None + ) -> Tuple[Prepare, bytes]: + return self._conn._prepared.get(pgq, prepare) + + def _stream_send_gen( + self, + query: Query, + params: Optional[Params] = None, + *, + binary: Optional[bool] = None, + ) -> PQGen[None]: + """Generator to send the query for `Cursor.stream()`.""" + yield from self._start_query(query) + pgq = self._convert_query(query, params) + self._execute_send(pgq, binary=binary, force_extended=True) + self._pgconn.set_single_row_mode() + self._last_query = query + yield from send(self._pgconn) + + def _stream_fetchone_gen(self, first: bool) -> PQGen[Optional["PGresult"]]: + res = yield from fetch(self._pgconn) + if res is None: + return None + + status = res.status + if status == SINGLE_TUPLE: + self.pgresult = res + self._tx.set_pgresult(res, set_loaders=first) + if first: + self._make_row = self._make_row_maker() + return res + + elif status == TUPLES_OK or status == COMMAND_OK: + # End of single row results + while res: + res = yield from fetch(self._pgconn) + if status != TUPLES_OK: + raise e.ProgrammingError( + "the operation in stream() didn't produce a result" + ) + return None + + else: + # Errors, unexpected values + return self._raise_for_result(res) + + def _start_query(self, query: Optional[Query] = None) -> PQGen[None]: + """Generator to start the processing of a query. + + It is implemented as generator because it may send additional queries, + such as `begin`. + """ + if self.closed: + raise e.InterfaceError("the cursor is closed") + + self._reset() + if not self._last_query or (self._last_query is not query): + self._last_query = None + self._tx = adapt.Transformer(self) + yield from self._conn._start_query() + + def _start_copy_gen( + self, statement: Query, params: Optional[Params] = None + ) -> PQGen[None]: + """Generator implementing sending a command for `Cursor.copy().""" + + # The connection gets in an unrecoverable state if we attempt COPY in + # pipeline mode. Forbid it explicitly. + if self._conn._pipeline: + raise e.NotSupportedError("COPY cannot be used in pipeline mode") + + yield from self._start_query() + + # Merge the params client-side + if params: + pgq = PostgresClientQuery(self._tx) + pgq.convert(statement, params) + statement = pgq.query + + query = self._convert_query(statement) + + self._execute_send(query, binary=False) + results = yield from execute(self._pgconn) + if len(results) != 1: + raise e.ProgrammingError("COPY cannot be mixed with other operations") + + self._check_copy_result(results[0]) + self._results = results + self._select_current_result(0) + + def _execute_send( + self, + query: PostgresQuery, + *, + force_extended: bool = False, + binary: Optional[bool] = None, + ) -> None: + """ + Implement part of execute() before waiting common to sync and async. + + This is not a generator, but a normal non-blocking function. + """ + if binary is None: + fmt = self.format + else: + fmt = BINARY if binary else TEXT + + self._query = query + + if self._conn._pipeline: + # In pipeline mode always use PQsendQueryParams - see #314 + # Multiple statements in the same query are not allowed anyway. + self._conn._pipeline.command_queue.append( + partial( + self._pgconn.send_query_params, + query.query, + query.params, + param_formats=query.formats, + param_types=query.types, + result_format=fmt, + ) + ) + elif force_extended or query.params or fmt == BINARY: + self._pgconn.send_query_params( + query.query, + query.params, + param_formats=query.formats, + param_types=query.types, + result_format=fmt, + ) + else: + # If we can, let's use simple query protocol, + # as it can execute more than one statement in a single query. + self._pgconn.send_query(query.query) + + def _convert_query( + self, query: Query, params: Optional[Params] = None + ) -> PostgresQuery: + pgq = PostgresQuery(self._tx) + pgq.convert(query, params) + return pgq + + def _check_results(self, results: List["PGresult"]) -> None: + """ + Verify that the results of a query are valid. + + Verify that the query returned at least one result and that they all + represent a valid result from the database. + """ + if not results: + raise e.InternalError("got no result from the query") + + for res in results: + status = res.status + if status != TUPLES_OK and status != COMMAND_OK and status != EMPTY_QUERY: + self._raise_for_result(res) + + def _raise_for_result(self, result: "PGresult") -> NoReturn: + """ + Raise an appropriate error message for an unexpected database result + """ + status = result.status + if status == FATAL_ERROR: + raise e.error_from_result(result, encoding=self._encoding) + elif status == PIPELINE_ABORTED: + raise e.PipelineAborted("pipeline aborted") + elif status == COPY_IN or status == COPY_OUT or status == COPY_BOTH: + raise e.ProgrammingError( + "COPY cannot be used with this method; use copy() instead" + ) + else: + raise e.InternalError( + "unexpected result status from query:" f" {pq.ExecStatus(status).name}" + ) + + def _select_current_result( + self, i: int, format: Optional[pq.Format] = None + ) -> None: + """ + Select one of the results in the cursor as the active one. + """ + self._iresult = i + res = self.pgresult = self._results[i] + + # Note: the only reason to override format is to correctly set + # binary loaders on server-side cursors, because send_describe_portal + # only returns a text result. + self._tx.set_pgresult(res, format=format) + + self._pos = 0 + + if res.status == TUPLES_OK: + self._rowcount = self.pgresult.ntuples + + # COPY_OUT has never info about nrows. We need such result for the + # columns in order to return a `description`, but not overwrite the + # cursor rowcount (which was set by the Copy object). + elif res.status != COPY_OUT: + nrows = self.pgresult.command_tuples + self._rowcount = nrows if nrows is not None else -1 + + self._make_row = self._make_row_maker() + + def _set_results_from_pipeline(self, results: List["PGresult"]) -> None: + self._check_results(results) + first_batch = not self._results + + if self._execmany_returning is None: + # Received from execute() + self._results.extend(results) + if first_batch: + self._select_current_result(0) + + else: + # Received from executemany() + if self._execmany_returning: + self._results.extend(results) + if first_batch: + self._select_current_result(0) + else: + # In non-returning case, set rowcount to the cumulated number of + # rows of executed queries. + for res in results: + self._rowcount += res.command_tuples or 0 + + def _send_prepare(self, name: bytes, query: PostgresQuery) -> None: + if self._conn._pipeline: + self._conn._pipeline.command_queue.append( + partial( + self._pgconn.send_prepare, + name, + query.query, + param_types=query.types, + ) + ) + self._conn._pipeline.result_queue.append(None) + else: + self._pgconn.send_prepare(name, query.query, param_types=query.types) + + def _send_query_prepared( + self, name: bytes, pgq: PostgresQuery, *, binary: Optional[bool] = None + ) -> None: + if binary is None: + fmt = self.format + else: + fmt = BINARY if binary else TEXT + + if self._conn._pipeline: + self._conn._pipeline.command_queue.append( + partial( + self._pgconn.send_query_prepared, + name, + pgq.params, + param_formats=pgq.formats, + result_format=fmt, + ) + ) + else: + self._pgconn.send_query_prepared( + name, pgq.params, param_formats=pgq.formats, result_format=fmt + ) + + def _check_result_for_fetch(self) -> None: + if self.closed: + raise e.InterfaceError("the cursor is closed") + res = self.pgresult + if not res: + raise e.ProgrammingError("no result available") + + status = res.status + if status == TUPLES_OK: + return + elif status == FATAL_ERROR: + raise e.error_from_result(res, encoding=self._encoding) + elif status == PIPELINE_ABORTED: + raise e.PipelineAborted("pipeline aborted") + else: + raise e.ProgrammingError("the last operation didn't produce a result") + + def _check_copy_result(self, result: "PGresult") -> None: + """ + Check that the value returned in a copy() operation is a legit COPY. + """ + status = result.status + if status == COPY_IN or status == COPY_OUT: + return + elif status == FATAL_ERROR: + raise e.error_from_result(result, encoding=self._encoding) + else: + raise e.ProgrammingError( + "copy() should be used only with COPY ... TO STDOUT or COPY ..." + f" FROM STDIN statements, got {pq.ExecStatus(status).name}" + ) + + def _scroll(self, value: int, mode: str) -> None: + self._check_result_for_fetch() + assert self.pgresult + if mode == "relative": + newpos = self._pos + value + elif mode == "absolute": + newpos = value + else: + raise ValueError(f"bad mode: {mode}. It should be 'relative' or 'absolute'") + if not 0 <= newpos < self.pgresult.ntuples: + raise IndexError("position out of bound") + self._pos = newpos + + def _close(self) -> None: + """Non-blocking part of closing. Common to sync/async.""" + # Don't reset the query because it may be useful to investigate after + # an error. + self._reset(reset_query=False) + self._closed = True + + @property + def _encoding(self) -> str: + return pgconn_encoding(self._pgconn) + + +class Cursor(BaseCursor["Connection[Any]", Row]): + __module__ = "psycopg" + __slots__ = () + _Self = TypeVar("_Self", bound="Cursor[Any]") + + @overload + def __init__(self: "Cursor[Row]", connection: "Connection[Row]"): + ... + + @overload + def __init__( + self: "Cursor[Row]", + connection: "Connection[Any]", + *, + row_factory: RowFactory[Row], + ): + ... + + def __init__( + self, + connection: "Connection[Any]", + *, + row_factory: Optional[RowFactory[Row]] = None, + ): + super().__init__(connection) + self._row_factory = row_factory or connection.row_factory + + def __enter__(self: _Self) -> _Self: + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.close() + + def close(self) -> None: + """ + Close the current cursor and free associated resources. + """ + self._close() + + @property + def row_factory(self) -> RowFactory[Row]: + """Writable attribute to control how result rows are formed.""" + return self._row_factory + + @row_factory.setter + def row_factory(self, row_factory: RowFactory[Row]) -> None: + self._row_factory = row_factory + if self.pgresult: + self._make_row = row_factory(self) + + def _make_row_maker(self) -> RowMaker[Row]: + return self._row_factory(self) + + def execute( + self: _Self, + query: Query, + params: Optional[Params] = None, + *, + prepare: Optional[bool] = None, + binary: Optional[bool] = None, + ) -> _Self: + """ + Execute a query or command to the database. + """ + try: + with self._conn.lock: + self._conn.wait( + self._execute_gen(query, params, prepare=prepare, binary=binary) + ) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + return self + + def executemany( + self, + query: Query, + params_seq: Iterable[Params], + *, + returning: bool = False, + ) -> None: + """ + Execute the same command with a sequence of input data. + """ + try: + if Pipeline.is_supported(): + # If there is already a pipeline, ride it, in order to avoid + # sending unnecessary Sync. + with self._conn.lock: + p = self._conn._pipeline + if p: + self._conn.wait( + self._executemany_gen_pipeline(query, params_seq, returning) + ) + # Otherwise, make a new one + if not p: + with self._conn.pipeline(), self._conn.lock: + self._conn.wait( + self._executemany_gen_pipeline(query, params_seq, returning) + ) + else: + with self._conn.lock: + self._conn.wait( + self._executemany_gen_no_pipeline(query, params_seq, returning) + ) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + def stream( + self, + query: Query, + params: Optional[Params] = None, + *, + binary: Optional[bool] = None, + ) -> Iterator[Row]: + """ + Iterate row-by-row on a result from the database. + """ + if self._pgconn.pipeline_status: + raise e.ProgrammingError("stream() cannot be used in pipeline mode") + + with self._conn.lock: + try: + self._conn.wait(self._stream_send_gen(query, params, binary=binary)) + first = True + while self._conn.wait(self._stream_fetchone_gen(first)): + # We know that, if we got a result, it has a single row. + rec: Row = self._tx.load_row(0, self._make_row) # type: ignore + yield rec + first = False + + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + finally: + if self._pgconn.transaction_status == ACTIVE: + # Try to cancel the query, then consume the results + # already received. + self._conn.cancel() + try: + while self._conn.wait(self._stream_fetchone_gen(first=False)): + pass + except Exception: + pass + + # Try to get out of ACTIVE state. Just do a single attempt, which + # should work to recover from an error or query cancelled. + try: + self._conn.wait(self._stream_fetchone_gen(first=False)) + except Exception: + pass + + def fetchone(self) -> Optional[Row]: + """ + Return the next record from the current recordset. + + Return `!None` the recordset is finished. + + :rtype: Optional[Row], with Row defined by `row_factory` + """ + self._fetch_pipeline() + self._check_result_for_fetch() + record = self._tx.load_row(self._pos, self._make_row) + if record is not None: + self._pos += 1 + return record + + def fetchmany(self, size: int = 0) -> List[Row]: + """ + Return the next `!size` records from the current recordset. + + `!size` default to `!self.arraysize` if not specified. + + :rtype: Sequence[Row], with Row defined by `row_factory` + """ + self._fetch_pipeline() + self._check_result_for_fetch() + assert self.pgresult + + if not size: + size = self.arraysize + records = self._tx.load_rows( + self._pos, + min(self._pos + size, self.pgresult.ntuples), + self._make_row, + ) + self._pos += len(records) + return records + + def fetchall(self) -> List[Row]: + """ + Return all the remaining records from the current recordset. + + :rtype: Sequence[Row], with Row defined by `row_factory` + """ + self._fetch_pipeline() + self._check_result_for_fetch() + assert self.pgresult + records = self._tx.load_rows(self._pos, self.pgresult.ntuples, self._make_row) + self._pos = self.pgresult.ntuples + return records + + def __iter__(self) -> Iterator[Row]: + self._fetch_pipeline() + self._check_result_for_fetch() + + def load(pos: int) -> Optional[Row]: + return self._tx.load_row(pos, self._make_row) + + while True: + row = load(self._pos) + if row is None: + break + self._pos += 1 + yield row + + def scroll(self, value: int, mode: str = "relative") -> None: + """ + Move the cursor in the result set to a new position according to mode. + + If `!mode` is ``'relative'`` (default), `!value` is taken as offset to + the current position in the result set; if set to ``'absolute'``, + `!value` states an absolute target position. + + Raise `!IndexError` in case a scroll operation would leave the result + set. In this case the position will not change. + """ + self._fetch_pipeline() + self._scroll(value, mode) + + @contextmanager + def copy( + self, + statement: Query, + params: Optional[Params] = None, + *, + writer: Optional[CopyWriter] = None, + ) -> Iterator[Copy]: + """ + Initiate a :sql:`COPY` operation and return an object to manage it. + + :rtype: Copy + """ + try: + with self._conn.lock: + self._conn.wait(self._start_copy_gen(statement, params)) + + with Copy(self, writer=writer) as copy: + yield copy + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + # If a fresher result has been set on the cursor by the Copy object, + # read its properties (especially rowcount). + self._select_current_result(0) + + def _fetch_pipeline(self) -> None: + if ( + self._execmany_returning is not False + and not self.pgresult + and self._conn._pipeline + ): + with self._conn.lock: + self._conn.wait(self._conn._pipeline._fetch_gen(flush=True)) diff --git a/lib/python3.11/site-packages/psycopg/cursor_async.py b/lib/python3.11/site-packages/psycopg/cursor_async.py new file mode 100644 index 0000000..ab7b073 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/cursor_async.py @@ -0,0 +1,249 @@ +""" +psycopg async cursor objects +""" + +# Copyright (C) 2020 The Psycopg Team + +from types import TracebackType +from typing import Any, AsyncIterator, Iterable, List +from typing import Optional, Type, TypeVar, TYPE_CHECKING, overload +from contextlib import asynccontextmanager + +from . import pq +from . import errors as e +from .abc import Query, Params +from .copy import AsyncCopy, AsyncWriter as AsyncCopyWriter +from .rows import Row, RowMaker, AsyncRowFactory +from .cursor import BaseCursor +from ._pipeline import Pipeline + +if TYPE_CHECKING: + from .connection_async import AsyncConnection + +ACTIVE = pq.TransactionStatus.ACTIVE + + +class AsyncCursor(BaseCursor["AsyncConnection[Any]", Row]): + __module__ = "psycopg" + __slots__ = () + _Self = TypeVar("_Self", bound="AsyncCursor[Any]") + + @overload + def __init__(self: "AsyncCursor[Row]", connection: "AsyncConnection[Row]"): + ... + + @overload + def __init__( + self: "AsyncCursor[Row]", + connection: "AsyncConnection[Any]", + *, + row_factory: AsyncRowFactory[Row], + ): + ... + + def __init__( + self, + connection: "AsyncConnection[Any]", + *, + row_factory: Optional[AsyncRowFactory[Row]] = None, + ): + super().__init__(connection) + self._row_factory = row_factory or connection.row_factory + + async def __aenter__(self: _Self) -> _Self: + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + await self.close() + + async def close(self) -> None: + self._close() + + @property + def row_factory(self) -> AsyncRowFactory[Row]: + return self._row_factory + + @row_factory.setter + def row_factory(self, row_factory: AsyncRowFactory[Row]) -> None: + self._row_factory = row_factory + if self.pgresult: + self._make_row = row_factory(self) + + def _make_row_maker(self) -> RowMaker[Row]: + return self._row_factory(self) + + async def execute( + self: _Self, + query: Query, + params: Optional[Params] = None, + *, + prepare: Optional[bool] = None, + binary: Optional[bool] = None, + ) -> _Self: + try: + async with self._conn.lock: + await self._conn.wait( + self._execute_gen(query, params, prepare=prepare, binary=binary) + ) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + return self + + async def executemany( + self, + query: Query, + params_seq: Iterable[Params], + *, + returning: bool = False, + ) -> None: + try: + if Pipeline.is_supported(): + # If there is already a pipeline, ride it, in order to avoid + # sending unnecessary Sync. + async with self._conn.lock: + p = self._conn._pipeline + if p: + await self._conn.wait( + self._executemany_gen_pipeline(query, params_seq, returning) + ) + # Otherwise, make a new one + if not p: + async with self._conn.pipeline(), self._conn.lock: + await self._conn.wait( + self._executemany_gen_pipeline(query, params_seq, returning) + ) + else: + await self._conn.wait( + self._executemany_gen_no_pipeline(query, params_seq, returning) + ) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + async def stream( + self, + query: Query, + params: Optional[Params] = None, + *, + binary: Optional[bool] = None, + ) -> AsyncIterator[Row]: + if self._pgconn.pipeline_status: + raise e.ProgrammingError("stream() cannot be used in pipeline mode") + + async with self._conn.lock: + try: + await self._conn.wait( + self._stream_send_gen(query, params, binary=binary) + ) + first = True + while await self._conn.wait(self._stream_fetchone_gen(first)): + # We know that, if we got a result, it has a single row. + rec: Row = self._tx.load_row(0, self._make_row) # type: ignore + yield rec + first = False + + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + finally: + if self._pgconn.transaction_status == ACTIVE: + # Try to cancel the query, then consume the results + # already received. + self._conn.cancel() + try: + while await self._conn.wait( + self._stream_fetchone_gen(first=False) + ): + pass + except Exception: + pass + + # Try to get out of ACTIVE state. Just do a single attempt, which + # should work to recover from an error or query cancelled. + try: + await self._conn.wait(self._stream_fetchone_gen(first=False)) + except Exception: + pass + + async def fetchone(self) -> Optional[Row]: + await self._fetch_pipeline() + self._check_result_for_fetch() + record = self._tx.load_row(self._pos, self._make_row) + if record is not None: + self._pos += 1 + return record + + async def fetchmany(self, size: int = 0) -> List[Row]: + await self._fetch_pipeline() + self._check_result_for_fetch() + assert self.pgresult + + if not size: + size = self.arraysize + records = self._tx.load_rows( + self._pos, + min(self._pos + size, self.pgresult.ntuples), + self._make_row, + ) + self._pos += len(records) + return records + + async def fetchall(self) -> List[Row]: + await self._fetch_pipeline() + self._check_result_for_fetch() + assert self.pgresult + records = self._tx.load_rows(self._pos, self.pgresult.ntuples, self._make_row) + self._pos = self.pgresult.ntuples + return records + + async def __aiter__(self) -> AsyncIterator[Row]: + await self._fetch_pipeline() + self._check_result_for_fetch() + + def load(pos: int) -> Optional[Row]: + return self._tx.load_row(pos, self._make_row) + + while True: + row = load(self._pos) + if row is None: + break + self._pos += 1 + yield row + + async def scroll(self, value: int, mode: str = "relative") -> None: + self._scroll(value, mode) + + @asynccontextmanager + async def copy( + self, + statement: Query, + params: Optional[Params] = None, + *, + writer: Optional[AsyncCopyWriter] = None, + ) -> AsyncIterator[AsyncCopy]: + """ + :rtype: AsyncCopy + """ + try: + async with self._conn.lock: + await self._conn.wait(self._start_copy_gen(statement, params)) + + async with AsyncCopy(self, writer=writer) as copy: + yield copy + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + self._select_current_result(0) + + async def _fetch_pipeline(self) -> None: + if ( + self._execmany_returning is not False + and not self.pgresult + and self._conn._pipeline + ): + async with self._conn.lock: + await self._conn.wait(self._conn._pipeline._fetch_gen(flush=True)) diff --git a/lib/python3.11/site-packages/psycopg/dbapi20.py b/lib/python3.11/site-packages/psycopg/dbapi20.py new file mode 100644 index 0000000..3c3d8b7 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/dbapi20.py @@ -0,0 +1,112 @@ +""" +Compatibility objects with DBAPI 2.0 +""" + +# Copyright (C) 2020 The Psycopg Team + +import time +import datetime as dt +from math import floor +from typing import Any, Sequence, Union + +from . import postgres +from .abc import AdaptContext, Buffer +from .types.string import BytesDumper, BytesBinaryDumper + + +class DBAPITypeObject: + def __init__(self, name: str, type_names: Sequence[str]): + self.name = name + self.values = tuple(postgres.types[n].oid for n in type_names) + + def __repr__(self) -> str: + return f"psycopg.{self.name}" + + def __eq__(self, other: Any) -> bool: + if isinstance(other, int): + return other in self.values + else: + return NotImplemented + + def __ne__(self, other: Any) -> bool: + if isinstance(other, int): + return other not in self.values + else: + return NotImplemented + + +BINARY = DBAPITypeObject("BINARY", ("bytea",)) +DATETIME = DBAPITypeObject( + "DATETIME", "timestamp timestamptz date time timetz interval".split() +) +NUMBER = DBAPITypeObject("NUMBER", "int2 int4 int8 float4 float8 numeric".split()) +ROWID = DBAPITypeObject("ROWID", ("oid",)) +STRING = DBAPITypeObject("STRING", "text varchar bpchar".split()) + + +class Binary: + def __init__(self, obj: Any): + self.obj = obj + + def __repr__(self) -> str: + sobj = repr(self.obj) + if len(sobj) > 40: + sobj = f"{sobj[:35]} ... ({len(sobj)} byteschars)" + return f"{self.__class__.__name__}({sobj})" + + +class BinaryBinaryDumper(BytesBinaryDumper): + def dump(self, obj: Union[Buffer, Binary]) -> Buffer: + if isinstance(obj, Binary): + return super().dump(obj.obj) + else: + return super().dump(obj) + + +class BinaryTextDumper(BytesDumper): + def dump(self, obj: Union[Buffer, Binary]) -> Buffer: + if isinstance(obj, Binary): + return super().dump(obj.obj) + else: + return super().dump(obj) + + +def Date(year: int, month: int, day: int) -> dt.date: + return dt.date(year, month, day) + + +def DateFromTicks(ticks: float) -> dt.date: + return TimestampFromTicks(ticks).date() + + +def Time(hour: int, minute: int, second: int) -> dt.time: + return dt.time(hour, minute, second) + + +def TimeFromTicks(ticks: float) -> dt.time: + return TimestampFromTicks(ticks).time() + + +def Timestamp( + year: int, month: int, day: int, hour: int, minute: int, second: int +) -> dt.datetime: + return dt.datetime(year, month, day, hour, minute, second) + + +def TimestampFromTicks(ticks: float) -> dt.datetime: + secs = floor(ticks) + frac = ticks - secs + t = time.localtime(ticks) + tzinfo = dt.timezone(dt.timedelta(seconds=t.tm_gmtoff)) + rv = dt.datetime(*t[:6], round(frac * 1_000_000), tzinfo=tzinfo) + return rv + + +def register_dbapi20_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper(Binary, BinaryTextDumper) + adapters.register_dumper(Binary, BinaryBinaryDumper) + + # Make them also the default dumpers when dumping by bytea oid + adapters.register_dumper(None, BinaryTextDumper) + adapters.register_dumper(None, BinaryBinaryDumper) diff --git a/lib/python3.11/site-packages/psycopg/errors.py b/lib/python3.11/site-packages/psycopg/errors.py new file mode 100644 index 0000000..d8b7f6f --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/errors.py @@ -0,0 +1,1544 @@ +""" +psycopg exceptions + +DBAPI-defined Exceptions are defined in the following hierarchy:: + + Exceptions + |__Warning + |__Error + |__InterfaceError + |__DatabaseError + |__DataError + |__OperationalError + |__IntegrityError + |__InternalError + |__ProgrammingError + |__NotSupportedError +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Any, Dict, Optional, Sequence, Tuple, Type, Union +from typing_extensions import TypeAlias +from asyncio import CancelledError + +from .pq.abc import PGconn, PGresult +from .pq._enums import DiagnosticField +from ._compat import TypeGuard + +ErrorInfo: TypeAlias = Union[None, PGresult, Dict[int, Optional[bytes]]] + +_sqlcodes: Dict[str, "Type[Error]"] = {} + + +class Warning(Exception): + """ + Exception raised for important warnings. + + Defined for DBAPI compatibility, but never raised by ``psycopg``. + """ + + __module__ = "psycopg" + + +class Error(Exception): + """ + Base exception for all the errors psycopg will raise. + + Exception that is the base class of all other error exceptions. You can + use this to catch all errors with one single `!except` statement. + + This exception is guaranteed to be picklable. + """ + + __module__ = "psycopg" + + sqlstate: Optional[str] = None + + def __init__( + self, + *args: Sequence[Any], + info: ErrorInfo = None, + encoding: str = "utf-8", + pgconn: Optional[PGconn] = None + ): + super().__init__(*args) + self._info = info + self._encoding = encoding + self._pgconn = pgconn + + # Handle sqlstate codes for which we don't have a class. + if not self.sqlstate and info: + self.sqlstate = self.diag.sqlstate + + @property + def pgconn(self) -> Optional[PGconn]: + """The connection object, if the error was raised from a connection attempt. + + :rtype: Optional[psycopg.pq.PGconn] + """ + return self._pgconn if self._pgconn else None + + @property + def pgresult(self) -> Optional[PGresult]: + """The result object, if the exception was raised after a failed query. + + :rtype: Optional[psycopg.pq.PGresult] + """ + return self._info if _is_pgresult(self._info) else None + + @property + def diag(self) -> "Diagnostic": + """ + A `Diagnostic` object to inspect details of the errors from the database. + """ + return Diagnostic(self._info, encoding=self._encoding) + + def __reduce__(self) -> Union[str, Tuple[Any, ...]]: + res = super().__reduce__() + if isinstance(res, tuple) and len(res) >= 3: + # To make the exception picklable + res[2]["_info"] = _info_to_dict(self._info) + res[2]["_pgconn"] = None + + return res + + +class InterfaceError(Error): + """ + An error related to the database interface rather than the database itself. + """ + + __module__ = "psycopg" + + +class DatabaseError(Error): + """ + Exception raised for errors that are related to the database. + """ + + __module__ = "psycopg" + + def __init_subclass__(cls, code: Optional[str] = None, name: Optional[str] = None): + if code: + _sqlcodes[code] = cls + cls.sqlstate = code + if name: + _sqlcodes[name] = cls + + +class DataError(DatabaseError): + """ + An error caused by problems with the processed data. + + Examples may be division by zero, numeric value out of range, etc. + """ + + __module__ = "psycopg" + + +class OperationalError(DatabaseError): + """ + An error related to the database's operation. + + These errors are not necessarily under the control of the programmer, e.g. + an unexpected disconnect occurs, the data source name is not found, a + transaction could not be processed, a memory allocation error occurred + during processing, etc. + """ + + __module__ = "psycopg" + + +class IntegrityError(DatabaseError): + """ + An error caused when the relational integrity of the database is affected. + + An example may be a foreign key check failed. + """ + + __module__ = "psycopg" + + +class InternalError(DatabaseError): + """ + An error generated when the database encounters an internal error, + + Examples could be the cursor is not valid anymore, the transaction is out + of sync, etc. + """ + + __module__ = "psycopg" + + +class ProgrammingError(DatabaseError): + """ + Exception raised for programming errors + + Examples may be table not found or already exists, syntax error in the SQL + statement, wrong number of parameters specified, etc. + """ + + __module__ = "psycopg" + + +class NotSupportedError(DatabaseError): + """ + A method or database API was used which is not supported by the database. + """ + + __module__ = "psycopg" + + +class ConnectionTimeout(OperationalError): + """ + Exception raised on timeout of the `~psycopg.Connection.connect()` method. + + The error is raised if the ``connect_timeout`` is specified and a + connection is not obtained in useful time. + + Subclass of `~psycopg.OperationalError`. + """ + + +class PipelineAborted(OperationalError): + """ + Raised when a operation fails because the current pipeline is in aborted state. + + Subclass of `~psycopg.OperationalError`. + """ + + +class Diagnostic: + """Details from a database error report.""" + + def __init__(self, info: ErrorInfo, encoding: str = "utf-8"): + self._info = info + self._encoding = encoding + + @property + def severity(self) -> Optional[str]: + return self._error_message(DiagnosticField.SEVERITY) + + @property + def severity_nonlocalized(self) -> Optional[str]: + return self._error_message(DiagnosticField.SEVERITY_NONLOCALIZED) + + @property + def sqlstate(self) -> Optional[str]: + return self._error_message(DiagnosticField.SQLSTATE) + + @property + def message_primary(self) -> Optional[str]: + return self._error_message(DiagnosticField.MESSAGE_PRIMARY) + + @property + def message_detail(self) -> Optional[str]: + return self._error_message(DiagnosticField.MESSAGE_DETAIL) + + @property + def message_hint(self) -> Optional[str]: + return self._error_message(DiagnosticField.MESSAGE_HINT) + + @property + def statement_position(self) -> Optional[str]: + return self._error_message(DiagnosticField.STATEMENT_POSITION) + + @property + def internal_position(self) -> Optional[str]: + return self._error_message(DiagnosticField.INTERNAL_POSITION) + + @property + def internal_query(self) -> Optional[str]: + return self._error_message(DiagnosticField.INTERNAL_QUERY) + + @property + def context(self) -> Optional[str]: + return self._error_message(DiagnosticField.CONTEXT) + + @property + def schema_name(self) -> Optional[str]: + return self._error_message(DiagnosticField.SCHEMA_NAME) + + @property + def table_name(self) -> Optional[str]: + return self._error_message(DiagnosticField.TABLE_NAME) + + @property + def column_name(self) -> Optional[str]: + return self._error_message(DiagnosticField.COLUMN_NAME) + + @property + def datatype_name(self) -> Optional[str]: + return self._error_message(DiagnosticField.DATATYPE_NAME) + + @property + def constraint_name(self) -> Optional[str]: + return self._error_message(DiagnosticField.CONSTRAINT_NAME) + + @property + def source_file(self) -> Optional[str]: + return self._error_message(DiagnosticField.SOURCE_FILE) + + @property + def source_line(self) -> Optional[str]: + return self._error_message(DiagnosticField.SOURCE_LINE) + + @property + def source_function(self) -> Optional[str]: + return self._error_message(DiagnosticField.SOURCE_FUNCTION) + + def _error_message(self, field: DiagnosticField) -> Optional[str]: + if self._info: + if isinstance(self._info, dict): + val = self._info.get(field) + else: + val = self._info.error_field(field) + + if val is not None: + return val.decode(self._encoding, "replace") + + return None + + def __reduce__(self) -> Union[str, Tuple[Any, ...]]: + res = super().__reduce__() + if isinstance(res, tuple) and len(res) >= 3: + res[2]["_info"] = _info_to_dict(self._info) + + return res + + +def _info_to_dict(info: ErrorInfo) -> ErrorInfo: + """ + Convert a PGresult to a dictionary to make the info picklable. + """ + # PGresult is a protocol, can't use isinstance + if _is_pgresult(info): + return {v: info.error_field(v) for v in DiagnosticField} + else: + return info + + +def lookup(sqlstate: str) -> Type[Error]: + """Lookup an error code or `constant name`__ and return its exception class. + + Raise `!KeyError` if the code is not found. + + .. __: https://www.postgresql.org/docs/current/errcodes-appendix.html + #ERRCODES-TABLE + """ + return _sqlcodes[sqlstate.upper()] + + +def error_from_result(result: PGresult, encoding: str = "utf-8") -> Error: + from psycopg import pq + + state = result.error_field(DiagnosticField.SQLSTATE) or b"" + cls = _class_for_state(state.decode("ascii")) + return cls( + pq.error_message(result, encoding=encoding), + info=result, + encoding=encoding, + ) + + +def _is_pgresult(info: ErrorInfo) -> TypeGuard[PGresult]: + """Return True if an ErrorInfo is a PGresult instance.""" + # PGresult is a protocol, can't use isinstance + return hasattr(info, "error_field") + + +def _class_for_state(sqlstate: str) -> Type[Error]: + try: + return lookup(sqlstate) + except KeyError: + return get_base_exception(sqlstate) + + +def get_base_exception(sqlstate: str) -> Type[Error]: + return ( + _base_exc_map.get(sqlstate[:2]) + or _base_exc_map.get(sqlstate[:1]) + or DatabaseError + ) + + +_base_exc_map = { + "08": OperationalError, # Connection Exception + "0A": NotSupportedError, # Feature Not Supported + "20": ProgrammingError, # Case Not Foud + "21": ProgrammingError, # Cardinality Violation + "22": DataError, # Data Exception + "23": IntegrityError, # Integrity Constraint Violation + "24": InternalError, # Invalid Cursor State + "25": InternalError, # Invalid Transaction State + "26": ProgrammingError, # Invalid SQL Statement Name * + "27": OperationalError, # Triggered Data Change Violation + "28": OperationalError, # Invalid Authorization Specification + "2B": InternalError, # Dependent Privilege Descriptors Still Exist + "2D": InternalError, # Invalid Transaction Termination + "2F": OperationalError, # SQL Routine Exception * + "34": ProgrammingError, # Invalid Cursor Name * + "38": OperationalError, # External Routine Exception * + "39": OperationalError, # External Routine Invocation Exception * + "3B": OperationalError, # Savepoint Exception * + "3D": ProgrammingError, # Invalid Catalog Name + "3F": ProgrammingError, # Invalid Schema Name + "40": OperationalError, # Transaction Rollback + "42": ProgrammingError, # Syntax Error or Access Rule Violation + "44": ProgrammingError, # WITH CHECK OPTION Violation + "53": OperationalError, # Insufficient Resources + "54": OperationalError, # Program Limit Exceeded + "55": OperationalError, # Object Not In Prerequisite State + "57": OperationalError, # Operator Intervention + "58": OperationalError, # System Error (errors external to PostgreSQL itself) + "F": OperationalError, # Configuration File Error + "H": OperationalError, # Foreign Data Wrapper Error (SQL/MED) + "P": ProgrammingError, # PL/pgSQL Error + "X": InternalError, # Internal Error +} + + +# Error classes generated by tools/update_errors.py + +# fmt: off +# autogenerated: start + + +# Class 02 - No Data (this is also a warning class per the SQL standard) + +class NoData(DatabaseError, + code='02000', name='NO_DATA'): + pass + +class NoAdditionalDynamicResultSetsReturned(DatabaseError, + code='02001', name='NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED'): + pass + + +# Class 03 - SQL Statement Not Yet Complete + +class SqlStatementNotYetComplete(DatabaseError, + code='03000', name='SQL_STATEMENT_NOT_YET_COMPLETE'): + pass + + +# Class 08 - Connection Exception + +class ConnectionException(OperationalError, + code='08000', name='CONNECTION_EXCEPTION'): + pass + +class SqlclientUnableToEstablishSqlconnection(OperationalError, + code='08001', name='SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION'): + pass + +class ConnectionDoesNotExist(OperationalError, + code='08003', name='CONNECTION_DOES_NOT_EXIST'): + pass + +class SqlserverRejectedEstablishmentOfSqlconnection(OperationalError, + code='08004', name='SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION'): + pass + +class ConnectionFailure(OperationalError, + code='08006', name='CONNECTION_FAILURE'): + pass + +class TransactionResolutionUnknown(OperationalError, + code='08007', name='TRANSACTION_RESOLUTION_UNKNOWN'): + pass + +class ProtocolViolation(OperationalError, + code='08P01', name='PROTOCOL_VIOLATION'): + pass + + +# Class 09 - Triggered Action Exception + +class TriggeredActionException(DatabaseError, + code='09000', name='TRIGGERED_ACTION_EXCEPTION'): + pass + + +# Class 0A - Feature Not Supported + +class FeatureNotSupported(NotSupportedError, + code='0A000', name='FEATURE_NOT_SUPPORTED'): + pass + + +# Class 0B - Invalid Transaction Initiation + +class InvalidTransactionInitiation(DatabaseError, + code='0B000', name='INVALID_TRANSACTION_INITIATION'): + pass + + +# Class 0F - Locator Exception + +class LocatorException(DatabaseError, + code='0F000', name='LOCATOR_EXCEPTION'): + pass + +class InvalidLocatorSpecification(DatabaseError, + code='0F001', name='INVALID_LOCATOR_SPECIFICATION'): + pass + + +# Class 0L - Invalid Grantor + +class InvalidGrantor(DatabaseError, + code='0L000', name='INVALID_GRANTOR'): + pass + +class InvalidGrantOperation(DatabaseError, + code='0LP01', name='INVALID_GRANT_OPERATION'): + pass + + +# Class 0P - Invalid Role Specification + +class InvalidRoleSpecification(DatabaseError, + code='0P000', name='INVALID_ROLE_SPECIFICATION'): + pass + + +# Class 0Z - Diagnostics Exception + +class DiagnosticsException(DatabaseError, + code='0Z000', name='DIAGNOSTICS_EXCEPTION'): + pass + +class StackedDiagnosticsAccessedWithoutActiveHandler(DatabaseError, + code='0Z002', name='STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER'): + pass + + +# Class 20 - Case Not Found + +class CaseNotFound(ProgrammingError, + code='20000', name='CASE_NOT_FOUND'): + pass + + +# Class 21 - Cardinality Violation + +class CardinalityViolation(ProgrammingError, + code='21000', name='CARDINALITY_VIOLATION'): + pass + + +# Class 22 - Data Exception + +class DataException(DataError, + code='22000', name='DATA_EXCEPTION'): + pass + +class StringDataRightTruncation(DataError, + code='22001', name='STRING_DATA_RIGHT_TRUNCATION'): + pass + +class NullValueNoIndicatorParameter(DataError, + code='22002', name='NULL_VALUE_NO_INDICATOR_PARAMETER'): + pass + +class NumericValueOutOfRange(DataError, + code='22003', name='NUMERIC_VALUE_OUT_OF_RANGE'): + pass + +class NullValueNotAllowed(DataError, + code='22004', name='NULL_VALUE_NOT_ALLOWED'): + pass + +class ErrorInAssignment(DataError, + code='22005', name='ERROR_IN_ASSIGNMENT'): + pass + +class InvalidDatetimeFormat(DataError, + code='22007', name='INVALID_DATETIME_FORMAT'): + pass + +class DatetimeFieldOverflow(DataError, + code='22008', name='DATETIME_FIELD_OVERFLOW'): + pass + +class InvalidTimeZoneDisplacementValue(DataError, + code='22009', name='INVALID_TIME_ZONE_DISPLACEMENT_VALUE'): + pass + +class EscapeCharacterConflict(DataError, + code='2200B', name='ESCAPE_CHARACTER_CONFLICT'): + pass + +class InvalidUseOfEscapeCharacter(DataError, + code='2200C', name='INVALID_USE_OF_ESCAPE_CHARACTER'): + pass + +class InvalidEscapeOctet(DataError, + code='2200D', name='INVALID_ESCAPE_OCTET'): + pass + +class ZeroLengthCharacterString(DataError, + code='2200F', name='ZERO_LENGTH_CHARACTER_STRING'): + pass + +class MostSpecificTypeMismatch(DataError, + code='2200G', name='MOST_SPECIFIC_TYPE_MISMATCH'): + pass + +class SequenceGeneratorLimitExceeded(DataError, + code='2200H', name='SEQUENCE_GENERATOR_LIMIT_EXCEEDED'): + pass + +class NotAnXmlDocument(DataError, + code='2200L', name='NOT_AN_XML_DOCUMENT'): + pass + +class InvalidXmlDocument(DataError, + code='2200M', name='INVALID_XML_DOCUMENT'): + pass + +class InvalidXmlContent(DataError, + code='2200N', name='INVALID_XML_CONTENT'): + pass + +class InvalidXmlComment(DataError, + code='2200S', name='INVALID_XML_COMMENT'): + pass + +class InvalidXmlProcessingInstruction(DataError, + code='2200T', name='INVALID_XML_PROCESSING_INSTRUCTION'): + pass + +class InvalidIndicatorParameterValue(DataError, + code='22010', name='INVALID_INDICATOR_PARAMETER_VALUE'): + pass + +class SubstringError(DataError, + code='22011', name='SUBSTRING_ERROR'): + pass + +class DivisionByZero(DataError, + code='22012', name='DIVISION_BY_ZERO'): + pass + +class InvalidPrecedingOrFollowingSize(DataError, + code='22013', name='INVALID_PRECEDING_OR_FOLLOWING_SIZE'): + pass + +class InvalidArgumentForNtileFunction(DataError, + code='22014', name='INVALID_ARGUMENT_FOR_NTILE_FUNCTION'): + pass + +class IntervalFieldOverflow(DataError, + code='22015', name='INTERVAL_FIELD_OVERFLOW'): + pass + +class InvalidArgumentForNthValueFunction(DataError, + code='22016', name='INVALID_ARGUMENT_FOR_NTH_VALUE_FUNCTION'): + pass + +class InvalidCharacterValueForCast(DataError, + code='22018', name='INVALID_CHARACTER_VALUE_FOR_CAST'): + pass + +class InvalidEscapeCharacter(DataError, + code='22019', name='INVALID_ESCAPE_CHARACTER'): + pass + +class InvalidRegularExpression(DataError, + code='2201B', name='INVALID_REGULAR_EXPRESSION'): + pass + +class InvalidArgumentForLogarithm(DataError, + code='2201E', name='INVALID_ARGUMENT_FOR_LOGARITHM'): + pass + +class InvalidArgumentForPowerFunction(DataError, + code='2201F', name='INVALID_ARGUMENT_FOR_POWER_FUNCTION'): + pass + +class InvalidArgumentForWidthBucketFunction(DataError, + code='2201G', name='INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION'): + pass + +class InvalidRowCountInLimitClause(DataError, + code='2201W', name='INVALID_ROW_COUNT_IN_LIMIT_CLAUSE'): + pass + +class InvalidRowCountInResultOffsetClause(DataError, + code='2201X', name='INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE'): + pass + +class CharacterNotInRepertoire(DataError, + code='22021', name='CHARACTER_NOT_IN_REPERTOIRE'): + pass + +class IndicatorOverflow(DataError, + code='22022', name='INDICATOR_OVERFLOW'): + pass + +class InvalidParameterValue(DataError, + code='22023', name='INVALID_PARAMETER_VALUE'): + pass + +class UnterminatedCString(DataError, + code='22024', name='UNTERMINATED_C_STRING'): + pass + +class InvalidEscapeSequence(DataError, + code='22025', name='INVALID_ESCAPE_SEQUENCE'): + pass + +class StringDataLengthMismatch(DataError, + code='22026', name='STRING_DATA_LENGTH_MISMATCH'): + pass + +class TrimError(DataError, + code='22027', name='TRIM_ERROR'): + pass + +class ArraySubscriptError(DataError, + code='2202E', name='ARRAY_SUBSCRIPT_ERROR'): + pass + +class InvalidTablesampleRepeat(DataError, + code='2202G', name='INVALID_TABLESAMPLE_REPEAT'): + pass + +class InvalidTablesampleArgument(DataError, + code='2202H', name='INVALID_TABLESAMPLE_ARGUMENT'): + pass + +class DuplicateJsonObjectKeyValue(DataError, + code='22030', name='DUPLICATE_JSON_OBJECT_KEY_VALUE'): + pass + +class InvalidArgumentForSqlJsonDatetimeFunction(DataError, + code='22031', name='INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION'): + pass + +class InvalidJsonText(DataError, + code='22032', name='INVALID_JSON_TEXT'): + pass + +class InvalidSqlJsonSubscript(DataError, + code='22033', name='INVALID_SQL_JSON_SUBSCRIPT'): + pass + +class MoreThanOneSqlJsonItem(DataError, + code='22034', name='MORE_THAN_ONE_SQL_JSON_ITEM'): + pass + +class NoSqlJsonItem(DataError, + code='22035', name='NO_SQL_JSON_ITEM'): + pass + +class NonNumericSqlJsonItem(DataError, + code='22036', name='NON_NUMERIC_SQL_JSON_ITEM'): + pass + +class NonUniqueKeysInAJsonObject(DataError, + code='22037', name='NON_UNIQUE_KEYS_IN_A_JSON_OBJECT'): + pass + +class SingletonSqlJsonItemRequired(DataError, + code='22038', name='SINGLETON_SQL_JSON_ITEM_REQUIRED'): + pass + +class SqlJsonArrayNotFound(DataError, + code='22039', name='SQL_JSON_ARRAY_NOT_FOUND'): + pass + +class SqlJsonMemberNotFound(DataError, + code='2203A', name='SQL_JSON_MEMBER_NOT_FOUND'): + pass + +class SqlJsonNumberNotFound(DataError, + code='2203B', name='SQL_JSON_NUMBER_NOT_FOUND'): + pass + +class SqlJsonObjectNotFound(DataError, + code='2203C', name='SQL_JSON_OBJECT_NOT_FOUND'): + pass + +class TooManyJsonArrayElements(DataError, + code='2203D', name='TOO_MANY_JSON_ARRAY_ELEMENTS'): + pass + +class TooManyJsonObjectMembers(DataError, + code='2203E', name='TOO_MANY_JSON_OBJECT_MEMBERS'): + pass + +class SqlJsonScalarRequired(DataError, + code='2203F', name='SQL_JSON_SCALAR_REQUIRED'): + pass + +class SqlJsonItemCannotBeCastToTargetType(DataError, + code='2203G', name='SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE'): + pass + +class FloatingPointException(DataError, + code='22P01', name='FLOATING_POINT_EXCEPTION'): + pass + +class InvalidTextRepresentation(DataError, + code='22P02', name='INVALID_TEXT_REPRESENTATION'): + pass + +class InvalidBinaryRepresentation(DataError, + code='22P03', name='INVALID_BINARY_REPRESENTATION'): + pass + +class BadCopyFileFormat(DataError, + code='22P04', name='BAD_COPY_FILE_FORMAT'): + pass + +class UntranslatableCharacter(DataError, + code='22P05', name='UNTRANSLATABLE_CHARACTER'): + pass + +class NonstandardUseOfEscapeCharacter(DataError, + code='22P06', name='NONSTANDARD_USE_OF_ESCAPE_CHARACTER'): + pass + + +# Class 23 - Integrity Constraint Violation + +class IntegrityConstraintViolation(IntegrityError, + code='23000', name='INTEGRITY_CONSTRAINT_VIOLATION'): + pass + +class RestrictViolation(IntegrityError, + code='23001', name='RESTRICT_VIOLATION'): + pass + +class NotNullViolation(IntegrityError, + code='23502', name='NOT_NULL_VIOLATION'): + pass + +class ForeignKeyViolation(IntegrityError, + code='23503', name='FOREIGN_KEY_VIOLATION'): + pass + +class UniqueViolation(IntegrityError, + code='23505', name='UNIQUE_VIOLATION'): + pass + +class CheckViolation(IntegrityError, + code='23514', name='CHECK_VIOLATION'): + pass + +class ExclusionViolation(IntegrityError, + code='23P01', name='EXCLUSION_VIOLATION'): + pass + + +# Class 24 - Invalid Cursor State + +class InvalidCursorState(InternalError, + code='24000', name='INVALID_CURSOR_STATE'): + pass + + +# Class 25 - Invalid Transaction State + +class InvalidTransactionState(InternalError, + code='25000', name='INVALID_TRANSACTION_STATE'): + pass + +class ActiveSqlTransaction(InternalError, + code='25001', name='ACTIVE_SQL_TRANSACTION'): + pass + +class BranchTransactionAlreadyActive(InternalError, + code='25002', name='BRANCH_TRANSACTION_ALREADY_ACTIVE'): + pass + +class InappropriateAccessModeForBranchTransaction(InternalError, + code='25003', name='INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION'): + pass + +class InappropriateIsolationLevelForBranchTransaction(InternalError, + code='25004', name='INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION'): + pass + +class NoActiveSqlTransactionForBranchTransaction(InternalError, + code='25005', name='NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION'): + pass + +class ReadOnlySqlTransaction(InternalError, + code='25006', name='READ_ONLY_SQL_TRANSACTION'): + pass + +class SchemaAndDataStatementMixingNotSupported(InternalError, + code='25007', name='SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED'): + pass + +class HeldCursorRequiresSameIsolationLevel(InternalError, + code='25008', name='HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL'): + pass + +class NoActiveSqlTransaction(InternalError, + code='25P01', name='NO_ACTIVE_SQL_TRANSACTION'): + pass + +class InFailedSqlTransaction(InternalError, + code='25P02', name='IN_FAILED_SQL_TRANSACTION'): + pass + +class IdleInTransactionSessionTimeout(InternalError, + code='25P03', name='IDLE_IN_TRANSACTION_SESSION_TIMEOUT'): + pass + + +# Class 26 - Invalid SQL Statement Name + +class InvalidSqlStatementName(ProgrammingError, + code='26000', name='INVALID_SQL_STATEMENT_NAME'): + pass + + +# Class 27 - Triggered Data Change Violation + +class TriggeredDataChangeViolation(OperationalError, + code='27000', name='TRIGGERED_DATA_CHANGE_VIOLATION'): + pass + + +# Class 28 - Invalid Authorization Specification + +class InvalidAuthorizationSpecification(OperationalError, + code='28000', name='INVALID_AUTHORIZATION_SPECIFICATION'): + pass + +class InvalidPassword(OperationalError, + code='28P01', name='INVALID_PASSWORD'): + pass + + +# Class 2B - Dependent Privilege Descriptors Still Exist + +class DependentPrivilegeDescriptorsStillExist(InternalError, + code='2B000', name='DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST'): + pass + +class DependentObjectsStillExist(InternalError, + code='2BP01', name='DEPENDENT_OBJECTS_STILL_EXIST'): + pass + + +# Class 2D - Invalid Transaction Termination + +class InvalidTransactionTermination(InternalError, + code='2D000', name='INVALID_TRANSACTION_TERMINATION'): + pass + + +# Class 2F - SQL Routine Exception + +class SqlRoutineException(OperationalError, + code='2F000', name='SQL_ROUTINE_EXCEPTION'): + pass + +class ModifyingSqlDataNotPermitted(OperationalError, + code='2F002', name='MODIFYING_SQL_DATA_NOT_PERMITTED'): + pass + +class ProhibitedSqlStatementAttempted(OperationalError, + code='2F003', name='PROHIBITED_SQL_STATEMENT_ATTEMPTED'): + pass + +class ReadingSqlDataNotPermitted(OperationalError, + code='2F004', name='READING_SQL_DATA_NOT_PERMITTED'): + pass + +class FunctionExecutedNoReturnStatement(OperationalError, + code='2F005', name='FUNCTION_EXECUTED_NO_RETURN_STATEMENT'): + pass + + +# Class 34 - Invalid Cursor Name + +class InvalidCursorName(ProgrammingError, + code='34000', name='INVALID_CURSOR_NAME'): + pass + + +# Class 38 - External Routine Exception + +class ExternalRoutineException(OperationalError, + code='38000', name='EXTERNAL_ROUTINE_EXCEPTION'): + pass + +class ContainingSqlNotPermitted(OperationalError, + code='38001', name='CONTAINING_SQL_NOT_PERMITTED'): + pass + +class ModifyingSqlDataNotPermittedExt(OperationalError, + code='38002', name='MODIFYING_SQL_DATA_NOT_PERMITTED'): + pass + +class ProhibitedSqlStatementAttemptedExt(OperationalError, + code='38003', name='PROHIBITED_SQL_STATEMENT_ATTEMPTED'): + pass + +class ReadingSqlDataNotPermittedExt(OperationalError, + code='38004', name='READING_SQL_DATA_NOT_PERMITTED'): + pass + + +# Class 39 - External Routine Invocation Exception + +class ExternalRoutineInvocationException(OperationalError, + code='39000', name='EXTERNAL_ROUTINE_INVOCATION_EXCEPTION'): + pass + +class InvalidSqlstateReturned(OperationalError, + code='39001', name='INVALID_SQLSTATE_RETURNED'): + pass + +class NullValueNotAllowedExt(OperationalError, + code='39004', name='NULL_VALUE_NOT_ALLOWED'): + pass + +class TriggerProtocolViolated(OperationalError, + code='39P01', name='TRIGGER_PROTOCOL_VIOLATED'): + pass + +class SrfProtocolViolated(OperationalError, + code='39P02', name='SRF_PROTOCOL_VIOLATED'): + pass + +class EventTriggerProtocolViolated(OperationalError, + code='39P03', name='EVENT_TRIGGER_PROTOCOL_VIOLATED'): + pass + + +# Class 3B - Savepoint Exception + +class SavepointException(OperationalError, + code='3B000', name='SAVEPOINT_EXCEPTION'): + pass + +class InvalidSavepointSpecification(OperationalError, + code='3B001', name='INVALID_SAVEPOINT_SPECIFICATION'): + pass + + +# Class 3D - Invalid Catalog Name + +class InvalidCatalogName(ProgrammingError, + code='3D000', name='INVALID_CATALOG_NAME'): + pass + + +# Class 3F - Invalid Schema Name + +class InvalidSchemaName(ProgrammingError, + code='3F000', name='INVALID_SCHEMA_NAME'): + pass + + +# Class 40 - Transaction Rollback + +class TransactionRollback(OperationalError, + code='40000', name='TRANSACTION_ROLLBACK'): + pass + +class SerializationFailure(OperationalError, + code='40001', name='SERIALIZATION_FAILURE'): + pass + +class TransactionIntegrityConstraintViolation(OperationalError, + code='40002', name='TRANSACTION_INTEGRITY_CONSTRAINT_VIOLATION'): + pass + +class StatementCompletionUnknown(OperationalError, + code='40003', name='STATEMENT_COMPLETION_UNKNOWN'): + pass + +class DeadlockDetected(OperationalError, + code='40P01', name='DEADLOCK_DETECTED'): + pass + + +# Class 42 - Syntax Error or Access Rule Violation + +class SyntaxErrorOrAccessRuleViolation(ProgrammingError, + code='42000', name='SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION'): + pass + +class InsufficientPrivilege(ProgrammingError, + code='42501', name='INSUFFICIENT_PRIVILEGE'): + pass + +class SyntaxError(ProgrammingError, + code='42601', name='SYNTAX_ERROR'): + pass + +class InvalidName(ProgrammingError, + code='42602', name='INVALID_NAME'): + pass + +class InvalidColumnDefinition(ProgrammingError, + code='42611', name='INVALID_COLUMN_DEFINITION'): + pass + +class NameTooLong(ProgrammingError, + code='42622', name='NAME_TOO_LONG'): + pass + +class DuplicateColumn(ProgrammingError, + code='42701', name='DUPLICATE_COLUMN'): + pass + +class AmbiguousColumn(ProgrammingError, + code='42702', name='AMBIGUOUS_COLUMN'): + pass + +class UndefinedColumn(ProgrammingError, + code='42703', name='UNDEFINED_COLUMN'): + pass + +class UndefinedObject(ProgrammingError, + code='42704', name='UNDEFINED_OBJECT'): + pass + +class DuplicateObject(ProgrammingError, + code='42710', name='DUPLICATE_OBJECT'): + pass + +class DuplicateAlias(ProgrammingError, + code='42712', name='DUPLICATE_ALIAS'): + pass + +class DuplicateFunction(ProgrammingError, + code='42723', name='DUPLICATE_FUNCTION'): + pass + +class AmbiguousFunction(ProgrammingError, + code='42725', name='AMBIGUOUS_FUNCTION'): + pass + +class GroupingError(ProgrammingError, + code='42803', name='GROUPING_ERROR'): + pass + +class DatatypeMismatch(ProgrammingError, + code='42804', name='DATATYPE_MISMATCH'): + pass + +class WrongObjectType(ProgrammingError, + code='42809', name='WRONG_OBJECT_TYPE'): + pass + +class InvalidForeignKey(ProgrammingError, + code='42830', name='INVALID_FOREIGN_KEY'): + pass + +class CannotCoerce(ProgrammingError, + code='42846', name='CANNOT_COERCE'): + pass + +class UndefinedFunction(ProgrammingError, + code='42883', name='UNDEFINED_FUNCTION'): + pass + +class GeneratedAlways(ProgrammingError, + code='428C9', name='GENERATED_ALWAYS'): + pass + +class ReservedName(ProgrammingError, + code='42939', name='RESERVED_NAME'): + pass + +class UndefinedTable(ProgrammingError, + code='42P01', name='UNDEFINED_TABLE'): + pass + +class UndefinedParameter(ProgrammingError, + code='42P02', name='UNDEFINED_PARAMETER'): + pass + +class DuplicateCursor(ProgrammingError, + code='42P03', name='DUPLICATE_CURSOR'): + pass + +class DuplicateDatabase(ProgrammingError, + code='42P04', name='DUPLICATE_DATABASE'): + pass + +class DuplicatePreparedStatement(ProgrammingError, + code='42P05', name='DUPLICATE_PREPARED_STATEMENT'): + pass + +class DuplicateSchema(ProgrammingError, + code='42P06', name='DUPLICATE_SCHEMA'): + pass + +class DuplicateTable(ProgrammingError, + code='42P07', name='DUPLICATE_TABLE'): + pass + +class AmbiguousParameter(ProgrammingError, + code='42P08', name='AMBIGUOUS_PARAMETER'): + pass + +class AmbiguousAlias(ProgrammingError, + code='42P09', name='AMBIGUOUS_ALIAS'): + pass + +class InvalidColumnReference(ProgrammingError, + code='42P10', name='INVALID_COLUMN_REFERENCE'): + pass + +class InvalidCursorDefinition(ProgrammingError, + code='42P11', name='INVALID_CURSOR_DEFINITION'): + pass + +class InvalidDatabaseDefinition(ProgrammingError, + code='42P12', name='INVALID_DATABASE_DEFINITION'): + pass + +class InvalidFunctionDefinition(ProgrammingError, + code='42P13', name='INVALID_FUNCTION_DEFINITION'): + pass + +class InvalidPreparedStatementDefinition(ProgrammingError, + code='42P14', name='INVALID_PREPARED_STATEMENT_DEFINITION'): + pass + +class InvalidSchemaDefinition(ProgrammingError, + code='42P15', name='INVALID_SCHEMA_DEFINITION'): + pass + +class InvalidTableDefinition(ProgrammingError, + code='42P16', name='INVALID_TABLE_DEFINITION'): + pass + +class InvalidObjectDefinition(ProgrammingError, + code='42P17', name='INVALID_OBJECT_DEFINITION'): + pass + +class IndeterminateDatatype(ProgrammingError, + code='42P18', name='INDETERMINATE_DATATYPE'): + pass + +class InvalidRecursion(ProgrammingError, + code='42P19', name='INVALID_RECURSION'): + pass + +class WindowingError(ProgrammingError, + code='42P20', name='WINDOWING_ERROR'): + pass + +class CollationMismatch(ProgrammingError, + code='42P21', name='COLLATION_MISMATCH'): + pass + +class IndeterminateCollation(ProgrammingError, + code='42P22', name='INDETERMINATE_COLLATION'): + pass + + +# Class 44 - WITH CHECK OPTION Violation + +class WithCheckOptionViolation(ProgrammingError, + code='44000', name='WITH_CHECK_OPTION_VIOLATION'): + pass + + +# Class 53 - Insufficient Resources + +class InsufficientResources(OperationalError, + code='53000', name='INSUFFICIENT_RESOURCES'): + pass + +class DiskFull(OperationalError, + code='53100', name='DISK_FULL'): + pass + +class OutOfMemory(OperationalError, + code='53200', name='OUT_OF_MEMORY'): + pass + +class TooManyConnections(OperationalError, + code='53300', name='TOO_MANY_CONNECTIONS'): + pass + +class ConfigurationLimitExceeded(OperationalError, + code='53400', name='CONFIGURATION_LIMIT_EXCEEDED'): + pass + + +# Class 54 - Program Limit Exceeded + +class ProgramLimitExceeded(OperationalError, + code='54000', name='PROGRAM_LIMIT_EXCEEDED'): + pass + +class StatementTooComplex(OperationalError, + code='54001', name='STATEMENT_TOO_COMPLEX'): + pass + +class TooManyColumns(OperationalError, + code='54011', name='TOO_MANY_COLUMNS'): + pass + +class TooManyArguments(OperationalError, + code='54023', name='TOO_MANY_ARGUMENTS'): + pass + + +# Class 55 - Object Not In Prerequisite State + +class ObjectNotInPrerequisiteState(OperationalError, + code='55000', name='OBJECT_NOT_IN_PREREQUISITE_STATE'): + pass + +class ObjectInUse(OperationalError, + code='55006', name='OBJECT_IN_USE'): + pass + +class CantChangeRuntimeParam(OperationalError, + code='55P02', name='CANT_CHANGE_RUNTIME_PARAM'): + pass + +class LockNotAvailable(OperationalError, + code='55P03', name='LOCK_NOT_AVAILABLE'): + pass + +class UnsafeNewEnumValueUsage(OperationalError, + code='55P04', name='UNSAFE_NEW_ENUM_VALUE_USAGE'): + pass + + +# Class 57 - Operator Intervention + +class OperatorIntervention(OperationalError, + code='57000', name='OPERATOR_INTERVENTION'): + pass + +class QueryCanceled(OperationalError, + code='57014', name='QUERY_CANCELED'): + pass + +class AdminShutdown(OperationalError, + code='57P01', name='ADMIN_SHUTDOWN'): + pass + +class CrashShutdown(OperationalError, + code='57P02', name='CRASH_SHUTDOWN'): + pass + +class CannotConnectNow(OperationalError, + code='57P03', name='CANNOT_CONNECT_NOW'): + pass + +class DatabaseDropped(OperationalError, + code='57P04', name='DATABASE_DROPPED'): + pass + +class IdleSessionTimeout(OperationalError, + code='57P05', name='IDLE_SESSION_TIMEOUT'): + pass + + +# Class 58 - System Error (errors external to PostgreSQL itself) + +class SystemError(OperationalError, + code='58000', name='SYSTEM_ERROR'): + pass + +class IoError(OperationalError, + code='58030', name='IO_ERROR'): + pass + +class UndefinedFile(OperationalError, + code='58P01', name='UNDEFINED_FILE'): + pass + +class DuplicateFile(OperationalError, + code='58P02', name='DUPLICATE_FILE'): + pass + + +# Class 72 - Snapshot Failure + +class SnapshotTooOld(DatabaseError, + code='72000', name='SNAPSHOT_TOO_OLD'): + pass + + +# Class F0 - Configuration File Error + +class ConfigFileError(OperationalError, + code='F0000', name='CONFIG_FILE_ERROR'): + pass + +class LockFileExists(OperationalError, + code='F0001', name='LOCK_FILE_EXISTS'): + pass + + +# Class HV - Foreign Data Wrapper Error (SQL/MED) + +class FdwError(OperationalError, + code='HV000', name='FDW_ERROR'): + pass + +class FdwOutOfMemory(OperationalError, + code='HV001', name='FDW_OUT_OF_MEMORY'): + pass + +class FdwDynamicParameterValueNeeded(OperationalError, + code='HV002', name='FDW_DYNAMIC_PARAMETER_VALUE_NEEDED'): + pass + +class FdwInvalidDataType(OperationalError, + code='HV004', name='FDW_INVALID_DATA_TYPE'): + pass + +class FdwColumnNameNotFound(OperationalError, + code='HV005', name='FDW_COLUMN_NAME_NOT_FOUND'): + pass + +class FdwInvalidDataTypeDescriptors(OperationalError, + code='HV006', name='FDW_INVALID_DATA_TYPE_DESCRIPTORS'): + pass + +class FdwInvalidColumnName(OperationalError, + code='HV007', name='FDW_INVALID_COLUMN_NAME'): + pass + +class FdwInvalidColumnNumber(OperationalError, + code='HV008', name='FDW_INVALID_COLUMN_NUMBER'): + pass + +class FdwInvalidUseOfNullPointer(OperationalError, + code='HV009', name='FDW_INVALID_USE_OF_NULL_POINTER'): + pass + +class FdwInvalidStringFormat(OperationalError, + code='HV00A', name='FDW_INVALID_STRING_FORMAT'): + pass + +class FdwInvalidHandle(OperationalError, + code='HV00B', name='FDW_INVALID_HANDLE'): + pass + +class FdwInvalidOptionIndex(OperationalError, + code='HV00C', name='FDW_INVALID_OPTION_INDEX'): + pass + +class FdwInvalidOptionName(OperationalError, + code='HV00D', name='FDW_INVALID_OPTION_NAME'): + pass + +class FdwOptionNameNotFound(OperationalError, + code='HV00J', name='FDW_OPTION_NAME_NOT_FOUND'): + pass + +class FdwReplyHandle(OperationalError, + code='HV00K', name='FDW_REPLY_HANDLE'): + pass + +class FdwUnableToCreateExecution(OperationalError, + code='HV00L', name='FDW_UNABLE_TO_CREATE_EXECUTION'): + pass + +class FdwUnableToCreateReply(OperationalError, + code='HV00M', name='FDW_UNABLE_TO_CREATE_REPLY'): + pass + +class FdwUnableToEstablishConnection(OperationalError, + code='HV00N', name='FDW_UNABLE_TO_ESTABLISH_CONNECTION'): + pass + +class FdwNoSchemas(OperationalError, + code='HV00P', name='FDW_NO_SCHEMAS'): + pass + +class FdwSchemaNotFound(OperationalError, + code='HV00Q', name='FDW_SCHEMA_NOT_FOUND'): + pass + +class FdwTableNotFound(OperationalError, + code='HV00R', name='FDW_TABLE_NOT_FOUND'): + pass + +class FdwFunctionSequenceError(OperationalError, + code='HV010', name='FDW_FUNCTION_SEQUENCE_ERROR'): + pass + +class FdwTooManyHandles(OperationalError, + code='HV014', name='FDW_TOO_MANY_HANDLES'): + pass + +class FdwInconsistentDescriptorInformation(OperationalError, + code='HV021', name='FDW_INCONSISTENT_DESCRIPTOR_INFORMATION'): + pass + +class FdwInvalidAttributeValue(OperationalError, + code='HV024', name='FDW_INVALID_ATTRIBUTE_VALUE'): + pass + +class FdwInvalidStringLengthOrBufferLength(OperationalError, + code='HV090', name='FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH'): + pass + +class FdwInvalidDescriptorFieldIdentifier(OperationalError, + code='HV091', name='FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER'): + pass + + +# Class P0 - PL/pgSQL Error + +class PlpgsqlError(ProgrammingError, + code='P0000', name='PLPGSQL_ERROR'): + pass + +class RaiseException(ProgrammingError, + code='P0001', name='RAISE_EXCEPTION'): + pass + +class NoDataFound(ProgrammingError, + code='P0002', name='NO_DATA_FOUND'): + pass + +class TooManyRows(ProgrammingError, + code='P0003', name='TOO_MANY_ROWS'): + pass + +class AssertFailure(ProgrammingError, + code='P0004', name='ASSERT_FAILURE'): + pass + + +# Class XX - Internal Error + +class InternalError_(InternalError, + code='XX000', name='INTERNAL_ERROR'): + pass + +class DataCorrupted(InternalError, + code='XX001', name='DATA_CORRUPTED'): + pass + +class IndexCorrupted(InternalError, + code='XX002', name='INDEX_CORRUPTED'): + pass + + +# autogenerated: end +# fmt: on + +# Don't show a complete traceback upon raising these exception. +# Usually the traceback starts from internal functions (for instance in the +# server communication callbacks) but, for the end user, it's more important +# to get the high level information about where the exception was raised, for +# instance in a certain `Cursor.execute()`. + +_NO_TRACEBACK = (Error, KeyboardInterrupt, CancelledError) diff --git a/lib/python3.11/site-packages/psycopg/generators.py b/lib/python3.11/site-packages/psycopg/generators.py new file mode 100644 index 0000000..584fe47 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/generators.py @@ -0,0 +1,320 @@ +""" +Generators implementing communication protocols with the libpq + +Certain operations (connection, querying) are an interleave of libpq calls and +waiting for the socket to be ready. This module contains the code to execute +the operations, yielding a polling state whenever there is to wait. The +functions in the `waiting` module are the ones who wait more or less +cooperatively for the socket to be ready and make these generators continue. + +All these generators yield pairs (fileno, `Wait`) whenever an operation would +block. The generator can be restarted sending the appropriate `Ready` state +when the file descriptor is ready. + +""" + +# Copyright (C) 2020 The Psycopg Team + +import logging +from typing import List, Optional, Union + +from . import pq +from . import errors as e +from .abc import Buffer, PipelineCommand, PQGen, PQGenConn +from .pq.abc import PGconn, PGresult +from .waiting import Wait, Ready +from ._compat import Deque +from ._cmodule import _psycopg +from ._encodings import pgconn_encoding, conninfo_encoding + +OK = pq.ConnStatus.OK +BAD = pq.ConnStatus.BAD + +POLL_OK = pq.PollingStatus.OK +POLL_READING = pq.PollingStatus.READING +POLL_WRITING = pq.PollingStatus.WRITING +POLL_FAILED = pq.PollingStatus.FAILED + +COMMAND_OK = pq.ExecStatus.COMMAND_OK +COPY_OUT = pq.ExecStatus.COPY_OUT +COPY_IN = pq.ExecStatus.COPY_IN +COPY_BOTH = pq.ExecStatus.COPY_BOTH +PIPELINE_SYNC = pq.ExecStatus.PIPELINE_SYNC + +WAIT_R = Wait.R +WAIT_W = Wait.W +WAIT_RW = Wait.RW +READY_R = Ready.R +READY_W = Ready.W +READY_RW = Ready.RW + +logger = logging.getLogger(__name__) + + +def _connect(conninfo: str) -> PQGenConn[PGconn]: + """ + Generator to create a database connection without blocking. + + """ + conn = pq.PGconn.connect_start(conninfo.encode()) + while True: + if conn.status == BAD: + encoding = conninfo_encoding(conninfo) + raise e.OperationalError( + f"connection is bad: {pq.error_message(conn, encoding=encoding)}", + pgconn=conn, + ) + + status = conn.connect_poll() + if status == POLL_OK: + break + elif status == POLL_READING: + yield conn.socket, WAIT_R + elif status == POLL_WRITING: + yield conn.socket, WAIT_W + elif status == POLL_FAILED: + encoding = conninfo_encoding(conninfo) + raise e.OperationalError( + f"connection failed: {pq.error_message(conn, encoding=encoding)}", + pgconn=conn, + ) + else: + raise e.InternalError(f"unexpected poll status: {status}", pgconn=conn) + + conn.nonblocking = 1 + return conn + + +def _execute(pgconn: PGconn) -> PQGen[List[PGresult]]: + """ + Generator sending a query and returning results without blocking. + + The query must have already been sent using `pgconn.send_query()` or + similar. Flush the query and then return the result using nonblocking + functions. + + Return the list of results returned by the database (whether success + or error). + """ + yield from _send(pgconn) + rv = yield from _fetch_many(pgconn) + return rv + + +def _send(pgconn: PGconn) -> PQGen[None]: + """ + Generator to send a query to the server without blocking. + + The query must have already been sent using `pgconn.send_query()` or + similar. Flush the query and then return the result using nonblocking + functions. + + After this generator has finished you may want to cycle using `fetch()` + to retrieve the results available. + """ + while True: + f = pgconn.flush() + if f == 0: + break + + ready = yield WAIT_RW + if ready & READY_R: + # This call may read notifies: they will be saved in the + # PGconn buffer and passed to Python later, in `fetch()`. + pgconn.consume_input() + + +def _fetch_many(pgconn: PGconn) -> PQGen[List[PGresult]]: + """ + Generator retrieving results from the database without blocking. + + The query must have already been sent to the server, so pgconn.flush() has + already returned 0. + + Return the list of results returned by the database (whether success + or error). + """ + results: List[PGresult] = [] + while True: + res = yield from _fetch(pgconn) + if not res: + break + + results.append(res) + status = res.status + if status == COPY_IN or status == COPY_OUT or status == COPY_BOTH: + # After entering copy mode the libpq will create a phony result + # for every request so let's break the endless loop. + break + + if status == PIPELINE_SYNC: + # PIPELINE_SYNC is not followed by a NULL, but we return it alone + # similarly to other result sets. + assert len(results) == 1, results + break + + return results + + +def _fetch(pgconn: PGconn) -> PQGen[Optional[PGresult]]: + """ + Generator retrieving a single result from the database without blocking. + + The query must have already been sent to the server, so pgconn.flush() has + already returned 0. + + Return a result from the database (whether success or error). + """ + if pgconn.is_busy(): + yield WAIT_R + while True: + pgconn.consume_input() + if not pgconn.is_busy(): + break + yield WAIT_R + + _consume_notifies(pgconn) + + return pgconn.get_result() + + +def _pipeline_communicate( + pgconn: PGconn, commands: Deque[PipelineCommand] +) -> PQGen[List[List[PGresult]]]: + """Generator to send queries from a connection in pipeline mode while also + receiving results. + + Return a list results, including single PIPELINE_SYNC elements. + """ + results = [] + + while True: + ready = yield WAIT_RW + + if ready & READY_R: + pgconn.consume_input() + _consume_notifies(pgconn) + + res: List[PGresult] = [] + while not pgconn.is_busy(): + r = pgconn.get_result() + if r is None: + if not res: + break + results.append(res) + res = [] + elif r.status == PIPELINE_SYNC: + assert not res + results.append([r]) + else: + res.append(r) + + if ready & READY_W: + pgconn.flush() + if not commands: + break + commands.popleft()() + + return results + + +def _consume_notifies(pgconn: PGconn) -> None: + # Consume notifies + while True: + n = pgconn.notifies() + if not n: + break + if pgconn.notify_handler: + pgconn.notify_handler(n) + + +def notifies(pgconn: PGconn) -> PQGen[List[pq.PGnotify]]: + yield WAIT_R + pgconn.consume_input() + + ns = [] + while True: + n = pgconn.notifies() + if n: + ns.append(n) + else: + break + + return ns + + +def copy_from(pgconn: PGconn) -> PQGen[Union[memoryview, PGresult]]: + while True: + nbytes, data = pgconn.get_copy_data(1) + if nbytes != 0: + break + + # would block + yield WAIT_R + pgconn.consume_input() + + if nbytes > 0: + # some data + return data + + # Retrieve the final result of copy + results = yield from _fetch_many(pgconn) + if len(results) > 1: + # TODO: too brutal? Copy worked. + raise e.ProgrammingError("you cannot mix COPY with other operations") + result = results[0] + if result.status != COMMAND_OK: + encoding = pgconn_encoding(pgconn) + raise e.error_from_result(result, encoding=encoding) + + return result + + +def copy_to(pgconn: PGconn, buffer: Buffer) -> PQGen[None]: + # Retry enqueuing data until successful. + # + # WARNING! This can cause an infinite loop if the buffer is too large. (see + # ticket #255). We avoid it in the Copy object by splitting a large buffer + # into smaller ones. We prefer to do it there instead of here in order to + # do it upstream the queue decoupling the writer task from the producer one. + while pgconn.put_copy_data(buffer) == 0: + yield WAIT_W + + +def copy_end(pgconn: PGconn, error: Optional[bytes]) -> PQGen[PGresult]: + # Retry enqueuing end copy message until successful + while pgconn.put_copy_end(error) == 0: + yield WAIT_W + + # Repeat until it the message is flushed to the server + while True: + yield WAIT_W + f = pgconn.flush() + if f == 0: + break + + # Retrieve the final result of copy + (result,) = yield from _fetch_many(pgconn) + if result.status != COMMAND_OK: + encoding = pgconn_encoding(pgconn) + raise e.error_from_result(result, encoding=encoding) + + return result + + +# Override functions with fast versions if available +if _psycopg: + connect = _psycopg.connect + execute = _psycopg.execute + send = _psycopg.send + fetch_many = _psycopg.fetch_many + fetch = _psycopg.fetch + pipeline_communicate = _psycopg.pipeline_communicate + +else: + connect = _connect + execute = _execute + send = _send + fetch_many = _fetch_many + fetch = _fetch + pipeline_communicate = _pipeline_communicate diff --git a/lib/python3.11/site-packages/psycopg/postgres.py b/lib/python3.11/site-packages/psycopg/postgres.py new file mode 100644 index 0000000..976533a --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/postgres.py @@ -0,0 +1,124 @@ +""" +Types configuration specific to PostgreSQL. +""" + +# Copyright (C) 2020 The Psycopg Team + +from ._typeinfo import TypeInfo, RangeInfo, MultirangeInfo, TypesRegistry +from .abc import AdaptContext +from ._adapters_map import AdaptersMap + +# Global objects with PostgreSQL builtins and globally registered user types. +types = TypesRegistry() + +# Global adapter maps with PostgreSQL types configuration +adapters = AdaptersMap(types=types) + +# Use tools/update_oids.py to update this data. +for t in [ + TypeInfo('"char"', 18, 1002), + # autogenerated: start + # Generated from PostgreSQL 15.0 + TypeInfo("aclitem", 1033, 1034), + TypeInfo("bit", 1560, 1561), + TypeInfo("bool", 16, 1000, regtype="boolean"), + TypeInfo("box", 603, 1020, delimiter=";"), + TypeInfo("bpchar", 1042, 1014, regtype="character"), + TypeInfo("bytea", 17, 1001), + TypeInfo("cid", 29, 1012), + TypeInfo("cidr", 650, 651), + TypeInfo("circle", 718, 719), + TypeInfo("date", 1082, 1182), + TypeInfo("float4", 700, 1021, regtype="real"), + TypeInfo("float8", 701, 1022, regtype="double precision"), + TypeInfo("gtsvector", 3642, 3644), + TypeInfo("inet", 869, 1041), + TypeInfo("int2", 21, 1005, regtype="smallint"), + TypeInfo("int2vector", 22, 1006), + TypeInfo("int4", 23, 1007, regtype="integer"), + TypeInfo("int8", 20, 1016, regtype="bigint"), + TypeInfo("interval", 1186, 1187), + TypeInfo("json", 114, 199), + TypeInfo("jsonb", 3802, 3807), + TypeInfo("jsonpath", 4072, 4073), + TypeInfo("line", 628, 629), + TypeInfo("lseg", 601, 1018), + TypeInfo("macaddr", 829, 1040), + TypeInfo("macaddr8", 774, 775), + TypeInfo("money", 790, 791), + TypeInfo("name", 19, 1003), + TypeInfo("numeric", 1700, 1231), + TypeInfo("oid", 26, 1028), + TypeInfo("oidvector", 30, 1013), + TypeInfo("path", 602, 1019), + TypeInfo("pg_lsn", 3220, 3221), + TypeInfo("point", 600, 1017), + TypeInfo("polygon", 604, 1027), + TypeInfo("record", 2249, 2287), + TypeInfo("refcursor", 1790, 2201), + TypeInfo("regclass", 2205, 2210), + TypeInfo("regcollation", 4191, 4192), + TypeInfo("regconfig", 3734, 3735), + TypeInfo("regdictionary", 3769, 3770), + TypeInfo("regnamespace", 4089, 4090), + TypeInfo("regoper", 2203, 2208), + TypeInfo("regoperator", 2204, 2209), + TypeInfo("regproc", 24, 1008), + TypeInfo("regprocedure", 2202, 2207), + TypeInfo("regrole", 4096, 4097), + TypeInfo("regtype", 2206, 2211), + TypeInfo("text", 25, 1009), + TypeInfo("tid", 27, 1010), + TypeInfo("time", 1083, 1183, regtype="time without time zone"), + TypeInfo("timestamp", 1114, 1115, regtype="timestamp without time zone"), + TypeInfo("timestamptz", 1184, 1185, regtype="timestamp with time zone"), + TypeInfo("timetz", 1266, 1270, regtype="time with time zone"), + TypeInfo("tsquery", 3615, 3645), + TypeInfo("tsvector", 3614, 3643), + TypeInfo("txid_snapshot", 2970, 2949), + TypeInfo("uuid", 2950, 2951), + TypeInfo("varbit", 1562, 1563, regtype="bit varying"), + TypeInfo("varchar", 1043, 1015, regtype="character varying"), + TypeInfo("xid", 28, 1011), + TypeInfo("xid8", 5069, 271), + TypeInfo("xml", 142, 143), + RangeInfo("daterange", 3912, 3913, subtype_oid=1082), + RangeInfo("int4range", 3904, 3905, subtype_oid=23), + RangeInfo("int8range", 3926, 3927, subtype_oid=20), + RangeInfo("numrange", 3906, 3907, subtype_oid=1700), + RangeInfo("tsrange", 3908, 3909, subtype_oid=1114), + RangeInfo("tstzrange", 3910, 3911, subtype_oid=1184), + MultirangeInfo("datemultirange", 4535, 6155, range_oid=3912, subtype_oid=1082), + MultirangeInfo("int4multirange", 4451, 6150, range_oid=3904, subtype_oid=23), + MultirangeInfo("int8multirange", 4536, 6157, range_oid=3926, subtype_oid=20), + MultirangeInfo("nummultirange", 4532, 6151, range_oid=3906, subtype_oid=1700), + MultirangeInfo("tsmultirange", 4533, 6152, range_oid=3908, subtype_oid=1114), + MultirangeInfo("tstzmultirange", 4534, 6153, range_oid=3910, subtype_oid=1184), + # autogenerated: end +]: + types.add(t) + + +# A few oids used a bit everywhere +INVALID_OID = 0 +TEXT_OID = types["text"].oid +TEXT_ARRAY_OID = types["text"].array_oid + + +def register_default_adapters(context: AdaptContext) -> None: + from .types import array, bool, composite, datetime, enum, json, multirange + from .types import net, none, numeric, range, string, uuid + + array.register_default_adapters(context) + bool.register_default_adapters(context) + composite.register_default_adapters(context) + datetime.register_default_adapters(context) + enum.register_default_adapters(context) + json.register_default_adapters(context) + multirange.register_default_adapters(context) + net.register_default_adapters(context) + none.register_default_adapters(context) + numeric.register_default_adapters(context) + range.register_default_adapters(context) + string.register_default_adapters(context) + uuid.register_default_adapters(context) diff --git a/lib/python3.11/site-packages/psycopg/pq/__init__.py b/lib/python3.11/site-packages/psycopg/pq/__init__.py new file mode 100644 index 0000000..0048ebb --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/pq/__init__.py @@ -0,0 +1,133 @@ +""" +psycopg libpq wrapper + +This package exposes the libpq functionalities as Python objects and functions. + +The real implementation (the binding to the C library) is +implementation-dependant but all the implementations share the same interface. +""" + +# Copyright (C) 2020 The Psycopg Team + +import os +import logging +from typing import Callable, List, Type + +from . import abc +from .misc import ConninfoOption, PGnotify, PGresAttDesc +from .misc import error_message +from ._enums import ConnStatus, DiagnosticField, ExecStatus, Format, Trace +from ._enums import Ping, PipelineStatus, PollingStatus, TransactionStatus + +logger = logging.getLogger(__name__) + +__impl__: str +"""The currently loaded implementation of the `!psycopg.pq` package. + +Possible values include ``python``, ``c``, ``binary``. +""" + +__build_version__: int +"""The libpq version the C package was built with. + +A number in the same format of `~psycopg.ConnectionInfo.server_version` +representing the libpq used to build the speedup module (``c``, ``binary``) if +available. + +Certain features might not be available if the built version is too old. +""" + +version: Callable[[], int] +PGconn: Type[abc.PGconn] +PGresult: Type[abc.PGresult] +Conninfo: Type[abc.Conninfo] +Escaping: Type[abc.Escaping] +PGcancel: Type[abc.PGcancel] + + +def import_from_libpq() -> None: + """ + Import pq objects implementation from the best libpq wrapper available. + + If an implementation is requested try to import only it, otherwise + try to import the best implementation available. + """ + # import these names into the module on success as side effect + global __impl__, version, __build_version__ + global PGconn, PGresult, Conninfo, Escaping, PGcancel + + impl = os.environ.get("PSYCOPG_IMPL", "").lower() + module = None + attempts: List[str] = [] + + def handle_error(name: str, e: Exception) -> None: + if not impl: + msg = f"couldn't import psycopg '{name}' implementation: {e}" + logger.debug(msg) + attempts.append(msg) + else: + msg = f"couldn't import requested psycopg '{name}' implementation: {e}" + raise ImportError(msg) from e + + # The best implementation: fast but requires the system libpq installed + if not impl or impl == "c": + try: + from psycopg_c import pq as module # type: ignore + except Exception as e: + handle_error("c", e) + + # Second best implementation: fast and stand-alone + if not module and (not impl or impl == "binary"): + try: + from psycopg_binary import pq as module # type: ignore + except Exception as e: + handle_error("binary", e) + + # Pure Python implementation, slow and requires the system libpq installed. + if not module and (not impl or impl == "python"): + try: + from . import pq_ctypes as module # type: ignore[assignment] + except Exception as e: + handle_error("python", e) + + if module: + __impl__ = module.__impl__ + version = module.version + PGconn = module.PGconn + PGresult = module.PGresult + Conninfo = module.Conninfo + Escaping = module.Escaping + PGcancel = module.PGcancel + __build_version__ = module.__build_version__ + elif impl: + raise ImportError(f"requested psycopg implementation '{impl}' unknown") + else: + sattempts = "\n".join(f"- {attempt}" for attempt in attempts) + raise ImportError( + f"""\ +no pq wrapper available. +Attempts made: +{sattempts}""" + ) + + +import_from_libpq() + +__all__ = ( + "ConnStatus", + "PipelineStatus", + "PollingStatus", + "TransactionStatus", + "ExecStatus", + "Ping", + "DiagnosticField", + "Format", + "Trace", + "PGconn", + "PGnotify", + "Conninfo", + "PGresAttDesc", + "error_message", + "ConninfoOption", + "version", +) diff --git a/lib/python3.11/site-packages/psycopg/pq/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/pq/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b9c9861e9897e0fa612bf4f405790424c2d8526 GIT binary patch literal 4700 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 N6#0Fu_(8x}_+NtMWZwV) literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/pq/__pycache__/_enums.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/pq/__pycache__/_enums.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6bfaa921e61b20da128cfc4b5141d140ef9484a GIT binary patch literal 6174 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 C1eFW` literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/pq/__pycache__/_pq_ctypes.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/pq/__pycache__/_pq_ctypes.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27b4cf56db7f1c3b6754e4b9b5cd6c4e4d593b90 GIT binary patch literal 21077 zcmc(GYit`wwq}!TzDZH<_k(&%en@`CZzq1+i7iW3Y{!ZnhGLgw+7wB5Q?{i@37t_A zIir~{xz3oGICnU?nOx1zF2)P&kL+T9WcGpCpUo_RGzbLHVllwYKMkA#g8bTZs+-L& zN{+AZ>|okdbv?d1b?VfqQ&p$h|Lpa;ICx&z^`&rSh~xe*CJK*Ri#$45&vExTfg9rl zlVFaR#!U2W9y8Oog}yBj^AtbEPg%#TQ?@ai39&rn*~jctjxooSbIdvA8gos#$J|q% zG0&8D%u6xWNZFKc%r{j&Rz6iRRsnf7!5*ocsv4_;xI=J8s;6qkYD}D&BUPUROTR1d z$BosJTFDLhb%N`26O_Q8`n+i(=4-&U`eYgkG2@%mvUSE9&D;r2a4&Fzhwz_UfFAs* z&sY<*Vk1o@HJXX(T1x>Vc(0o=E}n(9TMN0FwnEJK7RpK}`H5dLKhOQE`1Y67Z71#5 zIttXsI*5}vCd{NG&{@bM&5-KSQ;pZU3-Ph;Nse?IkWNVHNa%BSiNt$|XRMdX$p>;O zUn8eJT2=vNm21lSX;~GNRj(=AK+9^NtaeS=Mp{+}W%X;yHqo*MC~I6(wwaDuUx~B^ zXl{Q=?jX(GP?Eca=58#>-AZ#emE>-txtmLJx0A+eJ9KI9AdX2B*;q>OZT>DXN`;=2sUEs!!Ick9UAWD8K;UBn7zNExwv zbnG6=!JZ|PzampG`b9IUJ+&15fAe=k#ipI(0-ZEIf<3w-Tku={oFeu~}C zVD~fF13LBq#U3bPVJ015um^SQL5e-dU=K3bXLanebR?f;u+K8s=XC6IliapF=4>Q;!I`#;~9$~OYidexsc9ir8P1mhhL#zd@J*L+^ zO6wkF>K--JZ6QuajE+7- zDW5T5o#YIIg|%9J#)c?%h`|mq*t0tJEXAHRU>)QvgB{kf!xTGgz&gn=gB{VaBNRKr zU`H72IUReBV$U(ya}0J=$Bt6$D1#kkurKP^7b*5d2Kyp|J+EWWYol@AfF3008T17m zeF4$LNo`gyYqQp~V>HjX4z47RI42$C0>i-thJ%Yb2Nx*^kKtj`N-i=~E;3YJ(y6>; z=tqg|eF~oK8)MTWPFK1Ut-W>I(ke)k1^;m2K};*ewhry%Ji}U>x7hX zE?w5KmnrtL0qY=_8SE7udxZ?bsF=wW27QG=zoMgGp_E@KVqqP6g~0}NY=B||MJ%i> z0S5c3j(wG4UuCebGT5Mw4Qd<*4QK}mGU#y~J+7h04d`An&Y(j&I;5dP2DFoe7_^|H z1r04QXn{c!9ZfVeF`#=1VbBvgdO|}_7|>2K!JsE~^rVKKWYCig`l^n;N~L|3!Cqys zVI3Pr%Ag?@5-#HD+_AIs9m#ToTd!uUNXg?qdGcDDMt-h2Z=J+n2wE6Y>dIi7;Id}#wj*#!1j_jgT0|+ zZ%_;70{P!4;@6e`4TgfKQxJ6u;u9!{3Cq#ZBCQ%9D|-?(DOQaUPI3_=y?YHx{iLG?#Ny@UCK0giD+zr&#KFz7dR^qZ9On+*0%2Ky5o`xA=&34{F! zgI&6wdTRQeFihav~-A3MGuy5$+1oMPVXopkm&w)Zpr;wtuOfmIS#rlAKU&p>ryfA+6GuZbH*dC!nK zVmq*JxL2eK=nr-DhjhQP9kk;^1KtTKoeSX73M1krgC#!JUjU{1I;H#2?k_+-7INP} z=@*dFDZxml;qN2(`z8E+41W&{BO3*JpXl_`bX?K~T27KK(gN&1>e!Dc_9F)S5rh4e zj{POY{*uA|lEG$l?8g-QF@yb>!TwsuKA_kK4E8}0OUJT>ya%3?UKq1a4Cy{d|Dz$@ z59wbS(i+OMY{U_F2 z4E}rbDE;dnoNaPN!sGE9{$MCXB*{N5g`<=HP+}%dB-gjt@=(7e?;K5t)1kz)Nb=4j z$IlNPdGXTlvAliw?5Uv_kDcqc=WU@t=xR{RJJfd|p0|bq;b;Ogr0^^WB=Yu9V0wHe zK@dBw72S-5g+Lq{;7^Ao0H2K~!m(&DlDED%9gmQ2P0)V7DPKJijtT+FXJBGF5(&hE ziL2k5)xwIQSYmWK9*>C$A{-ONm^fRfb_qf;D9-q!v4npjHXRl8GZgjLOe7x!N&TO~JCaAm#sVU5jfA7qxAUeD(?uT2@p*(! z-eMQebCcYdh491*cPI7fJCa>$Mb#aW)}lO0XP{HoM>NU!=F<+kKW{HID0=`&K)b-fEp){!E}NtNQH z1*FA;w5)j;O;E@1#EdQ_kTcjd#9$O7MP0=#hPx-}sw!nG$QrB*gjUo~ z!A9eD3_(|InyyySxpXLzI7%c~B~;78qe;!%6T$Ha0r`WLMy98t5VK9h#HnB+Zv|6= zNq9v_H17;15)cK$Jk)PrPfzofvti-!%8F7JF}MhS5?%}#2ho?RmmQ4?DD4s1QIATA z%81Ha7}Un|?OQBvucVFvLP99Yxap~7Y^_OMNT1L0ojJZ!F8owkXWpi29h9V7 zLY|+NhzL_MG8q%YiK|l~gPw9WXrAi#-$MFx<~hsf(Aw|x7FFr*86F|gkT?@h3?qxM z03Lz)_rx*SQXGR?7=v|47)F9uM*^?&M7*aH@d8dlM*Q%oN?)@+5xgc7ievK^8|UeG z>e2CZWO|l+9(H}<%(@Tf+=pfUFddt}r*+veJQ5Gb3G7PADD3y9pGxg3K;&%gqO`?R zC|rX%DPMy{Oa3bqYQd;9Kcz?=oTnvyA?xnSxnYCZ^>-KME>s>kPYi1kJrfhi6IIw? zMyja_mk{_7kyfqKo;U_lT{cR!?dhfJ&)Bl=-kiHv=6nC{Qhf$`c{`l=w+giig<4Yo zM`T*L4jL~w|09U>Q9)5#pI)SGX;}Swa_%0P@A)xyNeMtQv%n)@yN7v^&D)?h?IC5QKDv+*8dT4 zf@ZEk;}ZSfL8Kz?MOAq~M1MRGqf7ax5WeGsZ&1N?65-zU(eF-8Q|5W_t_YR|Zr+r@ zWnX&)eimZ$=7h75!*O$Fc5}Luo43qaGPqS+^RQm5jDd0y%3|hu0XAX+SGqZix;we8 zutwi9-?m)hZkbHnCE(b^E&3)*f_1@>K-Y!#%<(LTM>)2Q%OIzD>%2{{EpT(t-kkL< zgGZ$lJ#U}n<{gQO0(Gv0TE-xo$6=0gS3aYyI_F(;&N=%{PBbmK66i0|o;eq6`hlK;C^q;1iX0WysY>5 zWA2j@`I)#S_^K1pAS>53^c2yDtv6pb=XgxJ&}V4TEqF5Mxm)whmE6bz);m`QVc91o zcf7#KZ{{3x{2X{supe`_x6J5+Vf9n+v69p@)Sw|n7KHN0@KhoLR@x>GH2yL4N|Ed9 zGafe9*JyeSsTdML8PJpJ3>-N=9Ssd9#1Ky4!h_QdPj8QI!_MkHOv)tngU*?ar_gCm z1b5UZlqQgx_Dpk9CFJP)ZjOT-C*&BWC#`9rH46>|s0}#xocWqQ)dgO2S=;7JcffT3 zE@~UrF(6RYyP&j6a4`9xO2$bCgYEi+wr8kYf+?Zw2Fg`}=c%cBX}z+4O}*#g!|XXT z@K!MgQwF95$l!McF~TS2{gp#`ekc|tdCQ^bOx}V%a_8ycfaY4aqVrsu^%Z>NFVplD zJSGB&_0Lw)9L7_bSMwN;(5zD@_ARQz52h=iBaK*jeK+E)a}?Jja4NmrZ_B$VbE;F{ zP2=b}1mC}dCW`!1cfW>?#G;dVI{?tZKI;q&#{fsfmygeu18=*eX>NNu2kvN$*B_!;Ne)Mvn?|B=zmuA~0NtB4e z1OaE$^!UL3NGueLNCyWBfUiNVB|ppna5lR=i+hx+hSW2Px9r2d#Vd zE|+&xGIG;i*^57=YD@aYgW2Ww<&Nc!2d~RjTeP2Ni`JeU+p}YP7?g9>TOU_p)y8@E z%Z>Y%M<9UT!(-|@>)Ds{?2|qF=#C(73a>d~qBrvqIvhSUy#UK8SQ73^8(m0D^X9vj z43w;WU>Pv8CieGDbEXU2eOQ*4{OWzoZ0BWZ1O5f46S2ZD3VSb08~ebAB_`%zztlej z%4-E5Vd!cIBl!=`{Yd9_Ts%1IFHkH|3>{$xjgs(e z|NXyk{{rd(16OUM!T<48Ego7-C~oh2yWia{SMUAeXx4ow=RO3U-fElTaIRVk&|;-x zZ0%kX%_cR)Nr>F%uA&I{&70;-8Az{vU~dBoTl^n3zptC4{|m@y4l{sQ`v?|+XT>g9 zi}ybtn3wj03&r*WFOUiUwIYiXO#GH3g(Mvd2^HwPy2`9iSl|;ZD2qau2 zH2(((8~j*!ec-c~=-NT0wqbO7jk2hSJU3f^ncE+;U8$~&{=-MRAaMJqUhtvwV(gFhquI}D0>>&3qR{`>W^S8Z!&<)7;OnVM`} zZ?3L))e6Ob#!3Di26s*;k1rlw_2_yyu>IkQhZi26`1et&U4KRm{SJfVu~i3GS)F|T zPc_Z&U%Gece&B;Zwx%an18jP%!zMMn>s;g)LyFs%+PQdO@qpr~{>Imk?o7{Qef>FK zKQQd9fy|YPszuv3)h+4JgGjb|W3GB5mK*{i7~VY!hUbRjseJFuyJzIaXEUbEp9<@<$7=kn!ebY?LUy~KcMDjJFjuQ)2d zb~JqDXpkF+GSv{kZ<+tS^WQli_GJ6^47>t0~Jj{|SdT)p@sNsRgE>wKm-jCh`+-}!+v-JLD>=gR$AM?1_^*-s|6LdRMJbhgPHk$k|#8ayI4_OG{#Os z-ttGDKjE3 zEr^I#Q^ftPh*n+Qvfu_--NCppMmIFLzo9o;@a=_qb&e++_5Pfn3QHjo&x>$%i(fZL z^emsZ!#xY#^|((>;kOU;%ZEH45+aej`*bWQoL0Yn$eZIg=vM@J2ky86ak!3m#3R83 z-lu`b9+=I03g1`Y=Ms4bP!6dZDvZI+n}GIBypKG6gp7EGN1)__dc{MpBgDg4NH6g5 zew$wZ(z{W5t4J@{;NnO9h5$M6==bQDs$R3*)G*rZtd`RDu9zxk?hY}>tYys#1kkpybKc~5MVYA zY2G?K0+*Y4=kQ33ei$QR<6!B*pPmONE!<2;rCd}ycNk8eK?;G%WXM8onug5|HbybX zE;~3j9904A0Zd*A zHeRQq@oD&|Yk$lj2Fqlj)-lnr1<0TdzUVz=yU1g7;uXc^{n zh=};XjEH9_@fz9!(1YnHEuq>5O-_+15ibtKQ7i}XO$D!$V^i_OOu?vXJyit)A6SSI z<{(=ka*l*Z80Nkz_rwsBDPBOjmoT`D!K)aAFu+SSdIu!ptp)YDivq;38(<9+XJLgH z9X(BVh3aP*>{mfQIQGM&fRE=6imh-Q!4ruz0jnBp>rAFqv)RPM@(qE9Gr5y4{HJi< zB>kswm2%;ya9iZZ{}k@5{PaJC>ysbf7bxKXYh%(}MZTw7#*%Zk;#@bcHz=C7>H>5Exwch1_KG_TrBCMV)cgT+0t$2B=& zk6S2$d&#QBU8x;+4=f!>I#w*Uh5e~rUs)PuOQYheS$gejU+-7G-epVHw<+h_lsu`p ztCDB&pW?1q+V{1)<12SZW_Q-TDd*mlJi6koSb8~mT&ZhLUzKZnlgAg%Dm5+e8d?Qs zMCH;ONsm(BnDpeh8o=PYdZoNM<$1sCURlx$17-InEy(=_WP00POSXBPkx8A>|b*`*t@nY&q*4vr$c7n$G zY8P*%-pKlTbG}}XULCl6?@!Gp-7o-3tsmc2t7UM=$W?SC%ao?h^oC?vj;m7|I`Lh*QeFu=>ZDg`>`FH$ zy^y2Sx8S=5&J${##%8U?X0=8kziCiz+@ck=s6}4i(iP}gU3)5$bV18XO+UUXSD^jM zuB1cLq)RvkDr<cbk;Ap*NLrQ3 z=2Uaix=^N+*Tc)Z;wf7?opgdKq%J3&FceC4GrlX)QHU?Isxp&%Yr(2k#u$ zth9F0NYhGnZLS&&V1?4!x7;VUY=>x$YlLy7kp^RV`f{PLT`SbJ0Q;>De49G(x=wYc zH)$%>uBy~pmC)FH?9ey2=9+iQT!YfHB?BxpNSDIRKP0z@na@~WO)9}u5 z?Mf$f2qONKwd&hQ)fXm^F7)(mxw22ygchm^DjzF+nZkP%-l_2JXQRixfv%yT2ceR?U?@~>tK5Ci1<&zJ|7Z<;{_~qz-zWiS=%Qeqy z!{}FsQIlLr`%i4t=V&rhL4)0B>`_HsQ`_Nr<{4U%s0{6;S8XeE8Jl*(CG;LgnXr#nA0X_y z?QBneyj1UJskjZ*io$82HWya^!qU{0dR=R+l@_h&)k+HrbFniO)p}8{&P5jodZ;cY zJC^%Ji zO~`P&0k)a0lm*jAry5T3<9E)&E(m8mrnD)y>a@0+Rl^7UZs|&&$ehSFZ^|`;Nd;5c zP*`wRXr=W@*!e~?U5kOC27lU~v1jZ1a`k<5T?URc0Wc(tELbhgW-1d<=%x;kN^iDt zL#}ZHl?%`;j7CT1q+GX|9e$>l|5k&hOQ4!->0tW}8;#7>hmJ40zpVSR?tfMNq4|F_ z%MC;9&ZDpbJ-t!$gXnR=0;|>rOAs zwZ6I(cTe?nbpf##7M|ABm}c(PA|od)ZMl}6GT#WUa>Y@u{=h)=+8__Ujs^qKvpI8d z`NFRQp9N@E$EwX~I$}~h4XYL!>Fm=YTXt%Z!za|piq*SF76PkQ#Nh#`B&_E^4uy>z ztOji`2h_bBtnqYW6qT`md8fSXu-ts4L?1!$)h($#=@&D*moI0l_U5YgqO1$^6LyI5 zru|=BmD^4fXu}$hv_U>K4KVSQx+a)KN^K)###+UE}L>Jl(Eg#J|$moNFAE`8uU*AhRFdkf(IO*P;+UDh(=aroN09bNf(x;8hv`qBlK{xxEjo=&LjU zL}&T{=5{WR(pPElWE!=cKJ#GrkZ#px3_ZlvtlG|)OmG*nCVbV*@t(!muPhC+r9t5< Vl4o!cQxE>D7LEt^Km)z>{C~KrQ~>}0 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/pq/__pycache__/abc.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/pq/__pycache__/abc.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19fe3b93c1b79daf3302f9865dc3d6626ffcfc72 GIT binary patch literal 19510 zcmc&c35*<9R@L3r_c8a3J>#(_apHJlXC{g5_=ugv$N0!Gaj;FC&MvhzUBB&i`pU2B z*xk!20lXq0t=2-I46vYH5wc?vp%GevVPOek#i@u{7{pL3z{{>!1+=1r1BhL*;=TXt zuAXt*(_(98Uj6^xtM}f&-aqQqd?}qy2yi{K_kHEX&4TbP%$Qf$NZi^U5QMjcbAlpd z1tp*ai-A%w8!Uygp^}&tOW|y|6v;+P(QGt;^bpWv*;px_jkCO1Oq7z@B&5Siq?jtD zv*}VMn}K{(i4}WFz1iM?K;kq3^mwta)SvAy4P*yOgV{mA$H)*FCL{UKM$;}KyMZLh zMkR3&FhSvjpd_yfN{aNp6B2}X;g4V0QASGxE#sq&F9Oal$R-!{*ctL_ zjg)gl51*}ph{>QHK34{so<951=^5$h$(f_ioSHo`8PMZr>s4~NSdi5Zp=|}=j2y4f zlB~g_RL+qPgNP02F|#C-AxNJnSF}RDu4j%`%H={iU*W3t)aesYw8NTqjHo$1a-@cZ z$)VBal{ON$rlQ!Dh>#6HX9}JZNQj6^-~x22e9&%SJ4M1u2%DMliEHwO8DB(+kSKI4 zAulSitKvKG?7OBFLN-R6^tg{6SE3}54=RbPVm7IqhmIv?QzQ-8jFPgg0*v_XqD;G+#$v_T(j*rE;jXd@PF*hkx7 z(MEiZ5J4Xk$LwxUvab6Iws&sC`ixhdSMC>D%mkZi^*z zi;p&8(I$Mfdo0>LKH9yEwiU{7ua9=0MceA5-EYzE^U<~`_p{y_fL^f;%JhJd4?_L{ z$ZuDIN{~!mdeH2``4HpS4mGj^{&w26(k`V;GQLDx+JkG*c8~;&p+G*R?7SMzKJ-Ji zA_!JI1XfJN1?45yAF$5WDp^zs=3~kfJTvX7y&!wO)7raz4F&TFWg7H6dh|z6bJq9Q4N^{}_%m zC1Cd!=<9m{zZX2(KDh5QJlcLp@3%(E0bj2^Kn`4b-0ZQ+uI;KHB>X-G$3)9tCr{%faRJE>0(IQw8H8Q+NQ$`*e`4%h< zgg1nnvE-YfTaXlPXDuBECJL)ofo=g{*h=q#w4OEuOR6SQtug3U$Fc13t@!wT0CHF# z=GCTdY;D&Ax~P(3UPZ16t}kWkt5%A|#(+m1BGD|Ph$~pcJ5)-y!}Cs!k$j##e? z#2Ibh?^MBYQ?6QChoS^m#2UTNr3X=uxYgWd@Yx+~GDs)!QO5}6y-chY$``Emz|8J$ zwMS5yYs8HbD0BO|C04AdgjyD323P4_=|Qootg4qQRB7}WcAJQ&x}`$ASWz|0ddwW_ zmgpEtlNE(p)|-fv-BKY|E8zOf(Tka9yCpiLY4t|JsCG!7?v~(ah3#flYl1NHXS<~! z0=2HyRLgDh?D=kq@7JhYR^=RS$(J&y69Y zbZ+#8ZmEl?mE0>ZSD7;{&%V+v@yR(@FTr|Bsuq-nIaxVym2N4@lnGH($@G#|wYkx1 zx74M<+e4vDCv7glT-eLqQkGEFqEskLAiZHu#5U^FE;YCcEtO#5eCI>$$3T#4sD;TD zl9Q}u49mTa+U!Bq@w87r<&~a*^Fl>}Lp@rzOJ$*c(xpdFu~9F*CKqc&)ssA@!8xC* zr+FsNj`$!8s}|TrNIajz^}l(oz3`3jbqUr2RS*yac?3AxRFpKqF1}t#vie}kRjX?| zaGwSKTX6ty2(4Zro-$X(9a}^T?bP%fA85hhs5rBEE zT^Ay+3pS;)3c^r(C-N78->iX@qXx{gceG_~JHie-6ySC= z2MR%B3~L6Q)xvF38l!D0#-M!>9ye{vIBe^kMHI0Lw5_7df6y%j$#SJUSA+!=?p)2)jRUuYimU?#JtWf$oex8Eqx`cV#5o%2&j6yGwq=*L zb!_~@`C<(YU(DkRmRmvL_OQPD9srJ7lT@g%B9Un2vQ(-l#NnuYv~Rc+<1t}QhSz|_ zb(D|wbuPu#*E#ART?*HsCdS?<7Km!?f=$FXT`Kg*9Dk|U@nXvC8ovN?oLvLfLN!f- zW68Rt$eL{JR9x6^yOoF8Hs;Q|<-AvS%F+UhIBPxNM1IGuIU=j|a!$H))xYdjokmaP zFSZN&uO8+3LXng!cdqv6ewp+XDV#Zu=h&Pij%`3}lODfCMK zJj<(Ic>ho9Rn6XanOlD^;lJ=gL>O zuEl+n?_;65;Xr$;g(@i)%EUbXFqb7B{0~r}HTkTg4-7!G1{_FO;$0rQ4J`z1;9w&Y_|EOa5*4a1qNSw=qz;*1ur)#?;? zD|8wGdrhzlQ+p8XMX(At)iJBG3@9vzj`lK8@fr2-s1_Phje& z5PTNFPb0tum>vO_3&Vnb4l!(_{d1W5c?54E_$34}0D7WCN)=jvtw1i*UqNgWK?cFE zA^3F!*Acvj;5QL0B49hXFJtPr5o|_)dpWiNr^A>+Fa&?<)&!n3*gq?So953q8_nY4 zv88SMmdE!m4<1+&@%QWEfi;OY!@aFwAe@@7wFI~=Y+yGVd=wHQeOF&*Jgo?%S*m%C zb6>F;S<20gVsjo2o{a#>O90^+Cj6SRG`3@Tc&CQ}WoNFQH!Nu6~#F+!o#~)9@(=pzV!<)x6&~jzW{Fb4Y$IWi3lTG=C3To7KfL& z?_1uoe|h*oD~g1eFuZyGVpIJ>X?bX8D~_myuwkMZTNrpdy*x72N+K#HY#8HGGeTmp z)q^;c?*ND5%S^788*|RcXYbFb5cgin|ND2iLHBGgsNp>d5kz>E+>v zThUGo9&BrHKXyj$@fH)ScGrbHjI?-mRgUHiBQ0E7m1BYXuEpJ}a?GD>W|ucTyei#G zz=1SB;Kkz9inAx5;O1}VA^MiXBW#|V=W|lCofFt#GPO|WHO}c(+;*ZxW0*xYU}kS` z9#|fo@{+ji@J#bKBQ4xUQ*-;mp0}qN>kV%~xolKs`1ysI#jT5t#p&gpM^@Eq%-_xS zeu)X=Gu48(nrwAm;W6Q4;MqVc6vCsAI1q3jrTWwR23 zSUncUPQnl|Df;64A{gUNFuFVJqs1UzJq*;iGky_b2csY}!Jb2z{z&$uMe|3or<6on znHbHUHfUkck%D~2k%yS}Y>y+)quIGEqq&8SfMCAWT*om&I9DVx#j|++nqi9N;p-U3j`r@wv&|wNv>L+s z8P5Pp--_1bwrL&Gaqo$TZH9DL=*Ngli5|}vNKwhbvG$#xF#S2Gah)(Fxh5tOPa<6U z8Fs8o6{ttc8h%)#HhL{J24=IXfOlVupn{p~Qo%9zx>R651lf&in18fu^2I!ybYV!7Sxu1L(>3Ygyjp0utjGL5w|vN1 z7p6n-=Lkl(<6(VoV$*YlvP|oeF&b^BMYNuC-7C8FGQ>yAKLa-( zGWe(!QW3}ZCoJN|(c>)KlW0IU&auDdHxYar z!M`B*5W&A8_%4EfN5GEF{{vH=qh7WEL(l`}tK%?C?So!^`e`lj`EJ18Sax_qRrBm3 ze7lh*-_|UgUnK8I9%ir3wYN6bo_B3F+!5|#k{9+Z&b;?zd!3GbqxYE5unIX;E{ET| zg4lNP4Cmmtwj8@S2fwxD*vdKhtu4peGOUVGJrDaEgO~M2h%vq&`?I01^?07)S-T$$ zc<6qaT)!N;c}fTiu4X|iQ<%-V zT+lk)e8h-h!B0fEcz*k&O9A(BVXu$-PpAX>-v~Uu<{IJ1n==Uf>N5iW zXd&+0;d*qi6A6!wgc5`A6XWnN35@Ry`D@jFu%PoMn+(tictC}kv_7W86_i5qG6X5B zjUiL|loLIN4Y(Da;kAdKN_9R(`o9+p!RKN^RO}UDKO3^s2B* zhJe*!uTGAycTHc)(1&3oa%0G=j-h|NYuYlkvP+-cj&8#1E{!~PChc`OI6v_K3l>(y z;zpR?f&cm=P!@)h#uTo{X&(ZQ^I<_y2rBTWehb9e&c|M{Lxe_tdHf-dN8nkuEPafn z7rgKK9UOU{w%E|&DD%|l!MHPLbx1X zJ_9OX2VIpl+KV}{RDjPE`jCp#G}~IT*+P%AzJ^l~{bQuC_WTN_SP%`{Ua@r#n=@G3 zx!d!5v4cE#>Iu3LiU+@f`T@XJC=dv=g28~;5-gAs0!IQ%!r{(;SA++a+Wq?RH-&qa z+WoEwo0r_bH$%P9lz~Gl;=!fWf8iD6(CGaA&5a9BFO5F7Jh=Cb$eZycVK4lCUD(@- zTn+_ban~NcdHy3t`PfO|6hreEK!o}k!;DPe<;UxEyuOfCUN3*^yAoZ(v*vo9&v^grQwji zGqfzO6wrkp)YO34pbHCajPhYO>mo0C*oPL_1-j@y^pO+>YhnNc0u}}~Zw%Z5fnU1k z4F4qy-Q-~}FVEb2?(dvA=R4=#fAM-<1k&`>AHr_M62vhd!nASH|jO(Hrbc< zNB!xZXivH~+6z3p=#T^HU^Hl!opN8gKiba_mPp*c|*ef}ukx+9gl3>Nay5)1I zf6?Ma_lqI1PjX2f$(vx?eZ_uh1jdgfY~sFkYxICPAbHHXMI2nWL=TGWdn7!R|Do#x zfu=G!l~3f9xR%N&f}GM)lFDltJ}oRsyd zb76~Ni3_S`xaNekB;L$rWyx?{%ho3}tnVu@^H(UoFl*S}y%NtTis5+o3YFBHtc5wl z^(JuM(*!N28of8Eps0emn+D7GZYnFuDMhN+zhZGF#<0eP_<{rle>RCz#v~=45mQPs z@5-tx@k}-u$=;6R4x6d@U7kmP^N>gcw2DO8_u*?x7LmCKT*(S0)+`~9!;)wLX<2c{ zN=8d1Rt!6pWCdQ;u+2-cY)Uk&(p`-TbHBA2j#vy^Vll%Ni={JSPR6n)7Q3Aj%rQ{2 z&aY^aYWQO@L4g?sl#>d4E~RL{CC_oUFRo195$NRd^73SQMb#vlk`$2&X<-s1Kbc+8 z7Bb42$Sbc*swqu6nHAzoLQ+yE8}B`ty*-&usqsj5h4#X1CK-T&dK^fh<5%?t3Uh_I zdvjHfzc5{xzBgTU_Y`IdGxy+Mn4$ZdqhBt^JT&hqN3N}pEty)SZmua`ka;)P(vrWm zRkE2S8_Z-kzlj6BiPP|*=A@KFrmk&(+ietIpoy`2B-r%OK>6Ww7-Ts=i?1TH)HgYgJ!w zVYV=P5B`PO`UY_Amw%QIpk>d`(o}C$^rrYNVqN6OtBV{Z3DnipQg1^`TXN}8U|->#!aMigX>=M+%p zA<>}NOp7fCATmpcL4=NKmS!sO|&O>?5@;w#qDlT>UKXRM^|H`(%ol`)dKBai>B+x zddc19wo9w5X!#su`-LfALvu!#Z%X5QUkt-urYlNioyG6udckxJ$rCr<)fOws(&cqS){$`OsvsS@An zfnGe3QpCFRzQB*G2AjPd?lCxZMKv5*Sm)mztZ; z(o9@ZRl@_`H@+0h|E7oDhpeczzItRn}G?kg0^5-7BeXY@c3>@)l|dz*4?;d zMh1pW&Loo(HLRjEpG!gzVTV;rIAK+osQxkrE8SJmoOnnSG1us8?kIaZmdMF+440wP z(DVxY)stYR1@g@9T3;>TavbEy(|RS&$nVXrwz&p?ehowH1hb$Dl)YR{2!GjE56e{=9x2Ol5*GG7kA zQ3<`Nhu(Y=y1Es*S_w_-q3I`~8(X0pmC#K+bhBuCIyCaxk>8y7)rr!b$7_|LOZw2I zqW$SW=$Fe6KmPRNQnE4-(FY7F$sKYw~D^8~7;$avuP> zzZ`BE(cUekHBMng#~QcFVSFZ>0%dTa>E1A1EiWj%L}`ZdX+RJNS@{Ibq(f`(Hv)e6m zo~!`jxCD_oFW_zxu+}_;;XFVnZ(<-EL?Zm<48kxKa2BbFd@7$&T7AsPOqr;S*EQT` zHI_(8viKaW=>kP({MBC}8QywhLw@dTgQQTa?Bs0)Wh4VUqHlUQlzo8aqEA}znK2{@r z)*H+-U*I3lZ@yRYjq1M94X)}B=ze~~QnL|H46RC3sp7p5D0p%`<0DF<8u0oD;fpqDI^>@wVG{|H7ldmV3DD9)3D7QBo@d z$Mu2Z8-Mp5*Z7N#_y@~_@BaJcKLme&_1~`Q7w4b`x#GL7`>vNA*SGEN8sV(tRbSx2 z(kDxsM@v^LzKHINY;YUgw(l?yH$<;yjB42G$J%%Yo|0C08h~&0kR*wTDs31CYg5&f7F%QJK?uqi&D&f9QN7)|*Bpo>c^G5P)e0qF9x(0< zjMWGPs;Gv$lE}f@?b%wvWM{{2TuD8#~z`!bDgX*mvAxpW%BRvvE%@H7e+Er`8B2l_Wa z_kC4@SkgrASPTG@#$x6~dG`rE+qizZWPT8i!w+Ap-odEJb z@GFpV{}klMeZ^$S@(ZP2>!c(nT?CjRq*~-{Cee7I0G*$7O*FERUp7XHQ z{qJuc*>aDT-J{=P#KdReE%%|a`_TVwjKllD^NFXp2wMq189Ti-cDgclRv$ZC?*CrJ zaZY!fE1MbISYTxH?ayW_y~lLSlN+{eZ_k4dKl!k(9AEasv(i7M1NBbn-l@XdAWe8( zD_`wBSWFZT;15N}Z`>)ndB~f#`m=1|O{EGm6#ae}qLWxm%*4Uweh76s1q9B4a4>}M z$#Blv(!kVO{&6wv>`WB8c72Ui;<*{ns8*vbLn&-`W5QF-);~MLQ<6`~p z_ci)4w4w)Bp8|zb83QLtma)_b5)WZq1t4^-M_LL5m^^~zN1q0=S z6+IP$l|7Y%RXtUM)jidNH9a+hOL~?te;@n{dzKE?_SE9tFBT3g8(iKK#dDDu!1Icp zmFzh`PH*U zER(kOImPmq+&$Z*l^3>aK4OJbDptZ}hwf4)I{Un0)l2TT;q3iASDvfzF|3Y=OAk@cRFk|X^ho?Noj z*XYf9+GII?C0lUf@grT`olj)lz41gc>rW(Q|8YzCKCLdd^;< z_yt*iToh##Xt*!y>y1&KVk22kZ>)bPNe+qrloU&53wmRt1H(h-$m!y6zlbpYkt?y` zvlmb+$c3wI=t|bt9v>KppB<30?qmJPgzxbY%6)tw>pLYqKPnCNN?A|$C`#7ol&Rlm zgWX>_(HUz$+}Zxvk*-4@5w=koC0QPp6CV+3Ko>t$p%gwLP6S+$qp&e+vv;&Su(Lf6fS;F%0_w-9Jxh~Vu{hg!MJ<{$$1YB z%Y&$;!p_T5?<#5D2jejFW3xM7WGPphV8Rpk}<8Dwo&R5ma$=LXz>xnEKf>YLe}eoQwmN`+#AisQl<)|GD$Y zC>jW89F1R$_cMHm_8YT@OvL?<0h2-#Xba(){q)ejS+=Tp8(Fph?FXlVKeX70B zj%~OYmp5FxbZNuj74#?>y;hXtgYgXrx`9{y=H^YCHYEC!()y8j?{jGQ#0IrU8%CbT zPsOC>5%d|gG&0fDdi*C!0j>#u9TEb?O3~6x(K4lIS=zl!-UN3vuzW6Ch*FLYBx55< zxmPES@b%)KwW){}G`H!PkR%`VO1iZtK`;|=GkLq9$C)z3FvP`Uj&NUfj-gA9IWKs$ z5DBL!oDz~j?OhPY9Omy`b@_!c=ae2J7ZPDz=CBT7sAZLq4CTVC7Ua6C?qqS!Wy+s> z&OM2aF}Jy74&f^p=C8V6a1Z(T{gUI7aM|@0;gUndmt%}spcJSCs{oB|TF6FcS86Hi z;Y3S`B=kyA&}gY2t=bx`OEeZS8Y5H7$Rz-vUBg33qVrkL#rVLelnwD{vGegEaR5XS zw1qcs*57%#S7OvF>m3+AcMhI@Np}jyM$YB%pwT05p>J%ZZ+J(}5uG9GoXENmB|-H| zm>rc{C_q^Krj}Lt09-fXKal~rCfo~_OssnC(i>MYm5oYeV)6w*FEsAGR~VUS%@i(E3YT4LpL2RVE8zU0ulBaDcCt6) zTdDX~rrGb)J4Iy_ZEp_Tp^#O#eO2k|?Kev^zCDU>PulkT6xW;!5$Wy~YFCWA6km0k z{XU)SP~W0ypZZHs(LN|IZ(A#T(BwE!FMP1J@Ia00gRM&rl)HXj?19VA%RO-Ud5w#n z>-`5dxOx#szcdWKKjNdFB?({*1!4+&T%xnbExIJn1!`kg0U=#l(z z^WnKrDiZxtK=g=0pIa=nu|7eQf04~UgtWp)D}c0$k$w>O5-9@LQYl=mWk5iPkS%T* z3s)|h!xh`YRUq9Gq+5x51otZSo27WJ*7Ap3xWzJC+#2?c0KN|f@NMKLM;&^W=zbM8 zzooigrOmHa_p`H#%XGhLTfF7EUyaQ#s{1Xm`K{3XmfHMQGCyj8TASZ0-EW!AZ?(9b zS{xS!&P8;xD%L9$Z7-zCv*;zO(%|Swqqe)X+BMV&_BDP!nosJL0tZ1;pyh)k}Vy zS`@YviaU|wF5aJkJ#MiTIJ{eZC!F4e_dN#x-FV+?@ZW>?eMAeyrW~fC$L)pte$d=~ zxVNb^cR!vFu)ak!r_I*4+NJgj9a_H;4={|TJha3E;hkeXZULhLT_aXo)0 z@cy`XQaXViNcnvN??^`1CH99?P~o1drx1z8#agQv~UY33ByCSUrz zNuAJmvqfMRDG8c1$UA{Dobl|tqBEZUSV9`;Bmb-~HX;xAVv3Jwu}f0?IZV@Iv20;3 z3DdlTrqMK0xc^rG-vy69CdBZ>FL2I6OrKG*H+{~M)C6w`nly0kW7b&-;^%}+NKc2#yLTfW>o4mCgf%(=Gn#DD8ai_3U)b!WV!Z?IT9XooD9BSr1{b8;2lR- zV?geN6RTMHAUzSYFVmz+K184yAX|!=x|Hl<(}X9~Sps9dWtwfs^l|wx0L?$CE##wk zNl<$0;b)`ZZy8XZyHY@m0+p?V|gV*^a~P{?}fiX4PAp zr;7-Rk&7S7z@iW$&qsuUqkTr+wY`s+N7v z_qq=ugX8#P(@=RGKGfB#w<_K!mkbBa;K4liwANluzVIBw1i4~Nn9^|q(e=w569P!o zHvP-T5TwzStFf$?i$>mY$X)PCP|no3PC+atN&~2|kX~c#{b>qE&4RhMR|rI2-f?}$ zMDoVf+eNF>MXP56#ou}CmB(H_e*O43`KCm=5)9PzsWLwf9r{9_Ya~($X$$85=612jF3=XvH!L!WuRDyblcO~@xd&t= ziLjA+iMEuSz@;&#nM#4$xVt_pJ9`CU->7tX1ky1HBHeQkc75i95Q2$#Q&qj12pPiA z;a*5yqa67mYc1@DlotX+CJ1HeWc}TcMR$_CGwUX?G^bWY5Ipj6L_C`0>|M za?|(2y+7KENB+x1jwz92>AA=p}aAZ6&(faa>*I!KgxXkSTA7~*{^)?pBebgxD2%IO-Pk;?RA-y>vVV0BfbL2As zVD8L8wY4CsN2pYpN;FNbgB0tFwd9)Vs!Vx{Qr_}VEomHZ2e`lPM~b! zOj4WrJuk38lCYiKn_}67#T+EVKpK- z%vK{theSypxI#;AXIAiHorz)@YP6RY3)V&Bv<#M%AY4_K6ELhHWY_SJbVge;P+OUn zI*>?# zIzdz%mJ+lExJF+{X=E#i>!MOW)=Xp)IJZZ!{)f9dAK(j%2M-?66XUBK{TM0|qge7o zSR1di}-8q_TWNCcIGzZzL|Sl*mIn27V0SZJEdcC2}AgI56jQ`RnhLF8Q!@!|l=y zGww|3R;6_7J*SM1+E7s zy1^J_eD#X2KCS&0Ai8IemYE;U%~H^P<{2UrWyTrG1ve65m%S6w{EXJcs&&L=<%s66 z7Hd_EBf;t_^Wyvn(V(nD$`(Hk29#+W#0MC=X(dP5A{I+!P$I_4;%;vsr34YOYXb02 z2}h^OlogvY;T9#_LO6E-I9IAfR;TOsXCiG%q%9q2qw(s1gZnN}dHa#-{8;l)yoM|z zEnX4ev{{kz@))$(D`BmdI1G&j=bV0kMC|-Ub0)k&32#XIHt@3Ojf&7j)mRU>fd?}p z{B4*R0eM_qvWUFN54=d;W!>bf(ClJ9go|H}1IKH?~oD|R6x`k6boARr@K|D)iWul4| z^=`QI!|?Lk;pK0+-}Li2SK8O~Yr^vHAPYR#Xf7~DvMt|ka@CuOUj8xS+_&ewC=*_% zgx95g>wXh?CuYu;cOSW48kR*}9;Z3{w^Z)e2y6n#KL+iG&m+PT*;LQxhrw}LM;AA_ z>h(-7{~cxTHz!Uv}tlWALBldE3W z^zsM4vAXu0IGIddv1QQ($5f$8FYx?_`75_D6JD!?*QR}If9;j)KXFp!P;HqnP(5@R zlluNYEaX^>kmmeK9q>FnJ3sTWG{c-BZhFq zR8cvqHC)Lhp?du>m8k-NhE*_J4byIA4aUixN_c15x04ks>n5qPNfzfu491C&G;w}9 z`0z77%+X9jU9B37oOlVChd9*sB*+R3HK9sHLiSU%3xQ1iCA97UFOc^?a|sjYrUB{H<{ z%Bd~Ns?C}379|Wx(3S;qzaKH@Z`sewFH_se!^z>^;Q>`Q(?%eQwE&v7Xi9G`HKykA zzf$2U0WfdPN$9p@!dsQ_*0gWyuf23(S|ub!*ZIm8;@(;TQspWlnw|eNZ@DbunEZUn zhj)vQ%B3v#@7*tasMCvXI!ZY(hSZ`8cFg7!CMlO$K1q;RG)`?pTm6m z8_2T!O#n@->69;;`mdJ<%u!<&@6V``xM=fku;e?>zVhrF9j_nf`i|qy*`nY?sDT;tStt}k;rPUn4jaxFseUmm+^4j8vBB*xsIWFn zS0yrexhD@|FbYjVAoK8Jl4a@h%lYMRW_cLe*^zp)TOO72$XMf}X!;@O(lRMP6eRlm zun4u<=SQ*sL5#+kT$Pyab-EDq>?kRG4@uEWka6lN-v$}&DM^a9jy&IbMi=Nqn%gBw zV&a6#!JlEfDMSgnbS>)seSf7J&mJGq+I7P3sP|ISeH0fATirkT}B%YjT;yHeJk33n*rjuv1JSmYFI5LFd+PZroe6Ug#Ly2_3P|oQ;Q_=XCO~cxY zue|t1^7R+Zd@y#@3}X)pwlB0Iw23#^@d(A!n%asyg9nX!-*e)9vSdvNUTnhVvc%U&{qRQmr>ovs(=9%4cl0iBtoiQ_C@+ew?T&WS(Su+J)^Ws zD~cUR*mcqe8Y79VQK${|Ar0$#ZBAYcnF+<^7_N_Tj8$W8rmAMh{}ZM1`vB&}Tn|N# z=>lc;=0bxe{yu_|bhLW1;jOKF{z0=4i?M~<#Ak)rIM;lDZ%ZuV zK5T<#HppN2?zBWU2+=!jz2fh^grC|)golj?|2rP$9}%D(=^S&7xyL+jWAJ{L25@#= z^@8-F!t9rg^yzW1SC78Pt}*Yog{uW)1;8(ztifLo3tgt578ZM}EE<-1NnF?vzQD%7 zIlJUE0$}+u!Z84YEhf|ntR$XG7}mVNv=ZSt!8~(}x`BxK*dik*V*d(B%CiLi7Xn#; zted6C$Qvo!X{;IF%T&au8vnG;^%~qt2?@s#4Xf0}7~?+-*WV7;&jv~-zBaXMCV2De z$1Z1a;U@yXxEs5P{6Xv5Ww1mEE}L?vgLPk!vgO4VVsL&l*z)KwMP2jzY=xQrfU^Lv zPB@Vp@e1TWL4ghEfyum1d-CE4l$yFI3LE3{pojdg;hUh|ry>T&i;^5^QV}y%rB9SK zqNVz*CLEzr_jBV27waU`VQhqR`9pldI9q(=$H#B2&TKiPY&n!JK7t>RtuzE=D-F#F z&R}THg}^KZAN$@qQ?EY)_s!L5vfxJPyl^A9doBZ z4aQuc6CThSLm2IoR!wJ%nuVS_uvt1?Vf4&K&4615YLjEiM5mDfTMQLqxP>J_Du(>O z0W|uvt^sL?PYPU*_lpdfvQX8c7C!;a)3_|<9mTvHkw~`3v5DwRwqS_kXx1BNBtJpj zl%o>IqyWPt=-N}lx|WyGaVz1^B%%R-LPGJ9Il<%KFz{!Fv_elWQ{- z^-4wk_@O%$H8;*rRc0#IOz%pUZy!IHS6@OQomgdM%S^}3hFjZzbube?rG!s?A?(uI z3^~=Y>o4)LF#Vyuuh>6}*oM){Glo5kqT?Hey$*1}eqW;tbt#5xs2}^a$Z^f{ZDC$Y zFiaCuHF@Zj>UV@Nj#lu2aS_9)Ry?t8$~`qW^NeLwD=wQjFmZC? z!1c?Mt0$kIlqcoavF@;P+&vHOHB3YGy4i$nhkm^NmOInZskC&ai$Tr~J%E-OM>}0d zej~c^uXQ@7q350G@)EK! zz(3|@c`6**Z%W;5PHCPz6GkuZG+uw0!oy{Awj(pLsXOf$DlXCt*VsEn^ zdJz5kemBzobNr!i3+@Ou*%R;z)iv0JQnO^T`mGByB|q-W)VC`2t&`OgZ4+(3^xTSn z;QNJd&ZCFV#nhkdQY@l?tO9o%E3lF&7KhChXvT^m?0;9QrHWK`Q6n@!cVPq0J>2p7 z32yQw0Asz#e*=eys}a(-zE3(7yhhSZ-T2*FF>^A#cF+5pr=Ndk+k4xlx7}>x9!AKD z%d+)ZJ#CPvQ@K%f&KD)2vF^r({?wWWhEpekFzldXfI-uq$}W=vqD+{cEqszpJap31 z8)H}Ge?wlK0EoXZQ~T!>zaXx%CcZd09#}O=$RClrFRo@ILBxymDhx7)g>l&Wa;+Wh zo}sbhI{*+jV@6c-uri=IpAdjYh%55c@i^|Gmg?}gR&9K$`+)UBX(D^HIf9zT4SaZf8q*K_>P#Cf1U zu~j~>RVqgnj!f*zgqM>*VEgTGQ##yqry@FAwtKd6*;}ru$1>545EG;;Hht`Jl(&5B za#iB{02tCrB7f}@DwkMzu<%k!e&=lE68ii-B)=yUUO`;gQ@5dX6kf-Y-^-Ifo{6?7 z(Ux?@W=ejGJ$YWZ>GkQ#9pi_QdCVaLOEKwWzX*e6vjP07=Suv=g>!=6U%0>&U=FSI z>l`*sUEgV3r!}vvTeeHNj7p-`p*H_^DK@Qf>(d&8=pxUw#xPVHWWMHU4KcR1>utEa ztGi-aV@!#d6Lw)3(!Za7S_2`C7tCn676a2OJtfhTtj@VFh8ayRF@*P;2`q*^Z`Wrv z4Wu>E5FH#%Fl$Ck36O91V(O8p+6GmGpFa%IRfrudVZpVp+89_PPIq)Ul(r2}2G$IK+$CNUxQn4S7r$F0hr9RDf8pW;7V zNO(6~^TlUw5QjfI*`X|5H!aQ_y7|m_zay9iN0>)8e)(MW<3rQ#EsC^dh)yh$O=HaM4CZ5+4YZ2Tl%PZrf zeUPQ-Bt&Z-y4#3OY0lTc?;1!5h>i!`FY&(ax6xDH)rr|v|Ck?y$3S2%=)AO8kgUz6 zyePu6+z{SxBRt@@X_bgkn7@^qps?*~gdHl-WO`%>Lh6X1VO^KjJmDf{MwP5>+~BlUEeaPtfOb$kt&z^aBO5AQ4K9kL}9CdF_*;}f2neoABTM*ENlRbJ4r}Hyzk;g(=duq zT(y{`+23ji2twZFvj=Jj=tMSEBf?y$+>gDZ8uI5>Odg~o5W#K`HTDDhFShRIbRO*6w)_GrtIg zrVD&+rh>1?bSwrrXAsLcwr80t11z`jZjr;sTBA(d=KYt1l&>N!uH0fm$|IcrKLq6# z_YYft)S6y;i2pK?!%F0EI&e4-QqsC!)ASZ)?XH{MneYK6e85CRkN)_XTU#<)4=Y;_ zr;Cr`_W+qV&BwIMiwDNR|CWG$aROSUp#t{*!yNFy;>l;Rfqb&4^D;j&%(+_>tisx7 zu|JbOo2pRJ)8hW`DCX~?!SmqdgQv22@RA08u7*F;oe8!o!B(AE{#NS>^=#b&g1J-P z^^iwFE2DN=X~Dq*C=(A{s7f3&6 z^nunfa@&JQ=#_;s9PHaa!SuX1Eogt`HFOS?YAy-{(5|DDw%hKojyd2v*JUA%TPIssQ^{@vDzq?HEiB@ znnX30CB%F@t)`4Yf=jY81*;Q-BvE&ePU>G4N~3GDhhU36$M^%E5)mrRhmrkR;76B?V_#eqOIDNjrlcC$)ejf zgtW^8bgbKgZ#+EKY51h>y2B=w{=|XNgsNF-EpS19B6b$Oy8KgpFQGz`pqW`QxPEoA zTd7^22{$X@=CrT*%g!`5A@wJ)qv9-9D4#b_b88$S_*p%OqttIQXB4rtw1nChD3aR z8EK2W3OyoUg;r689!F?wRx1j8D+xmce8!Z>gm)?7UAK#NrHgiH+Gic_Uj^5?;efK? zK)SdCKO5y00=p63j!Zh?`8mEt+Cdj^=NBx2Q2$V`oOYSr5=efcV@%5|d1RZ$oX@e8 z(RBI0;(Az;#Wt0>yHbsP1EY!aM65J2W#3@NO*=7hTdKqs9!fn#bPTFKY`lO?7Zy~G zlBaE$@GwtZ2cNwyr)E5h;B3z!mN02a;|YC|dmbn z9N3fQcxBu8HjTh_{jBy@GPCoTvh!HFt_#0ReCaqsSnJzLf1ov$#OW}UY7D88Axp`i zHD&W#L-oF$)jP8cQ$Lkd8n$P`JCyJaYJx+06Le-G2bIXdbl@Oqjvr#0 zS2xL_Ic%p2KY&kwO9@4;4|6Uzv_T1N7W=eM|rDU@c>JepC6MP#vGRQVzm>2@80#^Bdg$FamT5vO3*f@q*mAYVa*RYS=m*C^pNL{V4WDX*E__Ubb?o*6&L=0WQAo%)}xy4m-WwLe{( z2_95}2lI?;3rKo%0~_#|l&ehGqVq1_MwZOjl7Gr%Wgaapska_lQpXImq^|e@JXyrl z$<&h7rj~>Pa;_oOxf6EHsLj`j{h6I8$~+CXCx62Q^d>^;y3)GQ@h~;pA>M2>LtV!B zjG6LGaJv%Ro~K2g{AKO0l9{${rL8+%_auIq$Wuz>sdV5eLxXtZi7P`m!wre+m);^z zAg|^Yc^iS=)dPYkQa@L(9B+v}sk@uWrkR68OCns(iu+a9m`gW9u-e#SITDMOH0atc zt|jHIMrji5=Q68BS$1ILl!`3dNFC6uH!2fh)gLvKlTP%Z_nSjltwd7@Y&QMqKat6V zrTjc6;&JU1f-(6}J7jCX8ik-?+(aP?QTG-^lS#QjrY#QHLJSnJ0)4Sxx&*GRi`?6o zJ15%g>;Uf&H!AHWf?+*)Do6qnJ2^4Al0r*j8fk-^l-Iu6bE9Xx@J>m&Qo?7CKbCGD z&1^fQY&-O;icHA~rR2o8cebcx;)z#wkMCae%m)_VE9L~Rf9<`}rIS6=6`9hFO6kV& zjyr+k>s^zrnLxb~s80v#XG^Q!Xq^%>OV%n&)}~9>rUPs5GN<0}?R$M+y0j@B;Fi?L z0zGszhfRo2(cvK+CYTrwXyIh;WW%QQP$0jkcS1< zCv)uW8N%1ckqM@#76@P8J-PjM(aLnuN`{Sf>G~s?$WbM7G#xk!Jif7H^2w?0Oi2@r z;g5T9_=0M|bLwKo*R1$RxWj*}!)7skjGs&7$10Lbn#pMntI)>C7r(3n9NL&HtvFNv zNN?lz;i10%b1)&RH}hHPeEecR3=E^a7ieok)3!2YW;}r~Y_3OG!x6|3 z!(f#IGr4ZUhl5nyd60rk6*J1kOyn5C^VZ|GYUR^tJ)U$zYpNK_o4!b6aX(KD z8AX*by=Z?>@hxRSx9QQ0Z>!=XV?g|8mzPinW*vP89v0IiW;(Aoh^#kAM}NZD>(?d3kvB-1+DkR=72d+KHH?Y-6a}QCKsdzo+Syin)LqlCvAu$##M2 zs|zZ%&{SUY2ON3Ip zbZ&um7cZtRnX0bqZKUz8p3YS_cDKwY{xfs+i{Rai+`M&+zUnbe26KefGL~bk_pna) zJ9--%j#9<0I;0{ zBw}Br$-gELYxME%RSs=1?rTgk9}}A64YVC^UqkO>%`4M3gRE;9a(_0hpk^h+)O1aX z)lcM1v}hK(Y#xMQ!-&rMC067^>T1)rTU&lroe7;%LZ>j<44d_v9whw49)M8gMB?RV zuRlBPBr+VDNMw9Va9$29Q5YCnzQ3H?z{^jDFD@ES%|k6SND?+mN%P21b>0!P3=1Pb z*wmH6(5oI7t)KNF4UQzQ;KUEUIHk$gux)WL{+!fFo|+$TQ<}7z%!!<(Mzl``ODKMf zrLHY}XcN_bn^w{3yp z=e(_2@^b{{;u<(moqU-myXNp;cZe=jkvsK5Cp&6ED-s*&4J4{nj`t^U_`nNNv(>0~ zE1g?_Q^MKN<3xWL>oE+f#LjMj={GG=omvv4EWZB5T6Tqz%;dxv#woFN>T7FrCW=apbzbgI>aFuAnw-+3wHU3M zAJpPq7;6|Ch!q0~kr!&wD5}lYHzO3w(yE$uQ@hs>s8My9GBv7d|FUR{Qncl!<95-` zbkR=UsBb+pvn5lvL#fN1NJMRmR_9hw^RF08eXh1;%VnR##-ixb=bQO^yM=Kd5iUQxHqSR3kI% zC}DFO*j|2A4l{j9#GI{^M*EYAD0oN+F0o&?ug`Q$&%)yiM=hQT8INRNVJnVSbg9S} zs1+yULyVpM<%s7N}fEk5s@R*;@ zz_ir@rmhSGC+ntzhD>}b4JY(}Uj+EPYx_8x&UBuk8EuHOz2-bBz@#e;8qU-yz5lj@ zONH!)jr)w~pQFBNI}}Nla6A)E^*aX?Ve&-nT&G;yeO5K!0{%PdiAMTLhbGt=&CAy^ z+xfb-h2gY?-=`Kiz*=OE%tNXR^=4(y)|mW+2#tX3i`Gr?6#a1~>4 z$6uho+*~4mGd%sJH3O^qqhFxvao*KXGFRjBC91#60NCHpq`y?5Mp+B9&6_G#wGZ{f z)czS&Bsa5*O*so!WVm!ZIRUGuI1jQ8rn1w%I!@J)gnsE1br7m~2OyZY0-ys8yCqwvLqyXGbm26-i;EjVWxj zafJ;aE5+;L$1&migi27oB1f6D3>srN@i?ZQdiqszrRimsPL3V!#j&V3Ej2MPoWyCV zobObR$HUByj**i|_A8&F7%sTTXXvSj9k0qw7jyHTv_LA4uuycoAgu+k!}cJtmPuBM zBN|BCj~%uqm(f#_+eAb*PhZE)Z+7P2`df1kjAMc@Yn-X!o32)sjpmLB9E z5{MG`Cj@>%;13A=oB+eHKcc69O5lGaaGSvYOkgEI*4^Ftbhk{ZeDa?X_%i~3LE!%) z5Fzj<1U#ruxsU*z=O&jBC?ilwpoTy#fhYk|bAzBA>U3DfT|+Kw32Y!h5=D6jJ?$p2 zpFkzKbFKKk;shiD=LtMVV2Hr;1c?8UODV>82oU*@sVDKRkQ?b~ z6M+^29U9n&hs0+^)Ty+;Ij7U(g9$ePUqOlY+L5`4-?M`3;%|j52hR#CsBn9*x7-W@ zF3;x4RnV38Y_@_z!CNxtEbuI!9Gw$zn})p&+;ZS!7ec)BRTgG0qJ^G1%|l<#1!Pa= z&<;<_WG@!yJuOz?b$Re1GeA~CbIyQg%jDsyQ?DO~-4D-}9H5j#FFnly%q?X>eV+OW zF^vVY3fRKKOAhFP$+gVsX`l);0-w`Ehj7`T&*9lP*-p9LXa!zYcDJW)5@pA2D#30! zpqCw<7{#eD4$s<&PD*HP4(NF!S0u`Ut)Gx6#QGdC1Y4gAHd&Vo!JhI5TU=_Jcxsy{ zAr1_wZOVOgajC7FK)pCTXbKG&Qd_5|wsEqYLKv#o5Nx9!tZC9k!RX9h6&Qjw>A_m3 zSYwfORu2b;V6Agrr)MvrDsI!4Z+hN)kv&?0Pi=&))CU}%tvO&wY^(mwZBwf##I_tT z1ly(u+cL#U02Fo*9s?MHZBc`{JrOD>ZaJU_BUcTNHci4JpVmz5Ne@P@9FM%7gN`XT zR-17*LOm$+C}zd=csd=ENoY;sZiISR<`Gh>X5(ZBeRSSdEAT9(Zh_lWiruUr;_;kz zOaXi8K8?iao(EP48@J4E+B#di>h-VA1;ZZL$^p1rQZeVD7q3vceDdA1ICJDSwUSc;U5Ulr-J6Mu#avu zRoqSwObr3BildjjEk_=f;*gW2<;aP*96h1pf^%VdqVx^m1qZ9SN@`93R!(~1HAhdD zPmvR9u57M|o+yq1w6dC8HdoX_&HyYudQnRfP?m31Dz?oPkeknhYkqR#RYp&!va-1# zJyALaaNa>329zJS859LKD~J?$Lero~xXpC4n-w6$(y2}sZ~6keSpiFAvLKzebrf?|zoPpz5W`X(v>?>7-tb2dB$f}XWBQsFk;IkRdeHM2okhYh}Xw}NGU zR4IbuHU%g_{+Wc|DDkTO)`FhaJZpbFN}42*7N`6818?Y7M_{ z-E&j=QH(v`g{feV7LbMJV71$`beffL=}Zq554CCre7JIXwojE3d$&CY^l^n;3k%o? zWrM&}jN)bxDfH||quOAVmyIAcSX_w0l`SRx;En0pO*1=gcK&Ezy7mB0*_d;|j};Dg zO410BUj5{GI#8@N-LUKCsdU4BWmy|lWBsjOcC&(FFM7>o+K;#^y=M2#-t?L_WjR_E z&bQDoxLHB5(?b)+g&?06bYLRTi+}yngrfIJcjUW*B=lfEVGs0xdt9Qk$1S=fPfqQs z&ndcJa`zO7tHlD`eWFM5!_9~1Lb&;HFOmXq4N9S$p&x`Oe93KI-Rudoa3S~=+5C!` zUkUsIHou67wAmL*3}0}IA$+@3Pcv+bSElS26@0EC8VtB8@`%*n$)wX=qiZ#erzPx$GC5XFBkGs?scez;0%0&5I zhOkibR$z9s{8tGFsuFTkZel*atwPpvECN@H%L2C3_on!+;e2y zt@vuv?8iG7lhK$K$n?C>Y99%mrf|1k=DuM(dfSop^bSZk+58E_GVC&C(i##|>Nymp zfmrM#${@tfSuR@Dq%z?CA*bqX(Pj=zmZPHA#XflbO@4H3s8wJ3af-db?|q@2;OrV5^k#*@*Fmt~SZ%U=P2nSI)1E$i|xc@@1f8Pfao^b7@3?Z-T;d70EB zndr;Z@Pw7I*uSNErNmLMP=H(p&Bt`;D1Ou3?>(!mKg?goU3W^BOm@8fSf*r+QnChG zz2RLGo73T4_)XTozLr0|e|Dzqo%8RV=WiSS8|$Jtb&X=2GcC`ZS@$RL%7mFkf+6ZDLSlA|L7*rk}SZEzk3_ce^qs!K64 zai11R7=B%UflVed;Y~_-Q`)y_0V4Ux^37^+-h6XkW4^gd8S*W^fu`cP0}~emqk}`S zq0zy!l9~H@)c8Yt(`j9c)$}{+qU{f?NaJB)3_})sucF$f6&Hpm*T=}HZSzbp6W*(Y z_ojV&d420N1pyy*?qNBjFG*VP98uo1=G)7C4RnY*EJ4oIgHEx?$xUZ$n5oT#_bK6h zY2UstKj+xj%(H@~o+tBuJpid5sQpxTTSi4N^isBMvSsEtw?UTn9r*IgKzoC^nfZB2 zP@sAn5MFgzVQv84QD@e3<3MTO{x3iCg!nW{&y#fz^E6^S1zwG8%QQBA`T4`aj(t#O zohN&4@}r}QHMGEMgSk$BXL5_OWc~D2%NgQdW_P4IP4uVcuT%0g)+xO=nd=mlt6%VW zgu@Ehmb3jsarsL30%J>%2Z^a8OpXIExv!@@|E`7y*+Mccp%QD#vv$!$jNb1*%tjUa z232{jiDA>fU}V^6i;E?u+q4nZZQX*38Gxa#bCbq}Q8Pm?TfvASFU^ZxUU_jd*`ctY!8gQ~+9yjZ_Xx$X*r|q9C9RnrQ z-8P{@63^j-7=|ipaDW!)S6Xjf%~YILDo(TApO8-am)t2XyAh_-AzNmS-U?=lyOiQC zvO2JI^5m2^Q`(@EHlza$%n*@EPAOQpO9^*DAR1hPqaP-ccPncq61@K#>W{TEYwJhG zO7N3CI03M7*ME-U8mOvzK-q3&z`#bR2Uz|ZxCpd8%dJjOHTLt5P(>#8vyg?0Q9#;r zu9B~u<9=#P`>=K_6K+$&ZE0WImtFHHO7Eb!z|1BaQth5-`!=vENiBxiqn(OknCx(r z%7iy7;mv8^<^>8ul90vB4a~DNCZsU!7P1N{^4qdQag7x5CF+ni&1JpNDq*x2ntL3g zLaVz~bgOn7Gr>(ta1&G>YnG)Xy`UNWDk@O{yq2Yd!9ki3T zGiCkowviXz?HH9PH>Y@!j38{vgj9SjSIW3Y&TeUYN` zImRYn!#T+-)GN16VYM-U4FDJvU}eB0oTbr^WTp2B9lk4^gM96oVhA+z7In<=ZQ)ht z^%6{PNy!TIgNYhAiD*kEJ7DKmRi}gBCkT>tQ>7b;%V&kV2l^99^um$7skM5qq)oi> zWD>@+N0U;*VEA7Te3F`YJ<_D}w49|_(bd50#x39KPy&$0VPF3oj^;G@v8HFLf~iVo znd%89Fh^!(?Ko42OsN?1zoI^Mk21}zz8OMtl>7#T`X+!jEdEQx$QEz`S|aO#ggSnO zZ@8msg+xi)B^fdo4_VQuk=f$}mGKJVqKrmI34N*dp9 zpDB3f*n7t^B|C0zPZzh3d)PKTF0%P?;^y`rj{Rut*6B>}F(vp|o^1*F_a4YsQLx4a z8H@f#N%D*IdW`^Uc3o~{)1Z{UPJzy#95P8!MM5+#kv>OmQ3Bs1x7P_w z5qOIQA@Cl7e@x)NA@E}YHwpY6fj=ZbFHk(_+tXM36zn?asq!suNK8X+IP>E zVEz>SD3L+cU(^4Lih)AODkuiJ9iF2OveLJc7UPd%q0t7t4i6Lo%mBK0ySaAYZd$H2 zf3 zF^>qbmn*I9onA$rd#zv*X{efD+eu49Yex2Ds8O_~-?N130JobicDv>KRrxQ%?9mD; z)HEMl{Rh+vJD^q=DQ`NM3a0^TjlKn1U*&J&lbYfkdopBG)4qdFC|3}pC3%B-s2-GD zHSNI7ldN(LKo91CUahwPtv$VECZMbZ?$XPx)%?CNy*ZT|A z_5MP(*6$Y!*;;=gTgxqC8tAEWY%QUC_&Et@JL^XH*anwTS;n%iW={j#_3d zbrpr%`4h2QCVEEQf5FV^Fe`n`HUy0-?>K1fmmA9?b3O81&^HrHLq!Bd6YdiYoPPoM zPZ3X>22dKtk(z15v&{+YE;vf)U>{^bP$nXp4V&$Rh*tA z+n*;&N$j6X7}vd=41weZ)P;Q^^v{47B*ju|nG)=$D&{++=Zb|W+u4pi?MoRlOm0$F zLYLkNR85w={P^|9$JrmPghHtaz}^hBfX`A@4k1#qVnQoVA^VPK|pcav1b zVp-G3E?XyG7B(9j;1U~+i}M%sg??Jfzd*_Z?3(gxPsY3G65Zy7p}f|(`M%ss>YhYe zC&i*Z5e?NUQ~YdvNCdgS4wGIf!Im~P>rEU+D$%FW2gT=8Oc+GmTtcImERofuz!p={5KRis@ z23appi`k^)goZne5{_L%aJG>$ylQH5Ce)yW8lYeR6P1JPxTM-Ufs%<;wAOwn5T08uxtTCdbxrzNL1Oh_IO3sEJ z$+4kF*hp=GU^mKWP&NW@A*mCZK~;$KK<5D}El1vZkt6-0nKE7Xrvc0(r-T`)31@u&)B-QqPkD^zq(Cn0K|nLQhbnlc)Xi z7@ShAjGmrO_7C*Ku!?F&7sK>me5ik96b8p6!+1=35l|vf$t2rlW*RqWhDYRPL9wwp zHzfN>gpKojD{1?>!%zBAl&Vrps=OWS z5ZNKFZpsp%tR!mD91ecX)=gfyCvxn~%kG1z)`y8JNtSMgzK)9q3m`@^jQ z-h<7D0K|KlK%Ekx1Bvnbl;j3hw@*K1=P|!s))p2%2v@Y#x#T#$Zep*fAF$SUg3&Td z0T;Ao8#TASNpH+DOyxgl*Eq0Qu*IohuK-1sa5u#gVCEh58*a+p=1o~Y=h$e0s2Z-onh^; zS8B|EWS5pYu@V2gqv`(7WKm8=!H0!_c5Hy<@@2@AMM2> z|79Y_l*qAk;Ml#A>Q`%S)WBLI$(&bAt$Dw5rv9Dd?;SUteB|@jz*;A!b-|iD6)Vy! z4`nJ2D;0F$%)N?ArDDx&`H~x7OP8;iI`v`M#@l5ZXDV)1XUf{4fQ|v2P6r2=a6vu> z6~)lx#Y}O%Qe2-duAi-_p777PUH;WM%FvQ2ZB|N~Rm$MZ1Xd}5RcZE9DTCP!l!02~ z=ljaq*9d>OrlNhXi;*-FX&|1Ek%r&L!{7CgOcjcsjw!s^FH0A8k=Xf}1Fv{q_T&W2 z38zCC+A;3wbBNBDd}A(~VA_q)+LRWZLUhsY?lEWnVZ=y4M0Y>Jzv=k4h4eUt>+Q_s zgQqLi^qh3%61OyW@nT#C8V`=ZB&bMwe$j#WS!p0D_9sSq&&Orc_(+U06D+sj;Wfv1 z1$;_)rj*7&!hN*42fd}Rv!XczstH4 z&s|Dn9isdn5H>+03Qg^!`}wwI>bR+;3zdbI0}|Bnk#7i6Ld9gQV%LY^w%g&hOt@VM zw_}Jbg>=#5$3_@{@php8ja}%i!HU`9@(ItZR$7#9#tp!a-WhM3UAp}BW8-b(7hXO- z8wh>p$SX%)8%kF+;y3j?zh?qXN`TDf;&(S(GVW*f($yHs%OU?Al#okfsVd};>Gd2v z{S7_Q@*Agc5YcNC?s3+38XwKbn1yjBo{lkg-=vE8@A0Ow%}jc(Z|qjLRo72;PcrG{A}lQUNv_(54h@P|@FMbBf>ajx8zJw3743Hk6(s!#lQ~^aRNCUSlZh>rC{< zN5B%N+UDV-vC}z7&5ztU8(gP zBV(YzjLSzYi-VwH>iI5s6!IZyDH4Vm+ls_ayIVYAue4++8l2vLFH zP?o#`BJY1vw{X;*iJVpHeud({w;-I=~N8 zwV$U7?rbqeTTSHQw_Op9OV|H9yW&O_UD45o*x@#^E^3^oH`dG_L#AUH7uOrfxFj2v zj_4nrw?oQBG@6+EUx_UjshUnp7tEDO$LIw?@SjT=Rb>t^YipV5(1-)!u@en)kDZV9&m;a zh6#PxmH)u__V5Fyc`$|6j$w#24j|ScPIQpAj_4$sZX0-X82}9G>Oy~GJ}>AC0H)#3 zGQeSwH4I_a9GGHS2EVtFw|DW+FUUTea+7he%t=Ub7A_goRWD;6&84D!hxP$@=!r*O zU%GV0RKAC*88gkJ^HwhCEdu7$(NT&jG{K->lP37RsS zs<4t4UWj`{R@Ndm?crEptiD?mz7F-2N`DBeBiE077+8Hfuv$L^hHl5(adHY|AhXcH^()17cQ8xreYNmLAsp@$!_eHT z{u_RBlwJ+o2z*@R4Te4u0I(Gwpjaq|{);OZxx*zjWo9x|c0A2~IXMk914<%uF2sPH z<usN2>=W{g8NDPsu*u?;vk3)Fxo}5#!S0xG=sva7y2v>3F>8I z!1X=}k&8u)0$GP)Nm4#m5d!tu-%3=HA#3 zlQj8OFEG-mncTrMW_n>cnZY&GZpvMb9sjcPfwnPdLXyNfYNU8LXtqQvk-bgkk*e1k zV$kkvow|sw6gs@QUT`jyv0aL_xOQ3c7#+fcQ%mdZ5@E8Gt9E{}j2frIA{dQgRIIT? zCbDUmTjZz}BTpq7#W_HcbJU3uFd|V|FOF!6gMLs^vN%SLe~bm^t21mO!oyS`dsYF&k zI9h?5q5+Jz8&{BPXN!;itn_C0PpW@fJ@3qhA4f5H==I~%ZJDL(Gr?vh*u2om6ebd- zvseERwPuz#$kiYp8m0+T@V8$!@?juOWU1!J4Ik9wc z>Wl1}r;EF~Qfu;e@zEh;N6|ZZW0;E)m;k}j(^>z96hVv1yDVcnDu`vFise0+b#`+% zmf6|T)b1oh(1ZwDQZd#q4MGI7$4ct3{|s>~WE*1^`qwKo>Ms4Ro|)KihmW`IDVL-I*>v#(&ny zORl43f=x=WX`w#GH^v9^il&)batBrE;{=#gI>4%#Kq-M50<{Dz5@-*(5%@h~(Ed+W zao13J^k>u{c6hL$1u*&aR3DCiXU|sP4Z|cB)Pr%Gfx$7{tY9UD7~mmBt)48x%34qL z6zn45HnWx8tYGg_qybG3+-6`e5H~B>UB>f)8|4GHc>x!nQu!MX$V@rBiw_>d=gvV+ zoOKQ-WMZVU1(&4wbF$PYyXno#4KK)qq%u(qnMe_rixH`j8LAUm;inuj?ws`zhWRwy z$~3}bgu6oWXl}NagqM7Yfwd@GQy}snvpz$cm9l6_a`*;;r36?{a}V|>dbyoiwm8A` z#iQiC0wC*!{o>KVguIemRuNcDppHO2fd&F=2s8qa3F7|25tyOL(uTNWs0ysL?j~=h z`@WgNV1EJ5GwAP?o{)N_{)-532NfqDpimtIS_v@4AQJpD6oXab!~l)sWQ7Okune6# zbu3#Fi=7?qAHc>KNlrkz4%5bF6#dM%8=Fo?2c*3+9jZ*DMxqmK0#!VRW6tSyxWT#u zlnIWaYlZYTD}=7GzgeL?ZT`&)m1*GZ?@W`(x&!~AB2jp=;9yFyLc z{F@b`Y4dMZ*pZ(9H!EyT=ljhH>(lf9KuaA591kqQT~{%Pf}>*AU7j}o?iQ6^^WF8= zj8`iDn#r9Rf1Tp5yXJ*jv}5@Ms3vY!P$oFNilbuAS>#wT3Hy7vO(&HNP#(wAuh8na z|MoHW`@|gNqN~w?`I{YlOm3g# zJf3#6I6#l=;A3+8B str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + info = connection_summary(self._pgconn) + return f"<{cls} {info} at 0x{id(self):x}>" + + def __getattr__(self, attr: str) -> Any: + value = getattr(self._pgconn, attr) + if callable(value): + return debugging(value) + else: + logger.info("PGconn.%s -> %s", attr, value) + return value + + def __setattr__(self, attr: str, value: Any) -> None: + setattr(self._pgconn, attr, value) + logger.info("PGconn.%s <- %s", attr, value) + + @classmethod + def connect(cls: Type[_Self], conninfo: bytes) -> _Self: + return cls(debugging(PGconn.connect)(conninfo)) + + @classmethod + def connect_start(cls: Type[_Self], conninfo: bytes) -> _Self: + return cls(debugging(PGconn.connect_start)(conninfo)) + + @classmethod + def ping(self, conninfo: bytes) -> int: + return debugging(PGconn.ping)(conninfo) + + +def debugging(f: Func) -> Func: + """Wrap a function in order to log its arguments and return value on call.""" + + @wraps(f) + def debugging_(*args: Any, **kwargs: Any) -> Any: + reprs = [] + for arg in args: + reprs.append(f"{arg!r}") + for k, v in kwargs.items(): + reprs.append(f"{k}={v!r}") + + logger.info("PGconn.%s(%s)", f.__name__, ", ".join(reprs)) + rv = f(*args, **kwargs) + # Display the return value only if the function is declared to return + # something else than None. + ra = inspect.signature(f).return_annotation + if ra is not None or rv is not None: + logger.info(" <- %r", rv) + return rv + + return debugging_ # type: ignore diff --git a/lib/python3.11/site-packages/psycopg/pq/_enums.py b/lib/python3.11/site-packages/psycopg/pq/_enums.py new file mode 100644 index 0000000..e0d4018 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/pq/_enums.py @@ -0,0 +1,249 @@ +""" +libpq enum definitions for psycopg +""" + +# Copyright (C) 2020 The Psycopg Team + +from enum import IntEnum, IntFlag, auto + + +class ConnStatus(IntEnum): + """ + Current status of the connection. + """ + + __module__ = "psycopg.pq" + + OK = 0 + """The connection is in a working state.""" + BAD = auto() + """The connection is closed.""" + + STARTED = auto() + MADE = auto() + AWAITING_RESPONSE = auto() + AUTH_OK = auto() + SETENV = auto() + SSL_STARTUP = auto() + NEEDED = auto() + CHECK_WRITABLE = auto() + CONSUME = auto() + GSS_STARTUP = auto() + CHECK_TARGET = auto() + CHECK_STANDBY = auto() + + +class PollingStatus(IntEnum): + """ + The status of the socket during a connection. + + If ``READING`` or ``WRITING`` you may select before polling again. + """ + + __module__ = "psycopg.pq" + + FAILED = 0 + """Connection attempt failed.""" + READING = auto() + """Will have to wait before reading new data.""" + WRITING = auto() + """Will have to wait before writing new data.""" + OK = auto() + """Connection completed.""" + + ACTIVE = auto() + + +class ExecStatus(IntEnum): + """ + The status of a command. + """ + + __module__ = "psycopg.pq" + + EMPTY_QUERY = 0 + """The string sent to the server was empty.""" + + COMMAND_OK = auto() + """Successful completion of a command returning no data.""" + + TUPLES_OK = auto() + """ + Successful completion of a command returning data (such as a SELECT or SHOW). + """ + + COPY_OUT = auto() + """Copy Out (from server) data transfer started.""" + + COPY_IN = auto() + """Copy In (to server) data transfer started.""" + + BAD_RESPONSE = auto() + """The server's response was not understood.""" + + NONFATAL_ERROR = auto() + """A nonfatal error (a notice or warning) occurred.""" + + FATAL_ERROR = auto() + """A fatal error occurred.""" + + COPY_BOTH = auto() + """ + Copy In/Out (to and from server) data transfer started. + + This feature is currently used only for streaming replication, so this + status should not occur in ordinary applications. + """ + + SINGLE_TUPLE = auto() + """ + The PGresult contains a single result tuple from the current command. + + This status occurs only when single-row mode has been selected for the + query. + """ + + PIPELINE_SYNC = auto() + """ + The PGresult represents a synchronization point in pipeline mode, + requested by PQpipelineSync. + + This status occurs only when pipeline mode has been selected. + """ + + PIPELINE_ABORTED = auto() + """ + The PGresult represents a pipeline that has received an error from the server. + + PQgetResult must be called repeatedly, and each time it will return this + status code until the end of the current pipeline, at which point it will + return PGRES_PIPELINE_SYNC and normal processing can resume. + """ + + +class TransactionStatus(IntEnum): + """ + The transaction status of a connection. + """ + + __module__ = "psycopg.pq" + + IDLE = 0 + """Connection ready, no transaction active.""" + + ACTIVE = auto() + """A command is in progress.""" + + INTRANS = auto() + """Connection idle in an open transaction.""" + + INERROR = auto() + """An error happened in the current transaction.""" + + UNKNOWN = auto() + """Unknown connection state, broken connection.""" + + +class Ping(IntEnum): + """Response from a ping attempt.""" + + __module__ = "psycopg.pq" + + OK = 0 + """ + The server is running and appears to be accepting connections. + """ + + REJECT = auto() + """ + The server is running but is in a state that disallows connections. + """ + + NO_RESPONSE = auto() + """ + The server could not be contacted. + """ + + NO_ATTEMPT = auto() + """ + No attempt was made to contact the server. + """ + + +class PipelineStatus(IntEnum): + """Pipeline mode status of the libpq connection.""" + + __module__ = "psycopg.pq" + + OFF = 0 + """ + The libpq connection is *not* in pipeline mode. + """ + ON = auto() + """ + The libpq connection is in pipeline mode. + """ + ABORTED = auto() + """ + The libpq connection is in pipeline mode and an error occurred while + processing the current pipeline. The aborted flag is cleared when + PQgetResult returns a result of type PGRES_PIPELINE_SYNC. + """ + + +class DiagnosticField(IntEnum): + """ + Fields in an error report. + """ + + __module__ = "psycopg.pq" + + # from postgres_ext.h + SEVERITY = ord("S") + SEVERITY_NONLOCALIZED = ord("V") + SQLSTATE = ord("C") + MESSAGE_PRIMARY = ord("M") + MESSAGE_DETAIL = ord("D") + MESSAGE_HINT = ord("H") + STATEMENT_POSITION = ord("P") + INTERNAL_POSITION = ord("p") + INTERNAL_QUERY = ord("q") + CONTEXT = ord("W") + SCHEMA_NAME = ord("s") + TABLE_NAME = ord("t") + COLUMN_NAME = ord("c") + DATATYPE_NAME = ord("d") + CONSTRAINT_NAME = ord("n") + SOURCE_FILE = ord("F") + SOURCE_LINE = ord("L") + SOURCE_FUNCTION = ord("R") + + +class Format(IntEnum): + """ + Enum representing the format of a query argument or return value. + + These values are only the ones managed by the libpq. `~psycopg` may also + support automatically-chosen values: see `psycopg.adapt.PyFormat`. + """ + + __module__ = "psycopg.pq" + + TEXT = 0 + """Text parameter.""" + BINARY = 1 + """Binary parameter.""" + + +class Trace(IntFlag): + """ + Enum to control tracing of the client/server communication. + """ + + __module__ = "psycopg.pq" + + SUPPRESS_TIMESTAMPS = 1 + """Do not include timestamps in messages.""" + + REGRESS_MODE = 2 + """Redact some fields, e.g. OIDs, from messages.""" diff --git a/lib/python3.11/site-packages/psycopg/pq/_pq_ctypes.py b/lib/python3.11/site-packages/psycopg/pq/_pq_ctypes.py new file mode 100644 index 0000000..9ca1d12 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/pq/_pq_ctypes.py @@ -0,0 +1,804 @@ +""" +libpq access using ctypes +""" + +# Copyright (C) 2020 The Psycopg Team + +import sys +import ctypes +import ctypes.util +from ctypes import Structure, CFUNCTYPE, POINTER +from ctypes import c_char, c_char_p, c_int, c_size_t, c_ubyte, c_uint, c_void_p +from typing import List, Optional, Tuple + +from .misc import find_libpq_full_path +from ..errors import NotSupportedError + +libname = find_libpq_full_path() +if not libname: + raise ImportError("libpq library not found") + +pq = ctypes.cdll.LoadLibrary(libname) + + +class FILE(Structure): + pass + + +FILE_ptr = POINTER(FILE) + +if sys.platform == "linux": + libcname = ctypes.util.find_library("c") + assert libcname + libc = ctypes.cdll.LoadLibrary(libcname) + + fdopen = libc.fdopen + fdopen.argtypes = (c_int, c_char_p) + fdopen.restype = FILE_ptr + + +# Get the libpq version to define what functions are available. + +PQlibVersion = pq.PQlibVersion +PQlibVersion.argtypes = [] +PQlibVersion.restype = c_int + +libpq_version = PQlibVersion() + + +# libpq data types + + +Oid = c_uint + + +class PGconn_struct(Structure): + _fields_: List[Tuple[str, type]] = [] + + +class PGresult_struct(Structure): + _fields_: List[Tuple[str, type]] = [] + + +class PQconninfoOption_struct(Structure): + _fields_ = [ + ("keyword", c_char_p), + ("envvar", c_char_p), + ("compiled", c_char_p), + ("val", c_char_p), + ("label", c_char_p), + ("dispchar", c_char_p), + ("dispsize", c_int), + ] + + +class PGnotify_struct(Structure): + _fields_ = [ + ("relname", c_char_p), + ("be_pid", c_int), + ("extra", c_char_p), + ] + + +class PGcancel_struct(Structure): + _fields_: List[Tuple[str, type]] = [] + + +class PGresAttDesc_struct(Structure): + _fields_ = [ + ("name", c_char_p), + ("tableid", Oid), + ("columnid", c_int), + ("format", c_int), + ("typid", Oid), + ("typlen", c_int), + ("atttypmod", c_int), + ] + + +PGconn_ptr = POINTER(PGconn_struct) +PGresult_ptr = POINTER(PGresult_struct) +PQconninfoOption_ptr = POINTER(PQconninfoOption_struct) +PGnotify_ptr = POINTER(PGnotify_struct) +PGcancel_ptr = POINTER(PGcancel_struct) +PGresAttDesc_ptr = POINTER(PGresAttDesc_struct) + + +# Function definitions as explained in PostgreSQL 12 documentation + +# 33.1. Database Connection Control Functions + +# PQconnectdbParams: doesn't seem useful, won't wrap for now + +PQconnectdb = pq.PQconnectdb +PQconnectdb.argtypes = [c_char_p] +PQconnectdb.restype = PGconn_ptr + +# PQsetdbLogin: not useful +# PQsetdb: not useful + +# PQconnectStartParams: not useful + +PQconnectStart = pq.PQconnectStart +PQconnectStart.argtypes = [c_char_p] +PQconnectStart.restype = PGconn_ptr + +PQconnectPoll = pq.PQconnectPoll +PQconnectPoll.argtypes = [PGconn_ptr] +PQconnectPoll.restype = c_int + +PQconndefaults = pq.PQconndefaults +PQconndefaults.argtypes = [] +PQconndefaults.restype = PQconninfoOption_ptr + +PQconninfoFree = pq.PQconninfoFree +PQconninfoFree.argtypes = [PQconninfoOption_ptr] +PQconninfoFree.restype = None + +PQconninfo = pq.PQconninfo +PQconninfo.argtypes = [PGconn_ptr] +PQconninfo.restype = PQconninfoOption_ptr + +PQconninfoParse = pq.PQconninfoParse +PQconninfoParse.argtypes = [c_char_p, POINTER(c_char_p)] +PQconninfoParse.restype = PQconninfoOption_ptr + +PQfinish = pq.PQfinish +PQfinish.argtypes = [PGconn_ptr] +PQfinish.restype = None + +PQreset = pq.PQreset +PQreset.argtypes = [PGconn_ptr] +PQreset.restype = None + +PQresetStart = pq.PQresetStart +PQresetStart.argtypes = [PGconn_ptr] +PQresetStart.restype = c_int + +PQresetPoll = pq.PQresetPoll +PQresetPoll.argtypes = [PGconn_ptr] +PQresetPoll.restype = c_int + +PQping = pq.PQping +PQping.argtypes = [c_char_p] +PQping.restype = c_int + + +# 33.2. Connection Status Functions + +PQdb = pq.PQdb +PQdb.argtypes = [PGconn_ptr] +PQdb.restype = c_char_p + +PQuser = pq.PQuser +PQuser.argtypes = [PGconn_ptr] +PQuser.restype = c_char_p + +PQpass = pq.PQpass +PQpass.argtypes = [PGconn_ptr] +PQpass.restype = c_char_p + +PQhost = pq.PQhost +PQhost.argtypes = [PGconn_ptr] +PQhost.restype = c_char_p + +_PQhostaddr = None + +if libpq_version >= 120000: + _PQhostaddr = pq.PQhostaddr + _PQhostaddr.argtypes = [PGconn_ptr] + _PQhostaddr.restype = c_char_p + + +def PQhostaddr(pgconn: PGconn_struct) -> bytes: + if not _PQhostaddr: + raise NotSupportedError( + "PQhostaddr requires libpq from PostgreSQL 12," + f" {libpq_version} available instead" + ) + + return _PQhostaddr(pgconn) + + +PQport = pq.PQport +PQport.argtypes = [PGconn_ptr] +PQport.restype = c_char_p + +PQtty = pq.PQtty +PQtty.argtypes = [PGconn_ptr] +PQtty.restype = c_char_p + +PQoptions = pq.PQoptions +PQoptions.argtypes = [PGconn_ptr] +PQoptions.restype = c_char_p + +PQstatus = pq.PQstatus +PQstatus.argtypes = [PGconn_ptr] +PQstatus.restype = c_int + +PQtransactionStatus = pq.PQtransactionStatus +PQtransactionStatus.argtypes = [PGconn_ptr] +PQtransactionStatus.restype = c_int + +PQparameterStatus = pq.PQparameterStatus +PQparameterStatus.argtypes = [PGconn_ptr, c_char_p] +PQparameterStatus.restype = c_char_p + +PQprotocolVersion = pq.PQprotocolVersion +PQprotocolVersion.argtypes = [PGconn_ptr] +PQprotocolVersion.restype = c_int + +PQserverVersion = pq.PQserverVersion +PQserverVersion.argtypes = [PGconn_ptr] +PQserverVersion.restype = c_int + +PQerrorMessage = pq.PQerrorMessage +PQerrorMessage.argtypes = [PGconn_ptr] +PQerrorMessage.restype = c_char_p + +PQsocket = pq.PQsocket +PQsocket.argtypes = [PGconn_ptr] +PQsocket.restype = c_int + +PQbackendPID = pq.PQbackendPID +PQbackendPID.argtypes = [PGconn_ptr] +PQbackendPID.restype = c_int + +PQconnectionNeedsPassword = pq.PQconnectionNeedsPassword +PQconnectionNeedsPassword.argtypes = [PGconn_ptr] +PQconnectionNeedsPassword.restype = c_int + +PQconnectionUsedPassword = pq.PQconnectionUsedPassword +PQconnectionUsedPassword.argtypes = [PGconn_ptr] +PQconnectionUsedPassword.restype = c_int + +PQsslInUse = pq.PQsslInUse +PQsslInUse.argtypes = [PGconn_ptr] +PQsslInUse.restype = c_int + +# TODO: PQsslAttribute, PQsslAttributeNames, PQsslStruct, PQgetssl + + +# 33.3. Command Execution Functions + +PQexec = pq.PQexec +PQexec.argtypes = [PGconn_ptr, c_char_p] +PQexec.restype = PGresult_ptr + +PQexecParams = pq.PQexecParams +PQexecParams.argtypes = [ + PGconn_ptr, + c_char_p, + c_int, + POINTER(Oid), + POINTER(c_char_p), + POINTER(c_int), + POINTER(c_int), + c_int, +] +PQexecParams.restype = PGresult_ptr + +PQprepare = pq.PQprepare +PQprepare.argtypes = [PGconn_ptr, c_char_p, c_char_p, c_int, POINTER(Oid)] +PQprepare.restype = PGresult_ptr + +PQexecPrepared = pq.PQexecPrepared +PQexecPrepared.argtypes = [ + PGconn_ptr, + c_char_p, + c_int, + POINTER(c_char_p), + POINTER(c_int), + POINTER(c_int), + c_int, +] +PQexecPrepared.restype = PGresult_ptr + +PQdescribePrepared = pq.PQdescribePrepared +PQdescribePrepared.argtypes = [PGconn_ptr, c_char_p] +PQdescribePrepared.restype = PGresult_ptr + +PQdescribePortal = pq.PQdescribePortal +PQdescribePortal.argtypes = [PGconn_ptr, c_char_p] +PQdescribePortal.restype = PGresult_ptr + +PQresultStatus = pq.PQresultStatus +PQresultStatus.argtypes = [PGresult_ptr] +PQresultStatus.restype = c_int + +# PQresStatus: not needed, we have pretty enums + +PQresultErrorMessage = pq.PQresultErrorMessage +PQresultErrorMessage.argtypes = [PGresult_ptr] +PQresultErrorMessage.restype = c_char_p + +# TODO: PQresultVerboseErrorMessage + +PQresultErrorField = pq.PQresultErrorField +PQresultErrorField.argtypes = [PGresult_ptr, c_int] +PQresultErrorField.restype = c_char_p + +PQclear = pq.PQclear +PQclear.argtypes = [PGresult_ptr] +PQclear.restype = None + + +# 33.3.2. Retrieving Query Result Information + +PQntuples = pq.PQntuples +PQntuples.argtypes = [PGresult_ptr] +PQntuples.restype = c_int + +PQnfields = pq.PQnfields +PQnfields.argtypes = [PGresult_ptr] +PQnfields.restype = c_int + +PQfname = pq.PQfname +PQfname.argtypes = [PGresult_ptr, c_int] +PQfname.restype = c_char_p + +# PQfnumber: useless and hard to use + +PQftable = pq.PQftable +PQftable.argtypes = [PGresult_ptr, c_int] +PQftable.restype = Oid + +PQftablecol = pq.PQftablecol +PQftablecol.argtypes = [PGresult_ptr, c_int] +PQftablecol.restype = c_int + +PQfformat = pq.PQfformat +PQfformat.argtypes = [PGresult_ptr, c_int] +PQfformat.restype = c_int + +PQftype = pq.PQftype +PQftype.argtypes = [PGresult_ptr, c_int] +PQftype.restype = Oid + +PQfmod = pq.PQfmod +PQfmod.argtypes = [PGresult_ptr, c_int] +PQfmod.restype = c_int + +PQfsize = pq.PQfsize +PQfsize.argtypes = [PGresult_ptr, c_int] +PQfsize.restype = c_int + +PQbinaryTuples = pq.PQbinaryTuples +PQbinaryTuples.argtypes = [PGresult_ptr] +PQbinaryTuples.restype = c_int + +PQgetvalue = pq.PQgetvalue +PQgetvalue.argtypes = [PGresult_ptr, c_int, c_int] +PQgetvalue.restype = POINTER(c_char) # not a null-terminated string + +PQgetisnull = pq.PQgetisnull +PQgetisnull.argtypes = [PGresult_ptr, c_int, c_int] +PQgetisnull.restype = c_int + +PQgetlength = pq.PQgetlength +PQgetlength.argtypes = [PGresult_ptr, c_int, c_int] +PQgetlength.restype = c_int + +PQnparams = pq.PQnparams +PQnparams.argtypes = [PGresult_ptr] +PQnparams.restype = c_int + +PQparamtype = pq.PQparamtype +PQparamtype.argtypes = [PGresult_ptr, c_int] +PQparamtype.restype = Oid + +# PQprint: pretty useless + +# 33.3.3. Retrieving Other Result Information + +PQcmdStatus = pq.PQcmdStatus +PQcmdStatus.argtypes = [PGresult_ptr] +PQcmdStatus.restype = c_char_p + +PQcmdTuples = pq.PQcmdTuples +PQcmdTuples.argtypes = [PGresult_ptr] +PQcmdTuples.restype = c_char_p + +PQoidValue = pq.PQoidValue +PQoidValue.argtypes = [PGresult_ptr] +PQoidValue.restype = Oid + + +# 33.3.4. Escaping Strings for Inclusion in SQL Commands + +PQescapeLiteral = pq.PQescapeLiteral +PQescapeLiteral.argtypes = [PGconn_ptr, c_char_p, c_size_t] +PQescapeLiteral.restype = POINTER(c_char) + +PQescapeIdentifier = pq.PQescapeIdentifier +PQescapeIdentifier.argtypes = [PGconn_ptr, c_char_p, c_size_t] +PQescapeIdentifier.restype = POINTER(c_char) + +PQescapeStringConn = pq.PQescapeStringConn +# TODO: raises "wrong type" error +# PQescapeStringConn.argtypes = [ +# PGconn_ptr, c_char_p, c_char_p, c_size_t, POINTER(c_int) +# ] +PQescapeStringConn.restype = c_size_t + +PQescapeString = pq.PQescapeString +# TODO: raises "wrong type" error +# PQescapeString.argtypes = [c_char_p, c_char_p, c_size_t] +PQescapeString.restype = c_size_t + +PQescapeByteaConn = pq.PQescapeByteaConn +PQescapeByteaConn.argtypes = [ + PGconn_ptr, + POINTER(c_char), # actually POINTER(c_ubyte) but this is easier + c_size_t, + POINTER(c_size_t), +] +PQescapeByteaConn.restype = POINTER(c_ubyte) + +PQescapeBytea = pq.PQescapeBytea +PQescapeBytea.argtypes = [ + POINTER(c_char), # actually POINTER(c_ubyte) but this is easier + c_size_t, + POINTER(c_size_t), +] +PQescapeBytea.restype = POINTER(c_ubyte) + + +PQunescapeBytea = pq.PQunescapeBytea +PQunescapeBytea.argtypes = [ + POINTER(c_char), # actually POINTER(c_ubyte) but this is easier + POINTER(c_size_t), +] +PQunescapeBytea.restype = POINTER(c_ubyte) + + +# 33.4. Asynchronous Command Processing + +PQsendQuery = pq.PQsendQuery +PQsendQuery.argtypes = [PGconn_ptr, c_char_p] +PQsendQuery.restype = c_int + +PQsendQueryParams = pq.PQsendQueryParams +PQsendQueryParams.argtypes = [ + PGconn_ptr, + c_char_p, + c_int, + POINTER(Oid), + POINTER(c_char_p), + POINTER(c_int), + POINTER(c_int), + c_int, +] +PQsendQueryParams.restype = c_int + +PQsendPrepare = pq.PQsendPrepare +PQsendPrepare.argtypes = [PGconn_ptr, c_char_p, c_char_p, c_int, POINTER(Oid)] +PQsendPrepare.restype = c_int + +PQsendQueryPrepared = pq.PQsendQueryPrepared +PQsendQueryPrepared.argtypes = [ + PGconn_ptr, + c_char_p, + c_int, + POINTER(c_char_p), + POINTER(c_int), + POINTER(c_int), + c_int, +] +PQsendQueryPrepared.restype = c_int + +PQsendDescribePrepared = pq.PQsendDescribePrepared +PQsendDescribePrepared.argtypes = [PGconn_ptr, c_char_p] +PQsendDescribePrepared.restype = c_int + +PQsendDescribePortal = pq.PQsendDescribePortal +PQsendDescribePortal.argtypes = [PGconn_ptr, c_char_p] +PQsendDescribePortal.restype = c_int + +PQgetResult = pq.PQgetResult +PQgetResult.argtypes = [PGconn_ptr] +PQgetResult.restype = PGresult_ptr + +PQconsumeInput = pq.PQconsumeInput +PQconsumeInput.argtypes = [PGconn_ptr] +PQconsumeInput.restype = c_int + +PQisBusy = pq.PQisBusy +PQisBusy.argtypes = [PGconn_ptr] +PQisBusy.restype = c_int + +PQsetnonblocking = pq.PQsetnonblocking +PQsetnonblocking.argtypes = [PGconn_ptr, c_int] +PQsetnonblocking.restype = c_int + +PQisnonblocking = pq.PQisnonblocking +PQisnonblocking.argtypes = [PGconn_ptr] +PQisnonblocking.restype = c_int + +PQflush = pq.PQflush +PQflush.argtypes = [PGconn_ptr] +PQflush.restype = c_int + + +# 33.5. Retrieving Query Results Row-by-Row +PQsetSingleRowMode = pq.PQsetSingleRowMode +PQsetSingleRowMode.argtypes = [PGconn_ptr] +PQsetSingleRowMode.restype = c_int + + +# 33.6. Canceling Queries in Progress + +PQgetCancel = pq.PQgetCancel +PQgetCancel.argtypes = [PGconn_ptr] +PQgetCancel.restype = PGcancel_ptr + +PQfreeCancel = pq.PQfreeCancel +PQfreeCancel.argtypes = [PGcancel_ptr] +PQfreeCancel.restype = None + +PQcancel = pq.PQcancel +# TODO: raises "wrong type" error +# PQcancel.argtypes = [PGcancel_ptr, POINTER(c_char), c_int] +PQcancel.restype = c_int + + +# 33.8. Asynchronous Notification + +PQnotifies = pq.PQnotifies +PQnotifies.argtypes = [PGconn_ptr] +PQnotifies.restype = PGnotify_ptr + + +# 33.9. Functions Associated with the COPY Command + +PQputCopyData = pq.PQputCopyData +PQputCopyData.argtypes = [PGconn_ptr, c_char_p, c_int] +PQputCopyData.restype = c_int + +PQputCopyEnd = pq.PQputCopyEnd +PQputCopyEnd.argtypes = [PGconn_ptr, c_char_p] +PQputCopyEnd.restype = c_int + +PQgetCopyData = pq.PQgetCopyData +PQgetCopyData.argtypes = [PGconn_ptr, POINTER(c_char_p), c_int] +PQgetCopyData.restype = c_int + + +# 33.10. Control Functions + +PQtrace = pq.PQtrace +PQtrace.argtypes = [PGconn_ptr, FILE_ptr] +PQtrace.restype = None + +_PQsetTraceFlags = None + +if libpq_version >= 140000: + _PQsetTraceFlags = pq.PQsetTraceFlags + _PQsetTraceFlags.argtypes = [PGconn_ptr, c_int] + _PQsetTraceFlags.restype = None + + +def PQsetTraceFlags(pgconn: PGconn_struct, flags: int) -> None: + if not _PQsetTraceFlags: + raise NotSupportedError( + "PQsetTraceFlags requires libpq from PostgreSQL 14," + f" {libpq_version} available instead" + ) + + _PQsetTraceFlags(pgconn, flags) + + +PQuntrace = pq.PQuntrace +PQuntrace.argtypes = [PGconn_ptr] +PQuntrace.restype = None + +# 33.11. Miscellaneous Functions + +PQfreemem = pq.PQfreemem +PQfreemem.argtypes = [c_void_p] +PQfreemem.restype = None + +if libpq_version >= 100000: + _PQencryptPasswordConn = pq.PQencryptPasswordConn + _PQencryptPasswordConn.argtypes = [ + PGconn_ptr, + c_char_p, + c_char_p, + c_char_p, + ] + _PQencryptPasswordConn.restype = POINTER(c_char) + + +def PQencryptPasswordConn( + pgconn: PGconn_struct, passwd: bytes, user: bytes, algorithm: bytes +) -> Optional[bytes]: + if not _PQencryptPasswordConn: + raise NotSupportedError( + "PQencryptPasswordConn requires libpq from PostgreSQL 10," + f" {libpq_version} available instead" + ) + + return _PQencryptPasswordConn(pgconn, passwd, user, algorithm) + + +PQmakeEmptyPGresult = pq.PQmakeEmptyPGresult +PQmakeEmptyPGresult.argtypes = [PGconn_ptr, c_int] +PQmakeEmptyPGresult.restype = PGresult_ptr + +PQsetResultAttrs = pq.PQsetResultAttrs +PQsetResultAttrs.argtypes = [PGresult_ptr, c_int, PGresAttDesc_ptr] +PQsetResultAttrs.restype = c_int + + +# 33.12. Notice Processing + +PQnoticeReceiver = CFUNCTYPE(None, c_void_p, PGresult_ptr) + +PQsetNoticeReceiver = pq.PQsetNoticeReceiver +PQsetNoticeReceiver.argtypes = [PGconn_ptr, PQnoticeReceiver, c_void_p] +PQsetNoticeReceiver.restype = PQnoticeReceiver + +# 34.5 Pipeline Mode + +_PQpipelineStatus = None +_PQenterPipelineMode = None +_PQexitPipelineMode = None +_PQpipelineSync = None +_PQsendFlushRequest = None + +if libpq_version >= 140000: + _PQpipelineStatus = pq.PQpipelineStatus + _PQpipelineStatus.argtypes = [PGconn_ptr] + _PQpipelineStatus.restype = c_int + + _PQenterPipelineMode = pq.PQenterPipelineMode + _PQenterPipelineMode.argtypes = [PGconn_ptr] + _PQenterPipelineMode.restype = c_int + + _PQexitPipelineMode = pq.PQexitPipelineMode + _PQexitPipelineMode.argtypes = [PGconn_ptr] + _PQexitPipelineMode.restype = c_int + + _PQpipelineSync = pq.PQpipelineSync + _PQpipelineSync.argtypes = [PGconn_ptr] + _PQpipelineSync.restype = c_int + + _PQsendFlushRequest = pq.PQsendFlushRequest + _PQsendFlushRequest.argtypes = [PGconn_ptr] + _PQsendFlushRequest.restype = c_int + + +def PQpipelineStatus(pgconn: PGconn_struct) -> int: + if not _PQpipelineStatus: + raise NotSupportedError( + "PQpipelineStatus requires libpq from PostgreSQL 14," + f" {libpq_version} available instead" + ) + return _PQpipelineStatus(pgconn) + + +def PQenterPipelineMode(pgconn: PGconn_struct) -> int: + if not _PQenterPipelineMode: + raise NotSupportedError( + "PQenterPipelineMode requires libpq from PostgreSQL 14," + f" {libpq_version} available instead" + ) + return _PQenterPipelineMode(pgconn) + + +def PQexitPipelineMode(pgconn: PGconn_struct) -> int: + if not _PQexitPipelineMode: + raise NotSupportedError( + "PQexitPipelineMode requires libpq from PostgreSQL 14," + f" {libpq_version} available instead" + ) + return _PQexitPipelineMode(pgconn) + + +def PQpipelineSync(pgconn: PGconn_struct) -> int: + if not _PQpipelineSync: + raise NotSupportedError( + "PQpipelineSync requires libpq from PostgreSQL 14," + f" {libpq_version} available instead" + ) + return _PQpipelineSync(pgconn) + + +def PQsendFlushRequest(pgconn: PGconn_struct) -> int: + if not _PQsendFlushRequest: + raise NotSupportedError( + "PQsendFlushRequest requires libpq from PostgreSQL 14," + f" {libpq_version} available instead" + ) + return _PQsendFlushRequest(pgconn) + + +# 33.18. SSL Support + +PQinitOpenSSL = pq.PQinitOpenSSL +PQinitOpenSSL.argtypes = [c_int, c_int] +PQinitOpenSSL.restype = None + + +def generate_stub() -> None: + import re + from ctypes import _CFuncPtr # type: ignore + + def type2str(fname, narg, t): + if t is None: + return "None" + elif t is c_void_p: + return "Any" + elif t is c_int or t is c_uint or t is c_size_t: + return "int" + elif t is c_char_p or t.__name__ == "LP_c_char": + if narg is not None: + return "bytes" + else: + return "Optional[bytes]" + + elif t.__name__ in ( + "LP_PGconn_struct", + "LP_PGresult_struct", + "LP_PGcancel_struct", + ): + if narg is not None: + return f"Optional[{t.__name__[3:]}]" + else: + return t.__name__[3:] + + elif t.__name__ in ("LP_PQconninfoOption_struct",): + return f"Sequence[{t.__name__[3:]}]" + + elif t.__name__ in ( + "LP_c_ubyte", + "LP_c_char_p", + "LP_c_int", + "LP_c_uint", + "LP_c_ulong", + "LP_FILE", + ): + return f"_Pointer[{t.__name__[3:]}]" + + else: + assert False, f"can't deal with {t} in {fname}" + + fn = __file__ + "i" + with open(fn) as f: + lines = f.read().splitlines() + + istart, iend = ( + i + for i, line in enumerate(lines) + if re.match(r"\s*#\s*autogenerated:\s+(start|end)", line) + ) + + known = { + line[4:].split("(", 1)[0] for line in lines[:istart] if line.startswith("def ") + } + + signatures = [] + + for name, obj in globals().items(): + if name in known: + continue + if not isinstance(obj, _CFuncPtr): + continue + + params = [] + for i, t in enumerate(obj.argtypes): + params.append(f"arg{i + 1}: {type2str(name, i, t)}") + + resname = type2str(name, None, obj.restype) + + signatures.append(f"def {name}({', '.join(params)}) -> {resname}: ...") + + lines[istart + 1 : iend] = signatures + + with open(fn, "w") as f: + f.write("\n".join(lines)) + f.write("\n") + + +if __name__ == "__main__": + generate_stub() diff --git a/lib/python3.11/site-packages/psycopg/pq/abc.py b/lib/python3.11/site-packages/psycopg/pq/abc.py new file mode 100644 index 0000000..971d00e --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/pq/abc.py @@ -0,0 +1,384 @@ +""" +Protocol objects to represent objects exposed by different pq implementations. +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Any, Callable, List, Optional, Sequence, Tuple +from typing import Union, TYPE_CHECKING +from typing_extensions import TypeAlias + +from ._enums import Format, Trace +from .._compat import Protocol + +if TYPE_CHECKING: + from .misc import PGnotify, ConninfoOption, PGresAttDesc + +# An object implementing the buffer protocol (ish) +Buffer: TypeAlias = Union[bytes, bytearray, memoryview] + + +class PGconn(Protocol): + notice_handler: Optional[Callable[["PGresult"], None]] + notify_handler: Optional[Callable[["PGnotify"], None]] + + @classmethod + def connect(cls, conninfo: bytes) -> "PGconn": + ... + + @classmethod + def connect_start(cls, conninfo: bytes) -> "PGconn": + ... + + def connect_poll(self) -> int: + ... + + def finish(self) -> None: + ... + + @property + def info(self) -> List["ConninfoOption"]: + ... + + def reset(self) -> None: + ... + + def reset_start(self) -> None: + ... + + def reset_poll(self) -> int: + ... + + @classmethod + def ping(self, conninfo: bytes) -> int: + ... + + @property + def db(self) -> bytes: + ... + + @property + def user(self) -> bytes: + ... + + @property + def password(self) -> bytes: + ... + + @property + def host(self) -> bytes: + ... + + @property + def hostaddr(self) -> bytes: + ... + + @property + def port(self) -> bytes: + ... + + @property + def tty(self) -> bytes: + ... + + @property + def options(self) -> bytes: + ... + + @property + def status(self) -> int: + ... + + @property + def transaction_status(self) -> int: + ... + + def parameter_status(self, name: bytes) -> Optional[bytes]: + ... + + @property + def error_message(self) -> bytes: + ... + + @property + def server_version(self) -> int: + ... + + @property + def socket(self) -> int: + ... + + @property + def backend_pid(self) -> int: + ... + + @property + def needs_password(self) -> bool: + ... + + @property + def used_password(self) -> bool: + ... + + @property + def ssl_in_use(self) -> bool: + ... + + def exec_(self, command: bytes) -> "PGresult": + ... + + def send_query(self, command: bytes) -> None: + ... + + def exec_params( + self, + command: bytes, + param_values: Optional[Sequence[Optional[Buffer]]], + param_types: Optional[Sequence[int]] = None, + param_formats: Optional[Sequence[int]] = None, + result_format: int = Format.TEXT, + ) -> "PGresult": + ... + + def send_query_params( + self, + command: bytes, + param_values: Optional[Sequence[Optional[Buffer]]], + param_types: Optional[Sequence[int]] = None, + param_formats: Optional[Sequence[int]] = None, + result_format: int = Format.TEXT, + ) -> None: + ... + + def send_prepare( + self, + name: bytes, + command: bytes, + param_types: Optional[Sequence[int]] = None, + ) -> None: + ... + + def send_query_prepared( + self, + name: bytes, + param_values: Optional[Sequence[Optional[Buffer]]], + param_formats: Optional[Sequence[int]] = None, + result_format: int = Format.TEXT, + ) -> None: + ... + + def prepare( + self, + name: bytes, + command: bytes, + param_types: Optional[Sequence[int]] = None, + ) -> "PGresult": + ... + + def exec_prepared( + self, + name: bytes, + param_values: Optional[Sequence[Buffer]], + param_formats: Optional[Sequence[int]] = None, + result_format: int = 0, + ) -> "PGresult": + ... + + def describe_prepared(self, name: bytes) -> "PGresult": + ... + + def send_describe_prepared(self, name: bytes) -> None: + ... + + def describe_portal(self, name: bytes) -> "PGresult": + ... + + def send_describe_portal(self, name: bytes) -> None: + ... + + def get_result(self) -> Optional["PGresult"]: + ... + + def consume_input(self) -> None: + ... + + def is_busy(self) -> int: + ... + + @property + def nonblocking(self) -> int: + ... + + @nonblocking.setter + def nonblocking(self, arg: int) -> None: + ... + + def flush(self) -> int: + ... + + def set_single_row_mode(self) -> None: + ... + + def get_cancel(self) -> "PGcancel": + ... + + def notifies(self) -> Optional["PGnotify"]: + ... + + def put_copy_data(self, buffer: Buffer) -> int: + ... + + def put_copy_end(self, error: Optional[bytes] = None) -> int: + ... + + def get_copy_data(self, async_: int) -> Tuple[int, memoryview]: + ... + + def trace(self, fileno: int) -> None: + ... + + def set_trace_flags(self, flags: Trace) -> None: + ... + + def untrace(self) -> None: + ... + + def encrypt_password( + self, passwd: bytes, user: bytes, algorithm: Optional[bytes] = None + ) -> bytes: + ... + + def make_empty_result(self, exec_status: int) -> "PGresult": + ... + + @property + def pipeline_status(self) -> int: + ... + + def enter_pipeline_mode(self) -> None: + ... + + def exit_pipeline_mode(self) -> None: + ... + + def pipeline_sync(self) -> None: + ... + + def send_flush_request(self) -> None: + ... + + +class PGresult(Protocol): + def clear(self) -> None: + ... + + @property + def status(self) -> int: + ... + + @property + def error_message(self) -> bytes: + ... + + def error_field(self, fieldcode: int) -> Optional[bytes]: + ... + + @property + def ntuples(self) -> int: + ... + + @property + def nfields(self) -> int: + ... + + def fname(self, column_number: int) -> Optional[bytes]: + ... + + def ftable(self, column_number: int) -> int: + ... + + def ftablecol(self, column_number: int) -> int: + ... + + def fformat(self, column_number: int) -> int: + ... + + def ftype(self, column_number: int) -> int: + ... + + def fmod(self, column_number: int) -> int: + ... + + def fsize(self, column_number: int) -> int: + ... + + @property + def binary_tuples(self) -> int: + ... + + def get_value(self, row_number: int, column_number: int) -> Optional[bytes]: + ... + + @property + def nparams(self) -> int: + ... + + def param_type(self, param_number: int) -> int: + ... + + @property + def command_status(self) -> Optional[bytes]: + ... + + @property + def command_tuples(self) -> Optional[int]: + ... + + @property + def oid_value(self) -> int: + ... + + def set_attributes(self, descriptions: List["PGresAttDesc"]) -> None: + ... + + +class PGcancel(Protocol): + def free(self) -> None: + ... + + def cancel(self) -> None: + ... + + +class Conninfo(Protocol): + @classmethod + def get_defaults(cls) -> List["ConninfoOption"]: + ... + + @classmethod + def parse(cls, conninfo: bytes) -> List["ConninfoOption"]: + ... + + @classmethod + def _options_from_array(cls, opts: Sequence[Any]) -> List["ConninfoOption"]: + ... + + +class Escaping(Protocol): + def __init__(self, conn: Optional[PGconn] = None): + ... + + def escape_literal(self, data: Buffer) -> bytes: + ... + + def escape_identifier(self, data: Buffer) -> bytes: + ... + + def escape_string(self, data: Buffer) -> bytes: + ... + + def escape_bytea(self, data: Buffer) -> bytes: + ... + + def unescape_bytea(self, data: Buffer) -> bytes: + ... diff --git a/lib/python3.11/site-packages/psycopg/pq/misc.py b/lib/python3.11/site-packages/psycopg/pq/misc.py new file mode 100644 index 0000000..3a43133 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/pq/misc.py @@ -0,0 +1,146 @@ +""" +Various functionalities to make easier to work with the libpq. +""" + +# Copyright (C) 2020 The Psycopg Team + +import os +import sys +import logging +import ctypes.util +from typing import cast, NamedTuple, Optional, Union + +from .abc import PGconn, PGresult +from ._enums import ConnStatus, TransactionStatus, PipelineStatus +from .._compat import cache +from .._encodings import pgconn_encoding + +logger = logging.getLogger("psycopg.pq") + +OK = ConnStatus.OK + + +class PGnotify(NamedTuple): + relname: bytes + be_pid: int + extra: bytes + + +class ConninfoOption(NamedTuple): + keyword: bytes + envvar: Optional[bytes] + compiled: Optional[bytes] + val: Optional[bytes] + label: bytes + dispchar: bytes + dispsize: int + + +class PGresAttDesc(NamedTuple): + name: bytes + tableid: int + columnid: int + format: int + typid: int + typlen: int + atttypmod: int + + +@cache +def find_libpq_full_path() -> Optional[str]: + if sys.platform == "win32": + libname = ctypes.util.find_library("libpq.dll") + + elif sys.platform == "darwin": + libname = ctypes.util.find_library("libpq.dylib") + # (hopefully) temporary hack: libpq not in a standard place + # https://github.com/orgs/Homebrew/discussions/3595 + # If pg_config is available and agrees, let's use its indications. + if not libname: + try: + import subprocess as sp + + libdir = sp.check_output(["pg_config", "--libdir"]).strip().decode() + libname = os.path.join(libdir, "libpq.dylib") + if not os.path.exists(libname): + libname = None + except Exception as ex: + logger.debug("couldn't use pg_config to find libpq: %s", ex) + + else: + libname = ctypes.util.find_library("pq") + + return libname + + +def error_message(obj: Union[PGconn, PGresult], encoding: str = "utf8") -> str: + """ + Return an error message from a `PGconn` or `PGresult`. + + The return value is a `!str` (unlike pq data which is usually `!bytes`): + use the connection encoding if available, otherwise the `!encoding` + parameter as a fallback for decoding. Don't raise exceptions on decoding + errors. + + """ + bmsg: bytes + + if hasattr(obj, "error_field"): + # obj is a PGresult + obj = cast(PGresult, obj) + bmsg = obj.error_message + + # strip severity and whitespaces + if bmsg: + bmsg = bmsg.split(b":", 1)[-1].strip() + + elif hasattr(obj, "error_message"): + # obj is a PGconn + if obj.status == OK: + encoding = pgconn_encoding(obj) + bmsg = obj.error_message + + # strip severity and whitespaces + if bmsg: + bmsg = bmsg.split(b":", 1)[-1].strip() + + else: + raise TypeError(f"PGconn or PGresult expected, got {type(obj).__name__}") + + if bmsg: + msg = bmsg.decode(encoding, "replace") + else: + msg = "no details available" + + return msg + + +def connection_summary(pgconn: PGconn) -> str: + """ + Return summary information on a connection. + + Useful for __repr__ + """ + parts = [] + if pgconn.status == OK: + # Put together the [STATUS] + status = TransactionStatus(pgconn.transaction_status).name + if pgconn.pipeline_status: + status += f", pipeline={PipelineStatus(pgconn.pipeline_status).name}" + + # Put together the (CONNECTION) + if not pgconn.host.startswith(b"/"): + parts.append(("host", pgconn.host.decode())) + if pgconn.port != b"5432": + parts.append(("port", pgconn.port.decode())) + if pgconn.user != pgconn.db: + parts.append(("user", pgconn.user.decode())) + parts.append(("database", pgconn.db.decode())) + + else: + status = ConnStatus(pgconn.status).name + + sparts = " ".join("%s=%s" % part for part in parts) + if sparts: + sparts = f" ({sparts})" + return f"[{status}]{sparts}" diff --git a/lib/python3.11/site-packages/psycopg/pq/pq_ctypes.py b/lib/python3.11/site-packages/psycopg/pq/pq_ctypes.py new file mode 100644 index 0000000..204e384 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/pq/pq_ctypes.py @@ -0,0 +1,1088 @@ +""" +libpq Python wrapper using ctypes bindings. + +Clients shouldn't use this module directly, unless for testing: they should use +the `pq` module instead, which is in charge of choosing the best +implementation. +""" + +# Copyright (C) 2020 The Psycopg Team + +import sys +import logging +from os import getpid +from weakref import ref + +from ctypes import Array, POINTER, cast, string_at, create_string_buffer, byref +from ctypes import addressof, c_char_p, c_int, c_size_t, c_ulong, c_void_p, py_object +from typing import Any, Callable, List, Optional, Sequence, Tuple +from typing import cast as t_cast, TYPE_CHECKING + +from .. import errors as e +from . import _pq_ctypes as impl +from .misc import PGnotify, ConninfoOption, PGresAttDesc +from .misc import error_message, connection_summary +from ._enums import Format, ExecStatus, Trace + +# Imported locally to call them from __del__ methods +from ._pq_ctypes import PQclear, PQfinish, PQfreeCancel, PQstatus + +if TYPE_CHECKING: + from . import abc + +__impl__ = "python" + +logger = logging.getLogger("psycopg") + + +def version() -> int: + """Return the version number of the libpq currently loaded. + + The number is in the same format of `~psycopg.ConnectionInfo.server_version`. + + Certain features might not be available if the libpq library used is too old. + """ + return impl.PQlibVersion() + + +@impl.PQnoticeReceiver # type: ignore +def notice_receiver(arg: c_void_p, result_ptr: impl.PGresult_struct) -> None: + pgconn = cast(arg, POINTER(py_object)).contents.value() + if not (pgconn and pgconn.notice_handler): + return + + res = PGresult(result_ptr) + try: + pgconn.notice_handler(res) + except Exception as exc: + logger.exception("error in notice receiver: %s", exc) + finally: + res._pgresult_ptr = None # avoid destroying the pgresult_ptr + + +class PGconn: + """ + Python representation of a libpq connection. + """ + + __slots__ = ( + "_pgconn_ptr", + "notice_handler", + "notify_handler", + "_self_ptr", + "_procpid", + "__weakref__", + ) + + def __init__(self, pgconn_ptr: impl.PGconn_struct): + self._pgconn_ptr: Optional[impl.PGconn_struct] = pgconn_ptr + self.notice_handler: Optional[Callable[["abc.PGresult"], None]] = None + self.notify_handler: Optional[Callable[[PGnotify], None]] = None + + # Keep alive for the lifetime of PGconn + self._self_ptr = py_object(ref(self)) + impl.PQsetNoticeReceiver(pgconn_ptr, notice_receiver, byref(self._self_ptr)) + + self._procpid = getpid() + + def __del__(self) -> None: + # Close the connection only if it was created in this process, + # not if this object is being GC'd after fork. + if getpid() == self._procpid: + self.finish() + + def __repr__(self) -> str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + info = connection_summary(self) + return f"<{cls} {info} at 0x{id(self):x}>" + + @classmethod + def connect(cls, conninfo: bytes) -> "PGconn": + if not isinstance(conninfo, bytes): + raise TypeError(f"bytes expected, got {type(conninfo)} instead") + + pgconn_ptr = impl.PQconnectdb(conninfo) + if not pgconn_ptr: + raise MemoryError("couldn't allocate PGconn") + return cls(pgconn_ptr) + + @classmethod + def connect_start(cls, conninfo: bytes) -> "PGconn": + if not isinstance(conninfo, bytes): + raise TypeError(f"bytes expected, got {type(conninfo)} instead") + + pgconn_ptr = impl.PQconnectStart(conninfo) + if not pgconn_ptr: + raise MemoryError("couldn't allocate PGconn") + return cls(pgconn_ptr) + + def connect_poll(self) -> int: + return self._call_int(impl.PQconnectPoll) + + def finish(self) -> None: + self._pgconn_ptr, p = None, self._pgconn_ptr + if p: + PQfinish(p) + + @property + def pgconn_ptr(self) -> Optional[int]: + """The pointer to the underlying `!PGconn` structure, as integer. + + `!None` if the connection is closed. + + The value can be used to pass the structure to libpq functions which + psycopg doesn't (currently) wrap, either in C or in Python using FFI + libraries such as `ctypes`. + """ + if self._pgconn_ptr is None: + return None + + return addressof(self._pgconn_ptr.contents) # type: ignore[attr-defined] + + @property + def info(self) -> List["ConninfoOption"]: + self._ensure_pgconn() + opts = impl.PQconninfo(self._pgconn_ptr) + if not opts: + raise MemoryError("couldn't allocate connection info") + try: + return Conninfo._options_from_array(opts) + finally: + impl.PQconninfoFree(opts) + + def reset(self) -> None: + self._ensure_pgconn() + impl.PQreset(self._pgconn_ptr) + + def reset_start(self) -> None: + if not impl.PQresetStart(self._pgconn_ptr): + raise e.OperationalError("couldn't reset connection") + + def reset_poll(self) -> int: + return self._call_int(impl.PQresetPoll) + + @classmethod + def ping(self, conninfo: bytes) -> int: + if not isinstance(conninfo, bytes): + raise TypeError(f"bytes expected, got {type(conninfo)} instead") + + return impl.PQping(conninfo) + + @property + def db(self) -> bytes: + return self._call_bytes(impl.PQdb) + + @property + def user(self) -> bytes: + return self._call_bytes(impl.PQuser) + + @property + def password(self) -> bytes: + return self._call_bytes(impl.PQpass) + + @property + def host(self) -> bytes: + return self._call_bytes(impl.PQhost) + + @property + def hostaddr(self) -> bytes: + return self._call_bytes(impl.PQhostaddr) + + @property + def port(self) -> bytes: + return self._call_bytes(impl.PQport) + + @property + def tty(self) -> bytes: + return self._call_bytes(impl.PQtty) + + @property + def options(self) -> bytes: + return self._call_bytes(impl.PQoptions) + + @property + def status(self) -> int: + return PQstatus(self._pgconn_ptr) + + @property + def transaction_status(self) -> int: + return impl.PQtransactionStatus(self._pgconn_ptr) + + def parameter_status(self, name: bytes) -> Optional[bytes]: + self._ensure_pgconn() + return impl.PQparameterStatus(self._pgconn_ptr, name) + + @property + def error_message(self) -> bytes: + return impl.PQerrorMessage(self._pgconn_ptr) + + @property + def protocol_version(self) -> int: + return self._call_int(impl.PQprotocolVersion) + + @property + def server_version(self) -> int: + return self._call_int(impl.PQserverVersion) + + @property + def socket(self) -> int: + rv = self._call_int(impl.PQsocket) + if rv == -1: + raise e.OperationalError("the connection is lost") + return rv + + @property + def backend_pid(self) -> int: + return self._call_int(impl.PQbackendPID) + + @property + def needs_password(self) -> bool: + """True if the connection authentication method required a password, + but none was available. + + See :pq:`PQconnectionNeedsPassword` for details. + """ + return bool(impl.PQconnectionNeedsPassword(self._pgconn_ptr)) + + @property + def used_password(self) -> bool: + """True if the connection authentication method used a password. + + See :pq:`PQconnectionUsedPassword` for details. + """ + return bool(impl.PQconnectionUsedPassword(self._pgconn_ptr)) + + @property + def ssl_in_use(self) -> bool: + return self._call_bool(impl.PQsslInUse) + + def exec_(self, command: bytes) -> "PGresult": + if not isinstance(command, bytes): + raise TypeError(f"bytes expected, got {type(command)} instead") + self._ensure_pgconn() + rv = impl.PQexec(self._pgconn_ptr, command) + if not rv: + raise e.OperationalError(f"executing query failed: {error_message(self)}") + return PGresult(rv) + + def send_query(self, command: bytes) -> None: + if not isinstance(command, bytes): + raise TypeError(f"bytes expected, got {type(command)} instead") + self._ensure_pgconn() + if not impl.PQsendQuery(self._pgconn_ptr, command): + raise e.OperationalError(f"sending query failed: {error_message(self)}") + + def exec_params( + self, + command: bytes, + param_values: Optional[Sequence[Optional["abc.Buffer"]]], + param_types: Optional[Sequence[int]] = None, + param_formats: Optional[Sequence[int]] = None, + result_format: int = Format.TEXT, + ) -> "PGresult": + args = self._query_params_args( + command, param_values, param_types, param_formats, result_format + ) + self._ensure_pgconn() + rv = impl.PQexecParams(*args) + if not rv: + raise e.OperationalError(f"executing query failed: {error_message(self)}") + return PGresult(rv) + + def send_query_params( + self, + command: bytes, + param_values: Optional[Sequence[Optional["abc.Buffer"]]], + param_types: Optional[Sequence[int]] = None, + param_formats: Optional[Sequence[int]] = None, + result_format: int = Format.TEXT, + ) -> None: + args = self._query_params_args( + command, param_values, param_types, param_formats, result_format + ) + self._ensure_pgconn() + if not impl.PQsendQueryParams(*args): + raise e.OperationalError( + f"sending query and params failed: {error_message(self)}" + ) + + def send_prepare( + self, + name: bytes, + command: bytes, + param_types: Optional[Sequence[int]] = None, + ) -> None: + atypes: Optional[Array[impl.Oid]] + if not param_types: + nparams = 0 + atypes = None + else: + nparams = len(param_types) + atypes = (impl.Oid * nparams)(*param_types) + + self._ensure_pgconn() + if not impl.PQsendPrepare(self._pgconn_ptr, name, command, nparams, atypes): + raise e.OperationalError( + f"sending query and params failed: {error_message(self)}" + ) + + def send_query_prepared( + self, + name: bytes, + param_values: Optional[Sequence[Optional["abc.Buffer"]]], + param_formats: Optional[Sequence[int]] = None, + result_format: int = Format.TEXT, + ) -> None: + # repurpose this function with a cheeky replacement of query with name, + # drop the param_types from the result + args = self._query_params_args( + name, param_values, None, param_formats, result_format + ) + args = args[:3] + args[4:] + + self._ensure_pgconn() + if not impl.PQsendQueryPrepared(*args): + raise e.OperationalError( + f"sending prepared query failed: {error_message(self)}" + ) + + def _query_params_args( + self, + command: bytes, + param_values: Optional[Sequence[Optional["abc.Buffer"]]], + param_types: Optional[Sequence[int]] = None, + param_formats: Optional[Sequence[int]] = None, + result_format: int = Format.TEXT, + ) -> Any: + if not isinstance(command, bytes): + raise TypeError(f"bytes expected, got {type(command)} instead") + + aparams: Optional[Array[c_char_p]] + alenghts: Optional[Array[c_int]] + if param_values: + nparams = len(param_values) + aparams = (c_char_p * nparams)( + *( + # convert bytearray/memoryview to bytes + b if b is None or isinstance(b, bytes) else bytes(b) + for b in param_values + ) + ) + alenghts = (c_int * nparams)(*(len(p) if p else 0 for p in param_values)) + else: + nparams = 0 + aparams = alenghts = None + + atypes: Optional[Array[impl.Oid]] + if not param_types: + atypes = None + else: + if len(param_types) != nparams: + raise ValueError( + "got %d param_values but %d param_types" + % (nparams, len(param_types)) + ) + atypes = (impl.Oid * nparams)(*param_types) + + if not param_formats: + aformats = None + else: + if len(param_formats) != nparams: + raise ValueError( + "got %d param_values but %d param_formats" + % (nparams, len(param_formats)) + ) + aformats = (c_int * nparams)(*param_formats) + + return ( + self._pgconn_ptr, + command, + nparams, + atypes, + aparams, + alenghts, + aformats, + result_format, + ) + + def prepare( + self, + name: bytes, + command: bytes, + param_types: Optional[Sequence[int]] = None, + ) -> "PGresult": + if not isinstance(name, bytes): + raise TypeError(f"'name' must be bytes, got {type(name)} instead") + + if not isinstance(command, bytes): + raise TypeError(f"'command' must be bytes, got {type(command)} instead") + + if not param_types: + nparams = 0 + atypes = None + else: + nparams = len(param_types) + atypes = (impl.Oid * nparams)(*param_types) + + self._ensure_pgconn() + rv = impl.PQprepare(self._pgconn_ptr, name, command, nparams, atypes) + if not rv: + raise e.OperationalError(f"preparing query failed: {error_message(self)}") + return PGresult(rv) + + def exec_prepared( + self, + name: bytes, + param_values: Optional[Sequence["abc.Buffer"]], + param_formats: Optional[Sequence[int]] = None, + result_format: int = 0, + ) -> "PGresult": + if not isinstance(name, bytes): + raise TypeError(f"'name' must be bytes, got {type(name)} instead") + + aparams: Optional[Array[c_char_p]] + alenghts: Optional[Array[c_int]] + if param_values: + nparams = len(param_values) + aparams = (c_char_p * nparams)( + *( + # convert bytearray/memoryview to bytes + b if b is None or isinstance(b, bytes) else bytes(b) + for b in param_values + ) + ) + alenghts = (c_int * nparams)(*(len(p) if p else 0 for p in param_values)) + else: + nparams = 0 + aparams = alenghts = None + + if not param_formats: + aformats = None + else: + if len(param_formats) != nparams: + raise ValueError( + "got %d param_values but %d param_types" + % (nparams, len(param_formats)) + ) + aformats = (c_int * nparams)(*param_formats) + + self._ensure_pgconn() + rv = impl.PQexecPrepared( + self._pgconn_ptr, + name, + nparams, + aparams, + alenghts, + aformats, + result_format, + ) + if not rv: + raise e.OperationalError( + f"executing prepared query failed: {error_message(self)}" + ) + return PGresult(rv) + + def describe_prepared(self, name: bytes) -> "PGresult": + if not isinstance(name, bytes): + raise TypeError(f"'name' must be bytes, got {type(name)} instead") + self._ensure_pgconn() + rv = impl.PQdescribePrepared(self._pgconn_ptr, name) + if not rv: + raise e.OperationalError(f"describe prepared failed: {error_message(self)}") + return PGresult(rv) + + def send_describe_prepared(self, name: bytes) -> None: + if not isinstance(name, bytes): + raise TypeError(f"bytes expected, got {type(name)} instead") + self._ensure_pgconn() + if not impl.PQsendDescribePrepared(self._pgconn_ptr, name): + raise e.OperationalError( + f"sending describe prepared failed: {error_message(self)}" + ) + + def describe_portal(self, name: bytes) -> "PGresult": + if not isinstance(name, bytes): + raise TypeError(f"'name' must be bytes, got {type(name)} instead") + self._ensure_pgconn() + rv = impl.PQdescribePortal(self._pgconn_ptr, name) + if not rv: + raise e.OperationalError(f"describe portal failed: {error_message(self)}") + return PGresult(rv) + + def send_describe_portal(self, name: bytes) -> None: + if not isinstance(name, bytes): + raise TypeError(f"bytes expected, got {type(name)} instead") + self._ensure_pgconn() + if not impl.PQsendDescribePortal(self._pgconn_ptr, name): + raise e.OperationalError( + f"sending describe portal failed: {error_message(self)}" + ) + + def get_result(self) -> Optional["PGresult"]: + rv = impl.PQgetResult(self._pgconn_ptr) + return PGresult(rv) if rv else None + + def consume_input(self) -> None: + if 1 != impl.PQconsumeInput(self._pgconn_ptr): + raise e.OperationalError(f"consuming input failed: {error_message(self)}") + + def is_busy(self) -> int: + return impl.PQisBusy(self._pgconn_ptr) + + @property + def nonblocking(self) -> int: + return impl.PQisnonblocking(self._pgconn_ptr) + + @nonblocking.setter + def nonblocking(self, arg: int) -> None: + if 0 > impl.PQsetnonblocking(self._pgconn_ptr, arg): + raise e.OperationalError( + f"setting nonblocking failed: {error_message(self)}" + ) + + def flush(self) -> int: + # PQflush segfaults if it receives a NULL connection + if not self._pgconn_ptr: + raise e.OperationalError("flushing failed: the connection is closed") + rv: int = impl.PQflush(self._pgconn_ptr) + if rv < 0: + raise e.OperationalError(f"flushing failed: {error_message(self)}") + return rv + + def set_single_row_mode(self) -> None: + if not impl.PQsetSingleRowMode(self._pgconn_ptr): + raise e.OperationalError("setting single row mode failed") + + def get_cancel(self) -> "PGcancel": + """ + Create an object with the information needed to cancel a command. + + See :pq:`PQgetCancel` for details. + """ + rv = impl.PQgetCancel(self._pgconn_ptr) + if not rv: + raise e.OperationalError("couldn't create cancel object") + return PGcancel(rv) + + def notifies(self) -> Optional[PGnotify]: + ptr = impl.PQnotifies(self._pgconn_ptr) + if ptr: + c = ptr.contents + return PGnotify(c.relname, c.be_pid, c.extra) + impl.PQfreemem(ptr) + else: + return None + + def put_copy_data(self, buffer: "abc.Buffer") -> int: + if not isinstance(buffer, bytes): + buffer = bytes(buffer) + rv = impl.PQputCopyData(self._pgconn_ptr, buffer, len(buffer)) + if rv < 0: + raise e.OperationalError(f"sending copy data failed: {error_message(self)}") + return rv + + def put_copy_end(self, error: Optional[bytes] = None) -> int: + rv = impl.PQputCopyEnd(self._pgconn_ptr, error) + if rv < 0: + raise e.OperationalError(f"sending copy end failed: {error_message(self)}") + return rv + + def get_copy_data(self, async_: int) -> Tuple[int, memoryview]: + buffer_ptr = c_char_p() + nbytes = impl.PQgetCopyData(self._pgconn_ptr, byref(buffer_ptr), async_) + if nbytes == -2: + raise e.OperationalError( + f"receiving copy data failed: {error_message(self)}" + ) + if buffer_ptr: + # TODO: do it without copy + data = string_at(buffer_ptr, nbytes) + impl.PQfreemem(buffer_ptr) + return nbytes, memoryview(data) + else: + return nbytes, memoryview(b"") + + def trace(self, fileno: int) -> None: + """ + Enable tracing of the client/server communication to a file stream. + + See :pq:`PQtrace` for details. + """ + if sys.platform != "linux": + raise e.NotSupportedError("currently only supported on Linux") + stream = impl.fdopen(fileno, b"w") + impl.PQtrace(self._pgconn_ptr, stream) + + def set_trace_flags(self, flags: Trace) -> None: + """ + Configure tracing behavior of client/server communication. + + :param flags: operating mode of tracing. + + See :pq:`PQsetTraceFlags` for details. + """ + impl.PQsetTraceFlags(self._pgconn_ptr, flags) + + def untrace(self) -> None: + """ + Disable tracing, previously enabled through `trace()`. + + See :pq:`PQuntrace` for details. + """ + impl.PQuntrace(self._pgconn_ptr) + + def encrypt_password( + self, passwd: bytes, user: bytes, algorithm: Optional[bytes] = None + ) -> bytes: + """ + Return the encrypted form of a PostgreSQL password. + + See :pq:`PQencryptPasswordConn` for details. + """ + out = impl.PQencryptPasswordConn(self._pgconn_ptr, passwd, user, algorithm) + if not out: + raise e.OperationalError( + f"password encryption failed: {error_message(self)}" + ) + + rv = string_at(out) + impl.PQfreemem(out) + return rv + + def make_empty_result(self, exec_status: int) -> "PGresult": + rv = impl.PQmakeEmptyPGresult(self._pgconn_ptr, exec_status) + if not rv: + raise MemoryError("couldn't allocate empty PGresult") + return PGresult(rv) + + @property + def pipeline_status(self) -> int: + if version() < 140000: + return 0 + return impl.PQpipelineStatus(self._pgconn_ptr) + + def enter_pipeline_mode(self) -> None: + """Enter pipeline mode. + + :raises ~e.OperationalError: in case of failure to enter the pipeline + mode. + """ + if impl.PQenterPipelineMode(self._pgconn_ptr) != 1: + raise e.OperationalError("failed to enter pipeline mode") + + def exit_pipeline_mode(self) -> None: + """Exit pipeline mode. + + :raises ~e.OperationalError: in case of failure to exit the pipeline + mode. + """ + if impl.PQexitPipelineMode(self._pgconn_ptr) != 1: + raise e.OperationalError(error_message(self)) + + def pipeline_sync(self) -> None: + """Mark a synchronization point in a pipeline. + + :raises ~e.OperationalError: if the connection is not in pipeline mode + or if sync failed. + """ + rv = impl.PQpipelineSync(self._pgconn_ptr) + if rv == 0: + raise e.OperationalError("connection not in pipeline mode") + if rv != 1: + raise e.OperationalError("failed to sync pipeline") + + def send_flush_request(self) -> None: + """Sends a request for the server to flush its output buffer. + + :raises ~e.OperationalError: if the flush request failed. + """ + if impl.PQsendFlushRequest(self._pgconn_ptr) == 0: + raise e.OperationalError(f"flush request failed: {error_message(self)}") + + def _call_bytes( + self, func: Callable[[impl.PGconn_struct], Optional[bytes]] + ) -> bytes: + """ + Call one of the pgconn libpq functions returning a bytes pointer. + """ + if not self._pgconn_ptr: + raise e.OperationalError("the connection is closed") + rv = func(self._pgconn_ptr) + assert rv is not None + return rv + + def _call_int(self, func: Callable[[impl.PGconn_struct], int]) -> int: + """ + Call one of the pgconn libpq functions returning an int. + """ + if not self._pgconn_ptr: + raise e.OperationalError("the connection is closed") + return func(self._pgconn_ptr) + + def _call_bool(self, func: Callable[[impl.PGconn_struct], int]) -> bool: + """ + Call one of the pgconn libpq functions returning a logical value. + """ + if not self._pgconn_ptr: + raise e.OperationalError("the connection is closed") + return bool(func(self._pgconn_ptr)) + + def _ensure_pgconn(self) -> None: + if not self._pgconn_ptr: + raise e.OperationalError("the connection is closed") + + +class PGresult: + """ + Python representation of a libpq result. + """ + + __slots__ = ("_pgresult_ptr",) + + def __init__(self, pgresult_ptr: impl.PGresult_struct): + self._pgresult_ptr: Optional[impl.PGresult_struct] = pgresult_ptr + + def __del__(self) -> None: + self.clear() + + def __repr__(self) -> str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + status = ExecStatus(self.status) + return f"<{cls} [{status.name}] at 0x{id(self):x}>" + + def clear(self) -> None: + self._pgresult_ptr, p = None, self._pgresult_ptr + if p: + PQclear(p) + + @property + def pgresult_ptr(self) -> Optional[int]: + """The pointer to the underlying `!PGresult` structure, as integer. + + `!None` if the result was cleared. + + The value can be used to pass the structure to libpq functions which + psycopg doesn't (currently) wrap, either in C or in Python using FFI + libraries such as `ctypes`. + """ + if self._pgresult_ptr is None: + return None + + return addressof(self._pgresult_ptr.contents) # type: ignore[attr-defined] + + @property + def status(self) -> int: + return impl.PQresultStatus(self._pgresult_ptr) + + @property + def error_message(self) -> bytes: + return impl.PQresultErrorMessage(self._pgresult_ptr) + + def error_field(self, fieldcode: int) -> Optional[bytes]: + return impl.PQresultErrorField(self._pgresult_ptr, fieldcode) + + @property + def ntuples(self) -> int: + return impl.PQntuples(self._pgresult_ptr) + + @property + def nfields(self) -> int: + return impl.PQnfields(self._pgresult_ptr) + + def fname(self, column_number: int) -> Optional[bytes]: + return impl.PQfname(self._pgresult_ptr, column_number) + + def ftable(self, column_number: int) -> int: + return impl.PQftable(self._pgresult_ptr, column_number) + + def ftablecol(self, column_number: int) -> int: + return impl.PQftablecol(self._pgresult_ptr, column_number) + + def fformat(self, column_number: int) -> int: + return impl.PQfformat(self._pgresult_ptr, column_number) + + def ftype(self, column_number: int) -> int: + return impl.PQftype(self._pgresult_ptr, column_number) + + def fmod(self, column_number: int) -> int: + return impl.PQfmod(self._pgresult_ptr, column_number) + + def fsize(self, column_number: int) -> int: + return impl.PQfsize(self._pgresult_ptr, column_number) + + @property + def binary_tuples(self) -> int: + return impl.PQbinaryTuples(self._pgresult_ptr) + + def get_value(self, row_number: int, column_number: int) -> Optional[bytes]: + length: int = impl.PQgetlength(self._pgresult_ptr, row_number, column_number) + if length: + v = impl.PQgetvalue(self._pgresult_ptr, row_number, column_number) + return string_at(v, length) + else: + if impl.PQgetisnull(self._pgresult_ptr, row_number, column_number): + return None + else: + return b"" + + @property + def nparams(self) -> int: + return impl.PQnparams(self._pgresult_ptr) + + def param_type(self, param_number: int) -> int: + return impl.PQparamtype(self._pgresult_ptr, param_number) + + @property + def command_status(self) -> Optional[bytes]: + return impl.PQcmdStatus(self._pgresult_ptr) + + @property + def command_tuples(self) -> Optional[int]: + rv = impl.PQcmdTuples(self._pgresult_ptr) + return int(rv) if rv else None + + @property + def oid_value(self) -> int: + return impl.PQoidValue(self._pgresult_ptr) + + def set_attributes(self, descriptions: List[PGresAttDesc]) -> None: + structs = [ + impl.PGresAttDesc_struct(*desc) for desc in descriptions # type: ignore + ] + array = (impl.PGresAttDesc_struct * len(structs))(*structs) # type: ignore + rv = impl.PQsetResultAttrs(self._pgresult_ptr, len(structs), array) + if rv == 0: + raise e.OperationalError("PQsetResultAttrs failed") + + +class PGcancel: + """ + Token to cancel the current operation on a connection. + + Created by `PGconn.get_cancel()`. + """ + + __slots__ = ("pgcancel_ptr",) + + def __init__(self, pgcancel_ptr: impl.PGcancel_struct): + self.pgcancel_ptr: Optional[impl.PGcancel_struct] = pgcancel_ptr + + def __del__(self) -> None: + self.free() + + def free(self) -> None: + """ + Free the data structure created by :pq:`PQgetCancel()`. + + Automatically invoked by `!__del__()`. + + See :pq:`PQfreeCancel()` for details. + """ + self.pgcancel_ptr, p = None, self.pgcancel_ptr + if p: + PQfreeCancel(p) + + def cancel(self) -> None: + """Requests that the server abandon processing of the current command. + + See :pq:`PQcancel()` for details. + """ + buf = create_string_buffer(256) + res = impl.PQcancel( + self.pgcancel_ptr, + byref(buf), # type: ignore[arg-type] + len(buf), + ) + if not res: + raise e.OperationalError( + f"cancel failed: {buf.value.decode('utf8', 'ignore')}" + ) + + +class Conninfo: + """ + Utility object to manipulate connection strings. + """ + + @classmethod + def get_defaults(cls) -> List[ConninfoOption]: + opts = impl.PQconndefaults() + if not opts: + raise MemoryError("couldn't allocate connection defaults") + try: + return cls._options_from_array(opts) + finally: + impl.PQconninfoFree(opts) + + @classmethod + def parse(cls, conninfo: bytes) -> List[ConninfoOption]: + if not isinstance(conninfo, bytes): + raise TypeError(f"bytes expected, got {type(conninfo)} instead") + + errmsg = c_char_p() + rv = impl.PQconninfoParse(conninfo, byref(errmsg)) # type: ignore[arg-type] + if not rv: + if not errmsg: + raise MemoryError("couldn't allocate on conninfo parse") + else: + exc = e.OperationalError( + (errmsg.value or b"").decode("utf8", "replace") + ) + impl.PQfreemem(errmsg) + raise exc + + try: + return cls._options_from_array(rv) + finally: + impl.PQconninfoFree(rv) + + @classmethod + def _options_from_array( + cls, opts: Sequence[impl.PQconninfoOption_struct] + ) -> List[ConninfoOption]: + rv = [] + skws = "keyword envvar compiled val label dispchar".split() + for opt in opts: + if not opt.keyword: + break + d = {kw: getattr(opt, kw) for kw in skws} + d["dispsize"] = opt.dispsize + rv.append(ConninfoOption(**d)) + + return rv + + +class Escaping: + """ + Utility object to escape strings for SQL interpolation. + """ + + def __init__(self, conn: Optional[PGconn] = None): + self.conn = conn + + def escape_literal(self, data: "abc.Buffer") -> bytes: + if not self.conn: + raise e.OperationalError("escape_literal failed: no connection provided") + + self.conn._ensure_pgconn() + # TODO: might be done without copy (however C does that) + if not isinstance(data, bytes): + data = bytes(data) + out = impl.PQescapeLiteral(self.conn._pgconn_ptr, data, len(data)) + if not out: + raise e.OperationalError( + f"escape_literal failed: {error_message(self.conn)} bytes" + ) + rv = string_at(out) + impl.PQfreemem(out) + return rv + + def escape_identifier(self, data: "abc.Buffer") -> bytes: + if not self.conn: + raise e.OperationalError("escape_identifier failed: no connection provided") + + self.conn._ensure_pgconn() + + if not isinstance(data, bytes): + data = bytes(data) + out = impl.PQescapeIdentifier(self.conn._pgconn_ptr, data, len(data)) + if not out: + raise e.OperationalError( + f"escape_identifier failed: {error_message(self.conn)} bytes" + ) + rv = string_at(out) + impl.PQfreemem(out) + return rv + + def escape_string(self, data: "abc.Buffer") -> bytes: + if not isinstance(data, bytes): + data = bytes(data) + + if self.conn: + self.conn._ensure_pgconn() + error = c_int() + out = create_string_buffer(len(data) * 2 + 1) + impl.PQescapeStringConn( + self.conn._pgconn_ptr, + byref(out), # type: ignore[arg-type] + data, + len(data), + byref(error), # type: ignore[arg-type] + ) + + if error: + raise e.OperationalError( + f"escape_string failed: {error_message(self.conn)} bytes" + ) + + else: + out = create_string_buffer(len(data) * 2 + 1) + impl.PQescapeString( + byref(out), # type: ignore[arg-type] + data, + len(data), + ) + + return out.value + + def escape_bytea(self, data: "abc.Buffer") -> bytes: + len_out = c_size_t() + # TODO: might be able to do without a copy but it's a mess. + # the C library does it better anyway, so maybe not worth optimising + # https://mail.python.org/pipermail/python-dev/2012-September/121780.html + if not isinstance(data, bytes): + data = bytes(data) + if self.conn: + self.conn._ensure_pgconn() + out = impl.PQescapeByteaConn( + self.conn._pgconn_ptr, + data, + len(data), + byref(t_cast(c_ulong, len_out)), # type: ignore[arg-type] + ) + else: + out = impl.PQescapeBytea( + data, + len(data), + byref(t_cast(c_ulong, len_out)), # type: ignore[arg-type] + ) + if not out: + raise MemoryError( + f"couldn't allocate for escape_bytea of {len(data)} bytes" + ) + + rv = string_at(out, len_out.value - 1) # out includes final 0 + impl.PQfreemem(out) + return rv + + def unescape_bytea(self, data: "abc.Buffer") -> bytes: + # not needed, but let's keep it symmetric with the escaping: + # if a connection is passed in, it must be valid. + if self.conn: + self.conn._ensure_pgconn() + + len_out = c_size_t() + if not isinstance(data, bytes): + data = bytes(data) + out = impl.PQunescapeBytea( + data, + byref(t_cast(c_ulong, len_out)), # type: ignore[arg-type] + ) + if not out: + raise MemoryError( + f"couldn't allocate for unescape_bytea of {len(data)} bytes" + ) + + rv = string_at(out, len_out.value) + impl.PQfreemem(out) + return rv + + +# importing the ssl module sets up Python's libcrypto callbacks +import ssl # noqa + +# disable libcrypto setup in libpq, so it won't stomp on the callbacks +# that have already been set up +impl.PQinitOpenSSL(1, 0) + +__build_version__ = version() diff --git a/lib/python3.11/site-packages/psycopg/py.typed b/lib/python3.11/site-packages/psycopg/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/lib/python3.11/site-packages/psycopg/rows.py b/lib/python3.11/site-packages/psycopg/rows.py new file mode 100644 index 0000000..cb28b57 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/rows.py @@ -0,0 +1,256 @@ +""" +psycopg row factories +""" + +# Copyright (C) 2021 The Psycopg Team + +import functools +from typing import Any, Callable, Dict, List, Optional, NamedTuple, NoReturn +from typing import TYPE_CHECKING, Sequence, Tuple, Type, TypeVar +from collections import namedtuple +from typing_extensions import TypeAlias + +from . import pq +from . import errors as e +from ._compat import Protocol +from ._encodings import _as_python_identifier + +if TYPE_CHECKING: + from .cursor import BaseCursor, Cursor + from .cursor_async import AsyncCursor + from psycopg.pq.abc import PGresult + +COMMAND_OK = pq.ExecStatus.COMMAND_OK +TUPLES_OK = pq.ExecStatus.TUPLES_OK +SINGLE_TUPLE = pq.ExecStatus.SINGLE_TUPLE + +T = TypeVar("T", covariant=True) + +# Row factories + +Row = TypeVar("Row", covariant=True) + + +class RowMaker(Protocol[Row]): + """ + Callable protocol taking a sequence of value and returning an object. + + The sequence of value is what is returned from a database query, already + adapted to the right Python types. The return value is the object that your + program would like to receive: by default (`tuple_row()`) it is a simple + tuple, but it may be any type of object. + + Typically, `!RowMaker` functions are returned by `RowFactory`. + """ + + def __call__(self, __values: Sequence[Any]) -> Row: + ... + + +class RowFactory(Protocol[Row]): + """ + Callable protocol taking a `~psycopg.Cursor` and returning a `RowMaker`. + + A `!RowFactory` is typically called when a `!Cursor` receives a result. + This way it can inspect the cursor state (for instance the + `~psycopg.Cursor.description` attribute) and help a `!RowMaker` to create + a complete object. + + For instance the `dict_row()` `!RowFactory` uses the names of the column to + define the dictionary key and returns a `!RowMaker` function which would + use the values to create a dictionary for each record. + """ + + def __call__(self, __cursor: "Cursor[Any]") -> RowMaker[Row]: + ... + + +class AsyncRowFactory(Protocol[Row]): + """ + Like `RowFactory`, taking an async cursor as argument. + """ + + def __call__(self, __cursor: "AsyncCursor[Any]") -> RowMaker[Row]: + ... + + +class BaseRowFactory(Protocol[Row]): + """ + Like `RowFactory`, taking either type of cursor as argument. + """ + + def __call__(self, __cursor: "BaseCursor[Any, Any]") -> RowMaker[Row]: + ... + + +TupleRow: TypeAlias = Tuple[Any, ...] +""" +An alias for the type returned by `tuple_row()` (i.e. a tuple of any content). +""" + + +DictRow: TypeAlias = Dict[str, Any] +""" +An alias for the type returned by `dict_row()` + +A `!DictRow` is a dictionary with keys as string and any value returned by the +database. +""" + + +def tuple_row(cursor: "BaseCursor[Any, Any]") -> "RowMaker[TupleRow]": + r"""Row factory to represent rows as simple tuples. + + This is the default factory, used when `~psycopg.Connection.connect()` or + `~psycopg.Connection.cursor()` are called without a `!row_factory` + parameter. + + """ + # Implementation detail: make sure this is the tuple type itself, not an + # equivalent function, because the C code fast-paths on it. + return tuple + + +def dict_row(cursor: "BaseCursor[Any, Any]") -> "RowMaker[DictRow]": + """Row factory to represent rows as dictionaries. + + The dictionary keys are taken from the column names of the returned columns. + """ + names = _get_names(cursor) + if names is None: + return no_result + + def dict_row_(values: Sequence[Any]) -> Dict[str, Any]: + # https://github.com/python/mypy/issues/2608 + return dict(zip(names, values)) # type: ignore[arg-type] + + return dict_row_ + + +def namedtuple_row( + cursor: "BaseCursor[Any, Any]", +) -> "RowMaker[NamedTuple]": + """Row factory to represent rows as `~collections.namedtuple`. + + The field names are taken from the column names of the returned columns, + with some mangling to deal with invalid names. + """ + res = cursor.pgresult + if not res: + return no_result + + nfields = _get_nfields(res) + if nfields is None: + return no_result + + nt = _make_nt(cursor._encoding, *(res.fname(i) for i in range(nfields))) + return nt._make + + +@functools.lru_cache(512) +def _make_nt(enc: str, *names: bytes) -> Type[NamedTuple]: + snames = tuple(_as_python_identifier(n.decode(enc)) for n in names) + return namedtuple("Row", snames) # type: ignore[return-value] + + +def class_row(cls: Type[T]) -> BaseRowFactory[T]: + r"""Generate a row factory to represent rows as instances of the class `!cls`. + + The class must support every output column name as a keyword parameter. + + :param cls: The class to return for each row. It must support the fields + returned by the query as keyword arguments. + :rtype: `!Callable[[Cursor],` `RowMaker`\[~T]] + """ + + def class_row_(cursor: "BaseCursor[Any, Any]") -> "RowMaker[T]": + names = _get_names(cursor) + if names is None: + return no_result + + def class_row__(values: Sequence[Any]) -> T: + return cls(**dict(zip(names, values))) # type: ignore[arg-type] + + return class_row__ + + return class_row_ + + +def args_row(func: Callable[..., T]) -> BaseRowFactory[T]: + """Generate a row factory calling `!func` with positional parameters for every row. + + :param func: The function to call for each row. It must support the fields + returned by the query as positional arguments. + """ + + def args_row_(cur: "BaseCursor[Any, T]") -> "RowMaker[T]": + def args_row__(values: Sequence[Any]) -> T: + return func(*values) + + return args_row__ + + return args_row_ + + +def kwargs_row(func: Callable[..., T]) -> BaseRowFactory[T]: + """Generate a row factory calling `!func` with keyword parameters for every row. + + :param func: The function to call for each row. It must support the fields + returned by the query as keyword arguments. + """ + + def kwargs_row_(cursor: "BaseCursor[Any, T]") -> "RowMaker[T]": + names = _get_names(cursor) + if names is None: + return no_result + + def kwargs_row__(values: Sequence[Any]) -> T: + return func(**dict(zip(names, values))) # type: ignore[arg-type] + + return kwargs_row__ + + return kwargs_row_ + + +def no_result(values: Sequence[Any]) -> NoReturn: + """A `RowMaker` that always fail. + + It can be used as return value for a `RowFactory` called with no result. + Note that the `!RowFactory` *will* be called with no result, but the + resulting `!RowMaker` never should. + """ + raise e.InterfaceError("the cursor doesn't have a result") + + +def _get_names(cursor: "BaseCursor[Any, Any]") -> Optional[List[str]]: + res = cursor.pgresult + if not res: + return None + + nfields = _get_nfields(res) + if nfields is None: + return None + + enc = cursor._encoding + return [ + res.fname(i).decode(enc) for i in range(nfields) # type: ignore[union-attr] + ] + + +def _get_nfields(res: "PGresult") -> Optional[int]: + """ + Return the number of columns in a result, if it returns tuples else None + + Take into account the special case of results with zero columns. + """ + nfields = res.nfields + + if ( + res.status == TUPLES_OK + or res.status == SINGLE_TUPLE + # "describe" in named cursors + or (res.status == COMMAND_OK and nfields) + ): + return nfields + else: + return None diff --git a/lib/python3.11/site-packages/psycopg/server_cursor.py b/lib/python3.11/site-packages/psycopg/server_cursor.py new file mode 100644 index 0000000..7a86e59 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/server_cursor.py @@ -0,0 +1,478 @@ +""" +psycopg server-side cursor objects. +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Any, AsyncIterator, List, Iterable, Iterator +from typing import Optional, TypeVar, TYPE_CHECKING, overload +from warnings import warn + +from . import pq +from . import sql +from . import errors as e +from .abc import ConnectionType, Query, Params, PQGen +from .rows import Row, RowFactory, AsyncRowFactory +from .cursor import BaseCursor, Cursor +from .generators import execute +from .cursor_async import AsyncCursor + +if TYPE_CHECKING: + from .connection import Connection + from .connection_async import AsyncConnection + +DEFAULT_ITERSIZE = 100 + +TEXT = pq.Format.TEXT +BINARY = pq.Format.BINARY + +COMMAND_OK = pq.ExecStatus.COMMAND_OK +TUPLES_OK = pq.ExecStatus.TUPLES_OK + +IDLE = pq.TransactionStatus.IDLE +INTRANS = pq.TransactionStatus.INTRANS + + +class ServerCursorMixin(BaseCursor[ConnectionType, Row]): + """Mixin to add ServerCursor behaviour and implementation a BaseCursor.""" + + __slots__ = "_name _scrollable _withhold _described itersize _format".split() + + def __init__( + self, + name: str, + scrollable: Optional[bool], + withhold: bool, + ): + self._name = name + self._scrollable = scrollable + self._withhold = withhold + self._described = False + self.itersize: int = DEFAULT_ITERSIZE + self._format = TEXT + + def __repr__(self) -> str: + # Insert the name as the second word + parts = super().__repr__().split(None, 1) + parts.insert(1, f"{self._name!r}") + return " ".join(parts) + + @property + def name(self) -> str: + """The name of the cursor.""" + return self._name + + @property + def scrollable(self) -> Optional[bool]: + """ + Whether the cursor is scrollable or not. + + If `!None` leave the choice to the server. Use `!True` if you want to + use `scroll()` on the cursor. + """ + return self._scrollable + + @property + def withhold(self) -> bool: + """ + If the cursor can be used after the creating transaction has committed. + """ + return self._withhold + + @property + def rownumber(self) -> Optional[int]: + """Index of the next row to fetch in the current result. + + `!None` if there is no result to fetch. + """ + res = self.pgresult + # command_status is empty if the result comes from + # describe_portal, which means that we have just executed the DECLARE, + # so we can assume we are at the first row. + tuples = res and (res.status == TUPLES_OK or res.command_status == b"") + return self._pos if tuples else None + + def _declare_gen( + self, + query: Query, + params: Optional[Params] = None, + binary: Optional[bool] = None, + ) -> PQGen[None]: + """Generator implementing `ServerCursor.execute()`.""" + + query = self._make_declare_statement(query) + + # If the cursor is being reused, the previous one must be closed. + if self._described: + yield from self._close_gen() + self._described = False + + yield from self._start_query(query) + pgq = self._convert_query(query, params) + self._execute_send(pgq, force_extended=True) + results = yield from execute(self._conn.pgconn) + if results[-1].status != COMMAND_OK: + self._raise_for_result(results[-1]) + + # Set the format, which will be used by describe and fetch operations + if binary is None: + self._format = self.format + else: + self._format = BINARY if binary else TEXT + + # The above result only returned COMMAND_OK. Get the cursor shape + yield from self._describe_gen() + + def _describe_gen(self) -> PQGen[None]: + self._pgconn.send_describe_portal(self._name.encode(self._encoding)) + results = yield from execute(self._pgconn) + self._check_results(results) + self._results = results + self._select_current_result(0, format=self._format) + self._described = True + + def _close_gen(self) -> PQGen[None]: + ts = self._conn.pgconn.transaction_status + + # if the connection is not in a sane state, don't even try + if ts != IDLE and ts != INTRANS: + return + + # If we are IDLE, a WITHOUT HOLD cursor will surely have gone already. + if not self._withhold and ts == IDLE: + return + + # if we didn't declare the cursor ourselves we still have to close it + # but we must make sure it exists. + if not self._described: + query = sql.SQL( + "SELECT 1 FROM pg_catalog.pg_cursors WHERE name = {}" + ).format(sql.Literal(self._name)) + res = yield from self._conn._exec_command(query) + # pipeline mode otherwise, unsupported here. + assert res is not None + if res.ntuples == 0: + return + + query = sql.SQL("CLOSE {}").format(sql.Identifier(self._name)) + yield from self._conn._exec_command(query) + + def _fetch_gen(self, num: Optional[int]) -> PQGen[List[Row]]: + if self.closed: + raise e.InterfaceError("the cursor is closed") + # If we are stealing the cursor, make sure we know its shape + if not self._described: + yield from self._start_query() + yield from self._describe_gen() + + query = sql.SQL("FETCH FORWARD {} FROM {}").format( + sql.SQL("ALL") if num is None else sql.Literal(num), + sql.Identifier(self._name), + ) + res = yield from self._conn._exec_command(query, result_format=self._format) + # pipeline mode otherwise, unsupported here. + assert res is not None + + self.pgresult = res + self._tx.set_pgresult(res, set_loaders=False) + return self._tx.load_rows(0, res.ntuples, self._make_row) + + def _scroll_gen(self, value: int, mode: str) -> PQGen[None]: + if mode not in ("relative", "absolute"): + raise ValueError(f"bad mode: {mode}. It should be 'relative' or 'absolute'") + query = sql.SQL("MOVE{} {} FROM {}").format( + sql.SQL(" ABSOLUTE" if mode == "absolute" else ""), + sql.Literal(value), + sql.Identifier(self._name), + ) + yield from self._conn._exec_command(query) + + def _make_declare_statement(self, query: Query) -> sql.Composed: + if isinstance(query, bytes): + query = query.decode(self._encoding) + if not isinstance(query, sql.Composable): + query = sql.SQL(query) + + parts = [ + sql.SQL("DECLARE"), + sql.Identifier(self._name), + ] + if self._scrollable is not None: + parts.append(sql.SQL("SCROLL" if self._scrollable else "NO SCROLL")) + parts.append(sql.SQL("CURSOR")) + if self._withhold: + parts.append(sql.SQL("WITH HOLD")) + parts.append(sql.SQL("FOR")) + parts.append(query) + + return sql.SQL(" ").join(parts) + + +class ServerCursor(ServerCursorMixin["Connection[Any]", Row], Cursor[Row]): + __module__ = "psycopg" + __slots__ = () + _Self = TypeVar("_Self", bound="ServerCursor[Any]") + + @overload + def __init__( + self: "ServerCursor[Row]", + connection: "Connection[Row]", + name: str, + *, + scrollable: Optional[bool] = None, + withhold: bool = False, + ): + ... + + @overload + def __init__( + self: "ServerCursor[Row]", + connection: "Connection[Any]", + name: str, + *, + row_factory: RowFactory[Row], + scrollable: Optional[bool] = None, + withhold: bool = False, + ): + ... + + def __init__( + self, + connection: "Connection[Any]", + name: str, + *, + row_factory: Optional[RowFactory[Row]] = None, + scrollable: Optional[bool] = None, + withhold: bool = False, + ): + Cursor.__init__( + self, connection, row_factory=row_factory or connection.row_factory + ) + ServerCursorMixin.__init__(self, name, scrollable, withhold) + + def __del__(self) -> None: + if not self.closed: + warn( + f"the server-side cursor {self} was deleted while still open." + " Please use 'with' or '.close()' to close the cursor properly", + ResourceWarning, + ) + + def close(self) -> None: + """ + Close the current cursor and free associated resources. + """ + with self._conn.lock: + if self.closed: + return + if not self._conn.closed: + self._conn.wait(self._close_gen()) + super().close() + + def execute( + self: _Self, + query: Query, + params: Optional[Params] = None, + *, + binary: Optional[bool] = None, + **kwargs: Any, + ) -> _Self: + """ + Open a cursor to execute a query to the database. + """ + if kwargs: + raise TypeError(f"keyword not supported: {list(kwargs)[0]}") + if self._pgconn.pipeline_status: + raise e.NotSupportedError( + "server-side cursors not supported in pipeline mode" + ) + + try: + with self._conn.lock: + self._conn.wait(self._declare_gen(query, params, binary)) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + return self + + def executemany( + self, + query: Query, + params_seq: Iterable[Params], + *, + returning: bool = True, + ) -> None: + """Method not implemented for server-side cursors.""" + raise e.NotSupportedError("executemany not supported on server-side cursors") + + def fetchone(self) -> Optional[Row]: + with self._conn.lock: + recs = self._conn.wait(self._fetch_gen(1)) + if recs: + self._pos += 1 + return recs[0] + else: + return None + + def fetchmany(self, size: int = 0) -> List[Row]: + if not size: + size = self.arraysize + with self._conn.lock: + recs = self._conn.wait(self._fetch_gen(size)) + self._pos += len(recs) + return recs + + def fetchall(self) -> List[Row]: + with self._conn.lock: + recs = self._conn.wait(self._fetch_gen(None)) + self._pos += len(recs) + return recs + + def __iter__(self) -> Iterator[Row]: + while True: + with self._conn.lock: + recs = self._conn.wait(self._fetch_gen(self.itersize)) + for rec in recs: + self._pos += 1 + yield rec + if len(recs) < self.itersize: + break + + def scroll(self, value: int, mode: str = "relative") -> None: + with self._conn.lock: + self._conn.wait(self._scroll_gen(value, mode)) + # Postgres doesn't have a reliable way to report a cursor out of bound + if mode == "relative": + self._pos += value + else: + self._pos = value + + +class AsyncServerCursor( + ServerCursorMixin["AsyncConnection[Any]", Row], AsyncCursor[Row] +): + __module__ = "psycopg" + __slots__ = () + _Self = TypeVar("_Self", bound="AsyncServerCursor[Any]") + + @overload + def __init__( + self: "AsyncServerCursor[Row]", + connection: "AsyncConnection[Row]", + name: str, + *, + scrollable: Optional[bool] = None, + withhold: bool = False, + ): + ... + + @overload + def __init__( + self: "AsyncServerCursor[Row]", + connection: "AsyncConnection[Any]", + name: str, + *, + row_factory: AsyncRowFactory[Row], + scrollable: Optional[bool] = None, + withhold: bool = False, + ): + ... + + def __init__( + self, + connection: "AsyncConnection[Any]", + name: str, + *, + row_factory: Optional[AsyncRowFactory[Row]] = None, + scrollable: Optional[bool] = None, + withhold: bool = False, + ): + AsyncCursor.__init__( + self, connection, row_factory=row_factory or connection.row_factory + ) + ServerCursorMixin.__init__(self, name, scrollable, withhold) + + def __del__(self) -> None: + if not self.closed: + warn( + f"the server-side cursor {self} was deleted while still open." + " Please use 'with' or '.close()' to close the cursor properly", + ResourceWarning, + ) + + async def close(self) -> None: + async with self._conn.lock: + if self.closed: + return + if not self._conn.closed: + await self._conn.wait(self._close_gen()) + await super().close() + + async def execute( + self: _Self, + query: Query, + params: Optional[Params] = None, + *, + binary: Optional[bool] = None, + **kwargs: Any, + ) -> _Self: + if kwargs: + raise TypeError(f"keyword not supported: {list(kwargs)[0]}") + if self._pgconn.pipeline_status: + raise e.NotSupportedError( + "server-side cursors not supported in pipeline mode" + ) + + try: + async with self._conn.lock: + await self._conn.wait(self._declare_gen(query, params, binary)) + except e._NO_TRACEBACK as ex: + raise ex.with_traceback(None) + + return self + + async def executemany( + self, + query: Query, + params_seq: Iterable[Params], + *, + returning: bool = True, + ) -> None: + raise e.NotSupportedError("executemany not supported on server-side cursors") + + async def fetchone(self) -> Optional[Row]: + async with self._conn.lock: + recs = await self._conn.wait(self._fetch_gen(1)) + if recs: + self._pos += 1 + return recs[0] + else: + return None + + async def fetchmany(self, size: int = 0) -> List[Row]: + if not size: + size = self.arraysize + async with self._conn.lock: + recs = await self._conn.wait(self._fetch_gen(size)) + self._pos += len(recs) + return recs + + async def fetchall(self) -> List[Row]: + async with self._conn.lock: + recs = await self._conn.wait(self._fetch_gen(None)) + self._pos += len(recs) + return recs + + async def __aiter__(self) -> AsyncIterator[Row]: + while True: + async with self._conn.lock: + recs = await self._conn.wait(self._fetch_gen(self.itersize)) + for rec in recs: + self._pos += 1 + yield rec + if len(recs) < self.itersize: + break + + async def scroll(self, value: int, mode: str = "relative") -> None: + async with self._conn.lock: + await self._conn.wait(self._scroll_gen(value, mode)) diff --git a/lib/python3.11/site-packages/psycopg/sql.py b/lib/python3.11/site-packages/psycopg/sql.py new file mode 100644 index 0000000..099a01c --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/sql.py @@ -0,0 +1,467 @@ +""" +SQL composition utility module +""" + +# Copyright (C) 2020 The Psycopg Team + +import codecs +import string +from abc import ABC, abstractmethod +from typing import Any, Iterator, Iterable, List, Optional, Sequence, Union + +from .pq import Escaping +from .abc import AdaptContext +from .adapt import Transformer, PyFormat +from ._compat import LiteralString +from ._encodings import conn_encoding + + +def quote(obj: Any, context: Optional[AdaptContext] = None) -> str: + """ + Adapt a Python object to a quoted SQL string. + + Use this function only if you absolutely want to convert a Python string to + an SQL quoted literal to use e.g. to generate batch SQL and you won't have + a connection available when you will need to use it. + + This function is relatively inefficient, because it doesn't cache the + adaptation rules. If you pass a `!context` you can adapt the adaptation + rules used, otherwise only global rules are used. + + """ + return Literal(obj).as_string(context) + + +class Composable(ABC): + """ + Abstract base class for objects that can be used to compose an SQL string. + + `!Composable` objects can be passed directly to + `~psycopg.Cursor.execute()`, `~psycopg.Cursor.executemany()`, + `~psycopg.Cursor.copy()` in place of the query string. + + `!Composable` objects can be joined using the ``+`` operator: the result + will be a `Composed` instance containing the objects joined. The operator + ``*`` is also supported with an integer argument: the result is a + `!Composed` instance containing the left argument repeated as many times as + requested. + """ + + def __init__(self, obj: Any): + self._obj = obj + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self._obj!r})" + + @abstractmethod + def as_bytes(self, context: Optional[AdaptContext]) -> bytes: + """ + Return the value of the object as bytes. + + :param context: the context to evaluate the object into. + :type context: `connection` or `cursor` + + The method is automatically invoked by `~psycopg.Cursor.execute()`, + `~psycopg.Cursor.executemany()`, `~psycopg.Cursor.copy()` if a + `!Composable` is passed instead of the query string. + + """ + raise NotImplementedError + + def as_string(self, context: Optional[AdaptContext]) -> str: + """ + Return the value of the object as string. + + :param context: the context to evaluate the string into. + :type context: `connection` or `cursor` + + """ + conn = context.connection if context else None + enc = conn_encoding(conn) + b = self.as_bytes(context) + if isinstance(b, bytes): + return b.decode(enc) + else: + # buffer object + return codecs.lookup(enc).decode(b)[0] + + def __add__(self, other: "Composable") -> "Composed": + if isinstance(other, Composed): + return Composed([self]) + other + if isinstance(other, Composable): + return Composed([self]) + Composed([other]) + else: + return NotImplemented + + def __mul__(self, n: int) -> "Composed": + return Composed([self] * n) + + def __eq__(self, other: Any) -> bool: + return type(self) is type(other) and self._obj == other._obj + + def __ne__(self, other: Any) -> bool: + return not self.__eq__(other) + + +class Composed(Composable): + """ + A `Composable` object made of a sequence of `!Composable`. + + The object is usually created using `!Composable` operators and methods. + However it is possible to create a `!Composed` directly specifying a + sequence of objects as arguments: if they are not `!Composable` they will + be wrapped in a `Literal`. + + Example:: + + >>> comp = sql.Composed( + ... [sql.SQL("INSERT INTO "), sql.Identifier("table")]) + >>> print(comp.as_string(conn)) + INSERT INTO "table" + + `!Composed` objects are iterable (so they can be used in `SQL.join` for + instance). + """ + + _obj: List[Composable] + + def __init__(self, seq: Sequence[Any]): + seq = [obj if isinstance(obj, Composable) else Literal(obj) for obj in seq] + super().__init__(seq) + + def as_bytes(self, context: Optional[AdaptContext]) -> bytes: + return b"".join(obj.as_bytes(context) for obj in self._obj) + + def __iter__(self) -> Iterator[Composable]: + return iter(self._obj) + + def __add__(self, other: Composable) -> "Composed": + if isinstance(other, Composed): + return Composed(self._obj + other._obj) + if isinstance(other, Composable): + return Composed(self._obj + [other]) + else: + return NotImplemented + + def join(self, joiner: Union["SQL", LiteralString]) -> "Composed": + """ + Return a new `!Composed` interposing the `!joiner` with the `!Composed` items. + + The `!joiner` must be a `SQL` or a string which will be interpreted as + an `SQL`. + + Example:: + + >>> fields = sql.Identifier('foo') + sql.Identifier('bar') # a Composed + >>> print(fields.join(', ').as_string(conn)) + "foo", "bar" + + """ + if isinstance(joiner, str): + joiner = SQL(joiner) + elif not isinstance(joiner, SQL): + raise TypeError( + "Composed.join() argument must be strings or SQL," + f" got {joiner!r} instead" + ) + + return joiner.join(self._obj) + + +class SQL(Composable): + """ + A `Composable` representing a snippet of SQL statement. + + `!SQL` exposes `join()` and `format()` methods useful to create a template + where to merge variable parts of a query (for instance field or table + names). + + The `!obj` string doesn't undergo any form of escaping, so it is not + suitable to represent variable identifiers or values: you should only use + it to pass constant strings representing templates or snippets of SQL + statements; use other objects such as `Identifier` or `Literal` to + represent variable parts. + + Example:: + + >>> query = sql.SQL("SELECT {0} FROM {1}").format( + ... sql.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]), + ... sql.Identifier('table')) + >>> print(query.as_string(conn)) + SELECT "foo", "bar" FROM "table" + """ + + _obj: LiteralString + _formatter = string.Formatter() + + def __init__(self, obj: LiteralString): + super().__init__(obj) + if not isinstance(obj, str): + raise TypeError(f"SQL values must be strings, got {obj!r} instead") + + def as_string(self, context: Optional[AdaptContext]) -> str: + return self._obj + + def as_bytes(self, context: Optional[AdaptContext]) -> bytes: + enc = "utf-8" + if context: + enc = conn_encoding(context.connection) + return self._obj.encode(enc) + + def format(self, *args: Any, **kwargs: Any) -> Composed: + """ + Merge `Composable` objects into a template. + + :param args: parameters to replace to numbered (``{0}``, ``{1}``) or + auto-numbered (``{}``) placeholders + :param kwargs: parameters to replace to named (``{name}``) placeholders + :return: the union of the `!SQL` string with placeholders replaced + :rtype: `Composed` + + The method is similar to the Python `str.format()` method: the string + template supports auto-numbered (``{}``), numbered (``{0}``, + ``{1}``...), and named placeholders (``{name}``), with positional + arguments replacing the numbered placeholders and keywords replacing + the named ones. However placeholder modifiers (``{0!r}``, ``{0:<10}``) + are not supported. + + If a `!Composable` objects is passed to the template it will be merged + according to its `as_string()` method. If any other Python object is + passed, it will be wrapped in a `Literal` object and so escaped + according to SQL rules. + + Example:: + + >>> print(sql.SQL("SELECT * FROM {} WHERE {} = %s") + ... .format(sql.Identifier('people'), sql.Identifier('id')) + ... .as_string(conn)) + SELECT * FROM "people" WHERE "id" = %s + + >>> print(sql.SQL("SELECT * FROM {tbl} WHERE name = {name}") + ... .format(tbl=sql.Identifier('people'), name="O'Rourke")) + ... .as_string(conn)) + SELECT * FROM "people" WHERE name = 'O''Rourke' + + """ + rv: List[Composable] = [] + autonum: Optional[int] = 0 + # TODO: this is probably not the right way to whitelist pre + # pyre complains. Will wait for mypy to complain too to fix. + pre: LiteralString + for pre, name, spec, conv in self._formatter.parse(self._obj): + if spec: + raise ValueError("no format specification supported by SQL") + if conv: + raise ValueError("no format conversion supported by SQL") + if pre: + rv.append(SQL(pre)) + + if name is None: + continue + + if name.isdigit(): + if autonum: + raise ValueError( + "cannot switch from automatic field numbering to manual" + ) + rv.append(args[int(name)]) + autonum = None + + elif not name: + if autonum is None: + raise ValueError( + "cannot switch from manual field numbering to automatic" + ) + rv.append(args[autonum]) + autonum += 1 + + else: + rv.append(kwargs[name]) + + return Composed(rv) + + def join(self, seq: Iterable[Composable]) -> Composed: + """ + Join a sequence of `Composable`. + + :param seq: the elements to join. + :type seq: iterable of `!Composable` + + Use the `!SQL` object's string to separate the elements in `!seq`. + Note that `Composed` objects are iterable too, so they can be used as + argument for this method. + + Example:: + + >>> snip = sql.SQL(', ').join( + ... sql.Identifier(n) for n in ['foo', 'bar', 'baz']) + >>> print(snip.as_string(conn)) + "foo", "bar", "baz" + """ + rv = [] + it = iter(seq) + try: + rv.append(next(it)) + except StopIteration: + pass + else: + for i in it: + rv.append(self) + rv.append(i) + + return Composed(rv) + + +class Identifier(Composable): + """ + A `Composable` representing an SQL identifier or a dot-separated sequence. + + Identifiers usually represent names of database objects, such as tables or + fields. PostgreSQL identifiers follow `different rules`__ than SQL string + literals for escaping (e.g. they use double quotes instead of single). + + .. __: https://www.postgresql.org/docs/current/sql-syntax-lexical.html# \ + SQL-SYNTAX-IDENTIFIERS + + Example:: + + >>> t1 = sql.Identifier("foo") + >>> t2 = sql.Identifier("ba'r") + >>> t3 = sql.Identifier('ba"z') + >>> print(sql.SQL(', ').join([t1, t2, t3]).as_string(conn)) + "foo", "ba'r", "ba""z" + + Multiple strings can be passed to the object to represent a qualified name, + i.e. a dot-separated sequence of identifiers. + + Example:: + + >>> query = sql.SQL("SELECT {} FROM {}").format( + ... sql.Identifier("table", "field"), + ... sql.Identifier("schema", "table")) + >>> print(query.as_string(conn)) + SELECT "table"."field" FROM "schema"."table" + + """ + + _obj: Sequence[str] + + def __init__(self, *strings: str): + # init super() now to make the __repr__ not explode in case of error + super().__init__(strings) + + if not strings: + raise TypeError("Identifier cannot be empty") + + for s in strings: + if not isinstance(s, str): + raise TypeError( + f"SQL identifier parts must be strings, got {s!r} instead" + ) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({', '.join(map(repr, self._obj))})" + + def as_bytes(self, context: Optional[AdaptContext]) -> bytes: + conn = context.connection if context else None + if not conn: + raise ValueError("a connection is necessary for Identifier") + esc = Escaping(conn.pgconn) + enc = conn_encoding(conn) + escs = [esc.escape_identifier(s.encode(enc)) for s in self._obj] + return b".".join(escs) + + +class Literal(Composable): + """ + A `Composable` representing an SQL value to include in a query. + + Usually you will want to include placeholders in the query and pass values + as `~cursor.execute()` arguments. If however you really really need to + include a literal value in the query you can use this object. + + The string returned by `!as_string()` follows the normal :ref:`adaptation + rules ` for Python objects. + + Example:: + + >>> s1 = sql.Literal("fo'o") + >>> s2 = sql.Literal(42) + >>> s3 = sql.Literal(date(2000, 1, 1)) + >>> print(sql.SQL(', ').join([s1, s2, s3]).as_string(conn)) + 'fo''o', 42, '2000-01-01'::date + + """ + + def as_bytes(self, context: Optional[AdaptContext]) -> bytes: + tx = Transformer.from_context(context) + return tx.as_literal(self._obj) + + +class Placeholder(Composable): + """A `Composable` representing a placeholder for query parameters. + + If the name is specified, generate a named placeholder (e.g. ``%(name)s``, + ``%(name)b``), otherwise generate a positional placeholder (e.g. ``%s``, + ``%b``). + + The object is useful to generate SQL queries with a variable number of + arguments. + + Examples:: + + >>> names = ['foo', 'bar', 'baz'] + + >>> q1 = sql.SQL("INSERT INTO my_table ({}) VALUES ({})").format( + ... sql.SQL(', ').join(map(sql.Identifier, names)), + ... sql.SQL(', ').join(sql.Placeholder() * len(names))) + >>> print(q1.as_string(conn)) + INSERT INTO my_table ("foo", "bar", "baz") VALUES (%s, %s, %s) + + >>> q2 = sql.SQL("INSERT INTO my_table ({}) VALUES ({})").format( + ... sql.SQL(', ').join(map(sql.Identifier, names)), + ... sql.SQL(', ').join(map(sql.Placeholder, names))) + >>> print(q2.as_string(conn)) + INSERT INTO my_table ("foo", "bar", "baz") VALUES (%(foo)s, %(bar)s, %(baz)s) + + """ + + def __init__(self, name: str = "", format: Union[str, PyFormat] = PyFormat.AUTO): + super().__init__(name) + if not isinstance(name, str): + raise TypeError(f"expected string as name, got {name!r}") + + if ")" in name: + raise ValueError(f"invalid name: {name!r}") + + if type(format) is str: + format = PyFormat(format) + if not isinstance(format, PyFormat): + raise TypeError( + f"expected PyFormat as format, got {type(format).__name__!r}" + ) + + self._format: PyFormat = format + + def __repr__(self) -> str: + parts = [] + if self._obj: + parts.append(repr(self._obj)) + if self._format is not PyFormat.AUTO: + parts.append(f"format={self._format.name}") + + return f"{self.__class__.__name__}({', '.join(parts)})" + + def as_string(self, context: Optional[AdaptContext]) -> str: + code = self._format.value + return f"%({self._obj}){code}" if self._obj else f"%{code}" + + def as_bytes(self, context: Optional[AdaptContext]) -> bytes: + conn = context.connection if context else None + enc = conn_encoding(conn) + return self.as_string(context).encode(enc) + + +# Literals +NULL = SQL("NULL") +DEFAULT = SQL("DEFAULT") diff --git a/lib/python3.11/site-packages/psycopg/transaction.py b/lib/python3.11/site-packages/psycopg/transaction.py new file mode 100644 index 0000000..e13486e --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/transaction.py @@ -0,0 +1,290 @@ +""" +Transaction context managers returned by Connection.transaction() +""" + +# Copyright (C) 2020 The Psycopg Team + +import logging + +from types import TracebackType +from typing import Generic, Iterator, Optional, Type, Union, TypeVar, TYPE_CHECKING + +from . import pq +from . import sql +from . import errors as e +from .abc import ConnectionType, PQGen + +if TYPE_CHECKING: + from typing import Any + from .connection import Connection + from .connection_async import AsyncConnection + +IDLE = pq.TransactionStatus.IDLE + +OK = pq.ConnStatus.OK + +logger = logging.getLogger(__name__) + + +class Rollback(Exception): + """ + Exit the current `Transaction` context immediately and rollback any changes + made within this context. + + If a transaction context is specified in the constructor, rollback + enclosing transactions contexts up to and including the one specified. + """ + + __module__ = "psycopg" + + def __init__( + self, + transaction: Union["Transaction", "AsyncTransaction", None] = None, + ): + self.transaction = transaction + + def __repr__(self) -> str: + return f"{self.__class__.__qualname__}({self.transaction!r})" + + +class OutOfOrderTransactionNesting(e.ProgrammingError): + """Out-of-order transaction nesting detected""" + + +class BaseTransaction(Generic[ConnectionType]): + def __init__( + self, + connection: ConnectionType, + savepoint_name: Optional[str] = None, + force_rollback: bool = False, + ): + self._conn = connection + self.pgconn = self._conn.pgconn + self._savepoint_name = savepoint_name or "" + self.force_rollback = force_rollback + self._entered = self._exited = False + self._outer_transaction = False + self._stack_index = -1 + + @property + def savepoint_name(self) -> Optional[str]: + """ + The name of the savepoint; `!None` if handling the main transaction. + """ + # Yes, it may change on __enter__. No, I don't care, because the + # un-entered state is outside the public interface. + return self._savepoint_name + + def __repr__(self) -> str: + cls = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + info = pq.misc.connection_summary(self.pgconn) + if not self._entered: + status = "inactive" + elif not self._exited: + status = "active" + else: + status = "terminated" + + sp = f"{self.savepoint_name!r} " if self.savepoint_name else "" + return f"<{cls} {sp}({status}) {info} at 0x{id(self):x}>" + + def _enter_gen(self) -> PQGen[None]: + if self._entered: + raise TypeError("transaction blocks can be used only once") + self._entered = True + + self._push_savepoint() + for command in self._get_enter_commands(): + yield from self._conn._exec_command(command) + + def _exit_gen( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> PQGen[bool]: + if not exc_val and not self.force_rollback: + yield from self._commit_gen() + return False + else: + # try to rollback, but if there are problems (connection in a bad + # state) just warn without clobbering the exception bubbling up. + try: + return (yield from self._rollback_gen(exc_val)) + except OutOfOrderTransactionNesting: + # Clobber an exception happened in the block with the exception + # caused by out-of-order transaction detected, so make the + # behaviour consistent with _commit_gen and to make sure the + # user fixes this condition, which is unrelated from + # operational error that might arise in the block. + raise + except Exception as exc2: + logger.warning("error ignored in rollback of %s: %s", self, exc2) + return False + + def _commit_gen(self) -> PQGen[None]: + ex = self._pop_savepoint("commit") + self._exited = True + if ex: + raise ex + + for command in self._get_commit_commands(): + yield from self._conn._exec_command(command) + + def _rollback_gen(self, exc_val: Optional[BaseException]) -> PQGen[bool]: + if isinstance(exc_val, Rollback): + logger.debug(f"{self._conn}: Explicit rollback from: ", exc_info=True) + + ex = self._pop_savepoint("rollback") + self._exited = True + if ex: + raise ex + + for command in self._get_rollback_commands(): + yield from self._conn._exec_command(command) + + if isinstance(exc_val, Rollback): + if not exc_val.transaction or exc_val.transaction is self: + return True # Swallow the exception + + return False + + def _get_enter_commands(self) -> Iterator[bytes]: + if self._outer_transaction: + yield self._conn._get_tx_start_command() + + if self._savepoint_name: + yield ( + sql.SQL("SAVEPOINT {}") + .format(sql.Identifier(self._savepoint_name)) + .as_bytes(self._conn) + ) + + def _get_commit_commands(self) -> Iterator[bytes]: + if self._savepoint_name and not self._outer_transaction: + yield ( + sql.SQL("RELEASE {}") + .format(sql.Identifier(self._savepoint_name)) + .as_bytes(self._conn) + ) + + if self._outer_transaction: + assert not self._conn._num_transactions + yield b"COMMIT" + + def _get_rollback_commands(self) -> Iterator[bytes]: + if self._savepoint_name and not self._outer_transaction: + yield ( + sql.SQL("ROLLBACK TO {n}") + .format(n=sql.Identifier(self._savepoint_name)) + .as_bytes(self._conn) + ) + yield ( + sql.SQL("RELEASE {n}") + .format(n=sql.Identifier(self._savepoint_name)) + .as_bytes(self._conn) + ) + + if self._outer_transaction: + assert not self._conn._num_transactions + yield b"ROLLBACK" + + # Also clear the prepared statements cache. + if self._conn._prepared.clear(): + yield from self._conn._prepared.get_maintenance_commands() + + def _push_savepoint(self) -> None: + """ + Push the transaction on the connection transactions stack. + + Also set the internal state of the object and verify consistency. + """ + self._outer_transaction = self.pgconn.transaction_status == IDLE + if self._outer_transaction: + # outer transaction: if no name it's only a begin, else + # there will be an additional savepoint + assert not self._conn._num_transactions + else: + # inner transaction: it always has a name + if not self._savepoint_name: + self._savepoint_name = f"_pg3_{self._conn._num_transactions + 1}" + + self._stack_index = self._conn._num_transactions + self._conn._num_transactions += 1 + + def _pop_savepoint(self, action: str) -> Optional[Exception]: + """ + Pop the transaction from the connection transactions stack. + + Also verify the state consistency. + """ + self._conn._num_transactions -= 1 + if self._conn._num_transactions == self._stack_index: + return None + + return OutOfOrderTransactionNesting( + f"transaction {action} at the wrong nesting level: {self}" + ) + + +class Transaction(BaseTransaction["Connection[Any]"]): + """ + Returned by `Connection.transaction()` to handle a transaction block. + """ + + __module__ = "psycopg" + + _Self = TypeVar("_Self", bound="Transaction") + + @property + def connection(self) -> "Connection[Any]": + """The connection the object is managing.""" + return self._conn + + def __enter__(self: _Self) -> _Self: + with self._conn.lock: + self._conn.wait(self._enter_gen()) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> bool: + if self.pgconn.status == OK: + with self._conn.lock: + return self._conn.wait(self._exit_gen(exc_type, exc_val, exc_tb)) + else: + return False + + +class AsyncTransaction(BaseTransaction["AsyncConnection[Any]"]): + """ + Returned by `AsyncConnection.transaction()` to handle a transaction block. + """ + + __module__ = "psycopg" + + _Self = TypeVar("_Self", bound="AsyncTransaction") + + @property + def connection(self) -> "AsyncConnection[Any]": + return self._conn + + async def __aenter__(self: _Self) -> _Self: + async with self._conn.lock: + await self._conn.wait(self._enter_gen()) + return self + + async def __aexit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> bool: + if self.pgconn.status == OK: + async with self._conn.lock: + return await self._conn.wait(self._exit_gen(exc_type, exc_val, exc_tb)) + else: + return False diff --git a/lib/python3.11/site-packages/psycopg/types/__init__.py b/lib/python3.11/site-packages/psycopg/types/__init__.py new file mode 100644 index 0000000..bdddf05 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/__init__.py @@ -0,0 +1,11 @@ +""" +psycopg types package +""" + +# Copyright (C) 2020 The Psycopg Team + +from .. import _typeinfo + +# Exposed here +TypeInfo = _typeinfo.TypeInfo +TypesRegistry = _typeinfo.TypesRegistry diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/__init__.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36d71bc2ef8b2e8fb310ee19a5527c1d56b12e6a GIT binary patch literal 354 zcmZ3^%ge<81m5NcQnmu=#~=<2FhLogjev~l3@Hpz3@MB$OgW6XOi@gX45>_6%rK=< z%s?IsoX3*F9L%7}QYFq+P+XauUy!a)Qdy8%tWc1coSm4S%JmXtv?k*%&Ulb`W?ovp zpC;=q_W1ae{N(ufTMR`YgKu$!03|(vlDBw4tm2^5^vvRtqRN#FpFuYL^3yL%EYdG8 zFW1klEG|hc%1q5mDN4*u)X&LG(l4ki$;i($)-yEJFU~AU)rDGJtPgdOKG;S2@$s2? znI-Y@dIgogIBatBQ%ZAE?TWa8#xnwOu_ciBz|6?V_<@Ouk>vveh~Qyhl)S(ofs8(| aG4P09;g)USxFH~UML@lQ7X*tqfw}?l5?>tv literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/array.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/array.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf6bf8d736a4627215806d5c99f2ccd12088d97e GIT binary patch literal 24560 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�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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/bool.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/bool.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..680c4ceed9dfb63a297fb019b01c4f1ba365a39d GIT binary patch literal 3220 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 J6$DH~{l8o%$-@8u literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/enum.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/enum.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0cfba6818fcbe831b562d0ddf00d36fcfe31008 GIT binary patch literal 9444 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/hstore.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/hstore.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fa3096984c695ce01ab3e1416aff8875fdc57ed GIT binary patch literal 6478 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 Hv|aokq9oWc literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/json.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/json.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5bac437abee055e489c4204223eb5971e3a0366 GIT binary patch literal 12165 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 G+5Zb>(*B?T literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/multirange.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/multirange.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4a2a4a55bcaffe344ac63130e99fb582b34f562 GIT binary patch literal 29067 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 LJ)aJlUi*Im*n1_o literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/net.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/net.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50cd46a9f63cdaba5491a08975a53c2c5b8c601a GIT binary patch literal 13103 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/none.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/none.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8109f6ec63712a1c8314aa54c242baca8d92051d GIT binary patch literal 1517 zcmZ`(&2QX96rb_ex^9{j8X8&&X^M)-N)W5`fYcx)1PB4is-hsFy;xq)Byq7l&dh9= zUG)&595})$J?27C6>;atpRh%ds4Q{f#BEVH_0;$5-6W;-+5XM@7{52~!~Xfgg@6Ek z{_byFScLqA!i?N0bNmG`dxVoN;gnk$&8@DL+g+QYY-djHc3ny=@(JP2F5#|l4{SmX z;c2MraZgyh#r+M3pWAi1z}+G3V6+%~z~j;grP+p5tRoAt68sJ4AZ@Fft8E|3!iaB8 z<)iV-VJX_Q@;>V4rBKPtKd#PHIDQA1Jt9b#!htPLyEeDD%^l%Da2JBRXJij#kK1sV zRuy1`#`9=5U_c#dSj-Zcmzgkv@j5DtHA@ZSQt0AM!%{Tnq5ut;m)mc#ULUk)47&EU z-Iqq7SxdAgalv|m^|jzEEtuZU>NrxTCY8lX{Yqua-rY{+DPj7mNU$t3!qVb%%mDU? zp|DJe(*uwWPc+}rw$&LecfML%W2t6ktTCpM?6%ZqQwhkXVA5;}#Rl;PDRfxsVIs@T&_FYFSYXe~VdY@?MhmAsSV6^07!6^E{5gMZ{QBCX`Sqju z^|8Nx3`+7$O)%rSCLS;_t`xdzbupy+{%jl7F>&Uq^p50AfeYFIeD?9Eb3KOnlS8nZ7;ZLw>6}tXU51;t& zHB<1uVqnE1>K_3nHl=i8SrpoaFh^*6OqQR&ACs%&XYYv@(4`4^9)7s|4{HBCHC?52 Ub^ktenXdkd^Fdc%2z8=Q0gl#b`Tzg` literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/numeric.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/numeric.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54c8d706efca66fded12c1027db705e4f3ded87a GIT binary patch literal 27107 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 literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/shapely.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/shapely.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9122e7bc9c86f7452537c701bf739c9c43ada832 GIT binary patch literal 4764 zcmbtX-ES1v6~A|8cD!D%cZ@&q2c%45ietcQAStBaLQF{rZM;FTRW+NS?RsZyFWKE$ z?u;>ZOl2XY7>NfbqQVbF;w2P|JoKecm8$*;v(cigMnXlZ`jEG^><7eC&$%3&t*Egz zqhvec9oaqcJ;0?}DASqkig!_x>mDR}_d&v7mH<7i?Gfzc3EXbGMHk2o@e{H@1#*#S z;oC%O*F%p)kb&E6@gB~L08eS+?d7}<;O)^{8|L+LUMKLnns|L$zt*Eiw7t5Z%l-aR zMC;YMXJoDKb|Bubbx)Gvfu+|&<61Ir>C9AT45nT-OzYyMNp)5?vbx36x*7Tbrw>yn z_)*?U8@XiW2f-W2gYYcV&0)a_b1lC%a+ZF>a^&;#Gc!7aarwf0Hm@^B{?JHjFhU*q zeS>9_7Al-t%^3xer-MtTTv~L%qLTyCuenaXwu~lsg|Km>uNe@TFFdC*HRUWKu7Xk zwvIyQKG8{>0+Iw>yy|mEJfKls)&xzQku>SH6mQW2U_IIC_P2OGolCMs_fI;Kmb8+N z%yes>K zHfU^EbV6y98zGm{oxt>>rJF1avo-`rGWE<1+XF8quBfUnCq}O)+33Q;!f1BU1c0RV zoW_#b6J(^#%=8W81(c{NQ&9tSDcqTVTJ@<@q_l$b(iRKp_2|c{jzmvhD$l8xf z9|5vLo+tB6_Az6uhiak_sYuqWl0R|Ti;tI@OT*Gk6nqY8I|q~yq^K53OsIK13KdwMQ`Wq%x|}Z-sgg0}#d76a=_9 zr{5S3upW?gLRmd)u*K_XeSz(T0gg#W*7TGCIinXwJWRUYL3b^6)tiGuXb>e&16d*e zY3o_j9{i@zHdJgI+7UwcKmGdCuddv?@>sH!k%BT(R7ULJ2zONsHimFyuOUJ2RB^&y z$JZ)Ua7~8f4YK&w>YMOf%OPL zBrx#!7yPj+aeaikcJ@(Y9CNSuM}{BAowbH={lRUvi$4$m+#er6r_mqH@%6CgFo6kP ztB*?X+s}b9EO5U$vYz8{#(m)CemBn0qD#Ha+vOfR0ZbFk?Rjinvz5VuGFVgwzgG@_ zryMRQM~li)J9yM{VpB-%>a}B_l_5EfYcz%w4UD+%8gbnv^p@ zepA4bZk5bH5qmqRi53*ReycD3Zi*F22_yqn$d@CeK~h>49@eZ@mAgZ(Rua0^Q5~;O z*s%MbG9M2jukA3uW_P|6Ar=C_Ys=#QG)ronrO8m1wJaU{Sf5Q}&7yi0po&QbUXwXZ z#bN`>-RRPZoB<`_i~;qcY3f>3z2ugUL%gm{n?owpvU<*hqSu|IovVv`A01m5_kW_* z6Z{^zidf<;E@~9^B)oi+d3#FuMbTKsNF_7o*{FY%x!EALAvNSXM>Nvf24!!7MiWw<_Y#jfpeB|3Cgp^vC~7?Qs)h@4$Kt59Zq4 zH`LDFe>e+L7f^f*2|s7gK`%BOc3Sa!;XTF-<^=s6IKia%`NA-SdD`F^-%)&#gzIqj zOXMTY`Egytcd^0qFC6@6WcD_a^GMKC40m9n{y(VDT;q3C^n3nf?|}ejE3+GX1m-V? zNVo&DQ;a@~^xAzN79tbH$b=o7crFFMoVYcyHdK%Xiqe2B4U`5C+sgRrLQy$jD+m4- zEFK$Q`JgP(KrbrTojmP7vWWuQRVn#Z@?6`~1E-oMkwE+R(*EzH{p(YI{{7RTGX-g^ zD2>_DSV;<38Q=V|Ae}5qCvEBEbASB7XOGVoq|-&|v@M;kNI&?@K60)gy<3#twf)O= zC$AX>oR&mFGg45c%kZg?&do9m8HaE;I%0A<#V~8}!pjM8Co@cktQEzC{57|pZ%yEb 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 L4IXO(rkMT@tu?gx literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/__pycache__/uuid.cpython-311.pyc b/lib/python3.11/site-packages/psycopg/types/__pycache__/uuid.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..822f7cf534f00783390d4b9031bed9737fa9d16e GIT binary patch literal 4042 zcmcIn&2JmW6`$RmU9Konl=T%Ubs|P~EK_Yo8;NYRQiIsCoj7WgAg&99MX^|MM>5@A zl9^pbrl15oxTsnPs1u|RF9m$58^bNoV~_n4$bdnF1q=iTatP1^3;9s^Q1rc7E%|wMBu?L-4Cg#L5ac3wqBoRhAh52+l zkx5v(Im~2hU@BaluoG5v37%x~8nFiN5-Y~y4-`Tk!C!D?MuaU6wjnlh$Tli$39t>b zp+mMYVLJh~5jJ+nHg1iws5NHk>(m;*OEVLeeuJbYww{Y#vdp5#xSL!r@T7N(C2!um zekJLZi)=pn4SrEd@%3fXw#_x0`TAQ$FIUK$wjck=yKi4LmS4ZRymEc@wQpn`DfxP_ z;CdUJxu9#;3fwV0&|+edxel(XjX zBYcW78=w+M+Il#+49Xs1BqM?QWTxB>E#S%y*tbJxlZx*b}`eW|T>DGxw@)PBA}9!juH zU%AEZ_!`S+3l@7Q`_yIjIv;^yE-sKvK7AwozRA;@o11B;?1F!CEN^ksG1GQ#EnO^o zw+i`}=Fgu`yE%`2zi4KEVQw%tU3AOYLUALF?sL-u$zs{37Qnof=xPjx9cCDQ)G(ZaRkBf!8OD1h(+(^=0%Ltu ztO@7=gz8$^V=n&=^gks0BsBb46vLqy2gSV#qSF5DM@M$&s}qfAvJpL9S#DBEO;!h+ z1e#A((exF;3OM=kWceOgjwcJy0wUj11TCnbg$lIL{9y#^axQQ3azGB@96<{{iVJmf z0{t#HfuGRJi5rCDULQ()1{y9f4?G+of)H(uA6`uOXBtc{=CQy(<(fVzHVR(h&*5ax zqrg#I2LVBKef82i@A?`9GK5{QAkNQEq3C$wMSMhoUG9%Sba^2@y8H9WHAH_ZKz}Mg ze+tn*Rs=KSd_Cwx-WAuuHE4d-g}*gmLBIm$l&PIiU8g%_U9#xict*2S2H|N%AXIhm ziM~VbNSOifOEd`AR<__Tz|4Lm8>E#idLX;FBn?knqezlq=kwugr@`P}0`boZd925O9odb1p-+CM zPgX~(8+H9mLqAi~&wM?Y*jd_-y-+*uZYm@;xw9mk2#LbD=bdI8;* zyf#dP^uopyo(eCtu5IZ7IO0*;86QXPK^KF7J9~ zKFj>5!<+&yzn^29K^&kve9dA(z73E+4}Gn4D{%Iy4P_|ElP#dJV-ANcfB=jK$M0Fc zf1^G)+ZddMfEbv5JUUq&`)Ki##hojU6QlR8?5%vf^3j{0yjf4oG!ip4eI|$w%mJzB zp|JIpT;AijV?KZa-OMrI`9%Pm-J+S(3c1QIsY;ZGcd$@ zpZpuRf}^*-jhYzk|1WC(=@4}x9m%VF7FJAA{t|v1o(MW@;}_tun_j}J-MPMtWB9&{ z{{422RZrIv)9pGfpzl)=_*wj*6pA*h4%dQ3w4xB?>Qf68sKkO3$$%3{p$lAz0i>jP<9IzAa&Qg`a@%`Xxh!TP=x)*x8mn72ZHh94kW zOZE_~*7ZNU6${@vx)zoPEDd<5403t@OJjBp`-3C8{a$0O!=sF;AWUghGt6c}6kUvLZ41s@Ot6;z4`~u@*pza_T1x z!_4Oko{9gOK>6$-*a1xJ{t)}0>Px|i_7#2|W<;L4zXaJ-BuQ$@vP7GtEn-AksF9cZ z-CvStYQ6V?n{tbzVIjR5v literal 0 HcmV?d00001 diff --git a/lib/python3.11/site-packages/psycopg/types/array.py b/lib/python3.11/site-packages/psycopg/types/array.py new file mode 100644 index 0000000..419e3d4 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/array.py @@ -0,0 +1,460 @@ +""" +Adapters for arrays +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +import struct +from typing import Any, cast, Callable, List, Optional, Pattern, Set, Tuple, Type + +from .. import pq +from .. import errors as e +from .. import postgres +from ..abc import AdaptContext, Buffer, Dumper, DumperKey, NoneType, Loader, Transformer +from ..adapt import RecursiveDumper, RecursiveLoader, PyFormat +from .._compat import cache, prod +from .._struct import pack_len, unpack_len +from .._cmodule import _psycopg +from ..postgres import TEXT_OID, INVALID_OID +from .._typeinfo import TypeInfo + +_struct_head = struct.Struct("!III") # ndims, hasnull, elem oid +_pack_head = cast(Callable[[int, int, int], bytes], _struct_head.pack) +_unpack_head = cast(Callable[[Buffer], Tuple[int, int, int]], _struct_head.unpack_from) +_struct_dim = struct.Struct("!II") # dim, lower bound +_pack_dim = cast(Callable[[int, int], bytes], _struct_dim.pack) +_unpack_dim = cast(Callable[[Buffer, int], Tuple[int, int]], _struct_dim.unpack_from) + +TEXT_ARRAY_OID = postgres.types["text"].array_oid + +PY_TEXT = PyFormat.TEXT +PQ_BINARY = pq.Format.BINARY + + +class BaseListDumper(RecursiveDumper): + element_oid = 0 + + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + if cls is NoneType: + cls = list + + super().__init__(cls, context) + self.sub_dumper: Optional[Dumper] = None + if self.element_oid and context: + sdclass = context.adapters.get_dumper_by_oid(self.element_oid, self.format) + self.sub_dumper = sdclass(NoneType, context) + + def _find_list_element(self, L: List[Any], format: PyFormat) -> Any: + """ + Find the first non-null element of an eventually nested list + """ + items = list(self._flatiter(L, set())) + types = {type(item): item for item in items} + if not types: + return None + + if len(types) == 1: + t, v = types.popitem() + else: + # More than one type in the list. It might be still good, as long + # as they dump with the same oid (e.g. IPv4Network, IPv6Network). + dumpers = [self._tx.get_dumper(item, format) for item in types.values()] + oids = set(d.oid for d in dumpers) + if len(oids) == 1: + t, v = types.popitem() + else: + raise e.DataError( + "cannot dump lists of mixed types;" + f" got: {', '.join(sorted(t.__name__ for t in types))}" + ) + + # Checking for precise type. If the type is a subclass (e.g. Int4) + # we assume the user knows what type they are passing. + if t is not int: + return v + + # If we got an int, let's see what is the biggest one in order to + # choose the smallest OID and allow Postgres to do the right cast. + imax: int = max(items) + imin: int = min(items) + if imin >= 0: + return imax + else: + return max(imax, -imin - 1) + + def _flatiter(self, L: List[Any], seen: Set[int]) -> Any: + if id(L) in seen: + raise e.DataError("cannot dump a recursive list") + + seen.add(id(L)) + + for item in L: + if type(item) is list: + yield from self._flatiter(item, seen) + elif item is not None: + yield item + + return None + + def _get_base_type_info(self, base_oid: int) -> TypeInfo: + """ + Return info about the base type. + + Return text info as fallback. + """ + if base_oid: + info = self._tx.adapters.types.get(base_oid) + if info: + return info + + return self._tx.adapters.types["text"] + + +class ListDumper(BaseListDumper): + delimiter = b"," + + def get_key(self, obj: List[Any], format: PyFormat) -> DumperKey: + if self.oid: + return self.cls + + item = self._find_list_element(obj, format) + if item is None: + return self.cls + + sd = self._tx.get_dumper(item, format) + return (self.cls, sd.get_key(item, format)) + + def upgrade(self, obj: List[Any], format: PyFormat) -> "BaseListDumper": + # If we have an oid we don't need to upgrade + if self.oid: + return self + + item = self._find_list_element(obj, format) + if item is None: + # Empty lists can only be dumped as text if the type is unknown. + return self + + sd = self._tx.get_dumper(item, PyFormat.from_pq(self.format)) + dumper = type(self)(self.cls, self._tx) + dumper.sub_dumper = sd + + # We consider an array of unknowns as unknown, so we can dump empty + # lists or lists containing only None elements. + if sd.oid != INVALID_OID: + info = self._get_base_type_info(sd.oid) + dumper.oid = info.array_oid or TEXT_ARRAY_OID + dumper.delimiter = info.delimiter.encode() + else: + dumper.oid = INVALID_OID + + return dumper + + # Double quotes and backslashes embedded in element values will be + # backslash-escaped. + _re_esc = re.compile(rb'(["\\])') + + def dump(self, obj: List[Any]) -> bytes: + tokens: List[Buffer] = [] + needs_quotes = _get_needs_quotes_regexp(self.delimiter).search + + def dump_list(obj: List[Any]) -> None: + if not obj: + tokens.append(b"{}") + return + + tokens.append(b"{") + for item in obj: + if isinstance(item, list): + dump_list(item) + elif item is not None: + ad = self._dump_item(item) + if needs_quotes(ad): + if not isinstance(ad, bytes): + ad = bytes(ad) + ad = b'"' + self._re_esc.sub(rb"\\\1", ad) + b'"' + tokens.append(ad) + else: + tokens.append(b"NULL") + + tokens.append(self.delimiter) + + tokens[-1] = b"}" + + dump_list(obj) + + return b"".join(tokens) + + def _dump_item(self, item: Any) -> Buffer: + if self.sub_dumper: + return self.sub_dumper.dump(item) + else: + return self._tx.get_dumper(item, PY_TEXT).dump(item) + + +@cache +def _get_needs_quotes_regexp(delimiter: bytes) -> Pattern[bytes]: + """Return a regexp to recognise when a value needs quotes + + from https://www.postgresql.org/docs/current/arrays.html#ARRAYS-IO + + The array output routine will put double quotes around element values if + they are empty strings, contain curly braces, delimiter characters, + double quotes, backslashes, or white space, or match the word NULL. + """ + return re.compile( + rb"""(?xi) + ^$ # the empty string + | ["{}%s\\\s] # or a char to escape + | ^null$ # or the word NULL + """ + % delimiter + ) + + +class ListBinaryDumper(BaseListDumper): + format = pq.Format.BINARY + + def get_key(self, obj: List[Any], format: PyFormat) -> DumperKey: + if self.oid: + return self.cls + + item = self._find_list_element(obj, format) + if item is None: + return (self.cls,) + + sd = self._tx.get_dumper(item, format) + return (self.cls, sd.get_key(item, format)) + + def upgrade(self, obj: List[Any], format: PyFormat) -> "BaseListDumper": + # If we have an oid we don't need to upgrade + if self.oid: + return self + + item = self._find_list_element(obj, format) + if item is None: + return ListDumper(self.cls, self._tx) + + sd = self._tx.get_dumper(item, format.from_pq(self.format)) + dumper = type(self)(self.cls, self._tx) + dumper.sub_dumper = sd + info = self._get_base_type_info(sd.oid) + dumper.oid = info.array_oid or TEXT_ARRAY_OID + + return dumper + + def dump(self, obj: List[Any]) -> bytes: + # Postgres won't take unknown for element oid: fall back on text + sub_oid = self.sub_dumper and self.sub_dumper.oid or TEXT_OID + + if not obj: + return _pack_head(0, 0, sub_oid) + + data: List[Buffer] = [b"", b""] # placeholders to avoid a resize + dims: List[int] = [] + hasnull = 0 + + def calc_dims(L: List[Any]) -> None: + if isinstance(L, self.cls): + if not L: + raise e.DataError("lists cannot contain empty lists") + dims.append(len(L)) + calc_dims(L[0]) + + calc_dims(obj) + + def dump_list(L: List[Any], dim: int) -> None: + nonlocal hasnull + if len(L) != dims[dim]: + raise e.DataError("nested lists have inconsistent lengths") + + if dim == len(dims) - 1: + for item in L: + if item is not None: + # If we get here, the sub_dumper must have been set + ad = self.sub_dumper.dump(item) # type: ignore[union-attr] + data.append(pack_len(len(ad))) + data.append(ad) + else: + hasnull = 1 + data.append(b"\xff\xff\xff\xff") + else: + for item in L: + if not isinstance(item, self.cls): + raise e.DataError("nested lists have inconsistent depths") + dump_list(item, dim + 1) # type: ignore + + dump_list(obj, 0) + + data[0] = _pack_head(len(dims), hasnull, sub_oid) + data[1] = b"".join(_pack_dim(dim, 1) for dim in dims) + return b"".join(data) + + +class ArrayLoader(RecursiveLoader): + delimiter = b"," + base_oid: int + + def load(self, data: Buffer) -> List[Any]: + loader = self._tx.get_loader(self.base_oid, self.format) + return _load_text(data, loader, self.delimiter) + + +class ArrayBinaryLoader(RecursiveLoader): + format = pq.Format.BINARY + + def load(self, data: Buffer) -> List[Any]: + return _load_binary(data, self._tx) + + +def register_array(info: TypeInfo, context: Optional[AdaptContext] = None) -> None: + if not info.array_oid: + raise ValueError(f"the type info {info} doesn't describe an array") + + base: Type[Any] + adapters = context.adapters if context else postgres.adapters + + base = getattr(_psycopg, "ArrayLoader", ArrayLoader) + name = f"{info.name.title()}{base.__name__}" + attribs = { + "base_oid": info.oid, + "delimiter": info.delimiter.encode(), + } + loader = type(name, (base,), attribs) + adapters.register_loader(info.array_oid, loader) + + loader = getattr(_psycopg, "ArrayBinaryLoader", ArrayBinaryLoader) + adapters.register_loader(info.array_oid, loader) + + base = ListDumper + name = f"{info.name.title()}{base.__name__}" + attribs = { + "oid": info.array_oid, + "element_oid": info.oid, + "delimiter": info.delimiter.encode(), + } + dumper = type(name, (base,), attribs) + adapters.register_dumper(None, dumper) + + base = ListBinaryDumper + name = f"{info.name.title()}{base.__name__}" + attribs = { + "oid": info.array_oid, + "element_oid": info.oid, + } + dumper = type(name, (base,), attribs) + adapters.register_dumper(None, dumper) + + +def register_default_adapters(context: AdaptContext) -> None: + # The text dumper is more flexible as it can handle lists of mixed type, + # so register it later. + context.adapters.register_dumper(list, ListBinaryDumper) + context.adapters.register_dumper(list, ListDumper) + + +def register_all_arrays(context: AdaptContext) -> None: + """ + Associate the array oid of all the types in Loader.globals. + + This function is designed to be called once at import time, after having + registered all the base loaders. + """ + for t in context.adapters.types: + if t.array_oid: + t.register(context) + + +def _load_text( + data: Buffer, + loader: Loader, + delimiter: bytes = b",", + __re_unescape: Pattern[bytes] = re.compile(rb"\\(.)"), +) -> List[Any]: + rv = None + stack: List[Any] = [] + a: List[Any] = [] + rv = a + load = loader.load + + # Remove the dimensions information prefix (``[...]=``) + if data and data[0] == b"["[0]: + if isinstance(data, memoryview): + data = bytes(data) + idx = data.find(b"=") + if idx == -1: + raise e.DataError("malformed array: no '=' after dimension information") + data = data[idx + 1 :] + + re_parse = _get_array_parse_regexp(delimiter) + for m in re_parse.finditer(data): + t = m.group(1) + if t == b"{": + if stack: + stack[-1].append(a) + stack.append(a) + a = [] + + elif t == b"}": + if not stack: + raise e.DataError("malformed array: unexpected '}'") + rv = stack.pop() + + else: + if not stack: + wat = t[:10].decode("utf8", "replace") + "..." if len(t) > 10 else "" + raise e.DataError(f"malformed array: unexpected '{wat}'") + if t == b"NULL": + v = None + else: + if t.startswith(b'"'): + t = __re_unescape.sub(rb"\1", t[1:-1]) + v = load(t) + + stack[-1].append(v) + + assert rv is not None + return rv + + +@cache +def _get_array_parse_regexp(delimiter: bytes) -> Pattern[bytes]: + """ + Return a regexp to tokenize an array representation into item and brackets + """ + return re.compile( + rb"""(?xi) + ( [{}] # open or closed bracket + | " (?: [^"\\] | \\. )* " # or a quoted string + | [^"{}%s\\]+ # or an unquoted non-empty string + ) ,? + """ + % delimiter + ) + + +def _load_binary(data: Buffer, tx: Transformer) -> List[Any]: + ndims, hasnull, oid = _unpack_head(data) + load = tx.get_loader(oid, PQ_BINARY).load + + if not ndims: + return [] + + p = 12 + 8 * ndims + dims = [_unpack_dim(data, i)[0] for i in range(12, p, 8)] + nelems = prod(dims) + + out: List[Any] = [None] * nelems + for i in range(nelems): + size = unpack_len(data, p)[0] + p += 4 + if size == -1: + continue + out[i] = load(data[p : p + size]) + p += size + + # fon ndims > 1 we have to aggregate the array into sub-arrays + for dim in dims[-1:0:-1]: + out = [out[i : i + dim] for i in range(0, len(out), dim)] + + return out diff --git a/lib/python3.11/site-packages/psycopg/types/bool.py b/lib/python3.11/site-packages/psycopg/types/bool.py new file mode 100644 index 0000000..e259a11 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/bool.py @@ -0,0 +1,48 @@ +""" +Adapters for booleans. +""" + +# Copyright (C) 2020 The Psycopg Team + +from .. import postgres +from ..pq import Format +from ..abc import AdaptContext +from ..adapt import Buffer, Dumper, Loader + + +class BoolDumper(Dumper): + oid = postgres.types["bool"].oid + + def dump(self, obj: bool) -> bytes: + return b"t" if obj else b"f" + + def quote(self, obj: bool) -> bytes: + return b"true" if obj else b"false" + + +class BoolBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["bool"].oid + + def dump(self, obj: bool) -> bytes: + return b"\x01" if obj else b"\x00" + + +class BoolLoader(Loader): + def load(self, data: Buffer) -> bool: + return data == b"t" + + +class BoolBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> bool: + return data != b"\x00" + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper(bool, BoolDumper) + adapters.register_dumper(bool, BoolBinaryDumper) + adapters.register_loader("bool", BoolLoader) + adapters.register_loader("bool", BoolBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/composite.py b/lib/python3.11/site-packages/psycopg/types/composite.py new file mode 100644 index 0000000..40a1e17 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/composite.py @@ -0,0 +1,292 @@ +""" +Support for composite types adaptation. +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +import struct +from collections import namedtuple +from typing import Any, Callable, cast, Dict, Iterator, List, Optional +from typing import Sequence, Tuple, Type + +from .. import pq +from .. import abc +from .. import postgres +from ..adapt import Transformer, PyFormat, RecursiveDumper, Loader, Dumper +from .._struct import pack_len, unpack_len +from ..postgres import TEXT_OID +from .._typeinfo import CompositeInfo as CompositeInfo # exported here +from .._encodings import _as_python_identifier + +_struct_oidlen = struct.Struct("!Ii") +_pack_oidlen = cast(Callable[[int, int], bytes], _struct_oidlen.pack) +_unpack_oidlen = cast( + Callable[[abc.Buffer, int], Tuple[int, int]], _struct_oidlen.unpack_from +) + + +class SequenceDumper(RecursiveDumper): + def _dump_sequence( + self, obj: Sequence[Any], start: bytes, end: bytes, sep: bytes + ) -> bytes: + if not obj: + return start + end + + parts: List[abc.Buffer] = [start] + + for item in obj: + if item is None: + parts.append(sep) + continue + + dumper = self._tx.get_dumper(item, PyFormat.from_pq(self.format)) + ad = dumper.dump(item) + if not ad: + ad = b'""' + elif self._re_needs_quotes.search(ad): + ad = b'"' + self._re_esc.sub(rb"\1\1", ad) + b'"' + + parts.append(ad) + parts.append(sep) + + parts[-1] = end + + return b"".join(parts) + + _re_needs_quotes = re.compile(rb'[",\\\s()]') + _re_esc = re.compile(rb"([\\\"])") + + +class TupleDumper(SequenceDumper): + # Should be this, but it doesn't work + # oid = postgres_types["record"].oid + + def dump(self, obj: Tuple[Any, ...]) -> bytes: + return self._dump_sequence(obj, b"(", b")", b",") + + +class TupleBinaryDumper(Dumper): + format = pq.Format.BINARY + + # Subclasses must set an info + info: CompositeInfo + + def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None): + super().__init__(cls, context) + + # Note: this class is not a RecursiveDumper because it would use the + # same Transformer of the context, which would confuse dump_sequence() + # in case the composite contains another composite. Make sure to use + # a separate Transformer instance instead. + self._tx = Transformer(context) + self._tx.set_dumper_types(self.info.field_types, self.format) + + nfields = len(self.info.field_types) + self._formats = (PyFormat.from_pq(self.format),) * nfields + + def dump(self, obj: Tuple[Any, ...]) -> bytearray: + out = bytearray(pack_len(len(obj))) + adapted = self._tx.dump_sequence(obj, self._formats) + for i in range(len(obj)): + b = adapted[i] + oid = self.info.field_types[i] + if b is not None: + out += _pack_oidlen(oid, len(b)) + out += b + else: + out += _pack_oidlen(oid, -1) + + return out + + +class BaseCompositeLoader(Loader): + def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None): + super().__init__(oid, context) + self._tx = Transformer(context) + + def _parse_record(self, data: abc.Buffer) -> Iterator[Optional[bytes]]: + """ + Split a non-empty representation of a composite type into components. + + Terminators shouldn't be used in `!data` (so that both record and range + representations can be parsed). + """ + for m in self._re_tokenize.finditer(data): + if m.group(1): + yield None + elif m.group(2) is not None: + yield self._re_undouble.sub(rb"\1", m.group(2)) + else: + yield m.group(3) + + # If the final group ended in `,` there is a final NULL in the record + # that the regexp couldn't parse. + if m and m.group().endswith(b","): + yield None + + _re_tokenize = re.compile( + rb"""(?x) + (,) # an empty token, representing NULL + | " ((?: [^"] | "")*) " ,? # or a quoted string + | ([^",)]+) ,? # or an unquoted string + """ + ) + + _re_undouble = re.compile(rb'(["\\])\1') + + +class RecordLoader(BaseCompositeLoader): + def load(self, data: abc.Buffer) -> Tuple[Any, ...]: + if data == b"()": + return () + + cast = self._tx.get_loader(TEXT_OID, self.format).load + return tuple( + cast(token) if token is not None else None + for token in self._parse_record(data[1:-1]) + ) + + +class RecordBinaryLoader(Loader): + format = pq.Format.BINARY + + def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None): + super().__init__(oid, context) + self._ctx = context + # Cache a transformer for each sequence of oid found. + # Usually there will be only one, but if there is more than one + # row in the same query (in different columns, or even in different + # records), oids might differ and we'd need separate transformers. + self._txs: Dict[Tuple[int, ...], abc.Transformer] = {} + + def load(self, data: abc.Buffer) -> Tuple[Any, ...]: + nfields = unpack_len(data, 0)[0] + offset = 4 + oids = [] + record = [] + for _ in range(nfields): + oid, length = _unpack_oidlen(data, offset) + offset += 8 + record.append(data[offset : offset + length] if length != -1 else None) + oids.append(oid) + if length >= 0: + offset += length + + key = tuple(oids) + try: + tx = self._txs[key] + except KeyError: + tx = self._txs[key] = Transformer(self._ctx) + tx.set_loader_types(oids, self.format) + + return tx.load_sequence(tuple(record)) + + +class CompositeLoader(RecordLoader): + factory: Callable[..., Any] + fields_types: List[int] + _types_set = False + + def load(self, data: abc.Buffer) -> Any: + if not self._types_set: + self._config_types(data) + self._types_set = True + + if data == b"()": + return type(self).factory() + + return type(self).factory( + *self._tx.load_sequence(tuple(self._parse_record(data[1:-1]))) + ) + + def _config_types(self, data: abc.Buffer) -> None: + self._tx.set_loader_types(self.fields_types, self.format) + + +class CompositeBinaryLoader(RecordBinaryLoader): + format = pq.Format.BINARY + factory: Callable[..., Any] + + def load(self, data: abc.Buffer) -> Any: + r = super().load(data) + return type(self).factory(*r) + + +def register_composite( + info: CompositeInfo, + context: Optional[abc.AdaptContext] = None, + factory: Optional[Callable[..., Any]] = None, +) -> None: + """Register the adapters to load and dump a composite type. + + :param info: The object with the information about the composite to register. + :param context: The context where to register the adapters. If `!None`, + register it globally. + :param factory: Callable to convert the sequence of attributes read from + the composite into a Python object. + + .. note:: + + Registering the adapters doesn't affect objects already created, even + if they are children of the registered context. For instance, + registering the adapter globally doesn't affect already existing + connections. + """ + + # A friendly error warning instead of an AttributeError in case fetch() + # failed and it wasn't noticed. + if not info: + raise TypeError("no info passed. Is the requested composite available?") + + # Register arrays and type info + info.register(context) + + if not factory: + factory = namedtuple( # type: ignore + _as_python_identifier(info.name), + [_as_python_identifier(n) for n in info.field_names], + ) + + adapters = context.adapters if context else postgres.adapters + + # generate and register a customized text loader + loader: Type[BaseCompositeLoader] = type( + f"{info.name.title()}Loader", + (CompositeLoader,), + { + "factory": factory, + "fields_types": info.field_types, + }, + ) + adapters.register_loader(info.oid, loader) + + # generate and register a customized binary loader + loader = type( + f"{info.name.title()}BinaryLoader", + (CompositeBinaryLoader,), + {"factory": factory}, + ) + adapters.register_loader(info.oid, loader) + + # If the factory is a type, create and register dumpers for it + if isinstance(factory, type): + dumper = type( + f"{info.name.title()}BinaryDumper", + (TupleBinaryDumper,), + {"oid": info.oid, "info": info}, + ) + adapters.register_dumper(factory, dumper) + + # Default to the text dumper because it is more flexible + dumper = type(f"{info.name.title()}Dumper", (TupleDumper,), {"oid": info.oid}) + adapters.register_dumper(factory, dumper) + + info.python_type = factory + + +def register_default_adapters(context: abc.AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper(tuple, TupleDumper) + adapters.register_loader("record", RecordLoader) + adapters.register_loader("record", RecordBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/datetime.py b/lib/python3.11/site-packages/psycopg/types/datetime.py new file mode 100644 index 0000000..3fc4356 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/datetime.py @@ -0,0 +1,730 @@ +""" +Adapters for date/time types. +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +import struct +from datetime import date, datetime, time, timedelta, timezone +from typing import Any, Callable, cast, Optional, Tuple, TYPE_CHECKING + +from .. import postgres +from ..pq import Format +from .._tz import get_tzinfo +from ..abc import AdaptContext, DumperKey +from ..adapt import Buffer, Dumper, Loader, PyFormat +from ..errors import InterfaceError, DataError +from .._struct import pack_int4, pack_int8, unpack_int4, unpack_int8 + +if TYPE_CHECKING: + from ..connection import BaseConnection + +_struct_timetz = struct.Struct("!qi") # microseconds, sec tz offset +_pack_timetz = cast(Callable[[int, int], bytes], _struct_timetz.pack) +_unpack_timetz = cast(Callable[[Buffer], Tuple[int, int]], _struct_timetz.unpack) + +_struct_interval = struct.Struct("!qii") # microseconds, days, months +_pack_interval = cast(Callable[[int, int, int], bytes], _struct_interval.pack) +_unpack_interval = cast( + Callable[[Buffer], Tuple[int, int, int]], _struct_interval.unpack +) + +utc = timezone.utc +_pg_date_epoch_days = date(2000, 1, 1).toordinal() +_pg_datetime_epoch = datetime(2000, 1, 1) +_pg_datetimetz_epoch = datetime(2000, 1, 1, tzinfo=utc) +_py_date_min_days = date.min.toordinal() + + +class DateDumper(Dumper): + oid = postgres.types["date"].oid + + def dump(self, obj: date) -> bytes: + # NOTE: whatever the PostgreSQL DateStyle input format (DMY, MDY, YMD) + # the YYYY-MM-DD is always understood correctly. + return str(obj).encode() + + +class DateBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["date"].oid + + def dump(self, obj: date) -> bytes: + days = obj.toordinal() - _pg_date_epoch_days + return pack_int4(days) + + +class _BaseTimeDumper(Dumper): + def get_key(self, obj: time, format: PyFormat) -> DumperKey: + # Use (cls,) to report the need to upgrade to a dumper for timetz (the + # Frankenstein of the data types). + if not obj.tzinfo: + return self.cls + else: + return (self.cls,) + + def upgrade(self, obj: time, format: PyFormat) -> Dumper: + raise NotImplementedError + + +class _BaseTimeTextDumper(_BaseTimeDumper): + def dump(self, obj: time) -> bytes: + return str(obj).encode() + + +class TimeDumper(_BaseTimeTextDumper): + oid = postgres.types["time"].oid + + def upgrade(self, obj: time, format: PyFormat) -> Dumper: + if not obj.tzinfo: + return self + else: + return TimeTzDumper(self.cls) + + +class TimeTzDumper(_BaseTimeTextDumper): + oid = postgres.types["timetz"].oid + + +class TimeBinaryDumper(_BaseTimeDumper): + format = Format.BINARY + oid = postgres.types["time"].oid + + def dump(self, obj: time) -> bytes: + us = obj.microsecond + 1_000_000 * ( + obj.second + 60 * (obj.minute + 60 * obj.hour) + ) + return pack_int8(us) + + def upgrade(self, obj: time, format: PyFormat) -> Dumper: + if not obj.tzinfo: + return self + else: + return TimeTzBinaryDumper(self.cls) + + +class TimeTzBinaryDumper(_BaseTimeDumper): + format = Format.BINARY + oid = postgres.types["timetz"].oid + + def dump(self, obj: time) -> bytes: + us = obj.microsecond + 1_000_000 * ( + obj.second + 60 * (obj.minute + 60 * obj.hour) + ) + off = obj.utcoffset() + assert off is not None + return _pack_timetz(us, -int(off.total_seconds())) + + +class _BaseDatetimeDumper(Dumper): + def get_key(self, obj: datetime, format: PyFormat) -> DumperKey: + # Use (cls,) to report the need to upgrade (downgrade, actually) to a + # dumper for naive timestamp. + if obj.tzinfo: + return self.cls + else: + return (self.cls,) + + def upgrade(self, obj: datetime, format: PyFormat) -> Dumper: + raise NotImplementedError + + +class _BaseDatetimeTextDumper(_BaseDatetimeDumper): + def dump(self, obj: datetime) -> bytes: + # NOTE: whatever the PostgreSQL DateStyle input format (DMY, MDY, YMD) + # the YYYY-MM-DD is always understood correctly. + return str(obj).encode() + + +class DatetimeDumper(_BaseDatetimeTextDumper): + oid = postgres.types["timestamptz"].oid + + def upgrade(self, obj: datetime, format: PyFormat) -> Dumper: + if obj.tzinfo: + return self + else: + return DatetimeNoTzDumper(self.cls) + + +class DatetimeNoTzDumper(_BaseDatetimeTextDumper): + oid = postgres.types["timestamp"].oid + + +class DatetimeBinaryDumper(_BaseDatetimeDumper): + format = Format.BINARY + oid = postgres.types["timestamptz"].oid + + def dump(self, obj: datetime) -> bytes: + delta = obj - _pg_datetimetz_epoch + micros = delta.microseconds + 1_000_000 * (86_400 * delta.days + delta.seconds) + return pack_int8(micros) + + def upgrade(self, obj: datetime, format: PyFormat) -> Dumper: + if obj.tzinfo: + return self + else: + return DatetimeNoTzBinaryDumper(self.cls) + + +class DatetimeNoTzBinaryDumper(_BaseDatetimeDumper): + format = Format.BINARY + oid = postgres.types["timestamp"].oid + + def dump(self, obj: datetime) -> bytes: + delta = obj - _pg_datetime_epoch + micros = delta.microseconds + 1_000_000 * (86_400 * delta.days + delta.seconds) + return pack_int8(micros) + + +class TimedeltaDumper(Dumper): + oid = postgres.types["interval"].oid + + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + super().__init__(cls, context) + if self.connection: + if ( + self.connection.pgconn.parameter_status(b"IntervalStyle") + == b"sql_standard" + ): + setattr(self, "dump", self._dump_sql) + + def dump(self, obj: timedelta) -> bytes: + # The comma is parsed ok by PostgreSQL but it's not documented + # and it seems brittle to rely on it. CRDB doesn't consume it well. + return str(obj).encode().replace(b",", b"") + + def _dump_sql(self, obj: timedelta) -> bytes: + # sql_standard format needs explicit signs + # otherwise -1 day 1 sec will mean -1 sec + return b"%+d day %+d second %+d microsecond" % ( + obj.days, + obj.seconds, + obj.microseconds, + ) + + +class TimedeltaBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["interval"].oid + + def dump(self, obj: timedelta) -> bytes: + micros = 1_000_000 * obj.seconds + obj.microseconds + return _pack_interval(micros, obj.days, 0) + + +class DateLoader(Loader): + _ORDER_YMD = 0 + _ORDER_DMY = 1 + _ORDER_MDY = 2 + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + ds = _get_datestyle(self.connection) + if ds.startswith(b"I"): # ISO + self._order = self._ORDER_YMD + elif ds.startswith(b"G"): # German + self._order = self._ORDER_DMY + elif ds.startswith(b"S") or ds.startswith(b"P"): # SQL or Postgres + self._order = self._ORDER_DMY if ds.endswith(b"DMY") else self._ORDER_MDY + else: + raise InterfaceError(f"unexpected DateStyle: {ds.decode('ascii')}") + + def load(self, data: Buffer) -> date: + if self._order == self._ORDER_YMD: + ye = data[:4] + mo = data[5:7] + da = data[8:] + elif self._order == self._ORDER_DMY: + da = data[:2] + mo = data[3:5] + ye = data[6:] + else: + mo = data[:2] + da = data[3:5] + ye = data[6:] + + try: + return date(int(ye), int(mo), int(da)) + except ValueError as ex: + s = bytes(data).decode("utf8", "replace") + if s == "infinity" or (s and len(s.split()[0]) > 10): + raise DataError(f"date too large (after year 10K): {s!r}") from None + elif s == "-infinity" or "BC" in s: + raise DataError(f"date too small (before year 1): {s!r}") from None + else: + raise DataError(f"can't parse date {s!r}: {ex}") from None + + +class DateBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> date: + days = unpack_int4(data)[0] + _pg_date_epoch_days + try: + return date.fromordinal(days) + except (ValueError, OverflowError): + if days < _py_date_min_days: + raise DataError("date too small (before year 1)") from None + else: + raise DataError("date too large (after year 10K)") from None + + +class TimeLoader(Loader): + _re_format = re.compile(rb"^(\d+):(\d+):(\d+)(?:\.(\d+))?") + + def load(self, data: Buffer) -> time: + m = self._re_format.match(data) + if not m: + s = bytes(data).decode("utf8", "replace") + raise DataError(f"can't parse time {s!r}") + + ho, mi, se, fr = m.groups() + + # Pad the fraction of second to get micros + if fr: + us = int(fr) + if len(fr) < 6: + us *= _uspad[len(fr)] + else: + us = 0 + + try: + return time(int(ho), int(mi), int(se), us) + except ValueError as e: + s = bytes(data).decode("utf8", "replace") + raise DataError(f"can't parse time {s!r}: {e}") from None + + +class TimeBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> time: + val = unpack_int8(data)[0] + val, us = divmod(val, 1_000_000) + val, s = divmod(val, 60) + h, m = divmod(val, 60) + try: + return time(h, m, s, us) + except ValueError: + raise DataError(f"time not supported by Python: hour={h}") from None + + +class TimetzLoader(Loader): + _re_format = re.compile( + rb"""(?ix) + ^ + (\d+) : (\d+) : (\d+) (?: \. (\d+) )? # Time and micros + ([-+]) (\d+) (?: : (\d+) )? (?: : (\d+) )? # Timezone + $ + """ + ) + + def load(self, data: Buffer) -> time: + m = self._re_format.match(data) + if not m: + s = bytes(data).decode("utf8", "replace") + raise DataError(f"can't parse timetz {s!r}") + + ho, mi, se, fr, sgn, oh, om, os = m.groups() + + # Pad the fraction of second to get the micros + if fr: + us = int(fr) + if len(fr) < 6: + us *= _uspad[len(fr)] + else: + us = 0 + + # Calculate timezone + off = 60 * 60 * int(oh) + if om: + off += 60 * int(om) + if os: + off += int(os) + tz = timezone(timedelta(0, off if sgn == b"+" else -off)) + + try: + return time(int(ho), int(mi), int(se), us, tz) + except ValueError as e: + s = bytes(data).decode("utf8", "replace") + raise DataError(f"can't parse timetz {s!r}: {e}") from None + + +class TimetzBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> time: + val, off = _unpack_timetz(data) + + val, us = divmod(val, 1_000_000) + val, s = divmod(val, 60) + h, m = divmod(val, 60) + + try: + return time(h, m, s, us, timezone(timedelta(seconds=-off))) + except ValueError: + raise DataError(f"time not supported by Python: hour={h}") from None + + +class TimestampLoader(Loader): + _re_format = re.compile( + rb"""(?ix) + ^ + (\d+) [^a-z0-9] (\d+) [^a-z0-9] (\d+) # Date + (?: T | [^a-z0-9] ) # Separator, including T + (\d+) [^a-z0-9] (\d+) [^a-z0-9] (\d+) # Time + (?: \.(\d+) )? # Micros + $ + """ + ) + _re_format_pg = re.compile( + rb"""(?ix) + ^ + [a-z]+ [^a-z0-9] # DoW, separator + (\d+|[a-z]+) [^a-z0-9] # Month or day + (\d+|[a-z]+) [^a-z0-9] # Month or day + (\d+) [^a-z0-9] (\d+) [^a-z0-9] (\d+) # Time + (?: \.(\d+) )? # Micros + [^a-z0-9] (\d+) # Year + $ + """ + ) + + _ORDER_YMD = 0 + _ORDER_DMY = 1 + _ORDER_MDY = 2 + _ORDER_PGDM = 3 + _ORDER_PGMD = 4 + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + + ds = _get_datestyle(self.connection) + if ds.startswith(b"I"): # ISO + self._order = self._ORDER_YMD + elif ds.startswith(b"G"): # German + self._order = self._ORDER_DMY + elif ds.startswith(b"S"): # SQL + self._order = self._ORDER_DMY if ds.endswith(b"DMY") else self._ORDER_MDY + elif ds.startswith(b"P"): # Postgres + self._order = self._ORDER_PGDM if ds.endswith(b"DMY") else self._ORDER_PGMD + self._re_format = self._re_format_pg + else: + raise InterfaceError(f"unexpected DateStyle: {ds.decode('ascii')}") + + def load(self, data: Buffer) -> datetime: + m = self._re_format.match(data) + if not m: + raise _get_timestamp_load_error(self.connection, data) from None + + if self._order == self._ORDER_YMD: + ye, mo, da, ho, mi, se, fr = m.groups() + imo = int(mo) + elif self._order == self._ORDER_DMY: + da, mo, ye, ho, mi, se, fr = m.groups() + imo = int(mo) + elif self._order == self._ORDER_MDY: + mo, da, ye, ho, mi, se, fr = m.groups() + imo = int(mo) + else: + if self._order == self._ORDER_PGDM: + da, mo, ho, mi, se, fr, ye = m.groups() + else: + mo, da, ho, mi, se, fr, ye = m.groups() + try: + imo = _month_abbr[mo] + except KeyError: + s = mo.decode("utf8", "replace") + raise DataError(f"can't parse month: {s!r}") from None + + # Pad the fraction of second to get the micros + if fr: + us = int(fr) + if len(fr) < 6: + us *= _uspad[len(fr)] + else: + us = 0 + + try: + return datetime(int(ye), imo, int(da), int(ho), int(mi), int(se), us) + except ValueError as ex: + raise _get_timestamp_load_error(self.connection, data, ex) from None + + +class TimestampBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> datetime: + micros = unpack_int8(data)[0] + try: + return _pg_datetime_epoch + timedelta(microseconds=micros) + except OverflowError: + if micros <= 0: + raise DataError("timestamp too small (before year 1)") from None + else: + raise DataError("timestamp too large (after year 10K)") from None + + +class TimestamptzLoader(Loader): + _re_format = re.compile( + rb"""(?ix) + ^ + (\d+) [^a-z0-9] (\d+) [^a-z0-9] (\d+) # Date + (?: T | [^a-z0-9] ) # Separator, including T + (\d+) [^a-z0-9] (\d+) [^a-z0-9] (\d+) # Time + (?: \.(\d+) )? # Micros + ([-+]) (\d+) (?: : (\d+) )? (?: : (\d+) )? # Timezone + $ + """ + ) + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + self._timezone = get_tzinfo(self.connection.pgconn if self.connection else None) + + ds = _get_datestyle(self.connection) + if not ds.startswith(b"I"): # not ISO + setattr(self, "load", self._load_notimpl) + + def load(self, data: Buffer) -> datetime: + m = self._re_format.match(data) + if not m: + raise _get_timestamp_load_error(self.connection, data) from None + + ye, mo, da, ho, mi, se, fr, sgn, oh, om, os = m.groups() + + # Pad the fraction of second to get the micros + if fr: + us = int(fr) + if len(fr) < 6: + us *= _uspad[len(fr)] + else: + us = 0 + + # Calculate timezone offset + soff = 60 * 60 * int(oh) + if om: + soff += 60 * int(om) + if os: + soff += int(os) + tzoff = timedelta(0, soff if sgn == b"+" else -soff) + + # The return value is a datetime with the timezone of the connection + # (in order to be consistent with the binary loader, which is the only + # thing it can return). So create a temporary datetime object, in utc, + # shift it by the offset parsed from the timestamp, and then move it to + # the connection timezone. + dt = None + ex: Exception + try: + dt = datetime(int(ye), int(mo), int(da), int(ho), int(mi), int(se), us, utc) + return (dt - tzoff).astimezone(self._timezone) + except OverflowError as e: + # If we have created the temporary 'dt' it means that we have a + # datetime close to max, the shift pushed it past max, overflowing. + # In this case return the datetime in a fixed offset timezone. + if dt is not None: + return dt.replace(tzinfo=timezone(tzoff)) + else: + ex = e + except ValueError as e: + ex = e + + raise _get_timestamp_load_error(self.connection, data, ex) from None + + def _load_notimpl(self, data: Buffer) -> datetime: + s = bytes(data).decode("utf8", "replace") + ds = _get_datestyle(self.connection).decode("ascii") + raise NotImplementedError( + f"can't parse timestamptz with DateStyle {ds!r}: {s!r}" + ) + + +class TimestamptzBinaryLoader(Loader): + format = Format.BINARY + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + self._timezone = get_tzinfo(self.connection.pgconn if self.connection else None) + + def load(self, data: Buffer) -> datetime: + micros = unpack_int8(data)[0] + try: + ts = _pg_datetimetz_epoch + timedelta(microseconds=micros) + return ts.astimezone(self._timezone) + except OverflowError: + # If we were asked about a timestamp which would overflow in UTC, + # but not in the desired timezone (e.g. datetime.max at Chicago + # timezone) we can still save the day by shifting the value by the + # timezone offset and then replacing the timezone. + if self._timezone: + utcoff = self._timezone.utcoffset( + datetime.min if micros < 0 else datetime.max + ) + if utcoff: + usoff = 1_000_000 * int(utcoff.total_seconds()) + try: + ts = _pg_datetime_epoch + timedelta(microseconds=micros + usoff) + except OverflowError: + pass # will raise downstream + else: + return ts.replace(tzinfo=self._timezone) + + if micros <= 0: + raise DataError("timestamp too small (before year 1)") from None + else: + raise DataError("timestamp too large (after year 10K)") from None + + +class IntervalLoader(Loader): + _re_interval = re.compile( + rb""" + (?: ([-+]?\d+) \s+ years? \s* )? # Years + (?: ([-+]?\d+) \s+ mons? \s* )? # Months + (?: ([-+]?\d+) \s+ days? \s* )? # Days + (?: ([-+])? (\d+) : (\d+) : (\d+ (?:\.\d+)?) # Time + )? + """, + re.VERBOSE, + ) + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + if self.connection: + ints = self.connection.pgconn.parameter_status(b"IntervalStyle") + if ints != b"postgres": + setattr(self, "load", self._load_notimpl) + + def load(self, data: Buffer) -> timedelta: + m = self._re_interval.match(data) + if not m: + s = bytes(data).decode("utf8", "replace") + raise DataError(f"can't parse interval {s!r}") + + ye, mo, da, sgn, ho, mi, se = m.groups() + days = 0 + seconds = 0.0 + + if ye: + days += 365 * int(ye) + if mo: + days += 30 * int(mo) + if da: + days += int(da) + + if ho: + seconds = 3600 * int(ho) + 60 * int(mi) + float(se) + if sgn == b"-": + seconds = -seconds + + try: + return timedelta(days=days, seconds=seconds) + except OverflowError as e: + s = bytes(data).decode("utf8", "replace") + raise DataError(f"can't parse interval {s!r}: {e}") from None + + def _load_notimpl(self, data: Buffer) -> timedelta: + s = bytes(data).decode("utf8", "replace") + ints = ( + self.connection + and self.connection.pgconn.parameter_status(b"IntervalStyle") + or b"unknown" + ).decode("utf8", "replace") + raise NotImplementedError( + f"can't parse interval with IntervalStyle {ints}: {s!r}" + ) + + +class IntervalBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> timedelta: + micros, days, months = _unpack_interval(data) + if months > 0: + years, months = divmod(months, 12) + days = days + 30 * months + 365 * years + elif months < 0: + years, months = divmod(-months, 12) + days = days - 30 * months - 365 * years + + try: + return timedelta(days=days, microseconds=micros) + except OverflowError as e: + raise DataError(f"can't parse interval: {e}") from None + + +def _get_datestyle(conn: Optional["BaseConnection[Any]"]) -> bytes: + if conn: + ds = conn.pgconn.parameter_status(b"DateStyle") + if ds: + return ds + + return b"ISO, DMY" + + +def _get_timestamp_load_error( + conn: Optional["BaseConnection[Any]"], data: Buffer, ex: Optional[Exception] = None +) -> Exception: + s = bytes(data).decode("utf8", "replace") + + def is_overflow(s: str) -> bool: + if not s: + return False + + ds = _get_datestyle(conn) + if not ds.startswith(b"P"): # Postgres + return len(s.split()[0]) > 10 # date is first token + else: + return len(s.split()[-1]) > 4 # year is last token + + if s == "-infinity" or s.endswith("BC"): + return DataError("timestamp too small (before year 1): {s!r}") + elif s == "infinity" or is_overflow(s): + return DataError(f"timestamp too large (after year 10K): {s!r}") + else: + return DataError(f"can't parse timestamp {s!r}: {ex or '(unknown)'}") + + +_month_abbr = { + n: i + for i, n in enumerate(b"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(), 1) +} + +# Pad to get microseconds from a fraction of seconds +_uspad = [0, 100_000, 10_000, 1_000, 100, 10, 1] + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper("datetime.date", DateDumper) + adapters.register_dumper("datetime.date", DateBinaryDumper) + + # first register dumpers for 'timetz' oid, then the proper ones on time type. + adapters.register_dumper("datetime.time", TimeTzDumper) + adapters.register_dumper("datetime.time", TimeTzBinaryDumper) + adapters.register_dumper("datetime.time", TimeDumper) + adapters.register_dumper("datetime.time", TimeBinaryDumper) + + # first register dumpers for 'timestamp' oid, then the proper ones + # on the datetime type. + adapters.register_dumper("datetime.datetime", DatetimeNoTzDumper) + adapters.register_dumper("datetime.datetime", DatetimeNoTzBinaryDumper) + adapters.register_dumper("datetime.datetime", DatetimeDumper) + adapters.register_dumper("datetime.datetime", DatetimeBinaryDumper) + + adapters.register_dumper("datetime.timedelta", TimedeltaDumper) + adapters.register_dumper("datetime.timedelta", TimedeltaBinaryDumper) + + adapters.register_loader("date", DateLoader) + adapters.register_loader("date", DateBinaryLoader) + adapters.register_loader("time", TimeLoader) + adapters.register_loader("time", TimeBinaryLoader) + adapters.register_loader("timetz", TimetzLoader) + adapters.register_loader("timetz", TimetzBinaryLoader) + adapters.register_loader("timestamp", TimestampLoader) + adapters.register_loader("timestamp", TimestampBinaryLoader) + adapters.register_loader("timestamptz", TimestamptzLoader) + adapters.register_loader("timestamptz", TimestamptzBinaryLoader) + adapters.register_loader("interval", IntervalLoader) + adapters.register_loader("interval", IntervalBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/enum.py b/lib/python3.11/site-packages/psycopg/types/enum.py new file mode 100644 index 0000000..d3c7387 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/enum.py @@ -0,0 +1,177 @@ +""" +Adapters for the enum type. +""" +from enum import Enum +from typing import Any, Dict, Generic, Optional, Mapping, Sequence +from typing import Tuple, Type, TypeVar, Union, cast +from typing_extensions import TypeAlias + +from .. import postgres +from .. import errors as e +from ..pq import Format +from ..abc import AdaptContext +from ..adapt import Buffer, Dumper, Loader +from .._encodings import conn_encoding +from .._typeinfo import EnumInfo as EnumInfo # exported here + +E = TypeVar("E", bound=Enum) + +EnumDumpMap: TypeAlias = Dict[E, bytes] +EnumLoadMap: TypeAlias = Dict[bytes, E] +EnumMapping: TypeAlias = Union[Mapping[E, str], Sequence[Tuple[E, str]], None] + + +class _BaseEnumLoader(Loader, Generic[E]): + """ + Loader for a specific Enum class + """ + + enum: Type[E] + _load_map: EnumLoadMap[E] + + def load(self, data: Buffer) -> E: + if not isinstance(data, bytes): + data = bytes(data) + + try: + return self._load_map[data] + except KeyError: + enc = conn_encoding(self.connection) + label = data.decode(enc, "replace") + raise e.DataError( + f"bad member for enum {self.enum.__qualname__}: {label!r}" + ) + + +class _BaseEnumDumper(Dumper, Generic[E]): + """ + Dumper for a specific Enum class + """ + + enum: Type[E] + _dump_map: EnumDumpMap[E] + + def dump(self, value: E) -> Buffer: + return self._dump_map[value] + + +class EnumDumper(Dumper): + """ + Dumper for a generic Enum class + """ + + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + super().__init__(cls, context) + self._encoding = conn_encoding(self.connection) + + def dump(self, value: E) -> Buffer: + return value.name.encode(self._encoding) + + +class EnumBinaryDumper(EnumDumper): + format = Format.BINARY + + +def register_enum( + info: EnumInfo, + context: Optional[AdaptContext] = None, + enum: Optional[Type[E]] = None, + *, + mapping: EnumMapping[E] = None, +) -> None: + """Register the adapters to load and dump a enum type. + + :param info: The object with the information about the enum to register. + :param context: The context where to register the adapters. If `!None`, + register it globally. + :param enum: Python enum type matching to the PostgreSQL one. If `!None`, + a new enum will be generated and exposed as `EnumInfo.enum`. + :param mapping: Override the mapping between `!enum` members and `!info` + labels. + """ + + if not info: + raise TypeError("no info passed. Is the requested enum available?") + + if enum is None: + enum = cast(Type[E], Enum(info.name.title(), info.labels, module=__name__)) + + info.enum = enum + adapters = context.adapters if context else postgres.adapters + info.register(context) + + load_map = _make_load_map(info, enum, mapping, context) + attribs: Dict[str, Any] = {"enum": info.enum, "_load_map": load_map} + + name = f"{info.name.title()}Loader" + loader = type(name, (_BaseEnumLoader,), attribs) + adapters.register_loader(info.oid, loader) + + name = f"{info.name.title()}BinaryLoader" + loader = type(name, (_BaseEnumLoader,), {**attribs, "format": Format.BINARY}) + adapters.register_loader(info.oid, loader) + + dump_map = _make_dump_map(info, enum, mapping, context) + attribs = {"oid": info.oid, "enum": info.enum, "_dump_map": dump_map} + + name = f"{enum.__name__}Dumper" + dumper = type(name, (_BaseEnumDumper,), attribs) + adapters.register_dumper(info.enum, dumper) + + name = f"{enum.__name__}BinaryDumper" + dumper = type(name, (_BaseEnumDumper,), {**attribs, "format": Format.BINARY}) + adapters.register_dumper(info.enum, dumper) + + +def _make_load_map( + info: EnumInfo, + enum: Type[E], + mapping: EnumMapping[E], + context: Optional[AdaptContext], +) -> EnumLoadMap[E]: + enc = conn_encoding(context.connection if context else None) + rv: EnumLoadMap[E] = {} + for label in info.labels: + try: + member = enum[label] + except KeyError: + # tolerate a missing enum, assuming it won't be used. If it is we + # will get a DataError on fetch. + pass + else: + rv[label.encode(enc)] = member + + if mapping: + if isinstance(mapping, Mapping): + mapping = list(mapping.items()) + + for member, label in mapping: + rv[label.encode(enc)] = member + + return rv + + +def _make_dump_map( + info: EnumInfo, + enum: Type[E], + mapping: EnumMapping[E], + context: Optional[AdaptContext], +) -> EnumDumpMap[E]: + enc = conn_encoding(context.connection if context else None) + rv: EnumDumpMap[E] = {} + for member in enum: + rv[member] = member.name.encode(enc) + + if mapping: + if isinstance(mapping, Mapping): + mapping = list(mapping.items()) + + for member, label in mapping: + rv[member] = label.encode(enc) + + return rv + + +def register_default_adapters(context: AdaptContext) -> None: + context.adapters.register_dumper(Enum, EnumBinaryDumper) + context.adapters.register_dumper(Enum, EnumDumper) diff --git a/lib/python3.11/site-packages/psycopg/types/hstore.py b/lib/python3.11/site-packages/psycopg/types/hstore.py new file mode 100644 index 0000000..c3935d6 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/hstore.py @@ -0,0 +1,130 @@ +""" +Dict to hstore adaptation +""" + +# Copyright (C) 2021 The Psycopg Team + +import re +from typing import Dict, List, Optional +from typing_extensions import TypeAlias + +from .. import errors as e +from .. import postgres +from ..abc import Buffer, AdaptContext +from ..adapt import PyFormat, RecursiveDumper, RecursiveLoader +from ..postgres import TEXT_OID +from .._typeinfo import TypeInfo + +_re_escape = re.compile(r'(["\\])') +_re_unescape = re.compile(r"\\(.)") + +_re_hstore = re.compile( + r""" + # hstore key: + # a string of normal or escaped chars + "((?: [^"\\] | \\. )*)" + \s*=>\s* # hstore value + (?: + NULL # the value can be null - not caught + # or a quoted string like the key + | "((?: [^"\\] | \\. )*)" + ) + (?:\s*,\s*|$) # pairs separated by comma or end of string. +""", + re.VERBOSE, +) + + +Hstore: TypeAlias = Dict[str, Optional[str]] + + +class BaseHstoreDumper(RecursiveDumper): + def dump(self, obj: Hstore) -> Buffer: + if not obj: + return b"" + + tokens: List[str] = [] + + def add_token(s: str) -> None: + tokens.append('"') + tokens.append(_re_escape.sub(r"\\\1", s)) + tokens.append('"') + + for k, v in obj.items(): + if not isinstance(k, str): + raise e.DataError("hstore keys can only be strings") + add_token(k) + + tokens.append("=>") + + if v is None: + tokens.append("NULL") + elif not isinstance(v, str): + raise e.DataError("hstore keys can only be strings") + else: + add_token(v) + + tokens.append(",") + + del tokens[-1] + data = "".join(tokens) + dumper = self._tx.get_dumper(data, PyFormat.TEXT) + return dumper.dump(data) + + +class HstoreLoader(RecursiveLoader): + def load(self, data: Buffer) -> Hstore: + loader = self._tx.get_loader(TEXT_OID, self.format) + s: str = loader.load(data) + + rv: Hstore = {} + start = 0 + for m in _re_hstore.finditer(s): + if m is None or m.start() != start: + raise e.DataError(f"error parsing hstore pair at char {start}") + k = _re_unescape.sub(r"\1", m.group(1)) + v = m.group(2) + if v is not None: + v = _re_unescape.sub(r"\1", v) + + rv[k] = v + start = m.end() + + if start < len(s): + raise e.DataError(f"error parsing hstore: unparsed data after char {start}") + + return rv + + +def register_hstore(info: TypeInfo, context: Optional[AdaptContext] = None) -> None: + """Register the adapters to load and dump hstore. + + :param info: The object with the information about the hstore type. + :param context: The context where to register the adapters. If `!None`, + register it globally. + + .. note:: + + Registering the adapters doesn't affect objects already created, even + if they are children of the registered context. For instance, + registering the adapter globally doesn't affect already existing + connections. + """ + # A friendly error warning instead of an AttributeError in case fetch() + # failed and it wasn't noticed. + if not info: + raise TypeError("no info passed. Is the 'hstore' extension loaded?") + + # Register arrays and type info + info.register(context) + + adapters = context.adapters if context else postgres.adapters + + # Generate and register a customized text dumper + class HstoreDumper(BaseHstoreDumper): + oid = info.oid + + adapters.register_dumper(dict, HstoreDumper) + + # register the text loader on the oid + adapters.register_loader(info.oid, HstoreLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/json.py b/lib/python3.11/site-packages/psycopg/types/json.py new file mode 100644 index 0000000..b3323cf --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/json.py @@ -0,0 +1,228 @@ +""" +Adapers for JSON types. +""" + +# Copyright (C) 2020 The Psycopg Team + +import json +from typing import Any, Callable, Dict, Optional, Tuple, Type, Union + +from .. import abc +from .. import errors as e +from .. import postgres +from ..pq import Format +from ..adapt import Buffer, Dumper, Loader, PyFormat, AdaptersMap +from ..errors import DataError + +JsonDumpsFunction = Callable[[Any], str] +JsonLoadsFunction = Callable[[Union[str, bytes]], Any] + + +def set_json_dumps( + dumps: JsonDumpsFunction, context: Optional[abc.AdaptContext] = None +) -> None: + """ + Set the JSON serialisation function to store JSON objects in the database. + + :param dumps: The dump function to use. + :type dumps: `!Callable[[Any], str]` + :param context: Where to use the `!dumps` function. If not specified, use it + globally. + :type context: `~psycopg.Connection` or `~psycopg.Cursor` + + By default dumping JSON uses the builtin `json.dumps`. You can override + it to use a different JSON library or to use customised arguments. + + If the `Json` wrapper specified a `!dumps` function, use it in precedence + of the one set by this function. + """ + if context is None: + # If changing load function globally, just change the default on the + # global class + _JsonDumper._dumps = dumps + else: + adapters = context.adapters + + # If the scope is smaller than global, create subclassess and register + # them in the appropriate scope. + grid = [ + (Json, PyFormat.BINARY), + (Json, PyFormat.TEXT), + (Jsonb, PyFormat.BINARY), + (Jsonb, PyFormat.TEXT), + ] + dumper: Type[_JsonDumper] + for wrapper, format in grid: + base = _get_current_dumper(adapters, wrapper, format) + name = base.__name__ + if not base.__name__.startswith("Custom"): + name = f"Custom{name}" + dumper = type(name, (base,), {"_dumps": dumps}) + adapters.register_dumper(wrapper, dumper) + + +def set_json_loads( + loads: JsonLoadsFunction, context: Optional[abc.AdaptContext] = None +) -> None: + """ + Set the JSON parsing function to fetch JSON objects from the database. + + :param loads: The load function to use. + :type loads: `!Callable[[bytes], Any]` + :param context: Where to use the `!loads` function. If not specified, use + it globally. + :type context: `~psycopg.Connection` or `~psycopg.Cursor` + + By default loading JSON uses the builtin `json.loads`. You can override + it to use a different JSON library or to use customised arguments. + """ + if context is None: + # If changing load function globally, just change the default on the + # global class + _JsonLoader._loads = loads + else: + # If the scope is smaller than global, create subclassess and register + # them in the appropriate scope. + grid = [ + ("json", JsonLoader), + ("json", JsonBinaryLoader), + ("jsonb", JsonbLoader), + ("jsonb", JsonbBinaryLoader), + ] + loader: Type[_JsonLoader] + for tname, base in grid: + loader = type(f"Custom{base.__name__}", (base,), {"_loads": loads}) + context.adapters.register_loader(tname, loader) + + +class _JsonWrapper: + __slots__ = ("obj", "dumps") + + def __init__(self, obj: Any, dumps: Optional[JsonDumpsFunction] = None): + self.obj = obj + self.dumps = dumps + + def __repr__(self) -> str: + sobj = repr(self.obj) + if len(sobj) > 40: + sobj = f"{sobj[:35]} ... ({len(sobj)} chars)" + return f"{self.__class__.__name__}({sobj})" + + +class Json(_JsonWrapper): + __slots__ = () + + +class Jsonb(_JsonWrapper): + __slots__ = () + + +class _JsonDumper(Dumper): + # The globally used JSON dumps() function. It can be changed globally (by + # set_json_dumps) or by a subclass. + _dumps: JsonDumpsFunction = json.dumps + + def __init__(self, cls: type, context: Optional[abc.AdaptContext] = None): + super().__init__(cls, context) + self.dumps = self.__class__._dumps + + def dump(self, obj: Any) -> bytes: + if isinstance(obj, _JsonWrapper): + dumps = obj.dumps or self.dumps + obj = obj.obj + else: + dumps = self.dumps + return dumps(obj).encode() + + +class JsonDumper(_JsonDumper): + oid = postgres.types["json"].oid + + +class JsonBinaryDumper(_JsonDumper): + format = Format.BINARY + oid = postgres.types["json"].oid + + +class JsonbDumper(_JsonDumper): + oid = postgres.types["jsonb"].oid + + +class JsonbBinaryDumper(_JsonDumper): + format = Format.BINARY + oid = postgres.types["jsonb"].oid + + def dump(self, obj: Any) -> bytes: + return b"\x01" + super().dump(obj) + + +class _JsonLoader(Loader): + # The globally used JSON loads() function. It can be changed globally (by + # set_json_loads) or by a subclass. + _loads: JsonLoadsFunction = json.loads + + def __init__(self, oid: int, context: Optional[abc.AdaptContext] = None): + super().__init__(oid, context) + self.loads = self.__class__._loads + + def load(self, data: Buffer) -> Any: + # json.loads() cannot work on memoryview. + if not isinstance(data, bytes): + data = bytes(data) + return self.loads(data) + + +class JsonLoader(_JsonLoader): + pass + + +class JsonbLoader(_JsonLoader): + pass + + +class JsonBinaryLoader(_JsonLoader): + format = Format.BINARY + + +class JsonbBinaryLoader(_JsonLoader): + format = Format.BINARY + + def load(self, data: Buffer) -> Any: + if data and data[0] != 1: + raise DataError("unknown jsonb binary format: {data[0]}") + data = data[1:] + if not isinstance(data, bytes): + data = bytes(data) + return self.loads(data) + + +def _get_current_dumper( + adapters: AdaptersMap, cls: type, format: PyFormat +) -> Type[abc.Dumper]: + try: + return adapters.get_dumper(cls, format) + except e.ProgrammingError: + return _default_dumpers[cls, format] + + +_default_dumpers: Dict[Tuple[Type[_JsonWrapper], PyFormat], Type[Dumper]] = { + (Json, PyFormat.BINARY): JsonBinaryDumper, + (Json, PyFormat.TEXT): JsonDumper, + (Jsonb, PyFormat.BINARY): JsonbBinaryDumper, + (Jsonb, PyFormat.TEXT): JsonDumper, +} + + +def register_default_adapters(context: abc.AdaptContext) -> None: + adapters = context.adapters + + # Currently json binary format is nothing different than text, maybe with + # an extra memcopy we can avoid. + adapters.register_dumper(Json, JsonBinaryDumper) + adapters.register_dumper(Json, JsonDumper) + adapters.register_dumper(Jsonb, JsonbBinaryDumper) + adapters.register_dumper(Jsonb, JsonbDumper) + adapters.register_loader("json", JsonLoader) + adapters.register_loader("jsonb", JsonbLoader) + adapters.register_loader("json", JsonBinaryLoader) + adapters.register_loader("jsonb", JsonbBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/multirange.py b/lib/python3.11/site-packages/psycopg/types/multirange.py new file mode 100644 index 0000000..c893148 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/multirange.py @@ -0,0 +1,511 @@ +""" +Support for multirange types adaptation. +""" + +# Copyright (C) 2021 The Psycopg Team + +from decimal import Decimal +from typing import Any, Generic, List, Iterable +from typing import MutableSequence, Optional, Type, Union, overload +from datetime import date, datetime + +from .. import errors as e +from .. import postgres +from ..pq import Format +from ..abc import AdaptContext, Buffer, Dumper, DumperKey +from ..adapt import RecursiveDumper, RecursiveLoader, PyFormat +from .._struct import pack_len, unpack_len +from ..postgres import INVALID_OID, TEXT_OID +from .._typeinfo import MultirangeInfo as MultirangeInfo # exported here + +from .range import Range, T, load_range_text, load_range_binary +from .range import dump_range_text, dump_range_binary, fail_dump + + +class Multirange(MutableSequence[Range[T]]): + """Python representation for a PostgreSQL multirange type. + + :param items: Sequence of ranges to initialise the object. + """ + + def __init__(self, items: Iterable[Range[T]] = ()): + self._ranges: List[Range[T]] = list(map(self._check_type, items)) + + def _check_type(self, item: Any) -> Range[Any]: + if not isinstance(item, Range): + raise TypeError( + f"Multirange is a sequence of Range, got {type(item).__name__}" + ) + return item + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self._ranges!r})" + + def __str__(self) -> str: + return f"{{{', '.join(map(str, self._ranges))}}}" + + @overload + def __getitem__(self, index: int) -> Range[T]: + ... + + @overload + def __getitem__(self, index: slice) -> "Multirange[T]": + ... + + def __getitem__(self, index: Union[int, slice]) -> "Union[Range[T],Multirange[T]]": + if isinstance(index, int): + return self._ranges[index] + else: + return Multirange(self._ranges[index]) + + def __len__(self) -> int: + return len(self._ranges) + + @overload + def __setitem__(self, index: int, value: Range[T]) -> None: + ... + + @overload + def __setitem__(self, index: slice, value: Iterable[Range[T]]) -> None: + ... + + def __setitem__( + self, + index: Union[int, slice], + value: Union[Range[T], Iterable[Range[T]]], + ) -> None: + if isinstance(index, int): + self._check_type(value) + self._ranges[index] = self._check_type(value) + elif not isinstance(value, Iterable): + raise TypeError("can only assign an iterable") + else: + value = map(self._check_type, value) + self._ranges[index] = value + + def __delitem__(self, index: Union[int, slice]) -> None: + del self._ranges[index] + + def insert(self, index: int, value: Range[T]) -> None: + self._ranges.insert(index, self._check_type(value)) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Multirange): + return False + return self._ranges == other._ranges + + # Order is arbitrary but consistent + + def __lt__(self, other: Any) -> bool: + if not isinstance(other, Multirange): + return NotImplemented + return self._ranges < other._ranges + + def __le__(self, other: Any) -> bool: + return self == other or self < other # type: ignore + + def __gt__(self, other: Any) -> bool: + if not isinstance(other, Multirange): + return NotImplemented + return self._ranges > other._ranges + + def __ge__(self, other: Any) -> bool: + return self == other or self > other # type: ignore + + +# Subclasses to specify a specific subtype. Usually not needed + + +class Int4Multirange(Multirange[int]): + pass + + +class Int8Multirange(Multirange[int]): + pass + + +class NumericMultirange(Multirange[Decimal]): + pass + + +class DateMultirange(Multirange[date]): + pass + + +class TimestampMultirange(Multirange[datetime]): + pass + + +class TimestamptzMultirange(Multirange[datetime]): + pass + + +class BaseMultirangeDumper(RecursiveDumper): + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + super().__init__(cls, context) + self.sub_dumper: Optional[Dumper] = None + self._adapt_format = PyFormat.from_pq(self.format) + + def get_key(self, obj: Multirange[Any], format: PyFormat) -> DumperKey: + # If we are a subclass whose oid is specified we don't need upgrade + if self.cls is not Multirange: + return self.cls + + item = self._get_item(obj) + if item is not None: + sd = self._tx.get_dumper(item, self._adapt_format) + return (self.cls, sd.get_key(item, format)) + else: + return (self.cls,) + + def upgrade(self, obj: Multirange[Any], format: PyFormat) -> "BaseMultirangeDumper": + # If we are a subclass whose oid is specified we don't need upgrade + if self.cls is not Multirange: + return self + + item = self._get_item(obj) + if item is None: + return MultirangeDumper(self.cls) + + dumper: BaseMultirangeDumper + if type(item) is int: + # postgres won't cast int4range -> int8range so we must use + # text format and unknown oid here + sd = self._tx.get_dumper(item, PyFormat.TEXT) + dumper = MultirangeDumper(self.cls, self._tx) + dumper.sub_dumper = sd + dumper.oid = INVALID_OID + return dumper + + sd = self._tx.get_dumper(item, format) + dumper = type(self)(self.cls, self._tx) + dumper.sub_dumper = sd + if sd.oid == INVALID_OID and isinstance(item, str): + # Work around the normal mapping where text is dumped as unknown + dumper.oid = self._get_multirange_oid(TEXT_OID) + else: + dumper.oid = self._get_multirange_oid(sd.oid) + + return dumper + + def _get_item(self, obj: Multirange[Any]) -> Any: + """ + Return a member representative of the multirange + """ + for r in obj: + if r.lower is not None: + return r.lower + if r.upper is not None: + return r.upper + return None + + def _get_multirange_oid(self, sub_oid: int) -> int: + """ + Return the oid of the range from the oid of its elements. + """ + info = self._tx.adapters.types.get_by_subtype(MultirangeInfo, sub_oid) + return info.oid if info else INVALID_OID + + +class MultirangeDumper(BaseMultirangeDumper): + """ + Dumper for multirange types. + + The dumper can upgrade to one specific for a different range type. + """ + + def dump(self, obj: Multirange[Any]) -> Buffer: + if not obj: + return b"{}" + + item = self._get_item(obj) + if item is not None: + dump = self._tx.get_dumper(item, self._adapt_format).dump + else: + dump = fail_dump + + out: List[Buffer] = [b"{"] + for r in obj: + out.append(dump_range_text(r, dump)) + out.append(b",") + out[-1] = b"}" + return b"".join(out) + + +class MultirangeBinaryDumper(BaseMultirangeDumper): + format = Format.BINARY + + def dump(self, obj: Multirange[Any]) -> Buffer: + item = self._get_item(obj) + if item is not None: + dump = self._tx.get_dumper(item, self._adapt_format).dump + else: + dump = fail_dump + + out: List[Buffer] = [pack_len(len(obj))] + for r in obj: + data = dump_range_binary(r, dump) + out.append(pack_len(len(data))) + out.append(data) + return b"".join(out) + + +class BaseMultirangeLoader(RecursiveLoader, Generic[T]): + subtype_oid: int + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + self._load = self._tx.get_loader(self.subtype_oid, format=self.format).load + + +class MultirangeLoader(BaseMultirangeLoader[T]): + def load(self, data: Buffer) -> Multirange[T]: + if not data or data[0] != _START_INT: + raise e.DataError( + "malformed multirange starting with" + f" {bytes(data[:1]).decode('utf8', 'replace')}" + ) + + out = Multirange[T]() + if data == b"{}": + return out + + pos = 1 + data = data[pos:] + try: + while True: + r, pos = load_range_text(data, self._load) + out.append(r) + + sep = data[pos] # can raise IndexError + if sep == _SEP_INT: + data = data[pos + 1 :] + continue + elif sep == _END_INT: + if len(data) == pos + 1: + return out + else: + raise e.DataError( + "malformed multirange: data after closing brace" + ) + else: + raise e.DataError( + f"malformed multirange: found unexpected {chr(sep)}" + ) + + except IndexError: + raise e.DataError("malformed multirange: separator missing") + + return out + + +_SEP_INT = ord(",") +_START_INT = ord("{") +_END_INT = ord("}") + + +class MultirangeBinaryLoader(BaseMultirangeLoader[T]): + format = Format.BINARY + + def load(self, data: Buffer) -> Multirange[T]: + nelems = unpack_len(data, 0)[0] + pos = 4 + out = Multirange[T]() + for i in range(nelems): + length = unpack_len(data, pos)[0] + pos += 4 + out.append(load_range_binary(data[pos : pos + length], self._load)) + pos += length + + if pos != len(data): + raise e.DataError("unexpected trailing data in multirange") + + return out + + +def register_multirange( + info: MultirangeInfo, context: Optional[AdaptContext] = None +) -> None: + """Register the adapters to load and dump a multirange type. + + :param info: The object with the information about the range to register. + :param context: The context where to register the adapters. If `!None`, + register it globally. + + Register loaders so that loading data of this type will result in a `Range` + with bounds parsed as the right subtype. + + .. note:: + + Registering the adapters doesn't affect objects already created, even + if they are children of the registered context. For instance, + registering the adapter globally doesn't affect already existing + connections. + """ + # A friendly error warning instead of an AttributeError in case fetch() + # failed and it wasn't noticed. + if not info: + raise TypeError("no info passed. Is the requested multirange available?") + + # Register arrays and type info + info.register(context) + + adapters = context.adapters if context else postgres.adapters + + # generate and register a customized text loader + loader: Type[MultirangeLoader[Any]] = type( + f"{info.name.title()}Loader", + (MultirangeLoader,), + {"subtype_oid": info.subtype_oid}, + ) + adapters.register_loader(info.oid, loader) + + # generate and register a customized binary loader + bloader: Type[MultirangeBinaryLoader[Any]] = type( + f"{info.name.title()}BinaryLoader", + (MultirangeBinaryLoader,), + {"subtype_oid": info.subtype_oid}, + ) + adapters.register_loader(info.oid, bloader) + + +# Text dumpers for builtin multirange types wrappers +# These are registered on specific subtypes so that the upgrade mechanism +# doesn't kick in. + + +class Int4MultirangeDumper(MultirangeDumper): + oid = postgres.types["int4multirange"].oid + + +class Int8MultirangeDumper(MultirangeDumper): + oid = postgres.types["int8multirange"].oid + + +class NumericMultirangeDumper(MultirangeDumper): + oid = postgres.types["nummultirange"].oid + + +class DateMultirangeDumper(MultirangeDumper): + oid = postgres.types["datemultirange"].oid + + +class TimestampMultirangeDumper(MultirangeDumper): + oid = postgres.types["tsmultirange"].oid + + +class TimestamptzMultirangeDumper(MultirangeDumper): + oid = postgres.types["tstzmultirange"].oid + + +# Binary dumpers for builtin multirange types wrappers +# These are registered on specific subtypes so that the upgrade mechanism +# doesn't kick in. + + +class Int4MultirangeBinaryDumper(MultirangeBinaryDumper): + oid = postgres.types["int4multirange"].oid + + +class Int8MultirangeBinaryDumper(MultirangeBinaryDumper): + oid = postgres.types["int8multirange"].oid + + +class NumericMultirangeBinaryDumper(MultirangeBinaryDumper): + oid = postgres.types["nummultirange"].oid + + +class DateMultirangeBinaryDumper(MultirangeBinaryDumper): + oid = postgres.types["datemultirange"].oid + + +class TimestampMultirangeBinaryDumper(MultirangeBinaryDumper): + oid = postgres.types["tsmultirange"].oid + + +class TimestamptzMultirangeBinaryDumper(MultirangeBinaryDumper): + oid = postgres.types["tstzmultirange"].oid + + +# Text loaders for builtin multirange types + + +class Int4MultirangeLoader(MultirangeLoader[int]): + subtype_oid = postgres.types["int4"].oid + + +class Int8MultirangeLoader(MultirangeLoader[int]): + subtype_oid = postgres.types["int8"].oid + + +class NumericMultirangeLoader(MultirangeLoader[Decimal]): + subtype_oid = postgres.types["numeric"].oid + + +class DateMultirangeLoader(MultirangeLoader[date]): + subtype_oid = postgres.types["date"].oid + + +class TimestampMultirangeLoader(MultirangeLoader[datetime]): + subtype_oid = postgres.types["timestamp"].oid + + +class TimestampTZMultirangeLoader(MultirangeLoader[datetime]): + subtype_oid = postgres.types["timestamptz"].oid + + +# Binary loaders for builtin multirange types + + +class Int4MultirangeBinaryLoader(MultirangeBinaryLoader[int]): + subtype_oid = postgres.types["int4"].oid + + +class Int8MultirangeBinaryLoader(MultirangeBinaryLoader[int]): + subtype_oid = postgres.types["int8"].oid + + +class NumericMultirangeBinaryLoader(MultirangeBinaryLoader[Decimal]): + subtype_oid = postgres.types["numeric"].oid + + +class DateMultirangeBinaryLoader(MultirangeBinaryLoader[date]): + subtype_oid = postgres.types["date"].oid + + +class TimestampMultirangeBinaryLoader(MultirangeBinaryLoader[datetime]): + subtype_oid = postgres.types["timestamp"].oid + + +class TimestampTZMultirangeBinaryLoader(MultirangeBinaryLoader[datetime]): + subtype_oid = postgres.types["timestamptz"].oid + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper(Multirange, MultirangeBinaryDumper) + adapters.register_dumper(Multirange, MultirangeDumper) + adapters.register_dumper(Int4Multirange, Int4MultirangeDumper) + adapters.register_dumper(Int8Multirange, Int8MultirangeDumper) + adapters.register_dumper(NumericMultirange, NumericMultirangeDumper) + adapters.register_dumper(DateMultirange, DateMultirangeDumper) + adapters.register_dumper(TimestampMultirange, TimestampMultirangeDumper) + adapters.register_dumper(TimestamptzMultirange, TimestamptzMultirangeDumper) + adapters.register_dumper(Int4Multirange, Int4MultirangeBinaryDumper) + adapters.register_dumper(Int8Multirange, Int8MultirangeBinaryDumper) + adapters.register_dumper(NumericMultirange, NumericMultirangeBinaryDumper) + adapters.register_dumper(DateMultirange, DateMultirangeBinaryDumper) + adapters.register_dumper(TimestampMultirange, TimestampMultirangeBinaryDumper) + adapters.register_dumper(TimestamptzMultirange, TimestamptzMultirangeBinaryDumper) + adapters.register_loader("int4multirange", Int4MultirangeLoader) + adapters.register_loader("int8multirange", Int8MultirangeLoader) + adapters.register_loader("nummultirange", NumericMultirangeLoader) + adapters.register_loader("datemultirange", DateMultirangeLoader) + adapters.register_loader("tsmultirange", TimestampMultirangeLoader) + adapters.register_loader("tstzmultirange", TimestampTZMultirangeLoader) + adapters.register_loader("int4multirange", Int4MultirangeBinaryLoader) + adapters.register_loader("int8multirange", Int8MultirangeBinaryLoader) + adapters.register_loader("nummultirange", NumericMultirangeBinaryLoader) + adapters.register_loader("datemultirange", DateMultirangeBinaryLoader) + adapters.register_loader("tsmultirange", TimestampMultirangeBinaryLoader) + adapters.register_loader("tstzmultirange", TimestampTZMultirangeBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/net.py b/lib/python3.11/site-packages/psycopg/types/net.py new file mode 100644 index 0000000..36b4053 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/net.py @@ -0,0 +1,201 @@ +""" +Adapters for network types. +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Callable, Optional, Type, Union, TYPE_CHECKING +from typing_extensions import TypeAlias + +from .. import postgres +from ..pq import Format +from ..abc import AdaptContext +from ..adapt import Buffer, Dumper, Loader + +if TYPE_CHECKING: + import ipaddress + +Address: TypeAlias = Union["ipaddress.IPv4Address", "ipaddress.IPv6Address"] +Interface: TypeAlias = Union["ipaddress.IPv4Interface", "ipaddress.IPv6Interface"] +Network: TypeAlias = Union["ipaddress.IPv4Network", "ipaddress.IPv6Network"] + +# These objects will be imported lazily +ip_address: Callable[[str], Address] = None # type: ignore[assignment] +ip_interface: Callable[[str], Interface] = None # type: ignore[assignment] +ip_network: Callable[[str], Network] = None # type: ignore[assignment] +IPv4Address: "Type[ipaddress.IPv4Address]" = None # type: ignore[assignment] +IPv6Address: "Type[ipaddress.IPv6Address]" = None # type: ignore[assignment] +IPv4Interface: "Type[ipaddress.IPv4Interface]" = None # type: ignore[assignment] +IPv6Interface: "Type[ipaddress.IPv6Interface]" = None # type: ignore[assignment] +IPv4Network: "Type[ipaddress.IPv4Network]" = None # type: ignore[assignment] +IPv6Network: "Type[ipaddress.IPv6Network]" = None # type: ignore[assignment] + +PGSQL_AF_INET = 2 +PGSQL_AF_INET6 = 3 +IPV4_PREFIXLEN = 32 +IPV6_PREFIXLEN = 128 + + +class _LazyIpaddress: + def _ensure_module(self) -> None: + global ip_address, ip_interface, ip_network + global IPv4Address, IPv6Address, IPv4Interface, IPv6Interface + global IPv4Network, IPv6Network + + if ip_address is None: + from ipaddress import ip_address, ip_interface, ip_network + from ipaddress import IPv4Address, IPv6Address + from ipaddress import IPv4Interface, IPv6Interface + from ipaddress import IPv4Network, IPv6Network + + +class InterfaceDumper(Dumper): + oid = postgres.types["inet"].oid + + def dump(self, obj: Interface) -> bytes: + return str(obj).encode() + + +class NetworkDumper(Dumper): + oid = postgres.types["cidr"].oid + + def dump(self, obj: Network) -> bytes: + return str(obj).encode() + + +class _AIBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["inet"].oid + + +class AddressBinaryDumper(_AIBinaryDumper): + def dump(self, obj: Address) -> bytes: + packed = obj.packed + family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6 + head = bytes((family, obj.max_prefixlen, 0, len(packed))) + return head + packed + + +class InterfaceBinaryDumper(_AIBinaryDumper): + def dump(self, obj: Interface) -> bytes: + packed = obj.packed + family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6 + head = bytes((family, obj.network.prefixlen, 0, len(packed))) + return head + packed + + +class InetBinaryDumper(_AIBinaryDumper, _LazyIpaddress): + """Either an address or an interface to inet + + Used when looking up by oid. + """ + + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + super().__init__(cls, context) + self._ensure_module() + + def dump(self, obj: Union[Address, Interface]) -> bytes: + packed = obj.packed + family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6 + if isinstance(obj, (IPv4Interface, IPv6Interface)): + prefixlen = obj.network.prefixlen + else: + prefixlen = obj.max_prefixlen + + head = bytes((family, prefixlen, 0, len(packed))) + return head + packed + + +class NetworkBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["cidr"].oid + + def dump(self, obj: Network) -> bytes: + packed = obj.network_address.packed + family = PGSQL_AF_INET if obj.version == 4 else PGSQL_AF_INET6 + head = bytes((family, obj.prefixlen, 1, len(packed))) + return head + packed + + +class _LazyIpaddressLoader(Loader, _LazyIpaddress): + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + self._ensure_module() + + +class InetLoader(_LazyIpaddressLoader): + def load(self, data: Buffer) -> Union[Address, Interface]: + if isinstance(data, memoryview): + data = bytes(data) + + if b"/" in data: + return ip_interface(data.decode()) + else: + return ip_address(data.decode()) + + +class InetBinaryLoader(_LazyIpaddressLoader): + format = Format.BINARY + + def load(self, data: Buffer) -> Union[Address, Interface]: + if isinstance(data, memoryview): + data = bytes(data) + + prefix = data[1] + packed = data[4:] + if data[0] == PGSQL_AF_INET: + if prefix == IPV4_PREFIXLEN: + return IPv4Address(packed) + else: + return IPv4Interface((packed, prefix)) + else: + if prefix == IPV6_PREFIXLEN: + return IPv6Address(packed) + else: + return IPv6Interface((packed, prefix)) + + +class CidrLoader(_LazyIpaddressLoader): + def load(self, data: Buffer) -> Network: + if isinstance(data, memoryview): + data = bytes(data) + + return ip_network(data.decode()) + + +class CidrBinaryLoader(_LazyIpaddressLoader): + format = Format.BINARY + + def load(self, data: Buffer) -> Network: + if isinstance(data, memoryview): + data = bytes(data) + + prefix = data[1] + packed = data[4:] + if data[0] == PGSQL_AF_INET: + return IPv4Network((packed, prefix)) + else: + return IPv6Network((packed, prefix)) + + return ip_network(data.decode()) + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper("ipaddress.IPv4Address", InterfaceDumper) + adapters.register_dumper("ipaddress.IPv6Address", InterfaceDumper) + adapters.register_dumper("ipaddress.IPv4Interface", InterfaceDumper) + adapters.register_dumper("ipaddress.IPv6Interface", InterfaceDumper) + adapters.register_dumper("ipaddress.IPv4Network", NetworkDumper) + adapters.register_dumper("ipaddress.IPv6Network", NetworkDumper) + adapters.register_dumper("ipaddress.IPv4Address", AddressBinaryDumper) + adapters.register_dumper("ipaddress.IPv6Address", AddressBinaryDumper) + adapters.register_dumper("ipaddress.IPv4Interface", InterfaceBinaryDumper) + adapters.register_dumper("ipaddress.IPv6Interface", InterfaceBinaryDumper) + adapters.register_dumper("ipaddress.IPv4Network", NetworkBinaryDumper) + adapters.register_dumper("ipaddress.IPv6Network", NetworkBinaryDumper) + adapters.register_dumper(None, InetBinaryDumper) + adapters.register_loader("inet", InetLoader) + adapters.register_loader("inet", InetBinaryLoader) + adapters.register_loader("cidr", CidrLoader) + adapters.register_loader("cidr", CidrBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/none.py b/lib/python3.11/site-packages/psycopg/types/none.py new file mode 100644 index 0000000..2ab857c --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/none.py @@ -0,0 +1,25 @@ +""" +Adapters for None. +""" + +# Copyright (C) 2020 The Psycopg Team + +from ..abc import AdaptContext, NoneType +from ..adapt import Dumper + + +class NoneDumper(Dumper): + """ + Not a complete dumper as it doesn't implement dump(), but it implements + quote(), so it can be used in sql composition. + """ + + def dump(self, obj: None) -> bytes: + raise NotImplementedError("NULL is passed to Postgres in other ways") + + def quote(self, obj: None) -> bytes: + return b"NULL" + + +def register_default_adapters(context: AdaptContext) -> None: + context.adapters.register_dumper(NoneType, NoneDumper) diff --git a/lib/python3.11/site-packages/psycopg/types/numeric.py b/lib/python3.11/site-packages/psycopg/types/numeric.py new file mode 100644 index 0000000..0b9fb11 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/numeric.py @@ -0,0 +1,495 @@ +""" +Adapers for numeric types. +""" + +# Copyright (C) 2020 The Psycopg Team + +import struct +from math import log +from typing import Any, Callable, DefaultDict, Dict, Tuple, Union, cast +from decimal import Decimal, DefaultContext, Context + +from .. import postgres +from .. import errors as e +from ..pq import Format +from ..abc import AdaptContext +from ..adapt import Buffer, Dumper, Loader, PyFormat +from .._struct import pack_int2, pack_uint2, unpack_int2 +from .._struct import pack_int4, pack_uint4, unpack_int4, unpack_uint4 +from .._struct import pack_int8, unpack_int8 +from .._struct import pack_float4, pack_float8, unpack_float4, unpack_float8 + +# Exposed here +from .._wrappers import ( + Int2 as Int2, + Int4 as Int4, + Int8 as Int8, + IntNumeric as IntNumeric, + Oid as Oid, + Float4 as Float4, + Float8 as Float8, +) + + +class _IntDumper(Dumper): + def dump(self, obj: Any) -> Buffer: + t = type(obj) + if t is not int: + # Convert to int in order to dump IntEnum correctly + if issubclass(t, int): + obj = int(obj) + else: + raise e.DataError(f"integer expected, got {type(obj).__name__!r}") + + return str(obj).encode() + + def quote(self, obj: Any) -> Buffer: + value = self.dump(obj) + return value if obj >= 0 else b" " + value + + +class _SpecialValuesDumper(Dumper): + _special: Dict[bytes, bytes] = {} + + def dump(self, obj: Any) -> bytes: + return str(obj).encode() + + def quote(self, obj: Any) -> bytes: + value = self.dump(obj) + + if value in self._special: + return self._special[value] + + return value if obj >= 0 else b" " + value + + +class FloatDumper(_SpecialValuesDumper): + oid = postgres.types["float8"].oid + + _special = { + b"inf": b"'Infinity'::float8", + b"-inf": b"'-Infinity'::float8", + b"nan": b"'NaN'::float8", + } + + +class Float4Dumper(FloatDumper): + oid = postgres.types["float4"].oid + + +class FloatBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["float8"].oid + + def dump(self, obj: float) -> bytes: + return pack_float8(obj) + + +class Float4BinaryDumper(FloatBinaryDumper): + oid = postgres.types["float4"].oid + + def dump(self, obj: float) -> bytes: + return pack_float4(obj) + + +class DecimalDumper(_SpecialValuesDumper): + oid = postgres.types["numeric"].oid + + def dump(self, obj: Decimal) -> bytes: + if obj.is_nan(): + # cover NaN and sNaN + return b"NaN" + else: + return str(obj).encode() + + _special = { + b"Infinity": b"'Infinity'::numeric", + b"-Infinity": b"'-Infinity'::numeric", + b"NaN": b"'NaN'::numeric", + } + + +class Int2Dumper(_IntDumper): + oid = postgres.types["int2"].oid + + +class Int4Dumper(_IntDumper): + oid = postgres.types["int4"].oid + + +class Int8Dumper(_IntDumper): + oid = postgres.types["int8"].oid + + +class IntNumericDumper(_IntDumper): + oid = postgres.types["numeric"].oid + + +class OidDumper(_IntDumper): + oid = postgres.types["oid"].oid + + +class IntDumper(Dumper): + def dump(self, obj: Any) -> bytes: + raise TypeError( + f"{type(self).__name__} is a dispatcher to other dumpers:" + " dump() is not supposed to be called" + ) + + def get_key(self, obj: int, format: PyFormat) -> type: + return self.upgrade(obj, format).cls + + _int2_dumper = Int2Dumper(Int2) + _int4_dumper = Int4Dumper(Int4) + _int8_dumper = Int8Dumper(Int8) + _int_numeric_dumper = IntNumericDumper(IntNumeric) + + def upgrade(self, obj: int, format: PyFormat) -> Dumper: + if -(2**31) <= obj < 2**31: + if -(2**15) <= obj < 2**15: + return self._int2_dumper + else: + return self._int4_dumper + else: + if -(2**63) <= obj < 2**63: + return self._int8_dumper + else: + return self._int_numeric_dumper + + +class Int2BinaryDumper(Int2Dumper): + format = Format.BINARY + + def dump(self, obj: int) -> bytes: + return pack_int2(obj) + + +class Int4BinaryDumper(Int4Dumper): + format = Format.BINARY + + def dump(self, obj: int) -> bytes: + return pack_int4(obj) + + +class Int8BinaryDumper(Int8Dumper): + format = Format.BINARY + + def dump(self, obj: int) -> bytes: + return pack_int8(obj) + + +# Ratio between number of bits required to store a number and number of pg +# decimal digits required. +BIT_PER_PGDIGIT = log(2) / log(10_000) + + +class IntNumericBinaryDumper(IntNumericDumper): + format = Format.BINARY + + def dump(self, obj: int) -> Buffer: + return dump_int_to_numeric_binary(obj) + + +class OidBinaryDumper(OidDumper): + format = Format.BINARY + + def dump(self, obj: int) -> bytes: + return pack_uint4(obj) + + +class IntBinaryDumper(IntDumper): + format = Format.BINARY + + _int2_dumper = Int2BinaryDumper(Int2) + _int4_dumper = Int4BinaryDumper(Int4) + _int8_dumper = Int8BinaryDumper(Int8) + _int_numeric_dumper = IntNumericBinaryDumper(IntNumeric) + + +class IntLoader(Loader): + def load(self, data: Buffer) -> int: + # it supports bytes directly + return int(data) + + +class Int2BinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> int: + return unpack_int2(data)[0] + + +class Int4BinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> int: + return unpack_int4(data)[0] + + +class Int8BinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> int: + return unpack_int8(data)[0] + + +class OidBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> int: + return unpack_uint4(data)[0] + + +class FloatLoader(Loader): + def load(self, data: Buffer) -> float: + # it supports bytes directly + return float(data) + + +class Float4BinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> float: + return unpack_float4(data)[0] + + +class Float8BinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> float: + return unpack_float8(data)[0] + + +class NumericLoader(Loader): + def load(self, data: Buffer) -> Decimal: + if isinstance(data, memoryview): + data = bytes(data) + return Decimal(data.decode()) + + +DEC_DIGITS = 4 # decimal digits per Postgres "digit" +NUMERIC_POS = 0x0000 +NUMERIC_NEG = 0x4000 +NUMERIC_NAN = 0xC000 +NUMERIC_PINF = 0xD000 +NUMERIC_NINF = 0xF000 + +_decimal_special = { + NUMERIC_NAN: Decimal("NaN"), + NUMERIC_PINF: Decimal("Infinity"), + NUMERIC_NINF: Decimal("-Infinity"), +} + + +class _ContextMap(DefaultDict[int, Context]): + """ + Cache for decimal contexts to use when the precision requires it. + + Note: if the default context is used (prec=28) you can get an invalid + operation or a rounding to 0: + + - Decimal(1000).shift(24) = Decimal('1000000000000000000000000000') + - Decimal(1000).shift(25) = Decimal('0') + - Decimal(1000).shift(30) raises InvalidOperation + """ + + def __missing__(self, key: int) -> Context: + val = Context(prec=key) + self[key] = val + return val + + +_contexts = _ContextMap() +for i in range(DefaultContext.prec): + _contexts[i] = DefaultContext + +_unpack_numeric_head = cast( + Callable[[Buffer], Tuple[int, int, int, int]], + struct.Struct("!HhHH").unpack_from, +) +_pack_numeric_head = cast( + Callable[[int, int, int, int], bytes], + struct.Struct("!HhHH").pack, +) + + +class NumericBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> Decimal: + ndigits, weight, sign, dscale = _unpack_numeric_head(data) + if sign == NUMERIC_POS or sign == NUMERIC_NEG: + val = 0 + for i in range(8, len(data), 2): + val = val * 10_000 + data[i] * 0x100 + data[i + 1] + + shift = dscale - (ndigits - weight - 1) * DEC_DIGITS + ctx = _contexts[(weight + 2) * DEC_DIGITS + dscale] + return ( + Decimal(val if sign == NUMERIC_POS else -val) + .scaleb(-dscale, ctx) + .shift(shift, ctx) + ) + else: + try: + return _decimal_special[sign] + except KeyError: + raise e.DataError(f"bad value for numeric sign: 0x{sign:X}") from None + + +NUMERIC_NAN_BIN = _pack_numeric_head(0, 0, NUMERIC_NAN, 0) +NUMERIC_PINF_BIN = _pack_numeric_head(0, 0, NUMERIC_PINF, 0) +NUMERIC_NINF_BIN = _pack_numeric_head(0, 0, NUMERIC_NINF, 0) + + +class DecimalBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["numeric"].oid + + def dump(self, obj: Decimal) -> Buffer: + return dump_decimal_to_numeric_binary(obj) + + +class NumericDumper(DecimalDumper): + def dump(self, obj: Union[Decimal, int]) -> bytes: + if isinstance(obj, int): + return str(obj).encode() + else: + return super().dump(obj) + + +class NumericBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["numeric"].oid + + def dump(self, obj: Union[Decimal, int]) -> Buffer: + if isinstance(obj, int): + return dump_int_to_numeric_binary(obj) + else: + return dump_decimal_to_numeric_binary(obj) + + +def dump_decimal_to_numeric_binary(obj: Decimal) -> Union[bytearray, bytes]: + sign, digits, exp = obj.as_tuple() + if exp == "n" or exp == "N": + return NUMERIC_NAN_BIN + elif exp == "F": + return NUMERIC_NINF_BIN if sign else NUMERIC_PINF_BIN + + # Weights of py digits into a pg digit according to their positions. + # Starting with an index wi != 0 is equivalent to prepending 0's to + # the digits tuple, but without really changing it. + weights = (1000, 100, 10, 1) + wi = 0 + + ndigits = nzdigits = len(digits) + + # Find the last nonzero digit + while nzdigits > 0 and digits[nzdigits - 1] == 0: + nzdigits -= 1 + + if exp <= 0: + dscale = -exp + else: + dscale = 0 + # align the py digits to the pg digits if there's some py exponent + ndigits += exp % DEC_DIGITS + + if not nzdigits: + return _pack_numeric_head(0, 0, NUMERIC_POS, dscale) + + # Equivalent of 0-padding left to align the py digits to the pg digits + # but without changing the digits tuple. + mod = (ndigits - dscale) % DEC_DIGITS + if mod: + wi = DEC_DIGITS - mod + ndigits += wi + + tmp = nzdigits + wi + out = bytearray( + _pack_numeric_head( + tmp // DEC_DIGITS + (tmp % DEC_DIGITS and 1), # ndigits + (ndigits + exp) // DEC_DIGITS - 1, # weight + NUMERIC_NEG if sign else NUMERIC_POS, # sign + dscale, + ) + ) + + pgdigit = 0 + for i in range(nzdigits): + pgdigit += weights[wi] * digits[i] + wi += 1 + if wi >= DEC_DIGITS: + out += pack_uint2(pgdigit) + pgdigit = wi = 0 + + if pgdigit: + out += pack_uint2(pgdigit) + + return out + + +def dump_int_to_numeric_binary(obj: int) -> bytearray: + ndigits = int(obj.bit_length() * BIT_PER_PGDIGIT) + 1 + out = bytearray(b"\x00\x00" * (ndigits + 4)) + if obj < 0: + sign = NUMERIC_NEG + obj = -obj + else: + sign = NUMERIC_POS + + out[:8] = _pack_numeric_head(ndigits, ndigits - 1, sign, 0) + i = 8 + (ndigits - 1) * 2 + while obj: + rem = obj % 10_000 + obj //= 10_000 + out[i : i + 2] = pack_uint2(rem) + i -= 2 + + return out + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper(int, IntDumper) + adapters.register_dumper(int, IntBinaryDumper) + adapters.register_dumper(float, FloatDumper) + adapters.register_dumper(float, FloatBinaryDumper) + adapters.register_dumper(Int2, Int2Dumper) + adapters.register_dumper(Int4, Int4Dumper) + adapters.register_dumper(Int8, Int8Dumper) + adapters.register_dumper(IntNumeric, IntNumericDumper) + adapters.register_dumper(Oid, OidDumper) + + # The binary dumper is currently some 30% slower, so default to text + # (see tests/scripts/testdec.py for a rough benchmark) + # Also, must be after IntNumericDumper + adapters.register_dumper("decimal.Decimal", DecimalBinaryDumper) + adapters.register_dumper("decimal.Decimal", DecimalDumper) + + # Used only by oid, can take both int and Decimal as input + adapters.register_dumper(None, NumericBinaryDumper) + adapters.register_dumper(None, NumericDumper) + + adapters.register_dumper(Float4, Float4Dumper) + adapters.register_dumper(Float8, FloatDumper) + adapters.register_dumper(Int2, Int2BinaryDumper) + adapters.register_dumper(Int4, Int4BinaryDumper) + adapters.register_dumper(Int8, Int8BinaryDumper) + adapters.register_dumper(Oid, OidBinaryDumper) + adapters.register_dumper(Float4, Float4BinaryDumper) + adapters.register_dumper(Float8, FloatBinaryDumper) + adapters.register_loader("int2", IntLoader) + adapters.register_loader("int4", IntLoader) + adapters.register_loader("int8", IntLoader) + adapters.register_loader("oid", IntLoader) + adapters.register_loader("int2", Int2BinaryLoader) + adapters.register_loader("int4", Int4BinaryLoader) + adapters.register_loader("int8", Int8BinaryLoader) + adapters.register_loader("oid", OidBinaryLoader) + adapters.register_loader("float4", FloatLoader) + adapters.register_loader("float8", FloatLoader) + adapters.register_loader("float4", Float4BinaryLoader) + adapters.register_loader("float8", Float8BinaryLoader) + adapters.register_loader("numeric", NumericLoader) + adapters.register_loader("numeric", NumericBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/range.py b/lib/python3.11/site-packages/psycopg/types/range.py new file mode 100644 index 0000000..a27d039 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/range.py @@ -0,0 +1,698 @@ +""" +Support for range types adaptation. +""" + +# Copyright (C) 2020 The Psycopg Team + +import re +from typing import Any, Callable, Dict, Generic, List, Optional, TypeVar, Type, Tuple +from typing import cast +from decimal import Decimal +from datetime import date, datetime + +from .. import errors as e +from .. import postgres +from ..pq import Format +from ..abc import AdaptContext, Buffer, Dumper, DumperKey +from ..adapt import RecursiveDumper, RecursiveLoader, PyFormat +from .._struct import pack_len, unpack_len +from ..postgres import INVALID_OID, TEXT_OID +from .._typeinfo import RangeInfo as RangeInfo # exported here + +RANGE_EMPTY = 0x01 # range is empty +RANGE_LB_INC = 0x02 # lower bound is inclusive +RANGE_UB_INC = 0x04 # upper bound is inclusive +RANGE_LB_INF = 0x08 # lower bound is -infinity +RANGE_UB_INF = 0x10 # upper bound is +infinity + +_EMPTY_HEAD = bytes([RANGE_EMPTY]) + +T = TypeVar("T") + + +class Range(Generic[T]): + """Python representation for a PostgreSQL range type. + + :param lower: lower bound for the range. `!None` means unbound + :param upper: upper bound for the range. `!None` means unbound + :param bounds: one of the literal strings ``()``, ``[)``, ``(]``, ``[]``, + representing whether the lower or upper bounds are included + :param empty: if `!True`, the range is empty + + """ + + __slots__ = ("_lower", "_upper", "_bounds") + + def __init__( + self, + lower: Optional[T] = None, + upper: Optional[T] = None, + bounds: str = "[)", + empty: bool = False, + ): + if not empty: + if bounds not in ("[)", "(]", "()", "[]"): + raise ValueError("bound flags not valid: %r" % bounds) + + self._lower = lower + self._upper = upper + + # Make bounds consistent with infs + if lower is None and bounds[0] == "[": + bounds = "(" + bounds[1] + if upper is None and bounds[1] == "]": + bounds = bounds[0] + ")" + + self._bounds = bounds + else: + self._lower = self._upper = None + self._bounds = "" + + def __repr__(self) -> str: + if self._bounds: + args = f"{self._lower!r}, {self._upper!r}, {self._bounds!r}" + else: + args = "empty=True" + + return f"{self.__class__.__name__}({args})" + + def __str__(self) -> str: + if not self._bounds: + return "empty" + + items = [ + self._bounds[0], + str(self._lower), + ", ", + str(self._upper), + self._bounds[1], + ] + return "".join(items) + + @property + def lower(self) -> Optional[T]: + """The lower bound of the range. `!None` if empty or unbound.""" + return self._lower + + @property + def upper(self) -> Optional[T]: + """The upper bound of the range. `!None` if empty or unbound.""" + return self._upper + + @property + def bounds(self) -> str: + """The bounds string (two characters from '[', '(', ']', ')').""" + return self._bounds + + @property + def isempty(self) -> bool: + """`!True` if the range is empty.""" + return not self._bounds + + @property + def lower_inf(self) -> bool: + """`!True` if the range doesn't have a lower bound.""" + if not self._bounds: + return False + return self._lower is None + + @property + def upper_inf(self) -> bool: + """`!True` if the range doesn't have an upper bound.""" + if not self._bounds: + return False + return self._upper is None + + @property + def lower_inc(self) -> bool: + """`!True` if the lower bound is included in the range.""" + if not self._bounds or self._lower is None: + return False + return self._bounds[0] == "[" + + @property + def upper_inc(self) -> bool: + """`!True` if the upper bound is included in the range.""" + if not self._bounds or self._upper is None: + return False + return self._bounds[1] == "]" + + def __contains__(self, x: T) -> bool: + if not self._bounds: + return False + + if self._lower is not None: + if self._bounds[0] == "[": + # It doesn't seem that Python has an ABC for ordered types. + if x < self._lower: # type: ignore[operator] + return False + else: + if x <= self._lower: # type: ignore[operator] + return False + + if self._upper is not None: + if self._bounds[1] == "]": + if x > self._upper: # type: ignore[operator] + return False + else: + if x >= self._upper: # type: ignore[operator] + return False + + return True + + def __bool__(self) -> bool: + return bool(self._bounds) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Range): + return False + return ( + self._lower == other._lower + and self._upper == other._upper + and self._bounds == other._bounds + ) + + def __hash__(self) -> int: + return hash((self._lower, self._upper, self._bounds)) + + # as the postgres docs describe for the server-side stuff, + # ordering is rather arbitrary, but will remain stable + # and consistent. + + def __lt__(self, other: Any) -> bool: + if not isinstance(other, Range): + return NotImplemented + for attr in ("_lower", "_upper", "_bounds"): + self_value = getattr(self, attr) + other_value = getattr(other, attr) + if self_value == other_value: + pass + elif self_value is None: + return True + elif other_value is None: + return False + else: + return cast(bool, self_value < other_value) + return False + + def __le__(self, other: Any) -> bool: + return self == other or self < other # type: ignore + + def __gt__(self, other: Any) -> bool: + if isinstance(other, Range): + return other < self + else: + return NotImplemented + + def __ge__(self, other: Any) -> bool: + return self == other or self > other # type: ignore + + def __getstate__(self) -> Dict[str, Any]: + return { + slot: getattr(self, slot) for slot in self.__slots__ if hasattr(self, slot) + } + + def __setstate__(self, state: Dict[str, Any]) -> None: + for slot, value in state.items(): + setattr(self, slot, value) + + +# Subclasses to specify a specific subtype. Usually not needed: only needed +# in binary copy, where switching to text is not an option. + + +class Int4Range(Range[int]): + pass + + +class Int8Range(Range[int]): + pass + + +class NumericRange(Range[Decimal]): + pass + + +class DateRange(Range[date]): + pass + + +class TimestampRange(Range[datetime]): + pass + + +class TimestamptzRange(Range[datetime]): + pass + + +class BaseRangeDumper(RecursiveDumper): + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + super().__init__(cls, context) + self.sub_dumper: Optional[Dumper] = None + self._adapt_format = PyFormat.from_pq(self.format) + + def get_key(self, obj: Range[Any], format: PyFormat) -> DumperKey: + # If we are a subclass whose oid is specified we don't need upgrade + if self.cls is not Range: + return self.cls + + item = self._get_item(obj) + if item is not None: + sd = self._tx.get_dumper(item, self._adapt_format) + return (self.cls, sd.get_key(item, format)) + else: + return (self.cls,) + + def upgrade(self, obj: Range[Any], format: PyFormat) -> "BaseRangeDumper": + # If we are a subclass whose oid is specified we don't need upgrade + if self.cls is not Range: + return self + + item = self._get_item(obj) + if item is None: + return RangeDumper(self.cls) + + dumper: BaseRangeDumper + if type(item) is int: + # postgres won't cast int4range -> int8range so we must use + # text format and unknown oid here + sd = self._tx.get_dumper(item, PyFormat.TEXT) + dumper = RangeDumper(self.cls, self._tx) + dumper.sub_dumper = sd + dumper.oid = INVALID_OID + return dumper + + sd = self._tx.get_dumper(item, format) + dumper = type(self)(self.cls, self._tx) + dumper.sub_dumper = sd + if sd.oid == INVALID_OID and isinstance(item, str): + # Work around the normal mapping where text is dumped as unknown + dumper.oid = self._get_range_oid(TEXT_OID) + else: + dumper.oid = self._get_range_oid(sd.oid) + + return dumper + + def _get_item(self, obj: Range[Any]) -> Any: + """ + Return a member representative of the range + """ + rv = obj.lower + return rv if rv is not None else obj.upper + + def _get_range_oid(self, sub_oid: int) -> int: + """ + Return the oid of the range from the oid of its elements. + """ + info = self._tx.adapters.types.get_by_subtype(RangeInfo, sub_oid) + return info.oid if info else INVALID_OID + + +class RangeDumper(BaseRangeDumper): + """ + Dumper for range types. + + The dumper can upgrade to one specific for a different range type. + """ + + def dump(self, obj: Range[Any]) -> Buffer: + item = self._get_item(obj) + if item is not None: + dump = self._tx.get_dumper(item, self._adapt_format).dump + else: + dump = fail_dump + + return dump_range_text(obj, dump) + + +def dump_range_text(obj: Range[Any], dump: Callable[[Any], Buffer]) -> Buffer: + if obj.isempty: + return b"empty" + + parts: List[Buffer] = [b"[" if obj.lower_inc else b"("] + + def dump_item(item: Any) -> Buffer: + ad = dump(item) + if not ad: + return b'""' + elif _re_needs_quotes.search(ad): + return b'"' + _re_esc.sub(rb"\1\1", ad) + b'"' + else: + return ad + + if obj.lower is not None: + parts.append(dump_item(obj.lower)) + + parts.append(b",") + + if obj.upper is not None: + parts.append(dump_item(obj.upper)) + + parts.append(b"]" if obj.upper_inc else b")") + + return b"".join(parts) + + +_re_needs_quotes = re.compile(rb'[",\\\s()\[\]]') +_re_esc = re.compile(rb"([\\\"])") + + +class RangeBinaryDumper(BaseRangeDumper): + format = Format.BINARY + + def dump(self, obj: Range[Any]) -> Buffer: + item = self._get_item(obj) + if item is not None: + dump = self._tx.get_dumper(item, self._adapt_format).dump + else: + dump = fail_dump + + return dump_range_binary(obj, dump) + + +def dump_range_binary(obj: Range[Any], dump: Callable[[Any], Buffer]) -> Buffer: + if not obj: + return _EMPTY_HEAD + + out = bytearray([0]) # will replace the head later + + head = 0 + if obj.lower_inc: + head |= RANGE_LB_INC + if obj.upper_inc: + head |= RANGE_UB_INC + + if obj.lower is not None: + data = dump(obj.lower) + out += pack_len(len(data)) + out += data + else: + head |= RANGE_LB_INF + + if obj.upper is not None: + data = dump(obj.upper) + out += pack_len(len(data)) + out += data + else: + head |= RANGE_UB_INF + + out[0] = head + return out + + +def fail_dump(obj: Any) -> Buffer: + raise e.InternalError("trying to dump a range element without information") + + +class BaseRangeLoader(RecursiveLoader, Generic[T]): + """Generic loader for a range. + + Subclasses must specify the oid of the subtype and the class to load. + """ + + subtype_oid: int + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + self._load = self._tx.get_loader(self.subtype_oid, format=self.format).load + + +class RangeLoader(BaseRangeLoader[T]): + def load(self, data: Buffer) -> Range[T]: + return load_range_text(data, self._load)[0] + + +def load_range_text( + data: Buffer, load: Callable[[Buffer], Any] +) -> Tuple[Range[Any], int]: + if data == b"empty": + return Range(empty=True), 5 + + m = _re_range.match(data) + if m is None: + raise e.DataError( + f"failed to parse range: '{bytes(data).decode('utf8', 'replace')}'" + ) + + lower = None + item = m.group(3) + if item is None: + item = m.group(2) + if item is not None: + lower = load(_re_undouble.sub(rb"\1", item)) + else: + lower = load(item) + + upper = None + item = m.group(5) + if item is None: + item = m.group(4) + if item is not None: + upper = load(_re_undouble.sub(rb"\1", item)) + else: + upper = load(item) + + bounds = (m.group(1) + m.group(6)).decode() + + return Range(lower, upper, bounds), m.end() + + +_re_range = re.compile( + rb""" + ( \(|\[ ) # lower bound flag + (?: # lower bound: + " ( (?: [^"] | "")* ) " # - a quoted string + | ( [^",]+ ) # - or an unquoted string + )? # - or empty (not caught) + , + (?: # upper bound: + " ( (?: [^"] | "")* ) " # - a quoted string + | ( [^"\)\]]+ ) # - or an unquoted string + )? # - or empty (not caught) + ( \)|\] ) # upper bound flag + """, + re.VERBOSE, +) + +_re_undouble = re.compile(rb'(["\\])\1') + + +class RangeBinaryLoader(BaseRangeLoader[T]): + format = Format.BINARY + + def load(self, data: Buffer) -> Range[T]: + return load_range_binary(data, self._load) + + +def load_range_binary(data: Buffer, load: Callable[[Buffer], Any]) -> Range[Any]: + head = data[0] + if head & RANGE_EMPTY: + return Range(empty=True) + + lb = "[" if head & RANGE_LB_INC else "(" + ub = "]" if head & RANGE_UB_INC else ")" + + pos = 1 # after the head + if head & RANGE_LB_INF: + min = None + else: + length = unpack_len(data, pos)[0] + pos += 4 + min = load(data[pos : pos + length]) + pos += length + + if head & RANGE_UB_INF: + max = None + else: + length = unpack_len(data, pos)[0] + pos += 4 + max = load(data[pos : pos + length]) + pos += length + + return Range(min, max, lb + ub) + + +def register_range(info: RangeInfo, context: Optional[AdaptContext] = None) -> None: + """Register the adapters to load and dump a range type. + + :param info: The object with the information about the range to register. + :param context: The context where to register the adapters. If `!None`, + register it globally. + + Register loaders so that loading data of this type will result in a `Range` + with bounds parsed as the right subtype. + + .. note:: + + Registering the adapters doesn't affect objects already created, even + if they are children of the registered context. For instance, + registering the adapter globally doesn't affect already existing + connections. + """ + # A friendly error warning instead of an AttributeError in case fetch() + # failed and it wasn't noticed. + if not info: + raise TypeError("no info passed. Is the requested range available?") + + # Register arrays and type info + info.register(context) + + adapters = context.adapters if context else postgres.adapters + + # generate and register a customized text loader + loader: Type[RangeLoader[Any]] = type( + f"{info.name.title()}Loader", + (RangeLoader,), + {"subtype_oid": info.subtype_oid}, + ) + adapters.register_loader(info.oid, loader) + + # generate and register a customized binary loader + bloader: Type[RangeBinaryLoader[Any]] = type( + f"{info.name.title()}BinaryLoader", + (RangeBinaryLoader,), + {"subtype_oid": info.subtype_oid}, + ) + adapters.register_loader(info.oid, bloader) + + +# Text dumpers for builtin range types wrappers +# These are registered on specific subtypes so that the upgrade mechanism +# doesn't kick in. + + +class Int4RangeDumper(RangeDumper): + oid = postgres.types["int4range"].oid + + +class Int8RangeDumper(RangeDumper): + oid = postgres.types["int8range"].oid + + +class NumericRangeDumper(RangeDumper): + oid = postgres.types["numrange"].oid + + +class DateRangeDumper(RangeDumper): + oid = postgres.types["daterange"].oid + + +class TimestampRangeDumper(RangeDumper): + oid = postgres.types["tsrange"].oid + + +class TimestamptzRangeDumper(RangeDumper): + oid = postgres.types["tstzrange"].oid + + +# Binary dumpers for builtin range types wrappers +# These are registered on specific subtypes so that the upgrade mechanism +# doesn't kick in. + + +class Int4RangeBinaryDumper(RangeBinaryDumper): + oid = postgres.types["int4range"].oid + + +class Int8RangeBinaryDumper(RangeBinaryDumper): + oid = postgres.types["int8range"].oid + + +class NumericRangeBinaryDumper(RangeBinaryDumper): + oid = postgres.types["numrange"].oid + + +class DateRangeBinaryDumper(RangeBinaryDumper): + oid = postgres.types["daterange"].oid + + +class TimestampRangeBinaryDumper(RangeBinaryDumper): + oid = postgres.types["tsrange"].oid + + +class TimestamptzRangeBinaryDumper(RangeBinaryDumper): + oid = postgres.types["tstzrange"].oid + + +# Text loaders for builtin range types + + +class Int4RangeLoader(RangeLoader[int]): + subtype_oid = postgres.types["int4"].oid + + +class Int8RangeLoader(RangeLoader[int]): + subtype_oid = postgres.types["int8"].oid + + +class NumericRangeLoader(RangeLoader[Decimal]): + subtype_oid = postgres.types["numeric"].oid + + +class DateRangeLoader(RangeLoader[date]): + subtype_oid = postgres.types["date"].oid + + +class TimestampRangeLoader(RangeLoader[datetime]): + subtype_oid = postgres.types["timestamp"].oid + + +class TimestampTZRangeLoader(RangeLoader[datetime]): + subtype_oid = postgres.types["timestamptz"].oid + + +# Binary loaders for builtin range types + + +class Int4RangeBinaryLoader(RangeBinaryLoader[int]): + subtype_oid = postgres.types["int4"].oid + + +class Int8RangeBinaryLoader(RangeBinaryLoader[int]): + subtype_oid = postgres.types["int8"].oid + + +class NumericRangeBinaryLoader(RangeBinaryLoader[Decimal]): + subtype_oid = postgres.types["numeric"].oid + + +class DateRangeBinaryLoader(RangeBinaryLoader[date]): + subtype_oid = postgres.types["date"].oid + + +class TimestampRangeBinaryLoader(RangeBinaryLoader[datetime]): + subtype_oid = postgres.types["timestamp"].oid + + +class TimestampTZRangeBinaryLoader(RangeBinaryLoader[datetime]): + subtype_oid = postgres.types["timestamptz"].oid + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper(Range, RangeBinaryDumper) + adapters.register_dumper(Range, RangeDumper) + adapters.register_dumper(Int4Range, Int4RangeDumper) + adapters.register_dumper(Int8Range, Int8RangeDumper) + adapters.register_dumper(NumericRange, NumericRangeDumper) + adapters.register_dumper(DateRange, DateRangeDumper) + adapters.register_dumper(TimestampRange, TimestampRangeDumper) + adapters.register_dumper(TimestamptzRange, TimestamptzRangeDumper) + adapters.register_dumper(Int4Range, Int4RangeBinaryDumper) + adapters.register_dumper(Int8Range, Int8RangeBinaryDumper) + adapters.register_dumper(NumericRange, NumericRangeBinaryDumper) + adapters.register_dumper(DateRange, DateRangeBinaryDumper) + adapters.register_dumper(TimestampRange, TimestampRangeBinaryDumper) + adapters.register_dumper(TimestamptzRange, TimestamptzRangeBinaryDumper) + adapters.register_loader("int4range", Int4RangeLoader) + adapters.register_loader("int8range", Int8RangeLoader) + adapters.register_loader("numrange", NumericRangeLoader) + adapters.register_loader("daterange", DateRangeLoader) + adapters.register_loader("tsrange", TimestampRangeLoader) + adapters.register_loader("tstzrange", TimestampTZRangeLoader) + adapters.register_loader("int4range", Int4RangeBinaryLoader) + adapters.register_loader("int8range", Int8RangeBinaryLoader) + adapters.register_loader("numrange", NumericRangeBinaryLoader) + adapters.register_loader("daterange", DateRangeBinaryLoader) + adapters.register_loader("tsrange", TimestampRangeBinaryLoader) + adapters.register_loader("tstzrange", TimestampTZRangeBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/shapely.py b/lib/python3.11/site-packages/psycopg/types/shapely.py new file mode 100644 index 0000000..e99f256 --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/shapely.py @@ -0,0 +1,75 @@ +""" +Adapters for PostGIS geometries +""" + +from typing import Optional + +from .. import postgres +from ..abc import AdaptContext, Buffer +from ..adapt import Dumper, Loader +from ..pq import Format +from .._typeinfo import TypeInfo + + +try: + from shapely.wkb import loads, dumps + from shapely.geometry.base import BaseGeometry + +except ImportError: + raise ImportError( + "The module psycopg.types.shapely requires the package 'Shapely'" + " to be installed" + ) + + +class GeometryBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> "BaseGeometry": + if not isinstance(data, bytes): + data = bytes(data) + return loads(data) + + +class GeometryLoader(Loader): + def load(self, data: Buffer) -> "BaseGeometry": + # it's a hex string in binary + if isinstance(data, memoryview): + data = bytes(data) + return loads(data.decode(), hex=True) + + +class BaseGeometryBinaryDumper(Dumper): + format = Format.BINARY + + def dump(self, obj: "BaseGeometry") -> bytes: + return dumps(obj) # type: ignore + + +class BaseGeometryDumper(Dumper): + def dump(self, obj: "BaseGeometry") -> bytes: + return dumps(obj, hex=True).encode() # type: ignore + + +def register_shapely(info: TypeInfo, context: Optional[AdaptContext] = None) -> None: + """Register Shapely dumper and loaders.""" + + # A friendly error warning instead of an AttributeError in case fetch() + # failed and it wasn't noticed. + if not info: + raise TypeError("no info passed. Is the 'postgis' extension loaded?") + + info.register(context) + adapters = context.adapters if context else postgres.adapters + + class GeometryDumper(BaseGeometryDumper): + oid = info.oid + + class GeometryBinaryDumper(BaseGeometryBinaryDumper): + oid = info.oid + + adapters.register_loader(info.oid, GeometryBinaryLoader) + adapters.register_loader(info.oid, GeometryLoader) + # Default binary dump + adapters.register_dumper(BaseGeometry, GeometryDumper) + adapters.register_dumper(BaseGeometry, GeometryBinaryDumper) diff --git a/lib/python3.11/site-packages/psycopg/types/string.py b/lib/python3.11/site-packages/psycopg/types/string.py new file mode 100644 index 0000000..22f827e --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/string.py @@ -0,0 +1,229 @@ +""" +Adapters for textual types. +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Optional, Union, TYPE_CHECKING + +from .. import postgres +from ..pq import Format, Escaping +from ..abc import AdaptContext +from ..adapt import Buffer, Dumper, Loader +from ..errors import DataError +from .._encodings import conn_encoding + +if TYPE_CHECKING: + from ..pq.abc import Escaping as EscapingProto + + +class _BaseStrDumper(Dumper): + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + super().__init__(cls, context) + enc = conn_encoding(self.connection) + self._encoding = enc if enc != "ascii" else "utf-8" + + +class _StrBinaryDumper(_BaseStrDumper): + """ + Base class to dump a Python strings to a Postgres text type, in binary format. + + Subclasses shall specify the oids of real types (text, varchar, name...). + """ + + format = Format.BINARY + + def dump(self, obj: str) -> bytes: + # the server will raise DataError subclass if the string contains 0x00 + return obj.encode(self._encoding) + + +class _StrDumper(_BaseStrDumper): + """ + Base class to dump a Python strings to a Postgres text type, in text format. + + Subclasses shall specify the oids of real types (text, varchar, name...). + """ + + def dump(self, obj: str) -> bytes: + if "\x00" in obj: + raise DataError("PostgreSQL text fields cannot contain NUL (0x00) bytes") + else: + return obj.encode(self._encoding) + + +# The next are concrete dumpers, each one specifying the oid they dump to. + + +class StrBinaryDumper(_StrBinaryDumper): + oid = postgres.types["text"].oid + + +class StrBinaryDumperVarchar(_StrBinaryDumper): + oid = postgres.types["varchar"].oid + + +class StrBinaryDumperName(_StrBinaryDumper): + oid = postgres.types["name"].oid + + +class StrDumper(_StrDumper): + """ + Dumper for strings in text format to the text oid. + + Note that this dumper is not used by default because the type is too strict + and PostgreSQL would require an explicit casts to everything that is not a + text field. However it is useful where the unknown oid is ambiguous and the + text oid is required, for instance with variadic functions. + """ + + oid = postgres.types["text"].oid + + +class StrDumperVarchar(_StrDumper): + oid = postgres.types["varchar"].oid + + +class StrDumperName(_StrDumper): + oid = postgres.types["name"].oid + + +class StrDumperUnknown(_StrDumper): + """ + Dumper for strings in text format to the unknown oid. + + This dumper is the default dumper for strings and allows to use Python + strings to represent almost every data type. In a few places, however, the + unknown oid is not accepted (for instance in variadic functions such as + 'concat()'). In that case either a cast on the placeholder ('%s::text') or + the StrTextDumper should be used. + """ + + pass + + +class TextLoader(Loader): + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + enc = conn_encoding(self.connection) + self._encoding = enc if enc != "ascii" else "" + + def load(self, data: Buffer) -> Union[bytes, str]: + if self._encoding: + if isinstance(data, memoryview): + data = bytes(data) + return data.decode(self._encoding) + else: + # return bytes for SQL_ASCII db + if not isinstance(data, bytes): + data = bytes(data) + return data + + +class TextBinaryLoader(TextLoader): + format = Format.BINARY + + +class BytesDumper(Dumper): + oid = postgres.types["bytea"].oid + _qprefix = b"" + + def __init__(self, cls: type, context: Optional[AdaptContext] = None): + super().__init__(cls, context) + self._esc = Escaping(self.connection.pgconn if self.connection else None) + + def dump(self, obj: Buffer) -> Buffer: + return self._esc.escape_bytea(obj) + + def quote(self, obj: Buffer) -> bytes: + escaped = self.dump(obj) + + # We cannot use the base quoting because escape_bytea already returns + # the quotes content. if scs is off it will escape the backslashes in + # the format, otherwise it won't, but it doesn't tell us what quotes to + # use. + if self.connection: + if not self._qprefix: + scs = self.connection.pgconn.parameter_status( + b"standard_conforming_strings" + ) + self._qprefix = b"'" if scs == b"on" else b" E'" + + return self._qprefix + escaped + b"'" + + # We don't have a connection, so someone is using us to generate a file + # to use off-line or something like that. PQescapeBytea, like its + # string counterpart, is not predictable whether it will escape + # backslashes. + rv: bytes = b" E'" + escaped + b"'" + if self._esc.escape_bytea(b"\x00") == b"\\000": + rv = rv.replace(b"\\", b"\\\\") + return rv + + +class BytesBinaryDumper(Dumper): + format = Format.BINARY + oid = postgres.types["bytea"].oid + + def dump(self, obj: Buffer) -> Buffer: + return obj + + +class ByteaLoader(Loader): + _escaping: "EscapingProto" + + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + if not hasattr(self.__class__, "_escaping"): + self.__class__._escaping = Escaping() + + def load(self, data: Buffer) -> bytes: + return self._escaping.unescape_bytea(data) + + +class ByteaBinaryLoader(Loader): + format = Format.BINARY + + def load(self, data: Buffer) -> Buffer: + return data + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + + # NOTE: the order the dumpers are registered is relevant. The last one + # registered becomes the default for each type. Usually, binary is the + # default dumper. For text we use the text dumper as default because it + # plays the role of unknown, and it can be cast automatically to other + # types. However, before that, we register dumper with 'text', 'varchar', + # 'name' oids, which will be used when a text dumper is looked up by oid. + adapters.register_dumper(str, StrBinaryDumperName) + adapters.register_dumper(str, StrBinaryDumperVarchar) + adapters.register_dumper(str, StrBinaryDumper) + adapters.register_dumper(str, StrDumperName) + adapters.register_dumper(str, StrDumperVarchar) + adapters.register_dumper(str, StrDumper) + adapters.register_dumper(str, StrDumperUnknown) + + adapters.register_loader(postgres.INVALID_OID, TextLoader) + adapters.register_loader("bpchar", TextLoader) + adapters.register_loader("name", TextLoader) + adapters.register_loader("text", TextLoader) + adapters.register_loader("varchar", TextLoader) + adapters.register_loader('"char"', TextLoader) + adapters.register_loader("bpchar", TextBinaryLoader) + adapters.register_loader("name", TextBinaryLoader) + adapters.register_loader("text", TextBinaryLoader) + adapters.register_loader("varchar", TextBinaryLoader) + adapters.register_loader('"char"', TextBinaryLoader) + + adapters.register_dumper(bytes, BytesDumper) + adapters.register_dumper(bytearray, BytesDumper) + adapters.register_dumper(memoryview, BytesDumper) + adapters.register_dumper(bytes, BytesBinaryDumper) + adapters.register_dumper(bytearray, BytesBinaryDumper) + adapters.register_dumper(memoryview, BytesBinaryDumper) + + adapters.register_loader("bytea", ByteaLoader) + adapters.register_loader(postgres.INVALID_OID, ByteaBinaryLoader) + adapters.register_loader("bytea", ByteaBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/types/uuid.py b/lib/python3.11/site-packages/psycopg/types/uuid.py new file mode 100644 index 0000000..3cc5eba --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/types/uuid.py @@ -0,0 +1,62 @@ +""" +Adapters for the UUID type. +""" + +# Copyright (C) 2020 The Psycopg Team + +from typing import Callable, Optional, TYPE_CHECKING + +from .. import postgres +from ..pq import Format +from ..abc import AdaptContext +from ..adapt import Buffer, Dumper, Loader + +if TYPE_CHECKING: + import uuid + +# Importing the uuid module is slow, so import it only on request. +UUID: Callable[..., "uuid.UUID"] = None # type: ignore[assignment] + + +class UUIDDumper(Dumper): + oid = postgres.types["uuid"].oid + + def dump(self, obj: "uuid.UUID") -> bytes: + return obj.hex.encode() + + +class UUIDBinaryDumper(UUIDDumper): + format = Format.BINARY + + def dump(self, obj: "uuid.UUID") -> bytes: + return obj.bytes + + +class UUIDLoader(Loader): + def __init__(self, oid: int, context: Optional[AdaptContext] = None): + super().__init__(oid, context) + global UUID + if UUID is None: + from uuid import UUID + + def load(self, data: Buffer) -> "uuid.UUID": + if isinstance(data, memoryview): + data = bytes(data) + return UUID(data.decode()) + + +class UUIDBinaryLoader(UUIDLoader): + format = Format.BINARY + + def load(self, data: Buffer) -> "uuid.UUID": + if isinstance(data, memoryview): + data = bytes(data) + return UUID(bytes=data) + + +def register_default_adapters(context: AdaptContext) -> None: + adapters = context.adapters + adapters.register_dumper("uuid.UUID", UUIDDumper) + adapters.register_dumper("uuid.UUID", UUIDBinaryDumper) + adapters.register_loader("uuid", UUIDLoader) + adapters.register_loader("uuid", UUIDBinaryLoader) diff --git a/lib/python3.11/site-packages/psycopg/version.py b/lib/python3.11/site-packages/psycopg/version.py new file mode 100644 index 0000000..4f223ee --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/version.py @@ -0,0 +1,14 @@ +""" +psycopg distribution version file. +""" + +# Copyright (C) 2020 The Psycopg Team + +# Use a versioning scheme as defined in +# https://www.python.org/dev/peps/pep-0440/ + +# STOP AND READ! if you change: +__version__ = "3.1.9" +# also change: +# - `docs/news.rst` to declare this as the current version or an unreleased one +# - `psycopg_c/psycopg_c/version.py` to the same version. diff --git a/lib/python3.11/site-packages/psycopg/waiting.py b/lib/python3.11/site-packages/psycopg/waiting.py new file mode 100644 index 0000000..2c4a10f --- /dev/null +++ b/lib/python3.11/site-packages/psycopg/waiting.py @@ -0,0 +1,324 @@ +""" +Code concerned with waiting in different contexts (blocking, async, etc). + +These functions are designed to consume the generators returned by the +`generators` module function and to return their final value. + +""" + +# Copyright (C) 2020 The Psycopg Team + + +import os +import select +import selectors +from typing import Dict, Optional +from asyncio import get_event_loop, wait_for, Event, TimeoutError +from selectors import DefaultSelector + +from . import errors as e +from .abc import RV, PQGen, PQGenConn, WaitFunc +from ._enums import Wait as Wait, Ready as Ready # re-exported +from ._cmodule import _psycopg + +WAIT_R = Wait.R +WAIT_W = Wait.W +WAIT_RW = Wait.RW +READY_R = Ready.R +READY_W = Ready.W +READY_RW = Ready.RW + + +def wait_selector(gen: PQGen[RV], fileno: int, timeout: Optional[float] = None) -> RV: + """ + Wait for a generator using the best strategy available. + + :param gen: a generator performing database operations and yielding + `Ready` values when it would block. + :param fileno: the file descriptor to wait on. + :param timeout: timeout (in seconds) to check for other interrupt, e.g. + to allow Ctrl-C. + :type timeout: float + :return: whatever `!gen` returns on completion. + + Consume `!gen`, scheduling `fileno` for completion when it is reported to + block. Once ready again send the ready state back to `!gen`. + """ + try: + s = next(gen) + with DefaultSelector() as sel: + while True: + sel.register(fileno, s) + rlist = None + while not rlist: + rlist = sel.select(timeout=timeout) + sel.unregister(fileno) + # note: this line should require a cast, but mypy doesn't complain + ready: Ready = rlist[0][1] + assert s & ready + s = gen.send(ready) + + except StopIteration as ex: + rv: RV = ex.args[0] if ex.args else None + return rv + + +def wait_conn(gen: PQGenConn[RV], timeout: Optional[float] = None) -> RV: + """ + Wait for a connection generator using the best strategy available. + + :param gen: a generator performing database operations and yielding + (fd, `Ready`) pairs when it would block. + :param timeout: timeout (in seconds) to check for other interrupt, e.g. + to allow Ctrl-C. If zero or None, wait indefinitely. + :type timeout: float + :return: whatever `!gen` returns on completion. + + Behave like in `wait()`, but take the fileno to wait from the generator + itself, which might change during processing. + """ + try: + fileno, s = next(gen) + if not timeout: + timeout = None + with DefaultSelector() as sel: + while True: + sel.register(fileno, s) + rlist = sel.select(timeout=timeout) + sel.unregister(fileno) + if not rlist: + raise e.ConnectionTimeout("connection timeout expired") + ready: Ready = rlist[0][1] # type: ignore[assignment] + fileno, s = gen.send(ready) + + except StopIteration as ex: + rv: RV = ex.args[0] if ex.args else None + return rv + + +async def wait_async(gen: PQGen[RV], fileno: int) -> RV: + """ + Coroutine waiting for a generator to complete. + + :param gen: a generator performing database operations and yielding + `Ready` values when it would block. + :param fileno: the file descriptor to wait on. + :return: whatever `!gen` returns on completion. + + Behave like in `wait()`, but exposing an `asyncio` interface. + """ + # Use an event to block and restart after the fd state changes. + # Not sure this is the best implementation but it's a start. + ev = Event() + loop = get_event_loop() + ready: Ready + s: Wait + + def wakeup(state: Ready) -> None: + nonlocal ready + ready |= state # type: ignore[assignment] + ev.set() + + try: + s = next(gen) + while True: + reader = s & WAIT_R + writer = s & WAIT_W + if not reader and not writer: + raise e.InternalError(f"bad poll status: {s}") + ev.clear() + ready = 0 # type: ignore[assignment] + if reader: + loop.add_reader(fileno, wakeup, READY_R) + if writer: + loop.add_writer(fileno, wakeup, READY_W) + try: + await ev.wait() + finally: + if reader: + loop.remove_reader(fileno) + if writer: + loop.remove_writer(fileno) + s = gen.send(ready) + + except StopIteration as ex: + rv: RV = ex.args[0] if ex.args else None + return rv + + +async def wait_conn_async(gen: PQGenConn[RV], timeout: Optional[float] = None) -> RV: + """ + Coroutine waiting for a connection generator to complete. + + :param gen: a generator performing database operations and yielding + (fd, `Ready`) pairs when it would block. + :param timeout: timeout (in seconds) to check for other interrupt, e.g. + to allow Ctrl-C. If zero or None, wait indefinitely. + :return: whatever `!gen` returns on completion. + + Behave like in `wait()`, but take the fileno to wait from the generator + itself, which might change during processing. + """ + # Use an event to block and restart after the fd state changes. + # Not sure this is the best implementation but it's a start. + ev = Event() + loop = get_event_loop() + ready: Ready + s: Wait + + def wakeup(state: Ready) -> None: + nonlocal ready + ready = state + ev.set() + + try: + fileno, s = next(gen) + if not timeout: + timeout = None + while True: + reader = s & WAIT_R + writer = s & WAIT_W + if not reader and not writer: + raise e.InternalError(f"bad poll status: {s}") + ev.clear() + ready = 0 # type: ignore[assignment] + if reader: + loop.add_reader(fileno, wakeup, READY_R) + if writer: + loop.add_writer(fileno, wakeup, READY_W) + try: + await wait_for(ev.wait(), timeout) + finally: + if reader: + loop.remove_reader(fileno) + if writer: + loop.remove_writer(fileno) + fileno, s = gen.send(ready) + + except TimeoutError: + raise e.ConnectionTimeout("connection timeout expired") + + except StopIteration as ex: + rv: RV = ex.args[0] if ex.args else None + return rv + + +# Specialised implementation of wait functions. + + +def wait_select(gen: PQGen[RV], fileno: int, timeout: Optional[float] = None) -> RV: + """ + Wait for a generator using select where supported. + """ + try: + s = next(gen) + + empty = () + fnlist = (fileno,) + while True: + rl, wl, xl = select.select( + fnlist if s & WAIT_R else empty, + fnlist if s & WAIT_W else empty, + fnlist, + timeout, + ) + ready = 0 + if rl: + ready = READY_R + if wl: + ready |= READY_W + if not ready: + continue + # assert s & ready + s = gen.send(ready) # type: ignore + + except StopIteration as ex: + rv: RV = ex.args[0] if ex.args else None + return rv + + +poll_evmasks: Dict[Wait, int] + +if hasattr(selectors, "EpollSelector"): + poll_evmasks = { + WAIT_R: select.EPOLLONESHOT | select.EPOLLIN, + WAIT_W: select.EPOLLONESHOT | select.EPOLLOUT, + WAIT_RW: select.EPOLLONESHOT | select.EPOLLIN | select.EPOLLOUT, + } +else: + poll_evmasks = {} + + +def wait_epoll(gen: PQGen[RV], fileno: int, timeout: Optional[float] = None) -> RV: + """ + Wait for a generator using epoll where supported. + + Parameters are like for `wait()`. If it is detected that the best selector + strategy is `epoll` then this function will be used instead of `wait`. + + See also: https://linux.die.net/man/2/epoll_ctl + """ + try: + s = next(gen) + + if timeout is None or timeout < 0: + timeout = 0 + else: + timeout = int(timeout * 1000.0) + + with select.epoll() as epoll: + evmask = poll_evmasks[s] + epoll.register(fileno, evmask) + while True: + fileevs = None + while not fileevs: + fileevs = epoll.poll(timeout) + ev = fileevs[0][1] + ready = 0 + if ev & ~select.EPOLLOUT: + ready = READY_R + if ev & ~select.EPOLLIN: + ready |= READY_W + # assert s & ready + s = gen.send(ready) + evmask = poll_evmasks[s] + epoll.modify(fileno, evmask) + + except StopIteration as ex: + rv: RV = ex.args[0] if ex.args else None + return rv + + +if _psycopg: + wait_c = _psycopg.wait_c + + +# Choose the best wait strategy for the platform. +# +# the selectors objects have a generic interface but come with some overhead, +# so we also offer more finely tuned implementations. + +wait: WaitFunc + +# Allow the user to choose a specific function for testing +if "PSYCOPG_WAIT_FUNC" in os.environ: + fname = os.environ["PSYCOPG_WAIT_FUNC"] + if not fname.startswith("wait_") or fname not in globals(): + raise ImportError( + "PSYCOPG_WAIT_FUNC should be the name of an available wait function;" + f" got {fname!r}" + ) + wait = globals()[fname] + +elif _psycopg: + wait = wait_c + +elif selectors.DefaultSelector is getattr(selectors, "SelectSelector", None): + # On Windows, SelectSelector should be the default. + wait = wait_select + +elif selectors.DefaultSelector is getattr(selectors, "EpollSelector", None): + wait = wait_epoll + +else: + wait = wait_selector diff --git a/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/INSTALLER b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/LICENSE b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/LICENSE new file mode 100644 index 0000000..f26bcf4 --- /dev/null +++ b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/LICENSE @@ -0,0 +1,279 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see https://opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +Python software and documentation are licensed under the +Python Software Foundation License Version 2. + +Starting with Python 3.8.6, examples, recipes, and other code in +the documentation are dual licensed under the PSF License Version 2 +and the Zero-Clause BSD license. + +Some software incorporated into Python is under different licenses. +The licenses are listed with code falling under that license. + + +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, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +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 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 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 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +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. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION +---------------------------------------------------------------------- + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/METADATA b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/METADATA new file mode 100644 index 0000000..70e1d63 --- /dev/null +++ b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/METADATA @@ -0,0 +1,69 @@ +Metadata-Version: 2.1 +Name: typing_extensions +Version: 4.7.1 +Summary: Backported and Experimental Type Hints for Python 3.7+ +Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing +Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: Operating System :: OS Independent +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: Topic :: Software Development +Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues +Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md +Project-URL: Documentation, https://typing-extensions.readthedocs.io/ +Project-URL: Home, https://github.com/python/typing_extensions +Project-URL: Q & A, https://github.com/python/typing/discussions +Project-URL: Repository, https://github.com/python/typing_extensions + +# Typing Extensions + +[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) + +[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) – +[PyPI](https://pypi.org/project/typing-extensions/) + +## Overview + +The `typing_extensions` module serves two related purposes: + +- Enable use of new type system features on older Python versions. For example, + `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows + users on previous Python versions to use it too. +- Enable experimentation with new type system PEPs before they are accepted and + added to the `typing` module. + +`typing_extensions` is treated specially by static type checkers such as +mypy and pyright. Objects defined in `typing_extensions` are treated the same +way as equivalent forms in `typing`. + +`typing_extensions` uses +[Semantic Versioning](https://semver.org/). The +major version will be incremented only for backwards-incompatible changes. +Therefore, it's safe to depend +on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`, +where `x.y` is the first version that includes all features you need. + +`typing_extensions` supports Python versions 3.7 and higher. + +## Included items + +See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a +complete listing of module contents. + +## Contributing + +See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md) +for how to contribute to `typing_extensions`. + diff --git a/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/RECORD b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/RECORD new file mode 100644 index 0000000..ae54dd2 --- /dev/null +++ b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/RECORD @@ -0,0 +1,7 @@ +__pycache__/typing_extensions.cpython-311.pyc,, +typing_extensions-4.7.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +typing_extensions-4.7.1.dist-info/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 +typing_extensions-4.7.1.dist-info/METADATA,sha256=0W71u6mC24oVYJzibNoq2l-bQnVoU_p25uiNhAq5OcA,3078 +typing_extensions-4.7.1.dist-info/RECORD,, +typing_extensions-4.7.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +typing_extensions.py,sha256=zkLXjhMMSmKvLLqj-MCunbScGMu7kPLZYUsLun38I00,111082 diff --git a/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/WHEEL b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/lib/python3.11/site-packages/typing_extensions-4.7.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/lib/python3.11/site-packages/typing_extensions.py b/lib/python3.11/site-packages/typing_extensions.py new file mode 100644 index 0000000..901f3b9 --- /dev/null +++ b/lib/python3.11/site-packages/typing_extensions.py @@ -0,0 +1,3072 @@ +import abc +import collections +import collections.abc +import functools +import inspect +import operator +import sys +import types as _types +import typing +import warnings + +__all__ = [ + # Super-special typing primitives. + 'Any', + 'ClassVar', + 'Concatenate', + 'Final', + 'LiteralString', + 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', + 'Type', + 'TypeVar', + 'TypeVarTuple', + 'Unpack', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'Buffer', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'NamedTuple', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsAbs', + 'SupportsBytes', + 'SupportsComplex', + 'SupportsFloat', + 'SupportsIndex', + 'SupportsInt', + 'SupportsRound', + + # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'deprecated', + 'get_overloads', + 'final', + 'get_args', + 'get_origin', + 'get_original_bases', + 'get_protocol_members', + 'get_type_hints', + 'IntVar', + 'is_protocol', + 'is_typeddict', + 'Literal', + 'NewType', + 'overload', + 'override', + 'Protocol', + 'reveal_type', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeAliasType', + 'TypeGuard', + 'TYPE_CHECKING', + 'Never', + 'NoReturn', + 'Required', + 'NotRequired', + + # Pure aliases, have always been in typing + 'AbstractSet', + 'AnyStr', + 'BinaryIO', + 'Callable', + 'Collection', + 'Container', + 'Dict', + 'ForwardRef', + 'FrozenSet', + 'Generator', + 'Generic', + 'Hashable', + 'IO', + 'ItemsView', + 'Iterable', + 'Iterator', + 'KeysView', + 'List', + 'Mapping', + 'MappingView', + 'Match', + 'MutableMapping', + 'MutableSequence', + 'MutableSet', + 'Optional', + 'Pattern', + 'Reversible', + 'Sequence', + 'Set', + 'Sized', + 'TextIO', + 'Tuple', + 'Union', + 'ValuesView', + 'cast', + 'no_type_check', + 'no_type_check_decorator', +] + +# for backward compatibility +PEP_560 = True +GenericMeta = type + +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. + + +class _Sentinel: + def __repr__(self): + return "" + + +_marker = _Sentinel() + + +def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" + f" actual {alen}, expected {elen}") + + +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +elif sys.version_info >= (3, 9): + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) +else: + def _should_collect_from_parameters(t): + return isinstance(t, typing._GenericAlias) and not t._special + + +def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: + + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + for t in types: + if ( + isinstance(t, typevar_types) and + t not in tvars and + not _is_unpack(t) + ): + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + return tuple(tvars) + + +NoReturn = typing.NoReturn + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +if sys.version_info >= (3, 11): + from typing import Any +else: + + class _AnyMeta(type): + def __instancecheck__(self, obj): + if self is Any: + raise TypeError("typing_extensions.Any cannot be used with isinstance()") + return super().__instancecheck__(obj) + + def __repr__(self): + if self is Any: + return "typing_extensions.Any" + return super().__repr__() + + class Any(metaclass=_AnyMeta): + """Special type indicating an unconstrained type. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + checks. + """ + def __new__(cls, *args, **kwargs): + if cls is Any: + raise TypeError("Any cannot be instantiated") + return super().__new__(cls, *args, **kwargs) + + +ClassVar = typing.ClassVar + + +class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + +# On older versions of typing there is an internal class named "Final". +# 3.8+ +if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): + Final = typing.Final +# 3.7 +else: + class _FinalForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Final = _FinalForm('Final', + doc="""A special typing construct to indicate that a name + cannot be re-assigned or overridden in a subclass. + For example: + + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker + + class Connection: + TIMEOUT: Final[int] = 10 + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker + + There is no runtime checking of these properties.""") + +if sys.version_info >= (3, 11): + final = typing.final +else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return f + + +def IntVar(name): + return typing.TypeVar(name) + + +# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8 +if sys.version_info >= (3, 10, 1): + Literal = typing.Literal +else: + def _flatten_literal_params(parameters): + """An internal helper for Literal creation: flatten Literals among parameters""" + params = [] + for p in parameters: + if isinstance(p, _LiteralGenericAlias): + params.extend(p.__args__) + else: + params.append(p) + return tuple(params) + + def _value_and_type_iter(params): + for p in params: + yield p, type(p) + + class _LiteralGenericAlias(typing._GenericAlias, _root=True): + def __eq__(self, other): + if not isinstance(other, _LiteralGenericAlias): + return NotImplemented + these_args_deduped = set(_value_and_type_iter(self.__args__)) + other_args_deduped = set(_value_and_type_iter(other.__args__)) + return these_args_deduped == other_args_deduped + + def __hash__(self): + return hash(frozenset(_value_and_type_iter(self.__args__))) + + class _LiteralForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, doc: str): + self._name = 'Literal' + self._doc = self.__doc__ = doc + + def __getitem__(self, parameters): + if not isinstance(parameters, tuple): + parameters = (parameters,) + + parameters = _flatten_literal_params(parameters) + + val_type_pairs = list(_value_and_type_iter(parameters)) + try: + deduped_pairs = set(val_type_pairs) + except TypeError: + # unhashable parameters + pass + else: + # similar logic to typing._deduplicate on Python 3.9+ + if len(deduped_pairs) < len(val_type_pairs): + new_parameters = [] + for pair in val_type_pairs: + if pair in deduped_pairs: + new_parameters.append(pair[0]) + deduped_pairs.remove(pair) + assert not deduped_pairs, deduped_pairs + parameters = tuple(new_parameters) + + return _LiteralGenericAlias(self, parameters) + + Literal = _LiteralForm(doc="""\ + A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") + + +_overload_dummy = typing._overload_dummy + + +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads +else: + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) + + def overload(func): + """Decorator for overloaded functions/methods. + + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here + + The overloads for a function can be retrieved at runtime using the + get_overloads() function. + """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy + + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) + + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. + + +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +ContextManager = typing.ContextManager +AsyncContextManager = typing.AsyncContextManager +DefaultDict = typing.DefaultDict + +# 3.7.2+ +if hasattr(typing, 'OrderedDict'): + OrderedDict = typing.OrderedDict +# 3.7.0-3.7.2 +else: + OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) + +Counter = typing.Counter +ChainMap = typing.ChainMap +AsyncGenerator = typing.AsyncGenerator +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +_PROTO_ALLOWLIST = { + 'collections.abc': [ + 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', + ], + 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], + 'typing_extensions': ['Buffer'], +} + + +_EXCLUDED_ATTRS = { + "__abstractmethods__", "__annotations__", "__weakref__", "_is_protocol", + "_is_runtime_protocol", "__dict__", "__slots__", "__parameters__", + "__orig_bases__", "__module__", "_MutableMapping__marker", "__doc__", + "__subclasshook__", "__orig_class__", "__init__", "__new__", + "__protocol_attrs__", "__callable_proto_members_only__", +} + +if sys.version_info < (3, 8): + _EXCLUDED_ATTRS |= { + "_gorg", "__next_in_mro__", "__extra__", "__tree_hash__", "__args__", + "__origin__" + } + +if sys.version_info >= (3, 9): + _EXCLUDED_ATTRS.add("__class_getitem__") + +if sys.version_info >= (3, 12): + _EXCLUDED_ATTRS.add("__type_params__") + +_EXCLUDED_ATTRS = frozenset(_EXCLUDED_ATTRS) + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in {'Protocol', 'Generic'}: + continue + annotations = getattr(base, '__annotations__', {}) + for attr in (*base.__dict__, *annotations): + if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS): + attrs.add(attr) + return attrs + + +def _maybe_adjust_parameters(cls): + """Helper function used in Protocol.__init_subclass__ and _TypedDictMeta.__new__. + + The contents of this function are very similar + to logic found in typing.Generic.__init_subclass__ + on the CPython main branch. + """ + tvars = [] + if '__orig_bases__' in cls.__dict__: + tvars = _collect_type_vars(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...] and/or Protocol[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, typing._GenericAlias) and + base.__origin__ in (typing.Generic, Protocol)): + # for error messages + the_base = base.__origin__.__name__ + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...]" + " and/or Protocol[...] multiple types.") + gvars = base.__parameters__ + if gvars is None: + gvars = tvars + else: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in {the_base}[{s_args}]") + tvars = gvars + cls.__parameters__ = tuple(tvars) + + +def _caller(depth=2): + try: + return sys._getframe(depth).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): # For platforms without _getframe() + return None + + +# The performance of runtime-checkable protocols is significantly improved on Python 3.12, +# so we backport the 3.12 version of Protocol to Python <=3.11 +if sys.version_info >= (3, 12): + Protocol = typing.Protocol +else: + def _allow_reckless_class_checks(depth=3): + """Allow instance and class checks for special stdlib modules. + The abc and functools modules indiscriminately call isinstance() and + issubclass() on the whole MRO of a user class, which may contain protocols. + """ + return _caller(depth) in {'abc', 'functools', None} + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + if sys.version_info >= (3, 8): + # Inheriting from typing._ProtocolMeta isn't actually desirable, + # but is necessary to allow typing.Protocol and typing_extensions.Protocol + # to mix without getting TypeErrors about "metaclass conflict" + _typing_Protocol = typing.Protocol + _ProtocolMetaBase = type(_typing_Protocol) + else: + _typing_Protocol = _marker + _ProtocolMetaBase = abc.ABCMeta + + class _ProtocolMeta(_ProtocolMetaBase): + # This metaclass is somewhat unfortunate, + # but is necessary for several reasons... + # + # NOTE: DO NOT call super() in any methods in this class + # That would call the methods on typing._ProtocolMeta on Python 3.8-3.11 + # and those are slow + def __new__(mcls, name, bases, namespace, **kwargs): + if name == "Protocol" and len(bases) < 2: + pass + elif {Protocol, _typing_Protocol} & set(bases): + for base in bases: + if not ( + base in {object, typing.Generic, Protocol, _typing_Protocol} + or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) + or is_protocol(base) + ): + raise TypeError( + f"Protocols can only inherit from other protocols, " + f"got {base!r}" + ) + return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs) + + def __init__(cls, *args, **kwargs): + abc.ABCMeta.__init__(cls, *args, **kwargs) + if getattr(cls, "_is_protocol", False): + cls.__protocol_attrs__ = _get_protocol_attrs(cls) + # PEP 544 prohibits using issubclass() + # with protocols that have non-method members. + cls.__callable_proto_members_only__ = all( + callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__ + ) + + def __subclasscheck__(cls, other): + if cls is Protocol: + return type.__subclasscheck__(cls, other) + if ( + getattr(cls, '_is_protocol', False) + and not _allow_reckless_class_checks() + ): + if not isinstance(other, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') + if ( + not cls.__callable_proto_members_only__ + and cls.__dict__.get("__subclasshook__") is _proto_hook + ): + raise TypeError( + "Protocols with non-method members don't support issubclass()" + ) + if not getattr(cls, '_is_runtime_protocol', False): + raise TypeError( + "Instance and class checks can only be used with " + "@runtime_checkable protocols" + ) + return abc.ABCMeta.__subclasscheck__(cls, other) + + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if cls is Protocol: + return type.__instancecheck__(cls, instance) + if not getattr(cls, "_is_protocol", False): + # i.e., it's a concrete subclass of a protocol + return abc.ABCMeta.__instancecheck__(cls, instance) + + if ( + not getattr(cls, '_is_runtime_protocol', False) and + not _allow_reckless_class_checks() + ): + raise TypeError("Instance and class checks can only be used with" + " @runtime_checkable protocols") + + if abc.ABCMeta.__instancecheck__(cls, instance): + return True + + for attr in cls.__protocol_attrs__: + try: + val = inspect.getattr_static(instance, attr) + except AttributeError: + break + if val is None and callable(getattr(cls, attr, None)): + break + else: + return True + + return False + + def __eq__(cls, other): + # Hack so that typing.Generic.__class_getitem__ + # treats typing_extensions.Protocol + # as equivalent to typing.Protocol on Python 3.8+ + if abc.ABCMeta.__eq__(cls, other) is True: + return True + return ( + cls is Protocol and other is getattr(typing, "Protocol", object()) + ) + + # This has to be defined, or the abc-module cache + # complains about classes with this metaclass being unhashable, + # if we define only __eq__! + def __hash__(cls) -> int: + return type.__hash__(cls) + + @classmethod + def _proto_hook(cls, other): + if not cls.__dict__.get('_is_protocol', False): + return NotImplemented + + for attr in cls.__protocol_attrs__: + for base in other.__mro__: + # Check if the members appears in the class dictionary... + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + + # ...or in annotations, if it is a sub-protocol. + annotations = getattr(base, '__annotations__', {}) + if ( + isinstance(annotations, collections.abc.Mapping) + and attr in annotations + and is_protocol(other) + ): + break + else: + return NotImplemented + return True + + if sys.version_info >= (3, 8): + class Protocol(typing.Generic, metaclass=_ProtocolMeta): + __doc__ = typing.Protocol.__doc__ + __slots__ = () + _is_protocol = True + _is_runtime_protocol = False + + def __init_subclass__(cls, *args, **kwargs): + super().__init_subclass__(*args, **kwargs) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', False): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # Prohibit instantiation for protocol classes + if cls._is_protocol and cls.__init__ is Protocol.__init__: + cls.__init__ = _no_init + + else: + class Protocol(metaclass=_ProtocolMeta): + # There is quite a lot of overlapping code with typing.Generic. + # Unfortunately it is hard to avoid this on Python <3.8, + # as the typing module on Python 3.7 doesn't let us subclass typing.Generic! + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime_checkable act + as simple-minded runtime-checkable protocols that check + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + _is_runtime_protocol = False + + def __new__(cls, *args, **kwds): + if cls is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can only be used as a base class") + return super().__new__(cls) + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple): + params = (params,) + if not params and cls is not typing.Tuple: + raise TypeError( + f"Parameter list to {cls.__qualname__}[...] cannot be empty") + msg = "Parameters to generic types must be types." + params = tuple(typing._type_check(p, msg) for p in params) + if cls is Protocol: + # Generic can only be subscripted with unique type variables. + if not all(isinstance(p, typing.TypeVar) for p in params): + i = 0 + while isinstance(params[i], typing.TypeVar): + i += 1 + raise TypeError( + "Parameters to Protocol[...] must all be type variables." + f" Parameter {i + 1} is {params[i]}") + if len(set(params)) != len(params): + raise TypeError( + "Parameters to Protocol[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + _check_generic(cls, params, len(cls.__parameters__)) + return typing._GenericAlias(cls, params) + + def __init_subclass__(cls, *args, **kwargs): + if '__orig_bases__' in cls.__dict__: + error = typing.Generic in cls.__orig_bases__ + else: + error = typing.Generic in cls.__bases__ + if error: + raise TypeError("Cannot inherit from plain Generic") + _maybe_adjust_parameters(cls) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', None): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # Prohibit instantiation for protocol classes + if cls._is_protocol and cls.__init__ is Protocol.__init__: + cls.__init__ = _no_init + + +if sys.version_info >= (3, 8): + runtime_checkable = typing.runtime_checkable +else: + def runtime_checkable(cls): + """Mark a protocol class as a runtime protocol, so that it + can be used with isinstance() and issubclass(). Raise TypeError + if applied to a non-protocol class. + + This allows a simple-minded structural check very similar to the + one-offs in collections.abc such as Hashable. + """ + if not ( + (isinstance(cls, _ProtocolMeta) or issubclass(cls, typing.Generic)) + and getattr(cls, "_is_protocol", False) + ): + raise TypeError('@runtime_checkable can be only applied to protocol classes,' + f' got {cls!r}') + cls._is_runtime_protocol = True + return cls + + +# Exists for backwards compatibility. +runtime = runtime_checkable + + +# Our version of runtime-checkable protocols is faster on Python 3.7-3.11 +if sys.version_info >= (3, 12): + SupportsInt = typing.SupportsInt + SupportsFloat = typing.SupportsFloat + SupportsComplex = typing.SupportsComplex + SupportsBytes = typing.SupportsBytes + SupportsIndex = typing.SupportsIndex + SupportsAbs = typing.SupportsAbs + SupportsRound = typing.SupportsRound +else: + @runtime_checkable + class SupportsInt(Protocol): + """An ABC with one abstract method __int__.""" + __slots__ = () + + @abc.abstractmethod + def __int__(self) -> int: + pass + + @runtime_checkable + class SupportsFloat(Protocol): + """An ABC with one abstract method __float__.""" + __slots__ = () + + @abc.abstractmethod + def __float__(self) -> float: + pass + + @runtime_checkable + class SupportsComplex(Protocol): + """An ABC with one abstract method __complex__.""" + __slots__ = () + + @abc.abstractmethod + def __complex__(self) -> complex: + pass + + @runtime_checkable + class SupportsBytes(Protocol): + """An ABC with one abstract method __bytes__.""" + __slots__ = () + + @abc.abstractmethod + def __bytes__(self) -> bytes: + pass + + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + @runtime_checkable + class SupportsAbs(Protocol[T_co]): + """ + An ABC with one abstract method __abs__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __abs__(self) -> T_co: + pass + + @runtime_checkable + class SupportsRound(Protocol[T_co]): + """ + An ABC with one abstract method __round__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __round__(self, ndigits: int = 0) -> T_co: + pass + + +def _ensure_subclassable(mro_entries): + def inner(func): + if sys.implementation.name == "pypy" and sys.version_info < (3, 9): + cls_dict = { + "__call__": staticmethod(func), + "__mro_entries__": staticmethod(mro_entries) + } + t = type(func.__name__, (), cls_dict) + return functools.update_wrapper(t(), func) + else: + func.__mro_entries__ = mro_entries + return func + return inner + + +if sys.version_info >= (3, 13): + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. + # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. + # Aaaand on 3.12 we add __orig_bases__ to TypedDict + # to enable better runtime introspection. + # On 3.13 we deprecate some odd ways of creating TypedDicts. + TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict +else: + # 3.10.0 and later + _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters + + if sys.version_info >= (3, 8): + _fake_name = "Protocol" + else: + _fake_name = "_Protocol" + + class _TypedDictMeta(type): + def __new__(cls, name, bases, ns, total=True): + """Create new typed dict class object. + + This method is called when TypedDict is subclassed, + or when TypedDict is instantiated. This way + TypedDict supports all three syntax forms described in its docstring. + Subclasses and instances of TypedDict return actual dictionaries. + """ + for base in bases: + if type(base) is not _TypedDictMeta and base is not typing.Generic: + raise TypeError('cannot inherit from both a TypedDict type ' + 'and a non-TypedDict base class') + + if any(issubclass(b, typing.Generic) for b in bases): + generic_base = (typing.Generic,) + else: + generic_base = () + + # typing.py generally doesn't let you inherit from plain Generic, unless + # the name of the class happens to be "Protocol" (or "_Protocol" on 3.7). + tp_dict = type.__new__(_TypedDictMeta, _fake_name, (*generic_base, dict), ns) + tp_dict.__name__ = name + if tp_dict.__qualname__ == _fake_name: + tp_dict.__qualname__ = name + + if not hasattr(tp_dict, '__orig_bases__'): + tp_dict.__orig_bases__ = bases + + annotations = {} + own_annotations = ns.get('__annotations__', {}) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + if _TAKES_MODULE: + own_annotations = { + n: typing._type_check(tp, msg, module=tp_dict.__module__) + for n, tp in own_annotations.items() + } + else: + own_annotations = { + n: typing._type_check(tp, msg) + for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + + for base in bases: + annotations.update(base.__dict__.get('__annotations__', {})) + required_keys.update(base.__dict__.get('__required_keys__', ())) + optional_keys.update(base.__dict__.get('__optional_keys__', ())) + + annotations.update(own_annotations) + for annotation_key, annotation_type in own_annotations.items(): + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + annotation_origin = get_origin(annotation_type) + + if annotation_origin is Required: + required_keys.add(annotation_key) + elif annotation_origin is NotRequired: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) + else: + optional_keys.add(annotation_key) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __call__ = dict # static method + + def __subclasscheck__(cls, other): + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + + __instancecheck__ = __subclasscheck__ + + _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) + + @_ensure_subclassable(lambda bases: (_TypedDict,)) + def TypedDict(__typename, __fields=_marker, *, total=True, **kwargs): + """A simple typed namespace. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type such that a type checker will expect all + instances to have a certain set of keys, where each key is + associated with a value of a consistent type. This expectation + is not checked at runtime. + + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports an additional equivalent form:: + + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + By default, all keys must be present in a TypedDict. It is possible + to override this by specifying totality:: + + class Point2D(TypedDict, total=False): + x: int + y: int + + This means that a Point2D TypedDict can have any of the keys omitted. A type + checker is only expected to support a literal False or True as the value of + the total argument. True is the default, and makes all items defined in the + class body be required. + + The Required and NotRequired special forms can also be used to mark + individual keys as being required or not required:: + + class Point2D(TypedDict): + x: int # the "x" key must always be present (Required is the default) + y: NotRequired[int] # the "y" key can be omitted + + See PEP 655 for more details on Required and NotRequired. + """ + if __fields is _marker or __fields is None: + if __fields is _marker: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + + example = f"`{__typename} = TypedDict({__typename!r}, {{}})`" + deprecation_msg = ( + f"{deprecated_thing} is deprecated and will be disallowed in " + "Python 3.15. To create a TypedDict class with 0 fields " + "using the functional syntax, pass an empty dictionary, e.g. " + ) + example + "." + warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) + __fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + if kwargs: + warnings.warn( + "The kwargs-based syntax for TypedDict definitions is deprecated " + "in Python 3.11, will be removed in Python 3.13, and may not be " + "understood by third-party type checkers.", + DeprecationWarning, + stacklevel=2, + ) + + ns = {'__annotations__': dict(__fields)} + module = _caller() + if module is not None: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = module + + td = _TypedDictMeta(__typename, (), ns, total=total) + td.__orig_bases__ = (TypedDict,) + return td + + if hasattr(typing, "_TypedDictMeta"): + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + else: + _TYPEDDICT_TYPES = (_TypedDictMeta,) + + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + # On 3.8, this would otherwise return True + if hasattr(typing, "TypedDict") and tp is typing.TypedDict: + return False + return isinstance(tp, _TYPEDDICT_TYPES) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(__val, __typ): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return __val + + +if hasattr(typing, "Required"): + get_type_hints = typing.get_type_hints +else: + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, _AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return _types.GenericAlias(t.__origin__, stripped_args) + if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if hasattr(typing, "Annotated"): + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + else: + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + +# Python 3.9+ has PEP 593 (Annotated) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +# 3.7-3.8 +else: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__,) + self.__metadata__ + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + allowed_special_forms = (ClassVar, Final) + if get_origin(params[0]) in allowed_special_forms: + origin = params[0] + else: + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + f"Cannot subclass {cls.__module__}.Annotated" + ) + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +if sys.version_info[:2] >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.7-3.9 +else: + try: + # 3.9+ + from typing import _BaseGenericAlias + except ImportError: + _BaseGenericAlias = typing._GenericAlias + try: + # 3.9+ + from typing import GenericAlias as _typing_GenericAlias + except ImportError: + _typing_GenericAlias = typing._GenericAlias + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__,) + tp.__metadata__ + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): + if getattr(tp, "_special", False): + return () + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") +# 3.7-3.8 +else: + TypeAlias = _ExtensionsSpecialForm( + 'TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""" + ) + + +def _set_default(type_param, default): + if isinstance(default, (tuple, list)): + type_param.__default__ = tuple((typing._type_check(d, "Default must be a type") + for d in default)) + elif default != _marker: + type_param.__default__ = typing._type_check(default, "Default must be a type") + else: + type_param.__default__ = None + + +def _set_module(typevarlike): + # for pickling: + def_mod = _caller(depth=3) + if def_mod != 'typing_extensions': + typevarlike.__module__ = def_mod + + +class _DefaultMixin: + """Mixin for TypeVarLike defaults.""" + + __slots__ = () + __init__ = _set_default + + +# Classes using this metaclass must provide a _backported_typevarlike ClassVar +class _TypeVarLikeMeta(type): + def __instancecheck__(cls, __instance: Any) -> bool: + return isinstance(__instance, cls._backported_typevarlike) + + +# Add default and infer_variance parameters from PEP 696 and 695 +class TypeVar(metaclass=_TypeVarLikeMeta): + """Type variable.""" + + _backported_typevarlike = typing.TypeVar + + def __new__(cls, name, *constraints, bound=None, + covariant=False, contravariant=False, + default=_marker, infer_variance=False): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented, can pass infer_variance to typing.TypeVar + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant, + infer_variance=infer_variance) + else: + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant) + if infer_variance and (covariant or contravariant): + raise ValueError("Variance cannot be specified with infer_variance.") + typevar.__infer_variance__ = infer_variance + _set_default(typevar, default) + _set_module(typevar) + return typevar + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type") + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.7-3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + +# 3.10+ +if hasattr(typing, 'ParamSpec'): + + # Add default parameter - PEP 696 + class ParamSpec(metaclass=_TypeVarLikeMeta): + """Parameter specification.""" + + _backported_typevarlike = typing.ParamSpec + + def __new__(cls, name, *, bound=None, + covariant=False, contravariant=False, + infer_variance=False, default=_marker): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented, can pass infer_variance to typing.TypeVar + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant, + infer_variance=infer_variance) + else: + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant) + paramspec.__infer_variance__ = infer_variance + + _set_default(paramspec, default) + _set_module(paramspec) + return paramspec + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") + +# 3.7-3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list, _DefaultMixin): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + infer_variance=False, default=_marker): + super().__init__([self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + self.__infer_variance__ = bool(infer_variance) + if bound: + self.__bound__ = typing._type_check(bound, 'Bound must be a type.') + else: + self.__bound__ = None + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__infer_variance__: + prefix = '' + elif self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + +# 3.7-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + __class__ = typing._GenericAlias + + # Flag in 3.8. + _special = False + + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + +# 3.7-3.9 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) + + +# 3.10+ +if hasattr(typing, 'Concatenate'): + Concatenate = typing.Concatenate + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa: F811 +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) +# 3.7-8 +else: + class _ConcatenateForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateForm( + 'Concatenate', + doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """) + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.7-3.8 +else: + class _TypeGuardForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeGuard = _TypeGuardForm( + 'TypeGuard', + doc="""Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """) + + +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + +if hasattr(typing, "LiteralString"): + LiteralString = typing.LiteralString +else: + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. + + Example:: + + from typing_extensions import LiteralString + + def query(sql: LiteralString) -> ...: + ... + + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok + + See PEP 675 for details. + + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: + class _RequiredForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) + + +_UNPACK_DOC = """\ +Type unpack operator. + +The type unpack operator takes the child types from some container type, +such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For +example: + + # For some generic class `Foo`: + Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] + + Ts = TypeVarTuple('Ts') + # Specifies that `Bar` is generic in an arbitrary number of types. + # (Think of `Ts` as a tuple of an arbitrary number of individual + # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the + # `Generic[]`.) + class Bar(Generic[Unpack[Ts]]): ... + Bar[int] # Valid + Bar[int, str] # Also valid + +From Python 3.11, this can also be done using the `*` operator: + + Foo[*tuple[int, str]] + class Bar(Generic[*Ts]): ... + +The operator can also be used along with a `TypedDict` to annotate +`**kwargs` in a function signature. For instance: + + class Movie(TypedDict): + name: str + year: int + + # This function expects two keyword arguments - *name* of type `str` and + # *year* of type `int`. + def foo(**kwargs: Unpack[Movie]): ... + +Note that there is only some runtime checking of this operator. Not +everything the runtime allows may be accepted by static type checkers. + +For more information, see PEP 646 and PEP 692. +""" + + +if sys.version_info >= (3, 12): # PEP 692 changed the repr of Unpack[] + Unpack = typing.Unpack + + def _is_unpack(obj): + return get_origin(obj) is Unpack + +elif sys.version_info[:2] >= (3, 9): + class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, getitem): + super().__init__(getitem) + self.__doc__ = _UNPACK_DOC + + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + @_UnpackSpecialForm + def Unpack(self, parameters): + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + +else: + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + class _UnpackForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + Unpack = _UnpackForm('Unpack', doc=_UNPACK_DOC) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +if hasattr(typing, "TypeVarTuple"): # 3.11+ + + # Add default parameter - PEP 696 + class TypeVarTuple(metaclass=_TypeVarLikeMeta): + """Type variable tuple.""" + + _backported_typevarlike = typing.TypeVarTuple + + def __new__(cls, name, *, default=_marker): + tvt = typing.TypeVarTuple(name) + _set_default(tvt, default) + _set_module(tvt) + return tvt + + def __init_subclass__(self, *args, **kwds): + raise TypeError("Cannot subclass special typing classes") + +else: + class TypeVarTuple(_DefaultMixin): + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name, *, default=_marker): + self.__name__ = name + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] + + def __repr__(self): + return self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") + + +if hasattr(typing, "reveal_type"): + reveal_type = typing.reveal_type +else: + def reveal_type(__obj: T) -> T: + """Reveal the inferred type of a variable. + + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: + + x: int = 1 + reveal_type(x) + + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. + + At runtime, the function prints the runtime type of the + argument and returns it unchanged. + + """ + print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr) + return __obj + + +if hasattr(typing, "assert_never"): + assert_never = typing.assert_never +else: + def assert_never(__arg: Never) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + raise AssertionError("Expected code to be unreachable") + + +if sys.version_info >= (3, 12): + # dataclass_transform exists in 3.11 but lacks the frozen_default parameter + dataclass_transform = typing.dataclass_transform +else: + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + frozen_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``frozen_default`` indicates whether the ``frozen`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "frozen_default": frozen_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +if hasattr(typing, "override"): + override = typing.override +else: + _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) + + def override(__arg: _F) -> _F: + """Indicate that a method is intended to override a method in a base class. + + Usage: + + class Base: + def method(self) -> None: ... + pass + + class Child(Base): + @override + def method(self) -> None: + super().method() + + When this decorator is applied to a method, the type checker will + validate that it overrides a method with the same name on a base class. + This helps prevent bugs that may occur when a base class is changed + without an equivalent change to a child class. + + There is no runtime checking of these properties. The decorator + sets the ``__override__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + + See PEP 698 for details. + + """ + try: + __arg.__override__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return __arg + + +if hasattr(typing, "deprecated"): + deprecated = typing.deprecated +else: + _T = typing.TypeVar("_T") + + def deprecated( + __msg: str, + *, + category: typing.Optional[typing.Type[Warning]] = DeprecationWarning, + stacklevel: int = 1, + ) -> typing.Callable[[_T], _T]: + """Indicate that a class, function or overload is deprecated. + + Usage: + + @deprecated("Use B instead") + class A: + pass + + @deprecated("Use g instead") + def f(): + pass + + @overload + @deprecated("int support is deprecated") + def g(x: int) -> int: ... + @overload + def g(x: str) -> int: ... + + When this decorator is applied to an object, the type checker + will generate a diagnostic on usage of the deprecated object. + + The warning specified by ``category`` will be emitted on use + of deprecated objects. For functions, that happens on calls; + for classes, on instantiation. If the ``category`` is ``None``, + no warning is emitted. The ``stacklevel`` determines where the + warning is emitted. If it is ``1`` (the default), the warning + is emitted at the direct caller of the deprecated object; if it + is higher, it is emitted further up the stack. + + The decorator sets the ``__deprecated__`` + attribute on the decorated object to the deprecation message + passed to the decorator. If applied to an overload, the decorator + must be after the ``@overload`` decorator for the attribute to + exist on the overload as returned by ``get_overloads()``. + + See PEP 702 for details. + + """ + def decorator(__arg: _T) -> _T: + if category is None: + __arg.__deprecated__ = __msg + return __arg + elif isinstance(__arg, type): + original_new = __arg.__new__ + has_init = __arg.__init__ is not object.__init__ + + @functools.wraps(original_new) + def __new__(cls, *args, **kwargs): + warnings.warn(__msg, category=category, stacklevel=stacklevel + 1) + if original_new is not object.__new__: + return original_new(cls, *args, **kwargs) + # Mirrors a similar check in object.__new__. + elif not has_init and (args or kwargs): + raise TypeError(f"{cls.__name__}() takes no arguments") + else: + return original_new(cls) + + __arg.__new__ = staticmethod(__new__) + __arg.__deprecated__ = __new__.__deprecated__ = __msg + return __arg + elif callable(__arg): + @functools.wraps(__arg) + def wrapper(*args, **kwargs): + warnings.warn(__msg, category=category, stacklevel=stacklevel + 1) + return __arg(*args, **kwargs) + + __arg.__deprecated__ = wrapper.__deprecated__ = __msg + return wrapper + else: + raise TypeError( + "@deprecated decorator with non-None category must be applied to " + f"a class or callable, not {__arg!r}" + ) + + return decorator + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + typing._collect_type_vars = _collect_type_vars + typing._check_generic = _check_generic + + +# Backport typing.NamedTuple as it exists in Python 3.12. +# In 3.11, the ability to define generic `NamedTuple`s was supported. +# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. +# On 3.12, we added __orig_bases__ to call-based NamedTuples +# On 3.13, we deprecated kwargs-based NamedTuples +if sys.version_info >= (3, 13): + NamedTuple = typing.NamedTuple +else: + def _make_nmtuple(name, types, module, defaults=()): + fields = [n for n, t in types] + annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") + for n, t in types} + nm_tpl = collections.namedtuple(name, fields, + defaults=defaults, module=module) + nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations + # The `_field_types` attribute was removed in 3.9; + # in earlier versions, it is the same as the `__annotations__` attribute + if sys.version_info < (3, 9): + nm_tpl._field_types = annotations + return nm_tpl + + _prohibited_namedtuple_fields = typing._prohibited + _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) + + class _NamedTupleMeta(type): + def __new__(cls, typename, bases, ns): + assert _NamedTuple in bases + for base in bases: + if base is not _NamedTuple and base is not typing.Generic: + raise TypeError( + 'can only inherit from a NamedTuple type and Generic') + bases = tuple(tuple if base is _NamedTuple else base for base in bases) + types = ns.get('__annotations__', {}) + default_names = [] + for field_name in types: + if field_name in ns: + default_names.append(field_name) + elif default_names: + raise TypeError(f"Non-default namedtuple field {field_name} " + f"cannot follow default field" + f"{'s' if len(default_names) > 1 else ''} " + f"{', '.join(default_names)}") + nm_tpl = _make_nmtuple( + typename, types.items(), + defaults=[ns[n] for n in default_names], + module=ns['__module__'] + ) + nm_tpl.__bases__ = bases + if typing.Generic in bases: + if hasattr(typing, '_generic_class_getitem'): # 3.12+ + nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem) + else: + class_getitem = typing.Generic.__class_getitem__.__func__ + nm_tpl.__class_getitem__ = classmethod(class_getitem) + # update from user namespace without overriding special namedtuple attributes + for key in ns: + if key in _prohibited_namedtuple_fields: + raise AttributeError("Cannot overwrite NamedTuple attribute " + key) + elif key not in _special_namedtuple_fields and key not in nm_tpl._fields: + setattr(nm_tpl, key, ns[key]) + if typing.Generic in bases: + nm_tpl.__init_subclass__() + return nm_tpl + + _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) + + def _namedtuple_mro_entries(bases): + assert NamedTuple in bases + return (_NamedTuple,) + + @_ensure_subclassable(_namedtuple_mro_entries) + def NamedTuple(__typename, __fields=_marker, **kwargs): + """Typed version of namedtuple. + + Usage:: + + class Employee(NamedTuple): + name: str + id: int + + This is equivalent to:: + + Employee = collections.namedtuple('Employee', ['name', 'id']) + + The resulting class has an extra __annotations__ attribute, giving a + dict that maps field names to types. (The field names are also in + the _fields attribute, which is part of the namedtuple API.) + An alternative equivalent functional syntax is also accepted:: + + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + """ + if __fields is _marker: + if kwargs: + deprecated_thing = "Creating NamedTuple classes using keyword arguments" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "Use the class-based or functional syntax instead." + ) + else: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + example = f"`{__typename} = NamedTuple({__typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif __fields is None: + if kwargs: + raise TypeError( + "Cannot pass `None` as the 'fields' parameter " + "and also specify fields using keyword arguments" + ) + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + example = f"`{__typename} = NamedTuple({__typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif kwargs: + raise TypeError("Either list of fields or keywords" + " can be provided to NamedTuple, not both") + if __fields is _marker or __fields is None: + warnings.warn( + deprecation_msg.format(name=deprecated_thing, remove="3.15"), + DeprecationWarning, + stacklevel=2, + ) + __fields = kwargs.items() + nt = _make_nmtuple(__typename, __fields, module=_caller()) + nt.__orig_bases__ = (NamedTuple,) + return nt + + # On 3.8+, alter the signature so that it matches typing.NamedTuple. + # The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7, + # so just leave the signature as it is on 3.7. + if sys.version_info >= (3, 8): + _new_signature = '(typename, fields=None, /, **kwargs)' + if isinstance(NamedTuple, _types.FunctionType): + NamedTuple.__text_signature__ = _new_signature + else: + NamedTuple.__call__.__text_signature__ = _new_signature + + +if hasattr(collections.abc, "Buffer"): + Buffer = collections.abc.Buffer +else: + class Buffer(abc.ABC): + """Base class for classes that implement the buffer protocol. + + The buffer protocol allows Python objects to expose a low-level + memory buffer interface. Before Python 3.12, it is not possible + to implement the buffer protocol in pure Python code, or even + to check whether a class implements the buffer protocol. In + Python 3.12 and higher, the ``__buffer__`` method allows access + to the buffer protocol from Python code, and the + ``collections.abc.Buffer`` ABC allows checking whether a class + implements the buffer protocol. + + To indicate support for the buffer protocol in earlier versions, + inherit from this ABC, either in a stub file or at runtime, + or use ABC registration. This ABC provides no methods, because + there is no Python-accessible methods shared by pre-3.12 buffer + classes. It is useful primarily for static checks. + + """ + + # As a courtesy, register the most common stdlib buffer classes. + Buffer.register(memoryview) + Buffer.register(bytearray) + Buffer.register(bytes) + + +# Backport of types.get_original_bases, available on 3.12+ in CPython +if hasattr(_types, "get_original_bases"): + get_original_bases = _types.get_original_bases +else: + def get_original_bases(__cls): + """Return the class's "original" bases prior to modification by `__mro_entries__`. + + Examples:: + + from typing import TypeVar, Generic + from typing_extensions import NamedTuple, TypedDict + + T = TypeVar("T") + class Foo(Generic[T]): ... + class Bar(Foo[int], float): ... + class Baz(list[str]): ... + Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) + Spam = TypedDict("Spam", {"a": int, "b": str}) + + assert get_original_bases(Bar) == (Foo[int], float) + assert get_original_bases(Baz) == (list[str],) + assert get_original_bases(Eggs) == (NamedTuple,) + assert get_original_bases(Spam) == (TypedDict,) + assert get_original_bases(int) == (object,) + """ + try: + return __cls.__orig_bases__ + except AttributeError: + try: + return __cls.__bases__ + except AttributeError: + raise TypeError( + f'Expected an instance of type, not {type(__cls).__name__!r}' + ) from None + + +# NewType is a class on Python 3.10+, making it pickleable +# The error message for subclassing instances of NewType was improved on 3.11+ +if sys.version_info >= (3, 11): + NewType = typing.NewType +else: + class NewType: + """NewType creates simple unique types with almost zero + runtime overhead. NewType(name, tp) is considered a subtype of tp + by static type checkers. At runtime, NewType(name, tp) returns + a dummy callable that simply returns its argument. Usage:: + UserId = NewType('UserId', int) + def name_by_id(user_id: UserId) -> str: + ... + UserId('user') # Fails type check + name_by_id(42) # Fails type check + name_by_id(UserId(42)) # OK + num = UserId(5) + 1 # type: int + """ + + def __call__(self, obj): + return obj + + def __init__(self, name, tp): + self.__qualname__ = name + if '.' in name: + name = name.rpartition('.')[-1] + self.__name__ = name + self.__supertype__ = tp + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __mro_entries__(self, bases): + # We defined __mro_entries__ to get a better error message + # if a user attempts to subclass a NewType instance. bpo-46170 + supercls_name = self.__name__ + + class Dummy: + def __init_subclass__(cls): + subcls_name = cls.__name__ + raise TypeError( + f"Cannot subclass an instance of NewType. " + f"Perhaps you were looking for: " + f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`" + ) + + return (Dummy,) + + def __repr__(self): + return f'{self.__module__}.{self.__qualname__}' + + def __reduce__(self): + return self.__qualname__ + + if sys.version_info >= (3, 10): + # PEP 604 methods + # It doesn't make sense to have these methods on Python <3.10 + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + +if hasattr(typing, "TypeAliasType"): + TypeAliasType = typing.TypeAliasType +else: + def _is_unionable(obj): + """Corresponds to is_unionable() in unionobject.c in CPython.""" + return obj is None or isinstance(obj, ( + type, + _types.GenericAlias, + _types.UnionType, + TypeAliasType, + )) + + class TypeAliasType: + """Create named, parameterized type aliases. + + This provides a backport of the new `type` statement in Python 3.12: + + type ListOrSet[T] = list[T] | set[T] + + is equivalent to: + + T = TypeVar("T") + ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,)) + + The name ListOrSet can then be used as an alias for the type it refers to. + + The type_params argument should contain all the type parameters used + in the value of the type alias. If the alias is not generic, this + argument is omitted. + + Static type checkers should only support type aliases declared using + TypeAliasType that follow these rules: + + - The first argument (the name) must be a string literal. + - The TypeAliasType instance must be immediately assigned to a variable + of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid, + as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)'). + + """ + + def __init__(self, name: str, value, *, type_params=()): + if not isinstance(name, str): + raise TypeError("TypeAliasType name must be a string") + self.__value__ = value + self.__type_params__ = type_params + + parameters = [] + for type_param in type_params: + if isinstance(type_param, TypeVarTuple): + parameters.extend(type_param) + else: + parameters.append(type_param) + self.__parameters__ = tuple(parameters) + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + # Setting this attribute closes the TypeAliasType from further modification + self.__name__ = name + + def __setattr__(self, __name: str, __value: object) -> None: + if hasattr(self, "__name__"): + self._raise_attribute_error(__name) + super().__setattr__(__name, __value) + + def __delattr__(self, __name: str) -> Never: + self._raise_attribute_error(__name) + + def _raise_attribute_error(self, name: str) -> Never: + # Match the Python 3.12 error messages exactly + if name == "__name__": + raise AttributeError("readonly attribute") + elif name in {"__value__", "__type_params__", "__parameters__", "__module__"}: + raise AttributeError( + f"attribute '{name}' of 'typing.TypeAliasType' objects " + "is not writable" + ) + else: + raise AttributeError( + f"'typing.TypeAliasType' object has no attribute '{name}'" + ) + + def __repr__(self) -> str: + return self.__name__ + + def __getitem__(self, parameters): + if not isinstance(parameters, tuple): + parameters = (parameters,) + parameters = [ + typing._type_check( + item, f'Subscripting {self.__name__} requires a type.' + ) + for item in parameters + ] + return typing._GenericAlias(self, tuple(parameters)) + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + "type 'typing_extensions.TypeAliasType' is not an acceptable base type" + ) + + # The presence of this method convinces typing._type_check + # that TypeAliasTypes are types. + def __call__(self): + raise TypeError("Type alias is not callable") + + if sys.version_info >= (3, 10): + def __or__(self, right): + # For forward compatibility with 3.12, reject Unions + # that are not accepted by the built-in Union. + if not _is_unionable(right): + return NotImplemented + return typing.Union[self, right] + + def __ror__(self, left): + if not _is_unionable(left): + return NotImplemented + return typing.Union[left, self] + + +if hasattr(typing, "is_protocol"): + is_protocol = typing.is_protocol + get_protocol_members = typing.get_protocol_members +else: + def is_protocol(__tp: type) -> bool: + """Return True if the given type is a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, is_protocol + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> is_protocol(P) + True + >>> is_protocol(int) + False + """ + return ( + isinstance(__tp, type) + and getattr(__tp, '_is_protocol', False) + and __tp is not Protocol + and __tp is not getattr(typing, "Protocol", object()) + ) + + def get_protocol_members(__tp: type) -> typing.FrozenSet[str]: + """Return the set of members defined in a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, get_protocol_members + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> get_protocol_members(P) + frozenset({'a', 'b'}) + + Raise a TypeError for arguments that are not Protocols. + """ + if not is_protocol(__tp): + raise TypeError(f'{__tp!r} is not a Protocol') + if hasattr(__tp, '__protocol_attrs__'): + return frozenset(__tp.__protocol_attrs__) + return frozenset(_get_protocol_attrs(__tp)) + + +# Aliases for items that have always been in typing. +# Explicitly assign these (rather than using `from typing import *` at the top), +# so that we get a CI error if one of these is deleted from typing.py +# in a future version of Python +AbstractSet = typing.AbstractSet +AnyStr = typing.AnyStr +BinaryIO = typing.BinaryIO +Callable = typing.Callable +Collection = typing.Collection +Container = typing.Container +Dict = typing.Dict +ForwardRef = typing.ForwardRef +FrozenSet = typing.FrozenSet +Generator = typing.Generator +Generic = typing.Generic +Hashable = typing.Hashable +IO = typing.IO +ItemsView = typing.ItemsView +Iterable = typing.Iterable +Iterator = typing.Iterator +KeysView = typing.KeysView +List = typing.List +Mapping = typing.Mapping +MappingView = typing.MappingView +Match = typing.Match +MutableMapping = typing.MutableMapping +MutableSequence = typing.MutableSequence +MutableSet = typing.MutableSet +Optional = typing.Optional +Pattern = typing.Pattern +Reversible = typing.Reversible +Sequence = typing.Sequence +Set = typing.Set +Sized = typing.Sized +TextIO = typing.TextIO +Tuple = typing.Tuple +Union = typing.Union +ValuesView = typing.ValuesView +cast = typing.cast +no_type_check = typing.no_type_check +no_type_check_decorator = typing.no_type_check_decorator diff --git a/mysteriendrama/__pycache__/settings.cpython-311.pyc b/mysteriendrama/__pycache__/settings.cpython-311.pyc index e1ae18e9a3c223fa19456098ac992316ebb6ae4f..078d6b448e2e77f8306420893e4846a3370793d0 100644 GIT binary patch delta 533 zcmZ1~x=>7gIWI340}x!bJ&^K*mx19ihyw#0P{!wf6V=y-r3eC{P>OJhNQ&qjwoJw- z{uHqk@k~Y_DFG%W!K73sV>(NeK#FvfV2VtXPzpwLW z3(BxaaZd>|eQh)S}E@-=ZZF!A-b@N{<15B75`D04H_4sk6s(=YPOa|!TD52+H& ztt>7{Ey_&IODRgsP1H+C)nu;{Ny$pgOV8I!&d)0;%1qKr-29d)p1EEYDx8v}mz0>C z4b)PsSCC&^l3tWrT$po92-T?g^3E`BX6(L3*l_mzENfs8#MOkKv zmZiQSd5IyZX2pI{sh*WlDOF-Asd+$S6Lo~W#ni;uNK=>X7MrV| zyQiP)EfzmVUmzJ8>>6~7Bfv2@INU$T=48@N8OF>vxWus#q}xgelAc{XR2vf&K@6%Z0}x*?!(LqO~UFS`KS2L=$q U%*o5t!1+OGvLROiiyqJ*0D!ZfeEN<2j- zm_bu^vlgQpW2jR~R$^XyzHVk-acXjDQL3(iZBc1*NwR58R| ziAxh03XDKp95;Cjr?+4bV*}R*HU>`K2G$3H78e98Ckt>@$>`k>keFd}Q9%6zE3*LG Y2L=$q%*xBu!1+OH@>;F}7ImNr0E1p;82|tP diff --git a/templates/anmeldung.html b/templates/anmeldung.html index ae0b810..c044a68 100644 --- a/templates/anmeldung.html +++ b/templates/anmeldung.html @@ -6,7 +6,7 @@