plain 0.25.0__py3-none-any.whl → 0.26.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.
- plain/packages/__init__.py +2 -2
- plain/packages/config.py +48 -160
- plain/packages/registry.py +64 -10
- plain/templates/jinja/__init__.py +18 -13
- plain/utils/module_loading.py +0 -19
- {plain-0.25.0.dist-info → plain-0.26.0.dist-info}/METADATA +1 -1
- {plain-0.25.0.dist-info → plain-0.26.0.dist-info}/RECORD +10 -10
- {plain-0.25.0.dist-info → plain-0.26.0.dist-info}/WHEEL +0 -0
- {plain-0.25.0.dist-info → plain-0.26.0.dist-info}/entry_points.txt +0 -0
- {plain-0.25.0.dist-info → plain-0.26.0.dist-info}/licenses/LICENSE +0 -0
plain/packages/__init__.py
CHANGED
plain/packages/config.py
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
import inspect
|
2
1
|
import os
|
2
|
+
from functools import cached_property
|
3
3
|
from importlib import import_module
|
4
4
|
|
5
5
|
from plain.exceptions import ImproperlyConfigured
|
6
|
-
from plain.utils.module_loading import import_string, module_has_submodule
|
7
6
|
|
8
7
|
CONFIG_MODULE_NAME = "config"
|
9
8
|
|
@@ -13,13 +12,9 @@ class PackageConfig:
|
|
13
12
|
|
14
13
|
migrations_module = "migrations"
|
15
14
|
|
16
|
-
def __init__(self,
|
15
|
+
def __init__(self, name, *, label=""):
|
17
16
|
# Full Python path to the application e.g. 'plain.admin.admin'.
|
18
|
-
self.name =
|
19
|
-
|
20
|
-
# Root module for the application e.g. <module 'plain.admin.admin'
|
21
|
-
# from 'admin/__init__.py'>.
|
22
|
-
self.module = package_module
|
17
|
+
self.name = name
|
23
18
|
|
24
19
|
# Reference to the Packages registry that holds this PackageConfig. Set by the
|
25
20
|
# registry when it registers the PackageConfig instance.
|
@@ -27,168 +22,61 @@ class PackageConfig:
|
|
27
22
|
|
28
23
|
# The following attributes could be defined at the class level in a
|
29
24
|
# subclass, hence the test-and-set pattern.
|
25
|
+
if label and hasattr(self, "label"):
|
26
|
+
raise ImproperlyConfigured(
|
27
|
+
"PackageConfig class should not define a class label attribute and an init label"
|
28
|
+
)
|
29
|
+
|
30
|
+
if label:
|
31
|
+
# Set the label explicitly from the init
|
32
|
+
self.label = label
|
33
|
+
elif not hasattr(self, "label"):
|
34
|
+
# Last component of the Python path to the application e.g. 'admin'.
|
35
|
+
# This value must be unique across a Plain project.
|
36
|
+
self.label = self.name.rpartition(".")[2]
|
30
37
|
|
31
|
-
# Last component of the Python path to the application e.g. 'admin'.
|
32
|
-
# This value must be unique across a Plain project.
|
33
|
-
if not hasattr(self, "label"):
|
34
|
-
self.label = package_name.rpartition(".")[2]
|
35
38
|
if not self.label.isidentifier():
|
36
39
|
raise ImproperlyConfigured(
|
37
40
|
f"The app label '{self.label}' is not a valid Python identifier."
|
38
41
|
)
|
39
42
|
|
40
|
-
# Filesystem path to the application directory e.g.
|
41
|
-
# '/path/to/admin'.
|
42
|
-
if not hasattr(self, "path"):
|
43
|
-
self.path = self._path_from_module(package_module)
|
44
|
-
|
45
43
|
def __repr__(self):
|
46
44
|
return f"<{self.__class__.__name__}: {self.label}>"
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
#
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
if len(paths) > 1:
|
63
|
-
raise ImproperlyConfigured(
|
64
|
-
f"The app module {module!r} has multiple filesystem locations ({paths!r}); "
|
65
|
-
"you must configure this app with an PackageConfig subclass "
|
66
|
-
"with a 'path' class attribute."
|
67
|
-
)
|
68
|
-
elif not paths:
|
69
|
-
raise ImproperlyConfigured(
|
70
|
-
f"The app module {module!r} has no filesystem location, "
|
71
|
-
"you must configure this app with an PackageConfig subclass "
|
72
|
-
"with a 'path' class attribute."
|
73
|
-
)
|
74
|
-
return paths[0]
|
75
|
-
|
76
|
-
@classmethod
|
77
|
-
def create(cls, entry):
|
78
|
-
"""
|
79
|
-
Factory that creates an app config from an entry in INSTALLED_PACKAGES.
|
80
|
-
"""
|
81
|
-
# create() eventually returns package_config_class(package_name, package_module).
|
82
|
-
package_config_class = None
|
83
|
-
package_name = None
|
84
|
-
package_module = None
|
85
|
-
|
86
|
-
# If import_module succeeds, entry points to the app module.
|
87
|
-
try:
|
88
|
-
package_module = import_module(entry)
|
89
|
-
except Exception:
|
90
|
-
pass
|
91
|
-
else:
|
92
|
-
# If package_module has an packages submodule that defines a single
|
93
|
-
# PackageConfig subclass, use it automatically.
|
94
|
-
# To prevent this, an PackageConfig subclass can declare a class
|
95
|
-
# variable default = False.
|
96
|
-
# If the packages module defines more than one PackageConfig subclass,
|
97
|
-
# the default one can declare default = True.
|
98
|
-
if module_has_submodule(package_module, CONFIG_MODULE_NAME):
|
99
|
-
mod_path = f"{entry}.{CONFIG_MODULE_NAME}"
|
100
|
-
mod = import_module(mod_path)
|
101
|
-
# Check if there's exactly one PackageConfig candidate,
|
102
|
-
# excluding those that explicitly define default = False.
|
103
|
-
package_configs = [
|
104
|
-
(name, candidate)
|
105
|
-
for name, candidate in inspect.getmembers(mod, inspect.isclass)
|
106
|
-
if (
|
107
|
-
issubclass(candidate, cls)
|
108
|
-
and candidate is not cls
|
109
|
-
and getattr(candidate, "default", True)
|
110
|
-
)
|
111
|
-
]
|
112
|
-
if len(package_configs) == 1:
|
113
|
-
package_config_class = package_configs[0][1]
|
46
|
+
@cached_property
|
47
|
+
def path(self):
|
48
|
+
# Filesystem path to the application directory e.g.
|
49
|
+
# '/path/to/admin'.
|
50
|
+
def _path_from_module(module):
|
51
|
+
"""Attempt to determine app's filesystem path from its module."""
|
52
|
+
# See #21874 for extended discussion of the behavior of this method in
|
53
|
+
# various cases.
|
54
|
+
# Convert to list because __path__ may not support indexing.
|
55
|
+
paths = list(getattr(module, "__path__", []))
|
56
|
+
if len(paths) != 1:
|
57
|
+
filename = getattr(module, "__file__", None)
|
58
|
+
if filename is not None:
|
59
|
+
paths = [os.path.dirname(filename)]
|
114
60
|
else:
|
115
|
-
#
|
116
|
-
#
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
package_name = entry
|
135
|
-
|
136
|
-
# If import_string succeeds, entry is an app config class.
|
137
|
-
if package_config_class is None:
|
138
|
-
try:
|
139
|
-
package_config_class = import_string(entry)
|
140
|
-
except Exception:
|
141
|
-
pass
|
142
|
-
# If both import_module and import_string failed, it means that entry
|
143
|
-
# doesn't have a valid value.
|
144
|
-
if package_module is None and package_config_class is None:
|
145
|
-
# If the last component of entry starts with an uppercase letter,
|
146
|
-
# then it was likely intended to be an app config class; if not,
|
147
|
-
# an app module. Provide a nice error message in both cases.
|
148
|
-
mod_path, _, cls_name = entry.rpartition(".")
|
149
|
-
if mod_path and cls_name[0].isupper():
|
150
|
-
# We could simply re-trigger the string import exception, but
|
151
|
-
# we're going the extra mile and providing a better error
|
152
|
-
# message for typos in INSTALLED_PACKAGES.
|
153
|
-
# This may raise ImportError, which is the best exception
|
154
|
-
# possible if the module at mod_path cannot be imported.
|
155
|
-
mod = import_module(mod_path)
|
156
|
-
candidates = [
|
157
|
-
repr(name)
|
158
|
-
for name, candidate in inspect.getmembers(mod, inspect.isclass)
|
159
|
-
if issubclass(candidate, cls) and candidate is not cls
|
160
|
-
]
|
161
|
-
msg = f"Module '{mod_path}' does not contain a '{cls_name}' class."
|
162
|
-
if candidates:
|
163
|
-
msg += " Choices are: {}.".format(", ".join(candidates))
|
164
|
-
raise ImportError(msg)
|
165
|
-
else:
|
166
|
-
# Re-trigger the module import exception.
|
167
|
-
import_module(entry)
|
168
|
-
|
169
|
-
# Check for obvious errors. (This check prevents duck typing, but
|
170
|
-
# it could be removed if it became a problem in practice.)
|
171
|
-
if not issubclass(package_config_class, PackageConfig):
|
172
|
-
raise ImproperlyConfigured(f"'{entry}' isn't a subclass of PackageConfig.")
|
173
|
-
|
174
|
-
# Obtain package name here rather than in PackageClass.__init__ to keep
|
175
|
-
# all error checking for entries in INSTALLED_PACKAGES in one place.
|
176
|
-
if package_name is None:
|
177
|
-
try:
|
178
|
-
package_name = package_config_class.name
|
179
|
-
except AttributeError:
|
180
|
-
raise ImproperlyConfigured(f"'{entry}' must supply a name attribute.")
|
181
|
-
|
182
|
-
# Ensure package_name points to a valid module.
|
183
|
-
try:
|
184
|
-
package_module = import_module(package_name)
|
185
|
-
except ImportError:
|
186
|
-
raise ImproperlyConfigured(
|
187
|
-
f"Cannot import '{package_name}'. Check that '{package_config_class.__module__}.{package_config_class.__qualname__}.name' is correct."
|
188
|
-
)
|
189
|
-
|
190
|
-
# Entry is a path to an app config class.
|
191
|
-
return package_config_class(package_name, package_module)
|
61
|
+
# For unknown reasons, sometimes the list returned by __path__
|
62
|
+
# contains duplicates that must be removed (#25246).
|
63
|
+
paths = list(set(paths))
|
64
|
+
if len(paths) > 1:
|
65
|
+
raise ImproperlyConfigured(
|
66
|
+
f"The app module {module!r} has multiple filesystem locations ({paths!r}); "
|
67
|
+
"you must configure this app with an PackageConfig subclass "
|
68
|
+
"with a 'path' class attribute."
|
69
|
+
)
|
70
|
+
elif not paths:
|
71
|
+
raise ImproperlyConfigured(
|
72
|
+
f"The app module {module!r} has no filesystem location, "
|
73
|
+
"you must configure this app with an PackageConfig subclass "
|
74
|
+
"with a 'path' class attribute."
|
75
|
+
)
|
76
|
+
return paths[0]
|
77
|
+
|
78
|
+
module = import_module(self.name)
|
79
|
+
return _path_from_module(module)
|
192
80
|
|
193
81
|
def ready(self):
|
194
82
|
"""
|
plain/packages/registry.py
CHANGED
@@ -4,11 +4,14 @@ import threading
|
|
4
4
|
import warnings
|
5
5
|
from collections import Counter, defaultdict
|
6
6
|
from functools import partial
|
7
|
+
from importlib import import_module
|
7
8
|
|
8
9
|
from plain.exceptions import ImproperlyConfigured, PackageRegistryNotReady
|
9
10
|
|
10
11
|
from .config import PackageConfig
|
11
12
|
|
13
|
+
CONFIG_MODULE_NAME = "config"
|
14
|
+
|
12
15
|
|
13
16
|
class PackagesRegistry:
|
14
17
|
"""
|
@@ -82,17 +85,35 @@ class PackagesRegistry:
|
|
82
85
|
# Phase 1: initialize app configs and import app modules.
|
83
86
|
for entry in installed_packages:
|
84
87
|
if isinstance(entry, PackageConfig):
|
85
|
-
|
88
|
+
# Some instances of the registry pass in the
|
89
|
+
# PackageConfig directly...
|
90
|
+
self.register_config(entry)
|
86
91
|
else:
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
try:
|
93
|
+
import_module(f"{entry}.{CONFIG_MODULE_NAME}")
|
94
|
+
except ModuleNotFoundError:
|
95
|
+
pass
|
96
|
+
|
97
|
+
# The config for the package should now be registered, if it existed.
|
98
|
+
# And if it didn't, now we can auto generate one.
|
99
|
+
entry_config = None
|
100
|
+
for config in self.package_configs.values():
|
101
|
+
if config.name == entry:
|
102
|
+
entry_config = config
|
103
|
+
break
|
104
|
+
|
105
|
+
if not entry_config:
|
106
|
+
# Use PackageConfig class as-is, without any customization.
|
107
|
+
entry_config = self.register_config(
|
108
|
+
PackageConfig, module_name=entry
|
109
|
+
)
|
110
|
+
|
111
|
+
# Make sure we have the same number of configs as we have installed packages
|
112
|
+
if len(self.package_configs) != len(installed_packages):
|
113
|
+
raise ImproperlyConfigured(
|
114
|
+
f"The number of installed packages ({len(installed_packages)}) does not match the number of "
|
115
|
+
f"registered configs ({len(self.package_configs)})."
|
116
|
+
)
|
96
117
|
|
97
118
|
# Check for duplicate app names.
|
98
119
|
counts = Counter(
|
@@ -372,5 +393,38 @@ class PackagesRegistry:
|
|
372
393
|
for function in self._pending_operations.pop(key, []):
|
373
394
|
function(model)
|
374
395
|
|
396
|
+
def register_config(self, package_config, module_name=""):
|
397
|
+
"""
|
398
|
+
Add a config to the registry.
|
399
|
+
|
400
|
+
Typically used as a decorator on a PackageConfig subclass. Example:
|
401
|
+
|
402
|
+
@register_config
|
403
|
+
class Config(PackageConfig):
|
404
|
+
pass
|
405
|
+
"""
|
406
|
+
if not module_name:
|
407
|
+
module_name = package_config.__module__
|
408
|
+
|
409
|
+
# If it is in .config like expected, return the parent module name
|
410
|
+
if module_name.endswith(f".{CONFIG_MODULE_NAME}"):
|
411
|
+
module_name = module_name[: -len(CONFIG_MODULE_NAME) - 1]
|
412
|
+
|
413
|
+
if isinstance(package_config, type) and issubclass(
|
414
|
+
package_config, PackageConfig
|
415
|
+
):
|
416
|
+
# A class was passed, so init it
|
417
|
+
package_config = package_config(module_name)
|
418
|
+
|
419
|
+
if package_config.label in self.package_configs:
|
420
|
+
raise ImproperlyConfigured(
|
421
|
+
f"Package labels aren't unique, duplicates: {package_config.label}"
|
422
|
+
)
|
423
|
+
self.package_configs[package_config.label] = package_config
|
424
|
+
package_config.packages = self
|
425
|
+
|
426
|
+
return package_config
|
427
|
+
|
375
428
|
|
376
429
|
packages_registry = PackagesRegistry(installed_packages=None)
|
430
|
+
register_config = packages_registry.register_config
|
@@ -3,7 +3,7 @@ from importlib import import_module
|
|
3
3
|
from plain.packages import packages_registry
|
4
4
|
from plain.runtime import settings
|
5
5
|
from plain.utils.functional import LazyObject
|
6
|
-
from plain.utils.module_loading import import_string
|
6
|
+
from plain.utils.module_loading import import_string
|
7
7
|
|
8
8
|
from .environments import DefaultEnvironment, get_template_dirs
|
9
9
|
|
@@ -24,20 +24,25 @@ class JinjaEnvironment(LazyObject):
|
|
24
24
|
# We have to set _wrapped before we trigger the autoloading of "register" commands
|
25
25
|
self._wrapped = env
|
26
26
|
|
27
|
-
def _maybe_import_module(name):
|
28
|
-
if name not in self._imported_modules:
|
29
|
-
import_module(name)
|
30
|
-
self._imported_modules.add(name)
|
31
|
-
|
32
27
|
for package_config in packages_registry.get_package_configs():
|
33
|
-
if module_has_submodule(package_config.module, "templates"):
|
34
|
-
# Allow this to fail in case there are import errors inside of their file
|
35
|
-
_maybe_import_module(f"{package_config.name}.templates")
|
36
|
-
|
37
|
-
app = import_module("app")
|
38
|
-
if module_has_submodule(app, "templates"):
|
39
28
|
# Allow this to fail in case there are import errors inside of their file
|
40
|
-
|
29
|
+
import_name = f"{package_config.name}.templates"
|
30
|
+
if import_name in self._imported_modules:
|
31
|
+
continue
|
32
|
+
try:
|
33
|
+
import_module(import_name)
|
34
|
+
self._imported_modules.add(import_name)
|
35
|
+
except ModuleNotFoundError:
|
36
|
+
pass
|
37
|
+
|
38
|
+
# Allow this to fail in case there are import errors inside of their file
|
39
|
+
import_name = "app.templates"
|
40
|
+
if import_name not in self._imported_modules:
|
41
|
+
try:
|
42
|
+
import_module(import_name)
|
43
|
+
self._imported_modules.add(import_name)
|
44
|
+
except ModuleNotFoundError:
|
45
|
+
pass
|
41
46
|
|
42
47
|
|
43
48
|
environment = JinjaEnvironment()
|
plain/utils/module_loading.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
import sys
|
3
3
|
from importlib import import_module
|
4
|
-
from importlib.util import find_spec as importlib_find
|
5
4
|
|
6
5
|
|
7
6
|
def cached_import(module_path, class_name):
|
@@ -33,24 +32,6 @@ def import_string(dotted_path):
|
|
33
32
|
) from err
|
34
33
|
|
35
34
|
|
36
|
-
def module_has_submodule(package, module_name):
|
37
|
-
"""See if 'module' is in 'package'."""
|
38
|
-
try:
|
39
|
-
package_name = package.__name__
|
40
|
-
package_path = package.__path__
|
41
|
-
except AttributeError:
|
42
|
-
# package isn't a package.
|
43
|
-
return False
|
44
|
-
|
45
|
-
full_module_name = package_name + "." + module_name
|
46
|
-
try:
|
47
|
-
return importlib_find(full_module_name, package_path) is not None
|
48
|
-
except ModuleNotFoundError:
|
49
|
-
# When module_name is an invalid dotted path, Python raises
|
50
|
-
# ModuleNotFoundError.
|
51
|
-
return False
|
52
|
-
|
53
|
-
|
54
35
|
def module_dir(module):
|
55
36
|
"""
|
56
37
|
Find the name of the directory that contains a module, if possible.
|
@@ -60,9 +60,9 @@ plain/logs/configure.py,sha256=6mV7d1IxkDYT3VBz61qhIj0Esuy5l5QdQfsHaGCfI6w,1063
|
|
60
60
|
plain/logs/loggers.py,sha256=iz9SYcwP9w5QAuwpULl48SFkVyJuuMoQ_fdLgdCHpNg,2121
|
61
61
|
plain/logs/utils.py,sha256=9UzdCCQXJinGDs71Ngw297mlWkhgZStSd67ya4NOW98,1257
|
62
62
|
plain/packages/README.md,sha256=Vq1Nw3mmEmZ2IriQavuVi4BjcQC2nb8k7YIbnm8QjIg,799
|
63
|
-
plain/packages/__init__.py,sha256=
|
64
|
-
plain/packages/config.py,sha256=
|
65
|
-
plain/packages/registry.py,sha256=
|
63
|
+
plain/packages/__init__.py,sha256=OpQny0xLplPdPpozVUUkrW2gB-IIYyDT1b4zMzOcCC4,160
|
64
|
+
plain/packages/config.py,sha256=Gmu7QW4Z3Cx9_d7N2D5o7t292t7vAOE8aL-3yO7sGqc,3327
|
65
|
+
plain/packages/registry.py,sha256=UEagFzHXCSuGeMlz2E1JLj0fgigOR89i5yVZe8Pq9Ds,17589
|
66
66
|
plain/preflight/README.md,sha256=-PKVd0RBMh4ROiMkegPS2PgvT1Kq9qqN1KfNkmUSdFc,177
|
67
67
|
plain/preflight/__init__.py,sha256=H-TNRvaddPtOGmv4RXoc1fxDV1AOb7_K3u7ECF8mV58,607
|
68
68
|
plain/preflight/files.py,sha256=wbHCNgps7o1c1zQNBd8FDCaVaqX90UwuvLgEQ_DbUpY,510
|
@@ -83,7 +83,7 @@ plain/templates/README.md,sha256=VfA2HmrklG5weE1md85q9g84cWnMBEiXAynKzM7S1Sk,464
|
|
83
83
|
plain/templates/__init__.py,sha256=bX76FakE9T7mfK3N0deN85HlwHNQpeigytSC9Z8LcOs,451
|
84
84
|
plain/templates/core.py,sha256=iw58EAmyyv8N5HDA-Sq4-fLgz_qx8v8WJfurgR116jw,625
|
85
85
|
plain/templates/jinja/README.md,sha256=ft4781b4IAVI6fsIdAHIpOigdsZ6wGg06LK7BHxoj-g,6996
|
86
|
-
plain/templates/jinja/__init__.py,sha256=
|
86
|
+
plain/templates/jinja/__init__.py,sha256=qBESSL8XfwdxtwujjR5mZvk4VddlMn1-jOsSxGQy0oE,2768
|
87
87
|
plain/templates/jinja/environments.py,sha256=9plifzvQj--aTN1cCpJ2WdzQxZJpzB8S_4hghgQRQT0,2064
|
88
88
|
plain/templates/jinja/extensions.py,sha256=AEmmmHDbdRW8fhjYDzq9eSSNbp9WHsXenD8tPthjc0s,1351
|
89
89
|
plain/templates/jinja/filters.py,sha256=3KJKKbxcv9dLzUDWPcaa88k3NU2m1GG3iMIgFhzXrBA,860
|
@@ -117,7 +117,7 @@ plain/utils/http.py,sha256=VOOnwRXnDp5PL_qEmkInLTm10fF58vlhVjeSTdzV2cQ,6031
|
|
117
117
|
plain/utils/inspect.py,sha256=O3VMH5f4aGOrVpXJBKtQOxx01XrKnjjz6VO_MCV0xkE,1140
|
118
118
|
plain/utils/ipv6.py,sha256=pISQ2AIlG8xXlxpphn388q03fq-fOrlu4GZR0YYjQXw,1267
|
119
119
|
plain/utils/itercompat.py,sha256=lacIDjczhxbwG4ON_KfG1H6VNPOGOpbRhnVhbedo2CY,184
|
120
|
-
plain/utils/module_loading.py,sha256=
|
120
|
+
plain/utils/module_loading.py,sha256=11a1JbASB-KbahQe2Dlhiw_2VD71lKKZYmo3y_wfJeI,1640
|
121
121
|
plain/utils/regex_helper.py,sha256=pAdh_xG52BOyXLsiuIMPFgduUAoWOEje1ZpjhcefxiA,12769
|
122
122
|
plain/utils/safestring.py,sha256=sawOehuWjr4bkF5jXXCcziILQGoqUcA_eEfsURrAyN0,1801
|
123
123
|
plain/utils/text.py,sha256=42hJv06sadbWfsaAHNhqCQaP1W9qZ69trWDTS-Xva7k,9496
|
@@ -134,8 +134,8 @@ plain/views/forms.py,sha256=RhlaUcZCkeqokY_fvv-NOS-kgZAG4XhDLOPbf9K_Zlc,2691
|
|
134
134
|
plain/views/objects.py,sha256=g5Lzno0Zsv0K449UpcCtxwCoO7WMRAWqKlxxV2V0_qg,8263
|
135
135
|
plain/views/redirect.py,sha256=9zHZgKvtSkdrMX9KmsRM8hJTPmBktxhc4d8OitbuniI,1724
|
136
136
|
plain/views/templates.py,sha256=cBkFNCSXgVi8cMqQbhsqJ4M_rIQYVl8cUvq9qu4YIes,1951
|
137
|
-
plain-0.
|
138
|
-
plain-0.
|
139
|
-
plain-0.
|
140
|
-
plain-0.
|
141
|
-
plain-0.
|
137
|
+
plain-0.26.0.dist-info/METADATA,sha256=ubQaY6xdMzXNiRH6AvYXOWNyOdmthru0UB3-AKlPnxU,319
|
138
|
+
plain-0.26.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
139
|
+
plain-0.26.0.dist-info/entry_points.txt,sha256=DHHprvufgd7xypiBiqMANYRnpJ9xPPYhYbnPGwOkWqE,40
|
140
|
+
plain-0.26.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
|
141
|
+
plain-0.26.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|