A quick way to create a new class called *name* with *attrs*. :param str name: The name for the new class. :param attrs: A list of names or a dictionary of mappings of names to attributes. If *attrs* is a list or an ordered dict (`dict` on Python 3.6+, `collec
(name, attrs, bases=(object,), **attributes_arguments)
| 3008 | |
| 3009 | |
| 3010 | def make_class(name, attrs, bases=(object,), **attributes_arguments): |
| 3011 | """ |
| 3012 | A quick way to create a new class called *name* with *attrs*. |
| 3013 | |
| 3014 | :param str name: The name for the new class. |
| 3015 | |
| 3016 | :param attrs: A list of names or a dictionary of mappings of names to |
| 3017 | attributes. |
| 3018 | |
| 3019 | If *attrs* is a list or an ordered dict (`dict` on Python 3.6+, |
| 3020 | `collections.OrderedDict` otherwise), the order is deduced from |
| 3021 | the order of the names or attributes inside *attrs*. Otherwise the |
| 3022 | order of the definition of the attributes is used. |
| 3023 | :type attrs: `list` or `dict` |
| 3024 | |
| 3025 | :param tuple bases: Classes that the new class will subclass. |
| 3026 | |
| 3027 | :param attributes_arguments: Passed unmodified to `attr.s`. |
| 3028 | |
| 3029 | :return: A new class with *attrs*. |
| 3030 | :rtype: type |
| 3031 | |
| 3032 | .. versionadded:: 17.1.0 *bases* |
| 3033 | .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. |
| 3034 | """ |
| 3035 | if isinstance(attrs, dict): |
| 3036 | cls_dict = attrs |
| 3037 | elif isinstance(attrs, (list, tuple)): |
| 3038 | cls_dict = dict((a, attrib()) for a in attrs) |
| 3039 | else: |
| 3040 | raise TypeError("attrs argument must be a dict or a list.") |
| 3041 | |
| 3042 | pre_init = cls_dict.pop("__attrs_pre_init__", None) |
| 3043 | post_init = cls_dict.pop("__attrs_post_init__", None) |
| 3044 | user_init = cls_dict.pop("__init__", None) |
| 3045 | |
| 3046 | body = {} |
| 3047 | if pre_init is not None: |
| 3048 | body["__attrs_pre_init__"] = pre_init |
| 3049 | if post_init is not None: |
| 3050 | body["__attrs_post_init__"] = post_init |
| 3051 | if user_init is not None: |
| 3052 | body["__init__"] = user_init |
| 3053 | |
| 3054 | type_ = new_class(name, bases, {}, lambda ns: ns.update(body)) |
| 3055 | |
| 3056 | # For pickling to work, the __module__ variable needs to be set to the |
| 3057 | # frame where the class is created. Bypass this step in environments where |
| 3058 | # sys._getframe is not defined (Jython for example) or sys._getframe is not |
| 3059 | # defined for arguments greater than 0 (IronPython). |
| 3060 | try: |
| 3061 | type_.__module__ = sys._getframe(1).f_globals.get( |
| 3062 | "__name__", "__main__" |
| 3063 | ) |
| 3064 | except (AttributeError, ValueError): |
| 3065 | pass |
| 3066 | |
| 3067 | # We do it here for proper warnings with meaningful stacklevel. |