edx-enterprise-data 9.5.2__py3-none-any.whl → 9.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {edx_enterprise_data-9.5.2.dist-info → edx_enterprise_data-9.6.0.dist-info}/METADATA +1 -1
- {edx_enterprise_data-9.5.2.dist-info → edx_enterprise_data-9.6.0.dist-info}/RECORD +11 -9
- enterprise_data/__init__.py +1 -1
- enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +11 -0
- enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +14 -0
- enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py +4 -0
- enterprise_data/cache/__init__.py +59 -0
- enterprise_data/cache/decorators.py +42 -0
- {edx_enterprise_data-9.5.2.dist-info → edx_enterprise_data-9.6.0.dist-info}/LICENSE +0 -0
- {edx_enterprise_data-9.5.2.dist-info → edx_enterprise_data-9.6.0.dist-info}/WHEEL +0 -0
- {edx_enterprise_data-9.5.2.dist-info → edx_enterprise_data-9.6.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
enterprise_data/__init__.py,sha256=
|
1
|
+
enterprise_data/__init__.py,sha256=VFLkpUM-QjqgepwwvjAotcIKFN_2QHIHdVaKNhZs3ck,123
|
2
2
|
enterprise_data/apps.py,sha256=aF6hZwDfI2oWj95tUTm_2ikHueQj-jLj-u0GrgzpsQI,414
|
3
3
|
enterprise_data/clients.py,sha256=GvQupy5TVYfO_IKC3yzXSAgNP54r-PtIjidM5ws9Iks,3947
|
4
4
|
enterprise_data/constants.py,sha256=uCKjfpdlMYFZJsAj3n9RMw4Cmg5_6s3NuwocO-fch3s,238
|
@@ -20,9 +20,9 @@ enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,s
|
|
20
20
|
enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py,sha256=PgWwvtVCK5lbiq6z44lH0fwbkdWYukhyXZL9X8lNWCY,4099
|
21
21
|
enterprise_data/admin_analytics/database/tables/__init__.py,sha256=Z-c3P9hqR-dC9uYKe63qHkQG9Nms8cLE2jRN-4jeMM0,289
|
22
22
|
enterprise_data/admin_analytics/database/tables/base.py,sha256=1KyKsC18pW3m-5U-T6pdt5rIwsz6Wp3QFFbD3r6L6YQ,395
|
23
|
-
enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=
|
24
|
-
enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=
|
25
|
-
enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py,sha256=
|
23
|
+
enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=8aJsMsnMw67M6NGeUtWbQ-2g-OwN69XSAlD7KiMfOoA,10523
|
24
|
+
enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=FFpGtv2PUIDSdTqSZV4F3tVP9uDvS64ZqQXMGygCGok,11294
|
25
|
+
enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py,sha256=3xNwSi0wfCyBHcXPd6-9Ujs1NUm8kmZRg_gPrZzp9nQ,3233
|
26
26
|
enterprise_data/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
27
|
enterprise_data/api/urls.py,sha256=POqc_KATHdnpMf9zHtpO46pKD5KAlAExtx7G6iylLcU,273
|
28
28
|
enterprise_data/api/v0/__init__.py,sha256=1aAzAYU5hk-RW6cKUxa1645cbZMxn7GIZ7OMjWc9MKI,46
|
@@ -41,6 +41,8 @@ enterprise_data/api/v1/views/base.py,sha256=Kkmd5zgEBAhvwS_GoGXSK6lgbDNwSPioYn-Q
|
|
41
41
|
enterprise_data/api/v1/views/enterprise_admin.py,sha256=DsR1oHFhe6LCIFjIJ4YLLZ7PUChvNlFfdZD-sxHoijY,7388
|
42
42
|
enterprise_data/api/v1/views/enterprise_learner.py,sha256=NRo22ZvRBZ8nFvvOr6Tp1ZtMnjx55c9WcIdf2VoBYq4,18021
|
43
43
|
enterprise_data/api/v1/views/enterprise_offers.py,sha256=VifxgqTLFLVw4extYPlHcN1N_yjXcsYsAlYEnAbpb10,1266
|
44
|
+
enterprise_data/cache/__init__.py,sha256=fiBUploll1kmDy2vCmnNpeZVTD4ewsgtRF14vVs0Rb4,1850
|
45
|
+
enterprise_data/cache/decorators.py,sha256=vLbXK9VSv-HzVkkXS1-TkuSMxudwyxz04WFsAXqmjuM,1273
|
44
46
|
enterprise_data/fixtures/enterprise_enrollment.json,sha256=6onPXXR29pMdTdbl_mn81sDi3Re5jkLUZz2TPMB_1IY,5786
|
45
47
|
enterprise_data/fixtures/enterprise_user.json,sha256=6g8GvNY9j_fh1dvAU80bTAMI2F5vXCkb8a4UjsftMvQ,1970
|
46
48
|
enterprise_data/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -167,8 +169,8 @@ enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=WtL-RqGgu2x5PP
|
|
167
169
|
enterprise_reporting/tests/test_utils.py,sha256=Zt_TA0LVb-B6fQGkUkAKKVlUKKnQh8jnw1US1jKe7g8,9493
|
168
170
|
enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
|
169
171
|
enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
|
170
|
-
edx_enterprise_data-9.
|
171
|
-
edx_enterprise_data-9.
|
172
|
-
edx_enterprise_data-9.
|
173
|
-
edx_enterprise_data-9.
|
174
|
-
edx_enterprise_data-9.
|
172
|
+
edx_enterprise_data-9.6.0.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
173
|
+
edx_enterprise_data-9.6.0.dist-info/METADATA,sha256=JsMdNqhhyF1TMgIgv6t6t489_NzHkuaS9SI0ZFnvfu4,1569
|
174
|
+
edx_enterprise_data-9.6.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
175
|
+
edx_enterprise_data-9.6.0.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
|
176
|
+
edx_enterprise_data-9.6.0.dist-info/RECORD,,
|
enterprise_data/__init__.py
CHANGED
@@ -4,6 +4,8 @@ Module for interacting with the fact_enrollment_engagement_day_admin_dash table.
|
|
4
4
|
from datetime import date
|
5
5
|
from uuid import UUID
|
6
6
|
|
7
|
+
from enterprise_data.cache.decorators import cache_it
|
8
|
+
|
7
9
|
from ..queries import FactEngagementAdminDashQueries
|
8
10
|
from ..utils import run_query
|
9
11
|
from .base import BaseTable
|
@@ -15,6 +17,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
15
17
|
"""
|
16
18
|
queries = FactEngagementAdminDashQueries()
|
17
19
|
|
20
|
+
@cache_it()
|
18
21
|
def get_learning_hours_and_daily_sessions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
19
22
|
"""
|
20
23
|
Get the learning hours and daily sessions for the given enterprise customer.
|
@@ -40,6 +43,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
40
43
|
|
41
44
|
return tuple(results[0])
|
42
45
|
|
46
|
+
@cache_it()
|
43
47
|
def get_engagement_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
44
48
|
"""
|
45
49
|
Get the total number of engagements for the given enterprise customer.
|
@@ -64,6 +68,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
64
68
|
return 0
|
65
69
|
return results[0][0]
|
66
70
|
|
71
|
+
@cache_it()
|
67
72
|
def get_all_engagements(
|
68
73
|
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
|
69
74
|
):
|
@@ -92,6 +97,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
92
97
|
as_dict=True,
|
93
98
|
)
|
94
99
|
|
100
|
+
@cache_it()
|
95
101
|
def get_top_courses_by_engagement(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
96
102
|
"""
|
97
103
|
Get the top courses by user engagement for the given enterprise customer.
|
@@ -114,6 +120,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
114
120
|
as_dict=True,
|
115
121
|
)
|
116
122
|
|
123
|
+
@cache_it()
|
117
124
|
def get_top_subjects_by_engagement(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
118
125
|
"""
|
119
126
|
Get the top subjects by user engagement for the given enterprise customer.
|
@@ -136,6 +143,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
136
143
|
as_dict=True,
|
137
144
|
)
|
138
145
|
|
146
|
+
@cache_it()
|
139
147
|
def get_engagement_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
140
148
|
"""
|
141
149
|
Get the engagement time series data.
|
@@ -158,6 +166,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
158
166
|
as_dict=True,
|
159
167
|
)
|
160
168
|
|
169
|
+
@cache_it()
|
161
170
|
def _get_engagement_data_for_leaderboard(
|
162
171
|
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
|
163
172
|
):
|
@@ -189,6 +198,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
189
198
|
as_dict=True,
|
190
199
|
)
|
191
200
|
|
201
|
+
@cache_it()
|
192
202
|
def _get_completion_data_for_leaderboard_query(
|
193
203
|
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, email_list: list
|
194
204
|
):
|
@@ -257,6 +267,7 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
257
267
|
|
258
268
|
return list(engagement_data_dict.values())
|
259
269
|
|
270
|
+
@cache_it()
|
260
271
|
def get_leaderboard_data_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
261
272
|
"""
|
262
273
|
Get the total number of leaderboard records for the given enterprise customer.
|
@@ -4,6 +4,8 @@ Module for interacting with the fact_enrollment_admin_dash table.
|
|
4
4
|
from datetime import date, datetime
|
5
5
|
from uuid import UUID
|
6
6
|
|
7
|
+
from enterprise_data.cache.decorators import cache_it
|
8
|
+
|
7
9
|
from ..queries import FactEnrollmentAdminDashQueries
|
8
10
|
from ..utils import run_query
|
9
11
|
from .base import BaseTable
|
@@ -15,6 +17,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
15
17
|
"""
|
16
18
|
queries = FactEnrollmentAdminDashQueries()
|
17
19
|
|
20
|
+
@cache_it()
|
18
21
|
def get_enrollment_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
19
22
|
"""
|
20
23
|
Get the total number of enrollments for the given enterprise customer.
|
@@ -39,6 +42,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
39
42
|
return 0
|
40
43
|
return int(results[0][0] or 0)
|
41
44
|
|
45
|
+
@cache_it()
|
42
46
|
def get_all_enrollments(
|
43
47
|
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
|
44
48
|
):
|
@@ -67,6 +71,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
67
71
|
as_dict=True,
|
68
72
|
)
|
69
73
|
|
74
|
+
@cache_it()
|
70
75
|
def get_enrollment_date_range(self, enterprise_customer_uuid: UUID):
|
71
76
|
"""
|
72
77
|
Get the enrollment date range for the given enterprise customer.
|
@@ -94,6 +99,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
94
99
|
|
95
100
|
return min_date, max_date
|
96
101
|
|
102
|
+
@cache_it()
|
97
103
|
def get_enrollment_and_course_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
98
104
|
"""
|
99
105
|
Get the enrollment and course count for the given enterprise customer.
|
@@ -118,6 +124,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
118
124
|
return 0, 0
|
119
125
|
return tuple(results[0])
|
120
126
|
|
127
|
+
@cache_it()
|
121
128
|
def get_completion_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
122
129
|
"""
|
123
130
|
Get the completion count for the given enterprise customer.
|
@@ -143,6 +150,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
143
150
|
|
144
151
|
return int(results[0][0] or 0)
|
145
152
|
|
153
|
+
@cache_it()
|
146
154
|
def get_top_courses_by_enrollments(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
147
155
|
"""
|
148
156
|
Get the top courses enrollments for the given enterprise customer.
|
@@ -165,6 +173,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
165
173
|
as_dict=True,
|
166
174
|
)
|
167
175
|
|
176
|
+
@cache_it()
|
168
177
|
def get_top_subjects_by_enrollments(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
169
178
|
"""
|
170
179
|
Get the top subjects by enrollments for the given enterprise customer.
|
@@ -187,6 +196,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
187
196
|
as_dict=True,
|
188
197
|
)
|
189
198
|
|
199
|
+
@cache_it()
|
190
200
|
def get_enrolment_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
191
201
|
"""
|
192
202
|
Get the enrollment time series data for the given enterprise customer.
|
@@ -209,6 +219,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
209
219
|
as_dict=True,
|
210
220
|
)
|
211
221
|
|
222
|
+
@cache_it()
|
212
223
|
def get_all_completions(
|
213
224
|
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
|
214
225
|
):
|
@@ -237,6 +248,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
237
248
|
as_dict=True,
|
238
249
|
)
|
239
250
|
|
251
|
+
@cache_it()
|
240
252
|
def get_top_courses_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
241
253
|
"""
|
242
254
|
Get the top courses by completion for the given enterprise customer.
|
@@ -259,6 +271,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
259
271
|
as_dict=True,
|
260
272
|
)
|
261
273
|
|
274
|
+
@cache_it()
|
262
275
|
def get_top_subjects_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
263
276
|
"""
|
264
277
|
Get the top subjects by completions for the given enterprise customer.
|
@@ -281,6 +294,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
281
294
|
as_dict=True,
|
282
295
|
)
|
283
296
|
|
297
|
+
@cache_it()
|
284
298
|
def get_completions_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
285
299
|
"""
|
286
300
|
Get the completions time series data for the given enterprise customer.
|
@@ -9,6 +9,7 @@ from enterprise_data.admin_analytics.database.queries.skills_daily_rollup_admin_
|
|
9
9
|
)
|
10
10
|
from enterprise_data.admin_analytics.database.tables.base import BaseTable
|
11
11
|
from enterprise_data.admin_analytics.database.utils import run_query
|
12
|
+
from enterprise_data.cache.decorators import cache_it
|
12
13
|
|
13
14
|
|
14
15
|
class SkillsDailyRollupAdminDashTable(BaseTable):
|
@@ -17,6 +18,7 @@ class SkillsDailyRollupAdminDashTable(BaseTable):
|
|
17
18
|
"""
|
18
19
|
queries = SkillsDailyRollupAdminDashQueries()
|
19
20
|
|
21
|
+
@cache_it()
|
20
22
|
def get_top_skills(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
21
23
|
"""
|
22
24
|
Get the top skills for the given enterprise customer.
|
@@ -39,6 +41,7 @@ class SkillsDailyRollupAdminDashTable(BaseTable):
|
|
39
41
|
as_dict=True,
|
40
42
|
)
|
41
43
|
|
44
|
+
@cache_it()
|
42
45
|
def get_top_skills_by_enrollment(
|
43
46
|
self,
|
44
47
|
enterprise_customer_uuid: UUID,
|
@@ -66,6 +69,7 @@ class SkillsDailyRollupAdminDashTable(BaseTable):
|
|
66
69
|
as_dict=True,
|
67
70
|
)
|
68
71
|
|
72
|
+
@cache_it()
|
69
73
|
def get_top_skills_by_completion(
|
70
74
|
self,
|
71
75
|
enterprise_customer_uuid: UUID,
|
@@ -0,0 +1,59 @@
|
|
1
|
+
"""
|
2
|
+
Caching related utility classes and functions.
|
3
|
+
"""
|
4
|
+
import hashlib
|
5
|
+
|
6
|
+
from edx_django_utils.cache import TieredCache
|
7
|
+
|
8
|
+
DEFAULT_TIMEOUT = 60 * 60 # 1 hour
|
9
|
+
|
10
|
+
|
11
|
+
def get_key(*args, **kwargs):
|
12
|
+
"""
|
13
|
+
Get MD5 encoded cache key for given positional and keyword arguments.
|
14
|
+
|
15
|
+
MD5 encrytion is applied to a key that is generated by concatenating the positional and keyword arguments.
|
16
|
+
Following is the format of the generated key from arguments before applying the MD5 encryption.
|
17
|
+
arg1__arg2__key1:value1__key2:value2 ...
|
18
|
+
|
19
|
+
Example:
|
20
|
+
>>> get_key('ecommerce', site_domain='example.com', resource='catalogs')
|
21
|
+
1892cd85a30b8fc9180369c17b472c38
|
22
|
+
>>> # The generated key for the above call before applying MD5 encryption will be as follows
|
23
|
+
>>> # "ecommerce__site_domain:example.com__resource:catalogs"
|
24
|
+
|
25
|
+
Arguments:
|
26
|
+
*args: Arguments that need to be present in cache key.
|
27
|
+
**kwargs: Key word arguments that need to be present in cache key.
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
(str): An MD5 encoded key uniquely identified by the key word arguments.
|
31
|
+
"""
|
32
|
+
key = '{}__{}'.format(
|
33
|
+
'__'.join(map(str, args)),
|
34
|
+
'__'.join(['{}:{}'.format(item, str(value)) for item, value in kwargs.items()])
|
35
|
+
)
|
36
|
+
|
37
|
+
return hashlib.md5(key.encode('utf-8')).hexdigest()
|
38
|
+
|
39
|
+
|
40
|
+
def get(key):
|
41
|
+
"""
|
42
|
+
Get value from cache for given key.
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
(CachedResponse): CachedResponse object.
|
46
|
+
"""
|
47
|
+
return TieredCache.get_cached_response(key)
|
48
|
+
|
49
|
+
|
50
|
+
def set(key, value, timeout=DEFAULT_TIMEOUT): # pylint: disable=redefined-builtin
|
51
|
+
"""
|
52
|
+
Set value in cache for given key.
|
53
|
+
|
54
|
+
Arguments:
|
55
|
+
key (str): Cache key.
|
56
|
+
value (object): Value to be stored in cache.
|
57
|
+
timeout (int): Cache timeout in seconds.
|
58
|
+
"""
|
59
|
+
TieredCache.set_all_tiers(key, value, django_cache_timeout=timeout)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""
|
2
|
+
Decorators for caching the result of a function.
|
3
|
+
"""
|
4
|
+
from functools import wraps
|
5
|
+
from logging import getLogger
|
6
|
+
|
7
|
+
from enterprise_data import cache
|
8
|
+
|
9
|
+
LOGGER = getLogger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
def cache_it(timeout=cache.DEFAULT_TIMEOUT):
|
13
|
+
"""
|
14
|
+
Function to return the decorator to cache the result of a method.
|
15
|
+
|
16
|
+
Note: This decorator will only work for class methods.
|
17
|
+
|
18
|
+
Arguments:
|
19
|
+
timeout (int): Cache timeout in seconds.
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
(function): Decorator function.
|
23
|
+
"""
|
24
|
+
|
25
|
+
def inner_decorator(func):
|
26
|
+
@wraps(func)
|
27
|
+
def wrapper(self, *args, **kwargs):
|
28
|
+
"""
|
29
|
+
Wrapper function to cache the result of the function.
|
30
|
+
"""
|
31
|
+
cache_key = cache.get_key(func.__name__, *args, **kwargs)
|
32
|
+
cached_response = cache.get(cache_key)
|
33
|
+
if cached_response.is_found:
|
34
|
+
LOGGER.info("[ANALYTICS]: Cache hit for key: (%s)", (func.__name__, args, kwargs))
|
35
|
+
return cached_response.value
|
36
|
+
|
37
|
+
LOGGER.info("[ANALYTICS]: Cache miss for key: (%s)", (func.__name__, args, kwargs))
|
38
|
+
result = func(self, *args, **kwargs)
|
39
|
+
cache.set(cache_key, result, timeout=timeout)
|
40
|
+
return result
|
41
|
+
return wrapper
|
42
|
+
return inner_decorator
|
File without changes
|
File without changes
|
File without changes
|