1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
# util/_preloaded.py
# Copyright (C) 2005-2023 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: https://www.opensource.org/licenses/mit-license.php
# mypy: allow-untyped-defs, allow-untyped-calls
"""supplies the "preloaded" registry to resolve circular module imports at
runtime.
"""
from __future__ import annotations
import sys
from typing import Any
from typing import Callable
from typing import TYPE_CHECKING
from typing import TypeVar
_FN = TypeVar("_FN", bound=Callable[..., Any])
if TYPE_CHECKING:
from sqlalchemy import dialects as _dialects
from sqlalchemy import orm as _orm
from sqlalchemy.engine import cursor as _engine_cursor
from sqlalchemy.engine import default as _engine_default
from sqlalchemy.engine import reflection as _engine_reflection
from sqlalchemy.engine import result as _engine_result
from sqlalchemy.engine import url as _engine_url
from sqlalchemy.orm import attributes as _orm_attributes
from sqlalchemy.orm import base as _orm_base
from sqlalchemy.orm import clsregistry as _orm_clsregistry
from sqlalchemy.orm import decl_api as _orm_decl_api
from sqlalchemy.orm import decl_base as _orm_decl_base
from sqlalchemy.orm import dependency as _orm_dependency
from sqlalchemy.orm import descriptor_props as _orm_descriptor_props
from sqlalchemy.orm import mapperlib as _orm_mapper
from sqlalchemy.orm import properties as _orm_properties
from sqlalchemy.orm import relationships as _orm_relationships
from sqlalchemy.orm import session as _orm_session
from sqlalchemy.orm import state as _orm_state
from sqlalchemy.orm import strategies as _orm_strategies
from sqlalchemy.orm import strategy_options as _orm_strategy_options
from sqlalchemy.orm import util as _orm_util
from sqlalchemy.sql import default_comparator as _sql_default_comparator
from sqlalchemy.sql import dml as _sql_dml
from sqlalchemy.sql import elements as _sql_elements
from sqlalchemy.sql import functions as _sql_functions
from sqlalchemy.sql import naming as _sql_naming
from sqlalchemy.sql import schema as _sql_schema
from sqlalchemy.sql import selectable as _sql_selectable
from sqlalchemy.sql import sqltypes as _sql_sqltypes
from sqlalchemy.sql import traversals as _sql_traversals
from sqlalchemy.sql import util as _sql_util
# sigh, appease mypy 0.971 which does not accept imports as instance
# variables of a module
dialects = _dialects
engine_cursor = _engine_cursor
engine_default = _engine_default
engine_reflection = _engine_reflection
engine_result = _engine_result
engine_url = _engine_url
orm_clsregistry = _orm_clsregistry
orm_base = _orm_base
orm = _orm
orm_attributes = _orm_attributes
orm_decl_api = _orm_decl_api
orm_decl_base = _orm_decl_base
orm_descriptor_props = _orm_descriptor_props
orm_dependency = _orm_dependency
orm_mapper = _orm_mapper
orm_properties = _orm_properties
orm_relationships = _orm_relationships
orm_session = _orm_session
orm_strategies = _orm_strategies
orm_strategy_options = _orm_strategy_options
orm_state = _orm_state
orm_util = _orm_util
sql_default_comparator = _sql_default_comparator
sql_dml = _sql_dml
sql_elements = _sql_elements
sql_functions = _sql_functions
sql_naming = _sql_naming
sql_selectable = _sql_selectable
sql_traversals = _sql_traversals
sql_schema = _sql_schema
sql_sqltypes = _sql_sqltypes
sql_util = _sql_util
class _ModuleRegistry:
"""Registry of modules to load in a package init file.
To avoid potential thread safety issues for imports that are deferred
in a function, like https://bugs.python.org/issue38884, these modules
are added to the system module cache by importing them after the packages
has finished initialization.
A global instance is provided under the name :attr:`.preloaded`. Use
the function :func:`.preload_module` to register modules to load and
:meth:`.import_prefix` to load all the modules that start with the
given path.
While the modules are loaded in the global module cache, it's advisable
to access them using :attr:`.preloaded` to ensure that it was actually
registered. Each registered module is added to the instance ``__dict__``
in the form `<package>_<module>`, omitting ``sqlalchemy`` from the package
name. Example: ``sqlalchemy.sql.util`` becomes ``preloaded.sql_util``.
"""
def __init__(self, prefix="sqlalchemy."):
self.module_registry = set()
self.prefix = prefix
def preload_module(self, *deps: str) -> Callable[[_FN], _FN]:
"""Adds the specified modules to the list to load.
This method can be used both as a normal function and as a decorator.
No change is performed to the decorated object.
"""
self.module_registry.update(deps)
return lambda fn: fn
def import_prefix(self, path: str) -> None:
"""Resolve all the modules in the registry that start with the
specified path.
"""
for module in self.module_registry:
if self.prefix:
key = module.split(self.prefix)[-1].replace(".", "_")
else:
key = module
if (
not path or module.startswith(path)
) and key not in self.__dict__:
__import__(module, globals(), locals())
self.__dict__[key] = globals()[key] = sys.modules[module]
_reg = _ModuleRegistry()
preload_module = _reg.preload_module
import_prefix = _reg.import_prefix
# this appears to do absolutely nothing for any version of mypy
# if TYPE_CHECKING:
# def __getattr__(key: str) -> ModuleType:
# ...
|