Skip to content

Commit 75c7675

Browse files
Deprecation getter
1 parent b9d9ab4 commit 75c7675

2 files changed

Lines changed: 130 additions & 0 deletions

File tree

pymc/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __set_compiler_flags():
4747
__set_compiler_flags()
4848

4949
from pymc import _version, exceptions, gp, math, ode, plots, sampling, stats
50+
from pymc._deprecations import resolve as _resolve_deprecated_root_attribute
5051
from pymc.backends import *
5152
from pymc.data import *
5253
from pymc.distributions import *
@@ -63,4 +64,9 @@ def __set_compiler_flags():
6364
from pymc.tuning import *
6465
from pymc.variational import *
6566

67+
68+
def __getattr__(name: str):
69+
return _resolve_deprecated_root_attribute(name)
70+
71+
6672
__version__ = _version.get_versions()["version"]

pymc/_deprecations.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Copyright 2024 - present The PyMC Developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import importlib
16+
import warnings
17+
18+
# Symbols hand-relocated to a specific submodule during the namespace cleanup.
19+
_RELOCATED: dict[str, str] = {
20+
# blocking
21+
"DictToArrayBijection": "pymc.blocking",
22+
# exceptions
23+
"BlockModelAccessError": "pymc.exceptions",
24+
"DtypeError": "pymc.exceptions",
25+
"ImputationWarning": "pymc.exceptions",
26+
"IncorrectArgumentsError": "pymc.exceptions",
27+
"NotConstantValueError": "pymc.exceptions",
28+
"SamplingError": "pymc.exceptions",
29+
"ShapeError": "pymc.exceptions",
30+
"ShapeWarning": "pymc.exceptions",
31+
"TraceDirectoryError": "pymc.exceptions",
32+
"TruncationError": "pymc.exceptions",
33+
"UndefinedMomentException": "pymc.exceptions",
34+
# math
35+
"expand_packed_triangular": "pymc.math",
36+
"invlogit": "pymc.math",
37+
"invprobit": "pymc.math",
38+
"logaddexp": "pymc.math",
39+
"logit": "pymc.math",
40+
"logsumexp": "pymc.math",
41+
"probit": "pymc.math",
42+
# printing
43+
"str_for_data_var": "pymc.printing",
44+
"str_for_dist": "pymc.printing",
45+
"str_for_model": "pymc.printing",
46+
"str_for_potential_or_deterministic": "pymc.printing",
47+
# pytensorf
48+
"CallableTensor": "pymc.pytensorf",
49+
"cont_inputs": "pymc.pytensorf",
50+
"convert_data": "pymc.pytensorf",
51+
"convert_observed_data": "pymc.pytensorf",
52+
"floatX": "pymc.pytensorf",
53+
"gradient": "pymc.pytensorf",
54+
"hessian": "pymc.pytensorf",
55+
"hessian_diag": "pymc.pytensorf",
56+
"inputvars": "pymc.pytensorf",
57+
"intX": "pymc.pytensorf",
58+
"jacobian": "pymc.pytensorf",
59+
"join_nonshared_inputs": "pymc.pytensorf",
60+
"make_shared_replacements": "pymc.pytensorf",
61+
# stats
62+
"compute_log_prior": "pymc.stats",
63+
# step_methods
64+
"BlockedStep": "pymc.step_methods",
65+
"CauchyProposal": "pymc.step_methods",
66+
"CompoundStep": "pymc.step_methods",
67+
"LaplaceProposal": "pymc.step_methods",
68+
"MultivariateNormalProposal": "pymc.step_methods",
69+
"NormalProposal": "pymc.step_methods",
70+
"PoissonProposal": "pymc.step_methods",
71+
"STEP_METHODS": "pymc.step_methods",
72+
"UniformProposal": "pymc.step_methods",
73+
# tuning
74+
"guess_scaling": "pymc.tuning",
75+
"trace_cov": "pymc.tuning",
76+
# util
77+
"drop_warning_stat": "pymc.util",
78+
# variational
79+
"Approximation": "pymc.variational",
80+
"ImplicitGradient": "pymc.variational",
81+
"Inference": "pymc.variational",
82+
"KLqp": "pymc.variational",
83+
"Stein": "pymc.variational",
84+
# vartypes
85+
"bool_types": "pymc.vartypes",
86+
"complex_types": "pymc.vartypes",
87+
"continuous_types": "pymc.vartypes",
88+
"discrete_types": "pymc.vartypes",
89+
"float_types": "pymc.vartypes",
90+
"int_types": "pymc.vartypes",
91+
"isgenerator": "pymc.vartypes",
92+
"typefilter": "pymc.vartypes",
93+
}
94+
95+
# Bulk-relocated namespaces. A miss in :data:`_RELOCATED` falls back to looking
96+
# the name up in each of these submodules, which covers the dozens of
97+
# ``arviz_plots`` / ``arviz_stats`` functions that used to leak into the root.
98+
_FALLBACK_SUBMODULES: tuple[str, ...] = ("pymc.plots", "pymc.stats")
99+
100+
101+
def _warn(name: str, new_path: str) -> None:
102+
warnings.warn(
103+
f"`pymc.{name}` was moved out of the root namespace and will be removed in "
104+
f"the first PyMC release of 2027. Use `{new_path}` instead.",
105+
DeprecationWarning,
106+
stacklevel=4,
107+
)
108+
109+
110+
def resolve(name: str):
111+
"""Resolve a removed root-namespace symbol or raise ``AttributeError``."""
112+
target_module = _RELOCATED.get(name)
113+
if target_module is not None:
114+
module = importlib.import_module(target_module)
115+
_warn(name, f"{target_module}.{name}")
116+
return getattr(module, name)
117+
118+
for submodule_path in _FALLBACK_SUBMODULES:
119+
module = importlib.import_module(submodule_path)
120+
if hasattr(module, name):
121+
_warn(name, f"{submodule_path}.{name}")
122+
return getattr(module, name)
123+
124+
raise AttributeError(f"module 'pymc' has no attribute {name!r}")

0 commit comments

Comments
 (0)