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
    'SOCIAL_AUTH_TOKEN_STRATEGY': 'djoser.social.token.jwt.TokenStrategy',
15
    'SOCIAL_AUTH_ALLOWED_REDIRECT_URIS': [],
16
    'VIEW_PIPELINE_ADAPTER':
17
        'djoser.pipelines.base.default_view_pipeline_adapter',
18
19
    'PIPELINES': {
20
        'user_activate': [
21
            'djoser.pipelines.user_activate.serialize_request',
22
            'djoser.pipelines.user_activate.perform',
23
            'djoser.pipelines.user_activate.signal',
24
            'djoser.pipelines.email.confirmation_email',
25
        ],
26
        'user_create': [
27
            'djoser.pipelines.user_create.serialize_request',
28
            'djoser.pipelines.user_create.perform',
29
            'djoser.pipelines.user_create.serialize_instance',
30
            'djoser.pipelines.user_create.signal',
31
            'djoser.pipelines.email.confirmation_email',
32
        ],
33
        'user_detail': [
34
            'djoser.pipelines.user_detail.perform',
35
            'djoser.pipelines.user_detail.serialize_instance',
36
        ],
37
        'user_update': [
38
            'djoser.pipelines.user_update.serialize_request',
39
            'djoser.pipelines.user_update.perform',
40
            'djoser.pipelines.user_update.signal',
41
            'djoser.pipelines.user_update.serialize_instance',
42
        ],
43
        'user_delete': [
44
            'djoser.pipelines.user_delete.serialize_request',
45
            'djoser.pipelines.user_delete.perform',
46
            'djoser.pipelines.user_delete.signal',
47
        ],
48
        'username_update': [
49
            'djoser.pipelines.username_update.serialize_request',
50
            'djoser.pipelines.username_update.perform',
51
            'djoser.pipelines.username_update.signal',
52
        ],
53
        'password_update': [
54
            'djoser.pipelines.password_update.serialize_request',
55
            'djoser.pipelines.password_update.perform',
56
            'djoser.pipelines.password_update.signal',
57
        ],
58
        'password_reset': [
59
            'djoser.pipelines.password_reset.serialize_request',
60
            'djoser.pipelines.password_reset.perform',
61
        ],
62
        'password_reset_confirm': [
63
            'djoser.pipelines.password_reset_confirm.serialize_request',
64
            'djoser.pipelines.password_reset_confirm.perform',
65
            'djoser.pipelines.password_reset_confirm.signal',
66
        ],
67
        'token_create': [
68
            'djoser.pipelines.token_create.serialize_request',
69
            'djoser.pipelines.token_create.perform',
70
            'djoser.pipelines.token_create.signal',
71
        ],
72
        'token_destroy': [
73
            'djoser.pipelines.token_destroy.perform',
74
            'djoser.pipelines.token_destroy.signal',
75
        ]
76
    },
77
    'SERIALIZERS': {
78
        'user_activate':
79
            'djoser.serializers.UserActivateSerializer',
80
        'user_create':
81
            'djoser.serializers.UserCreateSerializer',
82
        'user':
83
            'djoser.serializers.UserSerializer',
84
        'user_delete':
85
            'djoser.serializers.UserDeleteSerializer',
86
        'username_update':
87
            'djoser.serializers.UsernameUpdateSerializer',
88
        'password_update':
89
            'djoser.serializers.PasswordUpdateSerializer',
90
        'password_reset':
91
            'djoser.serializers.PasswordResetSerializer',
92
        'password_reset_confirm':
93
            'djoser.serializers.PasswordResetConfirmSerializer',
94
        'token':
95
            'djoser.serializers.TokenSerializer',
96
        'token_create':
97
            'djoser.serializers.TokenCreateSerializer',
98
    },
99
    'EMAIL': {
100
        'activation': 'djoser.email.ActivationEmail',
101
        'confirmation': 'djoser.email.ConfirmationEmail',
102
        'password_reset': 'djoser.email.PasswordResetEmail',
103
    },
104
}
105
106
SETTINGS_TO_IMPORT = [
107
    'TOKEN_MODEL', 'SOCIAL_AUTH_TOKEN_STRATEGY', 'VIEW_PIPELINE_ADAPTER',
108
    'PIPELINES', 'SERIALIZERS', 'EMAIL'
109
]
110
111
112
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...
113
    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...
114
        if explicit_overriden_settings is None:
115
            explicit_overriden_settings = {}
116
117
        overriden_settings = getattr(
118
            django_settings, DJOSER_SETTINGS_NAMESPACE, {}
119
        ) or explicit_overriden_settings
120
121
        self._load_default_settings()
122
        self._override_settings(overriden_settings)
123
124
    def __getattribute__(self, item):
125
        """
126
        Override is necessary to achieve lazy imports in cases where imported
127
        resource depends on settings e.g. some serializers use TOKEN_MODEL.
128
        """
129
        setting_value = super(Settings, self).__getattribute__(item)
130
        if item in SETTINGS_TO_IMPORT:
131
            if isinstance(setting_value, str):
132
                setting_value = self._import_str_setting(item, setting_value)
133
            elif isinstance(setting_value, dict):
134
                setting_value = self._import_dict_setting(item, setting_value)
135
136
        return setting_value
137
138
    def _import_str_setting(self, item, value):
139
        value = import_string(value)
140
        setattr(self, item, value)
141
        return value
142
143
    def _import_dict_setting(self, item, value):
144
        for dict_key, dict_value in value.items():
145
            if isinstance(dict_value, str):
146
                value[dict_key] = import_string(dict_value)
147
                setattr(self, item, value)
148
149
            is_list_of_strings = (
150
                    isinstance(dict_value, list) and
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (remove 4 spaces).
Loading history...
151
                    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...
152
            )
153
            if is_list_of_strings:
154
                value[dict_key] = [
155
                    import_string(func) for func in dict_value
156
                ]
157
                setattr(self, item, value)
158
159
        return value
160
161
    def _load_default_settings(self):
162
        for setting_name, setting_value in six.iteritems(default_settings):
163
            if setting_name.isupper():
164
                setattr(self, setting_name, setting_value)
165
166
    def _override_settings(self, overriden_settings):
167
        for setting_name, setting_value in six.iteritems(overriden_settings):
168
            value = setting_value
169
            setattr(self, setting_name, value)
170
171
172
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...
173
    def _setup(self, explicit_overriden_settings=None):
0 ignored issues
show
Bug introduced by
Parameters differ from overridden '_setup' method
Loading history...
174
        self._wrapped = Settings(default_settings, explicit_overriden_settings)
175
176
177
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...
178
179
180
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...
181
    setting, value = kwargs['setting'], kwargs['value']
182
    if setting == DJOSER_SETTINGS_NAMESPACE:
183
        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...
184
185
186
setting_changed.connect(reload_djoser_settings)
187