fresco 3.3.0__py3-none-any.whl → 3.3.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.
fresco/__init__.py CHANGED
@@ -12,7 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  #
15
- __version__ = "3.3.0"
15
+ __version__ = "3.3.1"
16
16
 
17
17
  DEFAULT_CHARSET = "UTF-8"
18
18
 
fresco/core.py CHANGED
@@ -259,7 +259,7 @@ class FrescoApp(RouteCollection):
259
259
 
260
260
  # Is the URL just missing a trailing '/'?
261
261
  if not path or path[-1] != "/":
262
- for _ in self.get_methods(request, path + "/"):
262
+ if self.get_methods(request, path + "/"):
263
263
  return Response.unrestricted_redirect_permanent(path + "/")
264
264
 
265
265
  return Response.not_found()
@@ -287,7 +287,9 @@ class FrescoApp(RouteCollection):
287
287
 
288
288
  return response
289
289
 
290
- def handle_http_error_response(self, request, response):
290
+ def handle_http_error_response(
291
+ self, request: Request, response: Response
292
+ ) -> Response:
291
293
  """
292
294
  Call any process_http_error_response handlers and return the
293
295
  (potentially modified) response object.
@@ -303,8 +305,8 @@ class FrescoApp(RouteCollection):
303
305
  self.log_exception(request)
304
306
  return response
305
307
 
306
- def get_methods(self, request, path):
307
- """\
308
+ def get_methods(self, request: Request, path: str) -> Set[str]:
309
+ """
308
310
  Return the HTTP methods valid in routes to the given path
309
311
  """
310
312
  methods: Set[str] = set()
fresco/routing.py CHANGED
@@ -370,15 +370,15 @@ class PathConverter(StrConverter):
370
370
 
371
371
 
372
372
  class MatchAllURLsPattern(Pattern):
373
- """\
374
- A pattern matcher that matches all URLs starting with the given prefix. No
375
- arguments are parsed from the URL.
373
+ """
374
+ A pattern matcher that matches all paths starting with the given prefix.
375
+ No arguments are parsed from the URL.
376
376
  """
377
377
 
378
378
  def __init__(self, path):
379
379
  self.path = path
380
380
 
381
- def match(self, path):
381
+ def match(self, path: str) -> t.Optional[PathMatch]:
382
382
  if path.startswith(self.path):
383
383
  return PathMatch(self.path, path[len(self.path) :], (), {})
384
384
  return None
@@ -400,6 +400,32 @@ class MatchAllURLsPattern(Pattern):
400
400
  return "%s*" % (self.path,)
401
401
 
402
402
 
403
+ class PrefixPattern(MatchAllURLsPattern):
404
+ """
405
+ A pattern matcher that matches the given prefix. The prefix will only be
406
+ matched at a path separator boundary.
407
+
408
+ ``PrefixPattern('/foo')`` will match the paths ``/foo`` and ``/foo/bar``,
409
+ but not ``/foobar``.
410
+
411
+ No arguments are parsed from the URL.
412
+ """
413
+
414
+ def __init__(self, path):
415
+ super().__init__(path)
416
+ if path[-1] == "/":
417
+ self.path_with_sep = path
418
+ else:
419
+ self.path_with_sep = f"{self.path}/"
420
+
421
+ def match(self, path: str) -> t.Optional[PathMatch]:
422
+ prefix = path[: len(self.path_with_sep)]
423
+
424
+ if prefix == self.path or prefix == self.path_with_sep:
425
+ return PathMatch(self.path, path[len(self.path) :], (), {})
426
+ return None
427
+
428
+
403
429
  class ExtensiblePattern(Pattern):
404
430
  """\
405
431
  An extensible URL pattern matcher.
@@ -547,10 +573,10 @@ class ExtensiblePattern(Pattern):
547
573
  """
548
574
  return eval("(lambda *args, **kwargs: (args, kwargs))(%s)" % argstr)
549
575
 
550
- def match(self, path):
576
+ def match(self, path) -> t.Optional[PathMatch]:
551
577
  """
552
- Test ``path`` and return a tuple of parsed ``(args, kwargs)``, or
553
- ``None`` if there was no match.
578
+ Test ``path`` and return a PathMatch object or ``None`` if there was no
579
+ match.
554
580
  """
555
581
  mo = self.regex_match(path)
556
582
  if mo is None:
@@ -1358,13 +1384,18 @@ class RouteCollection(MutableSequence):
1358
1384
  exc = self.__routed_views__[viewspec] = RouteNotFound(viewspec)
1359
1385
  raise exc
1360
1386
 
1361
- def _get_routes(self, key):
1387
+ def _get_routes(
1388
+ self, key: Tuple[t.Optional[str], str]
1389
+ ) -> t.Sequence[t.Tuple[Route, t.Optional[PathMatch]]]:
1362
1390
  method, path = key
1363
1391
  routes = ((r, r.match(path, method)) for r in self.__routes__)
1364
1392
  return [(r, t) for (r, t) in routes if t is not None]
1365
1393
 
1366
1394
  def get_route_traversals(
1367
- self, path: str, method: Optional[str], request: Optional[Request] = None
1395
+ self,
1396
+ path: str,
1397
+ method: Optional[str],
1398
+ request: Optional[Request] = None,
1368
1399
  ) -> t.Iterator[RouteTraversal]:
1369
1400
  """
1370
1401
  Generate RouteTraversals for routes matching the given path and
@@ -1604,7 +1635,7 @@ class RouteCollection(MutableSequence):
1604
1635
  :param path: the path prefix at which the view will be routed
