fresco 3.3.0__tar.gz → 3.3.1__tar.gz

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.

Potentially problematic release.


This version of fresco might be problematic. Click here for more details.

Files changed (63) hide show
  1. {fresco-3.3.0 → fresco-3.3.1}/CHANGELOG.rst +9 -1
  2. {fresco-3.3.0/fresco.egg-info → fresco-3.3.1}/PKG-INFO +1 -1
  3. {fresco-3.3.0 → fresco-3.3.1}/fresco/__init__.py +1 -1
  4. {fresco-3.3.0 → fresco-3.3.1}/fresco/core.py +6 -4
  5. {fresco-3.3.0 → fresco-3.3.1}/fresco/routing.py +41 -10
  6. {fresco-3.3.0 → fresco-3.3.1}/fresco/subrequests.py +1 -0
  7. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_routing.py +14 -0
  8. {fresco-3.3.0 → fresco-3.3.1/fresco.egg-info}/PKG-INFO +1 -1
  9. {fresco-3.3.0 → fresco-3.3.1}/LICENSE.txt +0 -0
  10. {fresco-3.3.0 → fresco-3.3.1}/MANIFEST.in +0 -0
  11. {fresco-3.3.0 → fresco-3.3.1}/README.rst +0 -0
  12. {fresco-3.3.0 → fresco-3.3.1}/fresco/cookie.py +0 -0
  13. {fresco-3.3.0 → fresco-3.3.1}/fresco/decorators.py +0 -0
  14. {fresco-3.3.0 → fresco-3.3.1}/fresco/exceptions.py +0 -0
  15. {fresco-3.3.0 → fresco-3.3.1}/fresco/middleware.py +0 -0
  16. {fresco-3.3.0 → fresco-3.3.1}/fresco/multidict.py +0 -0
  17. {fresco-3.3.0 → fresco-3.3.1}/fresco/options.py +0 -0
  18. {fresco-3.3.0 → fresco-3.3.1}/fresco/request.py +0 -0
  19. {fresco-3.3.0 → fresco-3.3.1}/fresco/requestcontext.py +0 -0
  20. {fresco-3.3.0 → fresco-3.3.1}/fresco/response.py +0 -0
  21. {fresco-3.3.0 → fresco-3.3.1}/fresco/routeargs.py +0 -0
  22. {fresco-3.3.0 → fresco-3.3.1}/fresco/static.py +0 -0
  23. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/__init__.py +0 -0
  24. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/fixtures.py +0 -0
  25. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_cookie.py +0 -0
  26. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_core.py +0 -0
  27. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_decorators.py +0 -0
  28. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_exceptions.py +0 -0
  29. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_middleware.py +0 -0
  30. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_multidict.py +0 -0
  31. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_options.py +0 -0
  32. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_request.py +0 -0
  33. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_requestcontext.py +0 -0
  34. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_response.py +0 -0
  35. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_routeargs.py +0 -0
  36. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_static.py +0 -0
  37. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/test_subrequests.py +0 -0
  38. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/util/__init__.py +0 -0
  39. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/util/form_data.py +0 -0
  40. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/util/test_common.py +0 -0
  41. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/util/test_http.py +0 -0
  42. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/util/test_security.py +0 -0
  43. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/util/test_urls.py +0 -0
  44. {fresco-3.3.0 → fresco-3.3.1}/fresco/tests/util/test_wsgi.py +0 -0
  45. {fresco-3.3.0 → fresco-3.3.1}/fresco/types.py +0 -0
  46. {fresco-3.3.0 → fresco-3.3.1}/fresco/typing.py +0 -0
  47. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/__init__.py +0 -0
  48. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/cache.py +0 -0
  49. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/common.py +0 -0
  50. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/contentencodings.py +0 -0
  51. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/file.py +0 -0
  52. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/http.py +0 -0
  53. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/io.py +0 -0
  54. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/object.py +0 -0
  55. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/security.py +0 -0
  56. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/textproc.py +0 -0
  57. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/urls.py +0 -0
  58. {fresco-3.3.0 → fresco-3.3.1}/fresco/util/wsgi.py +0 -0
  59. {fresco-3.3.0 → fresco-3.3.1}/fresco.egg-info/SOURCES.txt +0 -0
  60. {fresco-3.3.0 → fresco-3.3.1}/fresco.egg-info/dependency_links.txt +0 -0
  61. {fresco-3.3.0 → fresco-3.3.1}/fresco.egg-info/top_level.txt +0 -0
  62. {fresco-3.3.0 → fresco-3.3.1}/setup.cfg +0 -0
  63. {fresco-3.3.0 → fresco-3.3.1}/setup.py +0 -0
@@ -1,9 +1,17 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- 3.3.0 (released 2023-05-02)
4
+ 3.3.1 (released 2023-05-18)
5
5
  ---------------------------
6
6
 
7
+ - The ``route_wsgi`` and ``route_all`` methods now only match at a
8
+ path separator boundary (``'/'``).
9
+ - Bugfix: subrequest now works with views routed via ``RRoute`` (and so expect
10
+ an initial ``request`` argument)
11
+
12
+ 3.3.0
13
+ -----
14
+
7
15
  - Options: fresco.options.Options can now take a list of paths as its first argument
8
16
  - Options: tags can now be specified with environment variable substitutions
9
17
  (eg "{FOO}" would load files tagged with the current value of the 'FOO'
@@ -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
@@ -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
 
@@ -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()
@@ -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,
@@ -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)
@@ -1092,3 +1092,17 @@ class TestRouteCache(object):
1092
1092
 
1093
1093
  # Check a subsequent call to get_routes doesn't hang onto the exception
1094
1094
  list(rc.get_route_traversals("/bacon", GET))
1095
+
1096
+
1097
+ class TestRouteAll:
1098
+
1099
+ def test_route_all_matches_on_separator(self):
1100
+ def view():
1101
+ return Response()
1102
+
1103
+ app = FrescoApp()
1104
+ app.route_all("/x", GET, view)
1105
+
1106
+ assert len(list(app.get_route_traversals("/x", GET))) == 1
1107
+ assert len(list(app.get_route_traversals("/x/y", GET))) == 1
1108
+ assert len(list(app.get_route_traversals("/xy", GET))) == 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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes