77840


# やりたいこと

自作ライブラリで、列挙型クラスを公開しています。  
クラスの名前をより良い名前に変更したいのですが、すでに公開しているクラスなので、変更前の名前も利用できるようにしたいです。

# 質問

以下のコードで、ひとまず変更前の名前も利用できるようになりました。

[code]

    from enum import Enum
    class NewColor(Enum):
        """色"""
        RED = 1
        GREEN = 2
        BLUE = 3
    
    OldColor = NewColor
    
[/code]

しかし、上記のコードでは以下の要件を満たせません。

  * `OldColor.__doc__`に、非推奨である旨のメッセージを追加したい
  * `OldColor`を参照した場合（`OldColor.RED`,`OldColor(1)`）は、警告メッセージを出力したい  
この要件を満たすには、どのようなコードを書けばよいでしょうか？

# 補足

通常のクラス場合は、以下のコードで、次の要件を満たせることは分かりました。

  * 変更前のクラスの`__doc__`に、非推奨である旨のメッセージを追加する
  * 変更前のクラスを使ってインスタンス生成する際に、警告メッセージを出力

[code]

    def moved_class(new_class, old_class_name, old_module_name,
                    message=None, version=None, removal_version=None,
                    stacklevel=3, category=None):
        # ...
        def decorator(f):
    
            @six.wraps(f, assigned=_utils.get_assigned(f))
            def wrapper(self, *args, **kwargs):
                _utils.deprecation(out_message, stacklevel=stacklevel,
                                   category=category)
                return f(self, *args, **kwargs)
    
            return wrapper
    
        old_class = type(old_class_name, (new_class,), {})
        old_class.__module__ = old_module_name
        old_class.__init__ = decorator(old_class.__init__)
        return old_class
    
[/code]

<https://opendev.org/openstack/debtcollector/src/branch/master/debtcollector/moves.py#L164>
引用

# 環境

  * Python3.8


CC BY-SA 4.0
2021-06-28T15:04:52.973
77839
2021-06-28T21:27:33.317
19524
question
python
ライブラリで公開している列挙型クラスの名前を変更したいです。変更前と変更後の


`Enum` インスタンスの内容を参照する場合は `__getattribute__()` メソッドをラップします。

[code]

    from my_color import OldColor, NewColor
    
    warning_message = "`OldColor' has moved to `NewColor'"
    def deprecation_warning():
      import warnings
      warnings.warn(
        warning_message, DeprecationWarning, stacklevel=4)
      return True
    
    OldColor.__getattribute__ = (
      lambda cls, name:
        deprecation_warning() and
        super(type(cls), cls).__getattribute__(name)
    )
    
    OldColor.__doc__ += f'\nWarning: {warning_message}.'
    
    if __name__ == '__main__':
      print(OldColor.RED)
      print(OldColor['RED'])
      print(OldColor(1))
    
      print('\ndocstring:')
      print(OldColor.__doc__)
    
[/code]

#### 実行結果

[code]

    deprecated_color.py:19: DeprecationWarning: `OldColor' has moved to `NewColor'
      print(OldColor.RED)
    OldColor.RED
    deprecated_color.py:20: DeprecationWarning: `OldColor' has moved to `NewColor'
      print(OldColor['RED'])
    OldColor.RED
    deprecated_color.py:21: DeprecationWarning: `OldColor' has moved to `NewColor'
      print(OldColor(1))
    OldColor.RED
    
    docstring:
    色
    Warning: `OldColor' has moved to `NewColor'.
    
[/code]


CC BY-SA 4.0
2021-06-28T20:08:29.730
77840
2021-06-28T21:27:33.317
2021-06-28T21:27:33.317
77839
answer