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.
Files changed (142) hide show
  1. kinto/__init__.py +92 -0
  2. kinto/__main__.py +249 -0
  3. kinto/authorization.py +134 -0
  4. kinto/config/__init__.py +94 -0
  5. kinto/config/kinto.tpl +270 -0
  6. kinto/contribute.json +27 -0
  7. kinto/core/__init__.py +246 -0
  8. kinto/core/authentication.py +48 -0
  9. kinto/core/authorization.py +311 -0
  10. kinto/core/cache/__init__.py +131 -0
  11. kinto/core/cache/memcached.py +112 -0
  12. kinto/core/cache/memory.py +104 -0
  13. kinto/core/cache/postgresql/__init__.py +178 -0
  14. kinto/core/cache/postgresql/schema.sql +23 -0
  15. kinto/core/cache/testing.py +208 -0
  16. kinto/core/cornice/__init__.py +93 -0
  17. kinto/core/cornice/cors.py +144 -0
  18. kinto/core/cornice/errors.py +40 -0
  19. kinto/core/cornice/pyramidhook.py +373 -0
  20. kinto/core/cornice/renderer.py +89 -0
  21. kinto/core/cornice/resource.py +205 -0
  22. kinto/core/cornice/service.py +641 -0
  23. kinto/core/cornice/util.py +138 -0
  24. kinto/core/cornice/validators/__init__.py +94 -0
  25. kinto/core/cornice/validators/_colander.py +142 -0
  26. kinto/core/cornice/validators/_marshmallow.py +182 -0
  27. kinto/core/cornice_swagger/__init__.py +92 -0
  28. kinto/core/cornice_swagger/converters/__init__.py +21 -0
  29. kinto/core/cornice_swagger/converters/exceptions.py +6 -0
  30. kinto/core/cornice_swagger/converters/parameters.py +90 -0
  31. kinto/core/cornice_swagger/converters/schema.py +249 -0
  32. kinto/core/cornice_swagger/swagger.py +725 -0
  33. kinto/core/cornice_swagger/templates/index.html +73 -0
  34. kinto/core/cornice_swagger/templates/index_script_template.html +21 -0
  35. kinto/core/cornice_swagger/util.py +42 -0
  36. kinto/core/cornice_swagger/views.py +78 -0
  37. kinto/core/decorators.py +74 -0
  38. kinto/core/errors.py +216 -0
  39. kinto/core/events.py +301 -0
  40. kinto/core/initialization.py +738 -0
  41. kinto/core/listeners/__init__.py +9 -0
  42. kinto/core/metrics.py +94 -0
  43. kinto/core/openapi.py +115 -0
  44. kinto/core/permission/__init__.py +202 -0
  45. kinto/core/permission/memory.py +167 -0
  46. kinto/core/permission/postgresql/__init__.py +489 -0
  47. kinto/core/permission/postgresql/migrations/migration_001_002.sql +18 -0
  48. kinto/core/permission/postgresql/schema.sql +41 -0
  49. kinto/core/permission/testing.py +487 -0
  50. kinto/core/resource/__init__.py +1311 -0
  51. kinto/core/resource/model.py +412 -0
  52. kinto/core/resource/schema.py +502 -0
  53. kinto/core/resource/viewset.py +230 -0
  54. kinto/core/schema.py +119 -0
  55. kinto/core/scripts.py +50 -0
  56. kinto/core/statsd.py +1 -0
  57. kinto/core/storage/__init__.py +436 -0
  58. kinto/core/storage/exceptions.py +53 -0
  59. kinto/core/storage/generators.py +58 -0
  60. kinto/core/storage/memory.py +651 -0
  61. kinto/core/storage/postgresql/__init__.py +1131 -0
  62. kinto/core/storage/postgresql/client.py +120 -0
  63. kinto/core/storage/postgresql/migrations/migration_001_002.sql +10 -0
  64. kinto/core/storage/postgresql/migrations/migration_002_003.sql +33 -0
  65. kinto/core/storage/postgresql/migrations/migration_003_004.sql +18 -0
  66. kinto/core/storage/postgresql/migrations/migration_004_005.sql +20 -0
  67. kinto/core/storage/postgresql/migrations/migration_005_006.sql +11 -0
  68. kinto/core/storage/postgresql/migrations/migration_006_007.sql +74 -0
  69. kinto/core/storage/postgresql/migrations/migration_007_008.sql +66 -0
  70. kinto/core/storage/postgresql/migrations/migration_008_009.sql +41 -0
  71. kinto/core/storage/postgresql/migrations/migration_009_010.sql +98 -0
  72. kinto/core/storage/postgresql/migrations/migration_010_011.sql +14 -0
  73. kinto/core/storage/postgresql/migrations/migration_011_012.sql +9 -0
  74. kinto/core/storage/postgresql/migrations/migration_012_013.sql +71 -0
  75. kinto/core/storage/postgresql/migrations/migration_013_014.sql +14 -0
  76. kinto/core/storage/postgresql/migrations/migration_014_015.sql +95 -0
  77. kinto/core/storage/postgresql/migrations/migration_015_016.sql +4 -0
  78. kinto/core/storage/postgresql/migrations/migration_016_017.sql +81 -0
  79. kinto/core/storage/postgresql/migrations/migration_017_018.sql +25 -0
  80. kinto/core/storage/postgresql/migrations/migration_018_019.sql +8 -0
  81. kinto/core/storage/postgresql/migrations/migration_019_020.sql +7 -0
  82. kinto/core/storage/postgresql/migrations/migration_020_021.sql +68 -0
  83. kinto/core/storage/postgresql/migrations/migration_021_022.sql +62 -0
  84. kinto/core/storage/postgresql/migrations/migration_022_023.sql +5 -0
  85. kinto/core/storage/postgresql/migrations/migration_023_024.sql +6 -0
  86. kinto/core/storage/postgresql/migrations/migration_024_025.sql +6 -0
  87. kinto/core/storage/postgresql/migrator.py +98 -0
  88. kinto/core/storage/postgresql/pool.py +55 -0
  89. kinto/core/storage/postgresql/schema.sql +143 -0
  90. kinto/core/storage/testing.py +1857 -0
  91. kinto/core/storage/utils.py +37 -0
  92. kinto/core/testing.py +182 -0
  93. kinto/core/utils.py +553 -0
  94. kinto/core/views/__init__.py +0 -0
  95. kinto/core/views/batch.py +163 -0
  96. kinto/core/views/errors.py +145 -0
  97. kinto/core/views/heartbeat.py +106 -0
  98. kinto/core/views/hello.py +69 -0
  99. kinto/core/views/openapi.py +35 -0
  100. kinto/core/views/version.py +50 -0
  101. kinto/events.py +3 -0
  102. kinto/plugins/__init__.py +0 -0
  103. kinto/plugins/accounts/__init__.py +94 -0
  104. kinto/plugins/accounts/authentication.py +63 -0
  105. kinto/plugins/accounts/scripts.py +61 -0
  106. kinto/plugins/accounts/utils.py +13 -0
  107. kinto/plugins/accounts/views.py +136 -0
  108. kinto/plugins/admin/README.md +3 -0
  109. kinto/plugins/admin/VERSION +1 -0
  110. kinto/plugins/admin/__init__.py +40 -0
  111. kinto/plugins/admin/build/VERSION +1 -0
  112. kinto/plugins/admin/build/assets/index-CYFwtKtL.css +6 -0
  113. kinto/plugins/admin/build/assets/index-DJ0m93zA.js +149 -0
  114. kinto/plugins/admin/build/assets/logo-VBRiKSPX.png +0 -0
  115. kinto/plugins/admin/build/index.html +18 -0
  116. kinto/plugins/admin/public/help.html +25 -0
  117. kinto/plugins/admin/views.py +42 -0
  118. kinto/plugins/default_bucket/__init__.py +191 -0
  119. kinto/plugins/flush.py +28 -0
  120. kinto/plugins/history/__init__.py +65 -0
  121. kinto/plugins/history/listener.py +181 -0
  122. kinto/plugins/history/views.py +66 -0
  123. kinto/plugins/openid/__init__.py +131 -0
  124. kinto/plugins/openid/utils.py +14 -0
  125. kinto/plugins/openid/views.py +193 -0
  126. kinto/plugins/prometheus.py +300 -0
  127. kinto/plugins/statsd.py +85 -0
  128. kinto/schema_validation.py +135 -0
  129. kinto/views/__init__.py +34 -0
  130. kinto/views/admin.py +195 -0
  131. kinto/views/buckets.py +45 -0
  132. kinto/views/collections.py +58 -0
  133. kinto/views/contribute.py +39 -0
  134. kinto/views/groups.py +90 -0
  135. kinto/views/permissions.py +235 -0
  136. kinto/views/records.py +133 -0
  137. kinto-23.2.1.dist-info/METADATA +232 -0
  138. kinto-23.2.1.dist-info/RECORD +142 -0
  139. kinto-23.2.1.dist-info/WHEEL +5 -0
  140. kinto-23.2.1.dist-info/entry_points.txt +5 -0
  141. kinto-23.2.1.dist-info/licenses/LICENSE +13 -0
  142. 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