kinto 23.2.1__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.
- kinto/__init__.py +92 -0
- kinto/__main__.py +249 -0
- kinto/authorization.py +134 -0
- kinto/config/__init__.py +94 -0
- kinto/config/kinto.tpl +270 -0
- kinto/contribute.json +27 -0
- kinto/core/__init__.py +246 -0
- kinto/core/authentication.py +48 -0
- kinto/core/authorization.py +311 -0
- kinto/core/cache/__init__.py +131 -0
- kinto/core/cache/memcached.py +112 -0
- kinto/core/cache/memory.py +104 -0
- kinto/core/cache/postgresql/__init__.py +178 -0
- kinto/core/cache/postgresql/schema.sql +23 -0
- kinto/core/cache/testing.py +208 -0
- kinto/core/cornice/__init__.py +93 -0
- kinto/core/cornice/cors.py +144 -0
- kinto/core/cornice/errors.py +40 -0
- kinto/core/cornice/pyramidhook.py +373 -0
- kinto/core/cornice/renderer.py +89 -0
- kinto/core/cornice/resource.py +205 -0
- kinto/core/cornice/service.py +641 -0
- kinto/core/cornice/util.py +138 -0
- kinto/core/cornice/validators/__init__.py +94 -0
- kinto/core/cornice/validators/_colander.py +142 -0
- kinto/core/cornice/validators/_marshmallow.py +182 -0
- kinto/core/cornice_swagger/__init__.py +92 -0
- kinto/core/cornice_swagger/converters/__init__.py +21 -0
- kinto/core/cornice_swagger/converters/exceptions.py +6 -0
- kinto/core/cornice_swagger/converters/parameters.py +90 -0
- kinto/core/cornice_swagger/converters/schema.py +249 -0
- kinto/core/cornice_swagger/swagger.py +725 -0
- kinto/core/cornice_swagger/templates/index.html +73 -0
- kinto/core/cornice_swagger/templates/index_script_template.html +21 -0
- kinto/core/cornice_swagger/util.py +42 -0
- kinto/core/cornice_swagger/views.py +78 -0
- kinto/core/decorators.py +74 -0
- kinto/core/errors.py +216 -0
- kinto/core/events.py +301 -0
- kinto/core/initialization.py +738 -0
- kinto/core/listeners/__init__.py +9 -0
- kinto/core/metrics.py +94 -0
- kinto/core/openapi.py +115 -0
- kinto/core/permission/__init__.py +202 -0
- kinto/core/permission/memory.py +167 -0
- kinto/core/permission/postgresql/__init__.py +489 -0
- kinto/core/permission/postgresql/migrations/migration_001_002.sql +18 -0
- kinto/core/permission/postgresql/schema.sql +41 -0
- kinto/core/permission/testing.py +487 -0
- kinto/core/resource/__init__.py +1311 -0
- kinto/core/resource/model.py +412 -0
- kinto/core/resource/schema.py +502 -0
- kinto/core/resource/viewset.py +230 -0
- kinto/core/schema.py +119 -0
- kinto/core/scripts.py +50 -0
- kinto/core/statsd.py +1 -0
- kinto/core/storage/__init__.py +436 -0
- kinto/core/storage/exceptions.py +53 -0
- kinto/core/storage/generators.py +58 -0
- kinto/core/storage/memory.py +651 -0
- kinto/core/storage/postgresql/__init__.py +1131 -0
- kinto/core/storage/postgresql/client.py +120 -0
- kinto/core/storage/postgresql/migrations/migration_001_002.sql +10 -0
- kinto/core/storage/postgresql/migrations/migration_002_003.sql +33 -0
- kinto/core/storage/postgresql/migrations/migration_003_004.sql +18 -0
- kinto/core/storage/postgresql/migrations/migration_004_005.sql +20 -0
- kinto/core/storage/postgresql/migrations/migration_005_006.sql +11 -0
- kinto/core/storage/postgresql/migrations/migration_006_007.sql +74 -0
- kinto/core/storage/postgresql/migrations/migration_007_008.sql +66 -0
- kinto/core/storage/postgresql/migrations/migration_008_009.sql +41 -0
- kinto/core/storage/postgresql/migrations/migration_009_010.sql +98 -0
- kinto/core/storage/postgresql/migrations/migration_010_011.sql +14 -0
- kinto/core/storage/postgresql/migrations/migration_011_012.sql +9 -0
- kinto/core/storage/postgresql/migrations/migration_012_013.sql +71 -0
- kinto/core/storage/postgresql/migrations/migration_013_014.sql +14 -0
- kinto/core/storage/postgresql/migrations/migration_014_015.sql +95 -0
- kinto/core/storage/postgresql/migrations/migration_015_016.sql +4 -0
- kinto/core/storage/postgresql/migrations/migration_016_017.sql +81 -0
- kinto/core/storage/postgresql/migrations/migration_017_018.sql +25 -0
- kinto/core/storage/postgresql/migrations/migration_018_019.sql +8 -0
- kinto/core/storage/postgresql/migrations/migration_019_020.sql +7 -0
- kinto/core/storage/postgresql/migrations/migration_020_021.sql +68 -0
- kinto/core/storage/postgresql/migrations/migration_021_022.sql +62 -0
- kinto/core/storage/postgresql/migrations/migration_022_023.sql +5 -0
- kinto/core/storage/postgresql/migrations/migration_023_024.sql +6 -0
- kinto/core/storage/postgresql/migrations/migration_024_025.sql +6 -0
- kinto/core/storage/postgresql/migrator.py +98 -0
- kinto/core/storage/postgresql/pool.py +55 -0
- kinto/core/storage/postgresql/schema.sql +143 -0
- kinto/core/storage/testing.py +1857 -0
- kinto/core/storage/utils.py +37 -0
- kinto/core/testing.py +182 -0
- kinto/core/utils.py +553 -0
- kinto/core/views/__init__.py +0 -0
- kinto/core/views/batch.py +163 -0
- kinto/core/views/errors.py +145 -0
- kinto/core/views/heartbeat.py +106 -0
- kinto/core/views/hello.py +69 -0
- kinto/core/views/openapi.py +35 -0
- kinto/core/views/version.py +50 -0
- kinto/events.py +3 -0
- kinto/plugins/__init__.py +0 -0
- kinto/plugins/accounts/__init__.py +94 -0
- kinto/plugins/accounts/authentication.py +63 -0
- kinto/plugins/accounts/scripts.py +61 -0
- kinto/plugins/accounts/utils.py +13 -0
- kinto/plugins/accounts/views.py +136 -0
- kinto/plugins/admin/README.md +3 -0
- kinto/plugins/admin/VERSION +1 -0
- kinto/plugins/admin/__init__.py +40 -0
- kinto/plugins/admin/build/VERSION +1 -0
- kinto/plugins/admin/build/assets/index-CYFwtKtL.css +6 -0
- kinto/plugins/admin/build/assets/index-DJ0m93zA.js +149 -0
- kinto/plugins/admin/build/assets/logo-VBRiKSPX.png +0 -0
- kinto/plugins/admin/build/index.html +18 -0
- kinto/plugins/admin/public/help.html +25 -0
- kinto/plugins/admin/views.py +42 -0
- kinto/plugins/default_bucket/__init__.py +191 -0
- kinto/plugins/flush.py +28 -0
- kinto/plugins/history/__init__.py +65 -0
- kinto/plugins/history/listener.py +181 -0
- kinto/plugins/history/views.py +66 -0
- kinto/plugins/openid/__init__.py +131 -0
- kinto/plugins/openid/utils.py +14 -0
- kinto/plugins/openid/views.py +193 -0
- kinto/plugins/prometheus.py +300 -0
- kinto/plugins/statsd.py +85 -0
- kinto/schema_validation.py +135 -0
- kinto/views/__init__.py +34 -0
- kinto/views/admin.py +195 -0
- kinto/views/buckets.py +45 -0
- kinto/views/collections.py +58 -0
- kinto/views/contribute.py +39 -0
- kinto/views/groups.py +90 -0
- kinto/views/permissions.py +235 -0
- kinto/views/records.py +133 -0
- kinto-23.2.1.dist-info/METADATA +232 -0
- kinto-23.2.1.dist-info/RECORD +142 -0
- kinto-23.2.1.dist-info/WHEEL +5 -0
- kinto-23.2.1.dist-info/entry_points.txt +5 -0
- kinto-23.2.1.dist-info/licenses/LICENSE +13 -0
- kinto-23.2.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
kinto.core.storage.utils: methods for making it easier to work with kinto storage objects
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from kinto.core.storage import Filter
|
|
6
|
+
from kinto.core.utils import COMPARISON
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
BATCH_SIZE = 25
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def paginated(storage, *args, sorting, batch_size=BATCH_SIZE, **kwargs):
|
|
13
|
+
"""A generator used to access paginated results from storage.list_all.
|
|
14
|
+
|
|
15
|
+
:param kwargs: Passed through unchanged to list_all.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
if len(sorting) > 1:
|
|
19
|
+
raise NotImplementedError("FIXME: only supports one-length sorting") # pragma: nocover
|
|
20
|
+
pagination_direction = COMPARISON.GT if sorting[0].direction > 0 else COMPARISON.LT
|
|
21
|
+
|
|
22
|
+
object_pagination = None
|
|
23
|
+
while True:
|
|
24
|
+
objects = storage.list_all(
|
|
25
|
+
sorting=sorting, limit=batch_size, pagination_rules=object_pagination, **kwargs
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
if not objects:
|
|
29
|
+
break
|
|
30
|
+
|
|
31
|
+
for obj in objects:
|
|
32
|
+
yield obj
|
|
33
|
+
|
|
34
|
+
object_pagination = [
|
|
35
|
+
# FIXME: support more than one-length sorting
|
|
36
|
+
[Filter(sorting[0].field, obj[sorting[0].field], pagination_direction)]
|
|
37
|
+
]
|
kinto/core/testing.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import threading
|
|
3
|
+
import unittest
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from unittest import mock
|
|
6
|
+
|
|
7
|
+
import webtest
|
|
8
|
+
from pyramid.url import parse_url_overrides
|
|
9
|
+
|
|
10
|
+
from kinto.core import DEFAULT_SETTINGS
|
|
11
|
+
from kinto.core.cornice import errors as cornice_errors
|
|
12
|
+
from kinto.core.storage import generators
|
|
13
|
+
from kinto.core.utils import encode64, follow_subrequest, memcache, sqlalchemy
|
|
14
|
+
from kinto.plugins import prometheus, statsd
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
skip_if_ci = unittest.skipIf("CI" in os.environ, "ci")
|
|
18
|
+
skip_if_no_postgresql = unittest.skipIf(sqlalchemy is None, "postgresql is not installed.")
|
|
19
|
+
skip_if_no_memcached = unittest.skipIf(memcache is None, "memcached is not installed.")
|
|
20
|
+
skip_if_no_statsd = unittest.skipIf(not statsd.statsd_module, "statsd is not installed.")
|
|
21
|
+
skip_if_no_prometheus = unittest.skipIf(
|
|
22
|
+
not prometheus.prometheus_module, "prometheus is not installed."
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class DummyRequest(mock.MagicMock):
|
|
27
|
+
"""Fully mocked request."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, *args, **kwargs):
|
|
30
|
+
super().__init__(*args, **kwargs)
|
|
31
|
+
self.upath_info = "/v0/"
|
|
32
|
+
self.registry = mock.MagicMock(settings={**DEFAULT_SETTINGS})
|
|
33
|
+
self.registry.id_generators = defaultdict(generators.UUID4)
|
|
34
|
+
self.GET = {}
|
|
35
|
+
self.headers = {}
|
|
36
|
+
self.errors = cornice_errors.Errors()
|
|
37
|
+
self.authenticated_userid = "bob"
|
|
38
|
+
self.authn_type = "basicauth"
|
|
39
|
+
self.prefixed_userid = "basicauth:bob"
|
|
40
|
+
self.effective_principals = ["system.Everyone", "system.Authenticated", "bob"]
|
|
41
|
+
self.prefixed_principals = self.effective_principals + [self.prefixed_userid]
|
|
42
|
+
self.json = {}
|
|
43
|
+
self.validated = {}
|
|
44
|
+
self.log_context = lambda **kw: kw
|
|
45
|
+
self.matchdict = {}
|
|
46
|
+
self.response = mock.MagicMock(headers={})
|
|
47
|
+
self.application_url = "" # used by parse_url_overrides
|
|
48
|
+
|
|
49
|
+
def route_url(*a, **kw):
|
|
50
|
+
# XXX: refactor DummyRequest to take advantage of `pyramid.testing`
|
|
51
|
+
parts = parse_url_overrides(self, kw)
|
|
52
|
+
return "".join([p for p in parts if p])
|
|
53
|
+
|
|
54
|
+
self.route_url = route_url
|
|
55
|
+
|
|
56
|
+
follow_subrequest = follow_subrequest
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_request_class(prefix):
|
|
60
|
+
class PrefixedRequestClass(webtest.app.TestRequest):
|
|
61
|
+
@classmethod
|
|
62
|
+
def blank(cls, path, *args, **kwargs):
|
|
63
|
+
if prefix:
|
|
64
|
+
path = f"/{prefix}{path}"
|
|
65
|
+
return webtest.app.TestRequest.blank(path, *args, **kwargs)
|
|
66
|
+
|
|
67
|
+
return PrefixedRequestClass
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class FormattedErrorMixin:
|
|
71
|
+
"""Test mixin in order to perform advanced error responses assertions."""
|
|
72
|
+
|
|
73
|
+
def assertFormattedError(self, response, code, errno, error, message=None, info=None):
|
|
74
|
+
self.assertIn("application/json", response.headers["Content-Type"])
|
|
75
|
+
self.assertEqual(response.json["code"], code)
|
|
76
|
+
self.assertEqual(response.json["errno"], errno.value)
|
|
77
|
+
self.assertEqual(response.json["error"], error)
|
|
78
|
+
if message is not None:
|
|
79
|
+
self.assertIn(message, response.json["message"])
|
|
80
|
+
else: # pragma: no cover
|
|
81
|
+
self.assertNotIn("message", response.json)
|
|
82
|
+
|
|
83
|
+
if info is not None:
|
|
84
|
+
self.assertIn(info, response.json["info"])
|
|
85
|
+
else: # pragma: no cover
|
|
86
|
+
self.assertNotIn("info", response.json)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_user_headers(user, password="secret"):
|
|
90
|
+
"""Helper to obtain a Basic Auth authorization headers from the specified
|
|
91
|
+
`user` (e.g. ``"user:pass"``)
|
|
92
|
+
|
|
93
|
+
:rtype: dict
|
|
94
|
+
"""
|
|
95
|
+
credentials = f"{user}:{password}"
|
|
96
|
+
authorization = f"Basic {encode64(credentials)}"
|
|
97
|
+
return {"Authorization": authorization}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class BaseWebTest:
|
|
101
|
+
"""Base Web Test to test your kinto.core service.
|
|
102
|
+
|
|
103
|
+
It setups the database before each test and delete it after.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
api_prefix = "v0"
|
|
107
|
+
"""URL version prefix"""
|
|
108
|
+
|
|
109
|
+
entry_point = None
|
|
110
|
+
"""Main application entry"""
|
|
111
|
+
|
|
112
|
+
headers = {"Content-Type": "application/json"}
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def setUpClass(cls):
|
|
116
|
+
cls.app = cls.make_app()
|
|
117
|
+
cls.storage = cls.app.app.registry.storage
|
|
118
|
+
cls.cache = cls.app.app.registry.cache
|
|
119
|
+
cls.permission = cls.app.app.registry.permission
|
|
120
|
+
|
|
121
|
+
cls.storage.initialize_schema()
|
|
122
|
+
cls.permission.initialize_schema()
|
|
123
|
+
cls.cache.initialize_schema()
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def make_app(cls, settings=None, config=None):
|
|
127
|
+
"""Instantiate the application and setup requests to use the api
|
|
128
|
+
prefix.
|
|
129
|
+
|
|
130
|
+
:param dict settings: extra settings values
|
|
131
|
+
:param pyramid.config.Configurator config: already initialized config
|
|
132
|
+
:returns: webtest application instance
|
|
133
|
+
"""
|
|
134
|
+
settings = cls.get_app_settings(extras=settings)
|
|
135
|
+
|
|
136
|
+
main = cls.entry_point
|
|
137
|
+
|
|
138
|
+
wsgi_app = main({}, config=config, **settings)
|
|
139
|
+
app = webtest.TestApp(wsgi_app)
|
|
140
|
+
app.RequestClass = get_request_class(cls.api_prefix)
|
|
141
|
+
return app
|
|
142
|
+
|
|
143
|
+
@classmethod
|
|
144
|
+
def get_app_settings(cls, extras=None):
|
|
145
|
+
"""Application settings to be used. Override to tweak default settings
|
|
146
|
+
for the tests.
|
|
147
|
+
|
|
148
|
+
:param dict extras: extra settings values
|
|
149
|
+
:rtype: dict
|
|
150
|
+
"""
|
|
151
|
+
settings = {**DEFAULT_SETTINGS}
|
|
152
|
+
|
|
153
|
+
settings["storage_backend"] = "kinto.core.storage.memory"
|
|
154
|
+
settings["cache_backend"] = "kinto.core.cache.memory"
|
|
155
|
+
settings["permission_backend"] = "kinto.core.permission.memory"
|
|
156
|
+
|
|
157
|
+
settings.update(extras or None)
|
|
158
|
+
|
|
159
|
+
return settings
|
|
160
|
+
|
|
161
|
+
def tearDown(self):
|
|
162
|
+
super().tearDown()
|
|
163
|
+
self.storage.flush()
|
|
164
|
+
self.cache.flush()
|
|
165
|
+
self.permission.flush()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class ThreadMixin:
|
|
169
|
+
def setUp(self):
|
|
170
|
+
super().setUp()
|
|
171
|
+
self._threads = []
|
|
172
|
+
|
|
173
|
+
def tearDown(self):
|
|
174
|
+
super().tearDown()
|
|
175
|
+
|
|
176
|
+
for thread in self._threads:
|
|
177
|
+
thread.join()
|
|
178
|
+
|
|
179
|
+
def _create_thread(self, *args, **kwargs):
|
|
180
|
+
thread = threading.Thread(*args, **kwargs)
|
|
181
|
+
self._threads.append(thread)
|
|
182
|
+
return thread
|