diff --git a/pep-562.rst b/pep-562.rst new file mode 100644 index 000000000..d16f3b6eb --- /dev/null +++ b/pep-562.rst @@ -0,0 +1,105 @@ +PEP: 562 +Title: Module __getattr__ +Author: Ivan Levkivskyi +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 09-Sep-2017 +Python-Version: 3.7 +Post-History: 09-Sep-2017 + + +Abstract +======== + +It is proposed to support ``__getattr__`` function defined on modules to +provide basic customization of module attribute access. + + +Rationale +========= + +It is sometimes convenient to customize or otherwise have control over +access to module attributes. A typical example is managing deprecation +warnings. Typical workarounds are assigning ``__class__`` of a module object +to a custom subclass of ``types.ModuleType`` or substituting ``sys.modules`` +item with a custom wrapper instance. It would be convenient to simplify this +procedure by recognizing ``__getattr__`` defined directly in a module that +would act like a normal ``__getattr__`` method, except that it will be defined +on module *instances*. For example:: + + # lib.py + + from warnings import warn + + deprecated_names = ["old_function", ...] + + def _deprecated_old_function(arg, other): + ... + + def __getattr__(name): + if name in deprecated_names: + warn(f"{name} is deprecated", DeprecationWarning) + return globals()[f"_deprecated_{name}"] + raise AttributeError(f"module {__name__} has no attribute {name}") + + # main.py + + from lib import old_function # Works, but emits the warning + +There is a related proposal PEP 549 that proposes to support instance +properties for a similar functionality. The difference is this PEP proposes +a faster and simpler mechanism, but provides more basic customization. +An additional motivation for this proposal is that PEP 484 already defines +the use of module ``__getattr__`` for this purpose in Python stub files, +see [1]_. + + +Specification +============= + +The ``__getattr__`` function at the module level should accept one argument +which is a name of an attribute and return the computed value or raise +an ``AttributeError``:: + + def __getattr__(name: str) -> Any: ... + +This function will be called only if ``name`` is not found in the module +through the normal attribute lookup. + +The reference implementation for this PEP can be found in [2]_. + + +Backwards compatibility and impact on performance +================================================= + +This PEP may break code that uses module level (global) name ``__getattr__``. +The performance implications of this PEP are minimal, since ``__getattr__`` +is called only for missing attributes. + + +References +========== + +.. [1] PEP 484 section about ``__getattr__`` in stub files + (https://www.python.org/dev/peps/pep-0484/#stub-files) + +.. [2] The reference implementation + (https://github.com/ilevkivskyi/cpython/pull/3/files) + + +Copyright +========= + +This document has been placed in the public domain. + + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: