Skip to content

Commit da48977

Browse files
authored
Merge pull request #2644 from jsiirola/cython-relocated-attrs
Update relocated_module_attribute to work with cythonized modules
2 parents 34f07c4 + b70b9db commit da48977

File tree

2 files changed

+30
-91
lines changed

2 files changed

+30
-91
lines changed

pyomo/common/deprecation.py

Lines changed: 26 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -272,62 +272,6 @@ def _import_object(name, target, version, remove_in, msg):
272272
deprecation_warning(msg, version=version, remove_in=remove_in)
273273
return _object
274274

275-
class _ModuleGetattrBackport_27(object):
276-
"""Backport for support of module.__getattr__
277-
278-
279-
Beginning in Python 3.7, modules support the declaration of a
280-
module-scoped __getattr__ and __dir__ to allow for the dynamic
281-
resolution of module attributes. This class wraps the module class
282-
and implements `__getattr__`. As it declares no local
283-
attributes, all module attribute accesses incur a slight runtime
284-
penalty (one extra function call).
285-
286-
"""
287-
def __init__(self, module):
288-
# Wrapped module needs to be a local attribute. Everything else
289-
# is delegated to the inner module type
290-
super(_ModuleGetattrBackport_27, self).__setattr__(
291-
'_wrapped_module', module)
292-
293-
def __getattr__(self, name):
294-
try:
295-
return getattr(self._wrapped_module, name)
296-
except AttributeError:
297-
info = self._wrapped_module.__relocated_attrs__.get(name, None)
298-
if info is not None:
299-
target_obj = _import_object(name, *info)
300-
setattr(self, name, target_obj)
301-
return target_obj
302-
raise
303-
304-
def __dir__(self):
305-
return dir(self._wrapped_module)
306-
307-
def __setattr__(self, name, val):
308-
setattr(self._wrapped_module, name, val)
309-
310-
class _ModuleGetattrBackport_35(types.ModuleType):
311-
"""Backport for support of module.__getattr__
312-
313-
Beginning in Python 3.7, modules support the declaration of a
314-
module-scoped __getattr__ and __dir__ to allow for the dynamic
315-
resolution of module attributes. This class derives from
316-
types.ModuleType and implements `__getattr__`. As it is a direct
317-
replacement for types.ModuleType (i.e., we can reassign the already
318-
loaded module to this type, it is more efficient that the
319-
ModuleGetattrBackport_27 class which must wrap the already loaded
320-
module.
321-
322-
"""
323-
def __getattr__(self, name):
324-
info = self.__relocated_attrs__.get(name, None)
325-
if info is not None:
326-
target_obj = _import_object(name, *info)
327-
setattr(self, name, target_obj)
328-
return target_obj
329-
raise AttributeError("module '%s' has no attribute '%s'"
330-
% (self.__name__, name))
331275

332276
def relocated_module(new_name, msg=None, logger=None,
333277
version=None, remove_in=None):
@@ -394,7 +338,7 @@ def relocated_module(new_name, msg=None, logger=None,
394338
'Please update your import.'
395339
deprecation_warning(msg, logger, version, remove_in, cf)
396340

397-
def relocated_module_attribute(local, target, version, remove_in=None, msg=None):
341+
def relocated_module_attribute(local, target, version, remove_in=None, msg=None, f_globals=None):
398342
"""Provide a deprecation path for moved / renamed module attributes
399343
400344
This function declares that a local module attribute has been moved
@@ -429,36 +373,31 @@ def relocated_module_attribute(local, target, version, remove_in=None, msg=None)
429373
location.
430374
431375
"""
432-
_module = sys.modules[inspect.currentframe().f_back.f_globals['__name__']]
433-
if not hasattr(_module, '__relocated_attrs__'):
434-
_module.__relocated_attrs__ = {}
435-
if sys.version_info >= (3,7):
436-
_relocated = _module.__relocated_attrs__
437-
_mod_getattr = getattr(_module, '__getattr__', None)
438-
def __getattr__(name):
439-
info = _relocated.get(name, None)
440-
if info is not None:
441-
target_obj = _import_object(name, *info)
442-
setattr(_module, name, target_obj)
443-
return target_obj
444-
elif _mod_getattr is not None:
445-
return _mod_getattr(name)
446-
raise AttributeError("module '%s' has no attribute '%s'"
447-
% (_module.__name__, name))
448-
_module.__getattr__ = __getattr__
449-
elif sys.version_info >= (3,5):
450-
# If you run across a case where this assertion fails
451-
# (because someone else has messed with the module type), we
452-
# could add logic to use the _ModuleGetattrBackport_27 class
453-
# to wrap the module. However, as I believe that this will
454-
# never happen in Pyomo, it is not worth adding unused
455-
# functionality at this point
456-
assert _module.__class__ is types.ModuleType
457-
_module.__class__ = _ModuleGetattrBackport_35
458-
else: # sys.version_info >= (2,7):
459-
_module = sys.modules[_module.__name__] \
460-
= _ModuleGetattrBackport_27(_module)
461-
_module.__relocated_attrs__[local] = (target, version, remove_in, msg)
376+
# Historical note: This method only works for Python >= 3.7. There
377+
# were backports to previous Python interpreters, but were removed
378+
# after SHA 4e04819aaeefc2c08b7718460918885e12343451
379+
if f_globals is None:
380+
f_globals = inspect.currentframe().f_back.f_globals
381+
if f_globals['__name__'].startswith('importlib.'):
382+
raise DeveloperError(
383+
"relocated_module_attribute() called from a cythonized "
384+
"module without passing f_globals")
385+
_relocated = f_globals.get('__relocated_attrs__', None)
386+
if _relocated is None:
387+
f_globals['__relocated_attrs__'] = _relocated = {}
388+
_mod_getattr = f_globals.get('__getattr__', None)
389+
def __getattr__(name):
390+
info = _relocated.get(name, None)
391+
if info is not None:
392+
target_obj = _import_object(name, *info)
393+
f_globals[name] = target_obj
394+
return target_obj
395+
elif _mod_getattr is not None:
396+
return _mod_getattr(name)
397+
raise AttributeError("module '%s' has no attribute '%s'"
398+
% (f_globals['__name__'], name))
399+
f_globals['__getattr__'] = __getattr__
400+
_relocated[local] = (target, version, remove_in, msg)
462401

463402

464403
class RenamedClass(type):

pyomo/core/expr/logical_expr.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,19 @@
4646
relocated_module_attribute(
4747
'EqualityExpression',
4848
'pyomo.core.expr.relational_expr.EqualityExpression',
49-
version='6.4.3')
49+
version='6.4.3', f_globals=globals())
5050
relocated_module_attribute(
5151
'InequalityExpression',
5252
'pyomo.core.expr.relational_expr.InequalityExpression',
53-
version='6.4.3')
53+
version='6.4.3', f_globals=globals())
5454
relocated_module_attribute(
5555
'RangedExpression',
5656
'pyomo.core.expr.relational_expr.RangedExpression',
57-
version='6.4.3')
57+
version='6.4.3', f_globals=globals())
5858
relocated_module_attribute(
5959
'inequality',
6060
'pyomo.core.expr.relational_expr.inequality',
61-
version='6.4.3')
61+
version='6.4.3', f_globals=globals())
6262

6363

6464
def _generate_logical_proposition(etype, lhs, rhs):

0 commit comments

Comments
 (0)