Passed
Pull Request — master (#259)
by Piotr
01:20
created

Settings.__getattribute__()   A

Complexity

Conditions 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
c 1
b 0
f 0
dl 0
loc 13
rs 9.2
1
from django.conf import settings as django_settings
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
from django.test.signals import setting_changed
3
from django.utils import six
4
from django.utils.functional import LazyObject
5
from django.utils.module_loading import import_string
6
7
8
DJOSER_SETTINGS_NAMESPACE = 'DJOSER'
9
10
default_settings = {
0 ignored issues
show
Coding Style Naming introduced by
The name default_settings does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
11
    'PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND': False,
12
    'PASSWORD_VALIDATORS': [],
13
    'TOKEN_MODEL': None,
14
    'VIEW_PIPELINE_ADAPTER':
15
        'djoser.pipelines.base.default_view_pipeline_adapter',
16
17
    'PIPELINES': {
18
        'user_activate': [
19
            'djoser.pipelines.user_activate.serialize_request',
20
            'djoser.pipelines.user_activate.perform',
21
            'djoser.pipelines.user_activate.signal',
22
            'djoser.pipelines.email.confirmation_email',
23
        ],
24
        'user_create': [
25
            'djoser.pipelines.user_create.serialize_request',
26
            'djoser.pipelines.user_create.perform',
27
            'djoser.pipelines.user_create.serialize_instance',
28
            'djoser.pipelines.user_create.signal',
29
            'djoser.pipelines.email.confirmation_email',
30
        ],
31
        'user_detail': [
32
            'djoser.pipelines.user_detail.perform',
33
            'djoser.pipelines.user_detail.serialize_instance',
34
        ],
35
        'user_update': [
36
            'djoser.pipelines.user_update.serialize_request',
37
            'djoser.pipelines.user_update.perform',
38
            'djoser.pipelines.user_update.signal',
39
            'djoser.pipelines.user_update.serialize_instance',
40
        ],
41
        'user_delete': [
42
            'djoser.pipelines.user_delete.serialize_request',
43
            'djoser.pipelines.user_delete.perform',
44
            'djoser.pipelines.user_delete.signal',
45
        ],
46
        'username_update': [
47
            'djoser.pipelines.username_update.serialize_request',
48
            'djoser.pipelines.username_update.perform',
49
            'djoser.pipelines.username_update.signal',
50
        ],
51
        'password_update': [
52
            'djoser.pipelines.password_update.serialize_request',
53
            'djoser.pipelines.password_update.perform',
54
            'djoser.pipelines.password_update.signal',
55
        ],
56
        'password_reset': [
57
            'djoser.pipelines.password_reset.serialize_request',
58
            'djoser.pipelines.password_reset.perform',
59
        ],
60
        'password_reset_confirm': [
61
            'djoser.pipelines.password_reset_confirm.serialize_request',
62
            'djoser.pipelines.password_reset_confirm.perform',
63
            'djoser.pipelines.password_reset_confirm.signal',
64
        ],
65
        'token_create': [
66
            'djoser.pipelines.token_create.serialize_request',
67
            'djoser.pipelines.token_create.perform',
68
            'djoser.pipelines.token_create.signal',
69
            'djoser.pipelines.token_create.serialize_instance',
70
        ],
71
        'token_delete': [
72
            'djoser.pipelines.token_delete.perform',
73
            'djoser.pipelines.token_delete.signal',
74
        ]
75
    },
76
    'SERIALIZERS': {
77
        'user_activate':
78
            'djoser.serializers.UserActivateSerializer',
79
        'user_create':
80
            'djoser.serializers.UserCreateSerializer',
81
        'user':
82
            'djoser.serializers.UserSerializer',
83
        'user_delete':
84
            'djoser.serializers.UserDeleteSerializer',
85
        'username_update':
86
            'djoser.serializers.UsernameUpdateSerializer',
87
        'password_update':
88
            'djoser.serializers.PasswordUpdateSerializer',
89
        'password_reset':
90
            'djoser.serializers.PasswordResetSerializer',
91
        'password_reset_confirm':
92
            'djoser.serializers.PasswordResetConfirmSerializer',
93
        'token':
94
            'djoser.serializers.TokenSerializer',
95
        'token_create':
96
            'djoser.serializers.TokenCreateSerializer',
97
    },
98
    'EMAIL': {
99
        'activation': 'djoser.email.ActivationEmail',
100
        'confirmation': 'djoser.email.ConfirmationEmail',
101
        'password_reset': 'djoser.email.PasswordResetEmail',
102
    },
103
}
104
105
SETTINGS_TO_IMPORT = [
106
    'TOKEN_MODEL', 'VIEW_PIPELINE_ADAPTER', 'PIPELINES', 'SERIALIZERS',
107
    'EMAIL'
108
]
109
110
111
class Settings(object):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
112
    def __init__(self, default_settings, explicit_overriden_settings=None):
0 ignored issues
show
Comprehensibility Bug introduced by
default_settings is re-defining a name which is already available in the outer-scope (previously defined on line 10).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
Unused Code introduced by
The argument default_settings seems to be unused.
Loading history...
113
        if explicit_overriden_settings is None:
114
            explicit_overriden_settings = {}
115
116
        overriden_settings = getattr(
117
            django_settings, DJOSER_SETTINGS_NAMESPACE, {}
118
        ) or explicit_overriden_settings
119
120
        self._load_default_settings()
121
        self._override_settings(overriden_settings)
122
123
    def __getattribute__(self, item):
124
        """
125
        Override is necessary to achieve lazy imports in cases where imported
126
        resource depends on settings e.g. some serializers use TOKEN_MODEL.
127
        """
128
        setting_value = super(Settings, self).__getattribute__(item)
129
        if item in SETTINGS_TO_IMPORT:
130
            if isinstance(setting_value, str):
131
                setting_value = self._import_str_setting(item, setting_value)
132
            elif isinstance(setting_value, dict):
133
                setting_value = self._import_dict_setting(item, setting_value)
134
135
        return setting_value
136
137
    def _import_str_setting(self, item, value):
138
        value = import_string(value)
139
        setattr(self, item, value)
140
        return value
141
142
    def _import_dict_setting(self, item, value):
143
        for dict_key, dict_value in value.items():
144
            if isinstance(dict_value, str):
145
                value[dict_key] = import_string(dict_value)
146
                setattr(self, item, value)
147
148
            is_list_of_strings = (
149
                    isinstance(dict_value, list) and
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
150
                    all(isinstance(elem, str) for elem in dict_value)
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
151
            )
152
            if is_list_of_strings:
153
                value[dict_key] = [
154
                    import_string(func) for func in dict_value
155
                ]
156
                setattr(self, item, value)
157
158
        return value
159
160
    def _load_default_settings(self):
161
        for setting_name, setting_value in six.iteritems(default_settings):
162
            if setting_name.isupper():
163
                setattr(self, setting_name, setting_value)
164
165
    def _override_settings(self, overriden_settings):
166
        for setting_name, setting_value in six.iteritems(overriden_settings):
167
            value = setting_value
168
            setattr(self, setting_name, value)
169
170
171
class LazySettings(LazyObject):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
172
    def _setup(self, explicit_overriden_settings=None):
0 ignored issues
show
Bug introduced by
Parameters differ from overridden '_setup' method
Loading history...
173
        self._wrapped = Settings(default_settings, explicit_overriden_settings)
174
175
176
settings = LazySettings()
0 ignored issues
show
Coding Style Naming introduced by
The name settings does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
177
178
179
def reload_djoser_settings(*args, **kwargs):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Unused Code introduced by
The argument args seems to be unused.
Loading history...
180
    setting, value = kwargs['setting'], kwargs['value']
181
    if setting == DJOSER_SETTINGS_NAMESPACE:
182
        settings._setup(explicit_overriden_settings=value)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _setup was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
183
184
185
setting_changed.connect(reload_djoser_settings)
186