plain 0.40.0__py3-none-any.whl → 0.42.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.
@@ -80,12 +80,12 @@ class BaseHandler:
80
80
  """
81
81
  resolver_match = self.resolve_request(request)
82
82
 
83
- response = resolver_match.func(
83
+ response = resolver_match.view(
84
84
  request, *resolver_match.args, **resolver_match.kwargs
85
85
  )
86
86
 
87
87
  # Complain if the view returned None (a common error).
88
- self.check_response(response, resolver_match.func)
88
+ self.check_response(response, resolver_match.view)
89
89
 
90
90
  return response
91
91
 
@@ -19,6 +19,8 @@ default_filters = {
19
19
  # The standard Python ones
20
20
  "strftime": datetime.datetime.strftime,
21
21
  "strptime": datetime.datetime.strptime,
22
+ "fromtimestamp": datetime.datetime.fromtimestamp,
23
+ "fromisoformat": datetime.datetime.fromisoformat,
22
24
  # To convert to user time zone
23
25
  "localtime": localtime_filter,
24
26
  "timeuntil": timeuntil,
plain/urls/patterns.py CHANGED
@@ -1,13 +1,10 @@
1
- import functools
2
- import inspect
3
1
  import re
4
2
  import string
5
3
 
6
4
  from plain.exceptions import ImproperlyConfigured
7
5
  from plain.internal import internalcode
8
- from plain.preflight import Error, Warning
6
+ from plain.preflight import Warning
9
7
  from plain.runtime import settings
10
- from plain.utils.functional import cached_property
11
8
  from plain.utils.regex_helper import _lazy_re_compile
12
9
 
13
10
  from .converters import get_converter
@@ -226,20 +223,6 @@ class URLPattern:
226
223
  else:
227
224
  return []
228
225
 
229
- def _check_view(self):
230
- from plain.views import View
231
-
232
- view = self.view
233
- if inspect.isclass(view) and issubclass(view, View):
234
- return [
235
- Error(
236
- f"Your URL pattern {self.pattern.describe()} has an invalid view, pass {view.__name__}.as_view() "
237
- f"instead of {view.__name__}.",
238
- id="urls.E009",
239
- )
240
- ]
241
- return []
242
-
243
226
  def resolve(self, path):
244
227
  match = self.pattern.match(path)
245
228
  if match:
@@ -247,25 +230,9 @@ class URLPattern:
247
230
  from .resolvers import ResolverMatch
248
231
 
249
232
  return ResolverMatch(
250
- self.view,
251
- args,
252
- captured_kwargs,
253
- self.pattern.name,
233
+ view=self.view,
234
+ args=args,
235
+ kwargs=captured_kwargs,
236
+ url_name=self.pattern.name,
254
237
  route=str(self.pattern),
255
- captured_kwargs=captured_kwargs,
256
238
  )
257
-
258
- @cached_property
259
- def lookup_str(self):
260
- """
261
- A string that identifies the view (e.g. 'path.to.view_function' or
262
- 'path.to.ClassBasedView').
263
- """
264
- view = self.view
265
- if isinstance(view, functools.partial):
266
- view = view.func
267
- if hasattr(view, "view_class"):
268
- view = view.view_class
269
- elif not hasattr(view, "__name__"):
270
- return view.__module__ + "." + view.__class__.__name__
271
- return view.__module__ + "." + view.__qualname__
plain/urls/resolvers.py CHANGED
@@ -8,7 +8,6 @@ attributes of the resolved URL match.
8
8
 
9
9
  import functools
10
10
  import re
11
- from pickle import PicklingError
12
11
  from threading import local
13
12
  from urllib.parse import quote
14
13
 
@@ -26,66 +25,29 @@ from .patterns import RegexPattern, URLPattern
26
25
  class ResolverMatch:
27
26
  def __init__(
28
27
  self,
29
- func,
28
+ *,
29
+ view,
30
30
  args,
31
31
  kwargs,
32
32
  url_name=None,
33
33
  namespaces=None,
34
34
  route=None,
35
- tried=None,
36
- captured_kwargs=None,
37
- extra_kwargs=None,
38
35
  ):
39
- self.func = func
36
+ self.view = view
40
37
  self.args = args
41
38
  self.kwargs = kwargs
42
39
  self.url_name = url_name
43
40
  self.route = route
44
- self.tried = tried
45
- self.captured_kwargs = captured_kwargs
46
- self.extra_kwargs = extra_kwargs
47
41
 
48
42
  # If a URLRegexResolver doesn't have a namespace or namespace, it passes
49
43
  # in an empty value.
50
44
  self.namespaces = [x for x in namespaces if x] if namespaces else []
51
45
  self.namespace = ":".join(self.namespaces)
52
46
 
53
- if hasattr(func, "view_class"):
54
- func = func.view_class
55
- if not hasattr(func, "__name__"):
56
- # A class-based view
57
- self._func_path = func.__class__.__module__ + "." + func.__class__.__name__
58
- else:
59
- # A function-based view
60
- self._func_path = func.__module__ + "." + func.__name__
61
-
62
- view_path = url_name or self._func_path
63
- self.view_name = ":".join(self.namespaces + [view_path])
64
-
65
- def __repr__(self):
66
- if isinstance(self.func, functools.partial):
67
- func = repr(self.func)
68
- else:
69
- func = self._func_path
70
- return (
71
- "ResolverMatch(func={}, args={!r}, kwargs={!r}, url_name={!r}, "
72
- "namespaces={!r}, route={!r}{}{})".format(
73
- func,
74
- self.args,
75
- self.kwargs,
76
- self.url_name,
77
- self.namespaces,
78
- self.route,
79
- f", captured_kwargs={self.captured_kwargs!r}"
80
- if self.captured_kwargs
81
- else "",
82
- f", extra_kwargs={self.extra_kwargs!r}" if self.extra_kwargs else "",
83
- )
47
+ self.namespaced_url_name = (
48
+ ":".join(self.namespaces + [url_name]) if url_name else None
84
49
  )
85
50
 
86
- def __reduce_ex__(self, protocol):
87
- raise PicklingError(f"Cannot pickle {self.__class__.__qualname__}.")
88
-
89
51
 
90
52
  def get_resolver(router=None):
91
53
  if router is None:
@@ -257,13 +219,6 @@ class URLResolver:
257
219
  self._populate()
258
220
  return self._app_dict
259
221
 
260
- @staticmethod
261
- def _extend_tried(tried, pattern, sub_tried=None):
262
- if sub_tried is None:
263
- tried.append([pattern])
264
- else:
265
- tried.extend([pattern, *t] for t in sub_tried)
266
-
267
222
  @staticmethod
268
223
  def _join_route(route1, route2):
269
224
  """Join two routes, without the starting ^ in the second route."""
@@ -274,15 +229,14 @@ class URLResolver:
274
229
 
275
230
  def resolve(self, path):
276
231
  path = str(path) # path may be a reverse_lazy object
277
- tried = []
278
232
  match = self.pattern.match(path)
279
233
  if match:
280
234
  new_path, args, kwargs = match
281
235
  for pattern in self.url_patterns:
282
236
  try:
283
237
  sub_match = pattern.resolve(new_path)
284
- except Resolver404 as e:
285
- self._extend_tried(tried, pattern, e.args[0].get("tried"))
238
+ except Resolver404:
239
+ pass
286
240
  else:
287
241
  if sub_match:
288
242
  # Merge captured arguments in match with submatch
@@ -299,20 +253,15 @@ class URLResolver:
299
253
  if isinstance(pattern, URLPattern)
300
254
  else str(pattern.pattern)
301
255
  )
302
- self._extend_tried(tried, pattern, sub_match.tried)
303
256
  return ResolverMatch(
304
- sub_match.func,
305
- sub_match_args,
306
- sub_match_dict,
307
- sub_match.url_name,
308
- [self.namespace] + sub_match.namespaces,
309
- self._join_route(current_route, sub_match.route),
310
- tried,
311
- captured_kwargs=sub_match.captured_kwargs,
312
- extra_kwargs=sub_match.extra_kwargs,
257
+ view=sub_match.view,
258
+ args=sub_match_args,
259
+ kwargs=sub_match_dict,
260
+ url_name=sub_match.url_name,
261
+ namespaces=[self.namespace] + sub_match.namespaces,
262
+ route=self._join_route(current_route, sub_match.route),
313
263
  )
314
- tried.append([pattern])
315
- raise Resolver404({"tried": tried, "path": new_path})
264
+ raise Resolver404({"path": new_path})
316
265
  raise Resolver404({"path": path})
317
266
 
318
267
  def reverse(self, lookup_view, *args, **kwargs):
plain/views/templates.py CHANGED
@@ -35,6 +35,7 @@ class TemplateView(View):
35
35
  def get_template_context(self) -> dict:
36
36
  return {
37
37
  "request": self.request,
38
+ "template_names": self.get_template_names(),
38
39
  "csrf_input": csrf_input_lazy(self.request),
39
40
  "csrf_token": csrf_token_lazy(self.request),
40
41
  "DEBUG": settings.DEBUG,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain
3
- Version: 0.40.0
3
+ Version: 0.42.0
4
4
  Summary: A web framework for building products with Python.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -58,7 +58,7 @@ plain/internal/files/uploadedfile.py,sha256=JRB7T3quQjg-1y3l1ASPxywtSQZhaeMc45uF
58
58
  plain/internal/files/uploadhandler.py,sha256=63_QUwAwfq3bevw79i0S7zt2EB2UBoO7MaauvezaVMY,7198
59
59
  plain/internal/files/utils.py,sha256=xN4HTJXDRdcoNyrL1dFd528MBwodRlHZM8DGTD_oBIg,2646
60
60
  plain/internal/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
- plain/internal/handlers/base.py,sha256=oRKni79ATI_u7sywGFExrzKvP5dpJTqIp1m521A90Ew,4169
61
+ plain/internal/handlers/base.py,sha256=6K8wd5DojOYA-UEQTd1jxdDggm5ThHXQahVcuJqd2qo,4169
62
62
  plain/internal/handlers/exception.py,sha256=vfha_6-fz6S6VYCP1PMBfue2Gw-_th6jqaTE372fGlw,4809
63
63
  plain/internal/handlers/wsgi.py,sha256=sOgqnE4fNzKD2a5EMubiEpHEK9Mi69FWx3BVWxGgMw0,8262
64
64
  plain/internal/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -96,7 +96,7 @@ plain/templates/core.py,sha256=iw58EAmyyv8N5HDA-Sq4-fLgz_qx8v8WJfurgR116jw,625
96
96
  plain/templates/jinja/__init__.py,sha256=qBESSL8XfwdxtwujjR5mZvk4VddlMn1-jOsSxGQy0oE,2768
97
97
  plain/templates/jinja/environments.py,sha256=9plifzvQj--aTN1cCpJ2WdzQxZJpzB8S_4hghgQRQT0,2064
98
98
  plain/templates/jinja/extensions.py,sha256=AEmmmHDbdRW8fhjYDzq9eSSNbp9WHsXenD8tPthjc0s,1351
99
- plain/templates/jinja/filters.py,sha256=3KJKKbxcv9dLzUDWPcaa88k3NU2m1GG3iMIgFhzXrBA,860
99
+ plain/templates/jinja/filters.py,sha256=t_u8BkWtEpJFLbLywONxWKrenSzOvDJhfOLwlZiXHDU,968
100
100
  plain/templates/jinja/globals.py,sha256=VMpuMZvwWOmb5MbzKK-ox-QEX_WSsXFxq0mm8biJgaU,558
101
101
  plain/test/README.md,sha256=fv4YzziU2QxgcNHSgv7aDUO45sDOofVuCNrV1NPbWzo,1106
102
102
  plain/test/__init__.py,sha256=MhNHtp7MYBl9kq-pMRGY11kJ6kU1I6vOkjNkit1TYRg,94
@@ -107,8 +107,8 @@ plain/urls/README.md,sha256=ijFGmrkUY9buBqO_i1GZaN3V55vl9xwEADtHOx_ZHPY,3724
107
107
  plain/urls/__init__.py,sha256=DFO2OL1IllHW5USPIb5uYvvzf_G-Bl0Qu1zrRLHmWyM,542
108
108
  plain/urls/converters.py,sha256=s2JZVOdzZC16lgobsI93hygcdH5L0Kj4742WEkXsVcs,1193
109
109
  plain/urls/exceptions.py,sha256=q4iPh3Aa-zHbA-tw8v6WyX1J1n5WdAady2xvxFuyXB0,114
110
- plain/urls/patterns.py,sha256=jTfZ4hLfUhp9DR3UGA1cMog36DDheLSccSW8fGcirRU,9352
111
- plain/urls/resolvers.py,sha256=PyqbO1JIoJq2ayCSmONW_6O8a3vM7cTVbqQJdCJHIK0,15218
110
+ plain/urls/patterns.py,sha256=7DxL5LWq40lI4hFxAJ2I4MyA3HrbCmNx_dHOk8yYiK8,8259
111
+ plain/urls/resolvers.py,sha256=3I10pLpLvhL4NamABJGH8e5Se6Iqa2y7V6hMAFQxVSg,13264
112
112
  plain/urls/routers.py,sha256=iEsQtTpPNDDVn7r_BQX84FESGSjOeD5qgyO_ep5rzaU,2819
113
113
  plain/urls/utils.py,sha256=WiGq6hHI-5DLFOxCQTAZ2qm0J-UdGosLcjuxlfK6_Tg,2137
114
114
  plain/utils/README.md,sha256=hRRkcg4CxMX-zz8d4Bn6V2uJr_VKgTLurc1jY7QlEx8,198
@@ -145,9 +145,9 @@ plain/views/exceptions.py,sha256=b4euI49ZUKS9O8AGAcFfiDpstzkRAuuj_uYQXzWNHME,138
145
145
  plain/views/forms.py,sha256=ESZOXuo6IeYixp1RZvPb94KplkowRiwO2eGJCM6zJI0,2400
146
146
  plain/views/objects.py,sha256=GGbcfg_9fPZ-PiaBwIHG2e__8GfWDR7JQtQ15wTyiHg,5970
147
147
  plain/views/redirect.py,sha256=daq2cQIkdDF78bt43sjuZxRAyJm_t_SKw6tyPmiXPIc,1985
148
- plain/views/templates.py,sha256=ORBabNc9p2QbW_rTfq2650yJtzUuUJoPXoHogrhYLCo,2028
149
- plain-0.40.0.dist-info/METADATA,sha256=WccAr8tpVrNh7gYPQXG7gCS3dUtm1zv9Nn8IkHTQpFI,4297
150
- plain-0.40.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
151
- plain-0.40.0.dist-info/entry_points.txt,sha256=1Ys2lsSeMepD1vz8RSrJopna0RQfUd951vYvCRsvl6A,45
152
- plain-0.40.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
153
- plain-0.40.0.dist-info/RECORD,,
148
+ plain/views/templates.py,sha256=SU1fO9gVMp-gEQHYeFplxvmgeMyrLgT8MJ12WNVmQC8,2085
149
+ plain-0.42.0.dist-info/METADATA,sha256=C3twqGn46rZA-SF4AzmsLnQMfuq5mO-CNTmzN_vv-PQ,4297
150
+ plain-0.42.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
151
+ plain-0.42.0.dist-info/entry_points.txt,sha256=1Ys2lsSeMepD1vz8RSrJopna0RQfUd951vYvCRsvl6A,45
152
+ plain-0.42.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
153
+ plain-0.42.0.dist-info/RECORD,,
File without changes