1605
1636
  """
1606
1637
  return self.route(
1607
- MatchAllURLsPattern(path),
1638
+ PrefixPattern(path),
1608
1639
  methods,
1609
1640
  view,
1610
1641
  route_class=route_class,
fresco/subrequests.py CHANGED
@@ -272,6 +272,7 @@ def _get_args_for_route(
272
272
  route_kwargs = {}
273
273
  route_args = list(
274
274
  chain(
275
+ [request] if route.provide_request else [],
275
276
  ((a(request) if isinstance(a, RouteArg) else a) for a in route.view_args),
276
277
  (
277
278
  mutable_args.pop(0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fresco
3
- Version: 3.3.0
3
+ Version: 3.3.1
4
4
  Summary: A Web/WSGI micro-framework
5
5
  Home-page: https://ollycope.com/software/fresco/latest/
6
6
  Author: Oliver Cope
@@ -1,6 +1,6 @@
1
- fresco/__init__.py,sha256=jE_pFG-3XUTi6myDqNDowJ_W45C3OFc1fag95JMBXsk,3520
1
+ fresco/__init__.py,sha256=e0KXsDXDex3v2Efu5cGbMvN-jttFfz1aDo7pyG7O_rE,3520
2
2
  fresco/cookie.py,sha256=Qnx8yOjU4LUJ1fqi7YvqbhAA01rCsclJGl_fxI68slw,7055
3
- fresco/core.py,sha256=qOYE3mSqZNVo7v6zXwfBedIiyfnJMkID1FUYoDRZtus,26551
3
+ fresco/core.py,sha256=mwYR6UP0zRSjcFlNZf51-otX9EcmvgjEZ7GDVQoQexg,26615
4
4
  fresco/decorators.py,sha256=84NUpRJ-M7GK6wDl42bmCRSvgoWzCsy1huyvGnSAPPw,3232
5
5
  fresco/exceptions.py,sha256=KE-LoYUGnho6KltzkU6cnm9vUiUhAiDIjPqn5ba-YCA,4410
6
6
  fresco/middleware.py,sha256=uCAuOtBnvaVBJGrQa8ecvLkSZ6aSKmWaJqxB8Rv4SsQ,4173
@@ -10,9 +10,9 @@ fresco/request.py,sha256=JCETzqzGZgPpS7IBdqi4Hk3CTwTGiaTtRXFW_nPP1yg,27071
10
10
  fresco/requestcontext.py,sha256=P-SkKJkKLYVqNiR2zwooRROnSnE2VMj2P2-eD5DW5Qg,3504
11
11
  fresco/response.py,sha256=Pz8icriWhHNVsTkB5x5y99yvcz-nFC7Eobuv7tfLE3s,37078
12
12
  fresco/routeargs.py,sha256=dxNlqbQ1FrgIY6OCFzcEMdZ0OVyjlMQdQGLmUJgdPYU,10176
13
- fresco/routing.py,sha256=BrzTcT788JG_u4eLHaFcViztee1-OWHloD8WZI1CSA8,57738
13
+ fresco/routing.py,sha256=nh7TiyDPQ1Y4RCXJGj_Wk-BP1UqpNyh6BKqxhNHlQ8U,58670
14
14
  fresco/static.py,sha256=9SKQ3P1YFTP45Qiic-ycvkpKRvqIURp1XSzPazTmYLI,2513
15
- fresco/subrequests.py,sha256=QvcEKgWtJqDkHzjNKIoFENO372S_b4D1Lh5_LHhrPLI,11025
15
+ fresco/subrequests.py,sha256=wFJWLuhVAcei5imYc5NBSCBaHBEm-X4_XswPtK3O4Zw,11081
16
16
  fresco/types.py,sha256=UHITRMDoS90s2zV2wNpqLFhRWESfaBAMuQnL4c21mqY,106
17
17
  fresco/typing.py,sha256=jQ1r_wme54J08XZUdmuuW4M8ve-gEhm1Wriwctls3r8,347
18
18
  fresco/util/__init__.py,sha256=mJkaZzvYgBnxsBAGv8y_P1yzonHqWgw6VF2Zs4rmJEA,7
@@ -27,8 +27,8 @@ fresco/util/security.py,sha256=nXEdoCak_2c4OA1L1wGwhZygS22s2fzwR0Kp-DdwKZg,1058
27
27
  fresco/util/textproc.py,sha256=e5jLTofKCqdm6_Fy8XOyR43AJr5APtL59Kd8cNA9PrQ,2309
28
28
  fresco/util/urls.py,sha256=aaVovLyXNlVoGviiLN94ImqXf-LTQs_xooEIyi3LBc4,9195
29
29
  fresco/util/wsgi.py,sha256=dV69VjJ7W8OqAxWzlA0dz7vAuC1MliNBnbr1MSyB6Is,12970
30
- fresco-3.3.0.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
31
- fresco-3.3.0.dist-info/METADATA,sha256=Q_8zOUv7tS4JlhN5TjXxN82m2kRrY5-6PzxGyxb38DA,1575
32
- fresco-3.3.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
33
- fresco-3.3.0.dist-info/top_level.txt,sha256=p_1aMce5Shjq9fIfdbB-aN8wCDhjF_iYnn98bUebbII,7
34
- fresco-3.3.0.dist-info/RECORD,,
30
+ fresco-3.3.1.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
31
+ fresco-3.3.1.dist-info/METADATA,sha256=DEjrYiyD-gUvPOYEjyZz8y1y8PBrzIUxPx9wFuv7w_o,1575
32
+ fresco-3.3.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
33
+ fresco-3.3.1.dist-info/top_level.txt,sha256=p_1aMce5Shjq9fIfdbB-aN8wCDhjF_iYnn98bUebbII,7
34
+ fresco-3.3.1.dist-info/RECORD,,
File without changes