fresco 3.3.2__py3-none-any.whl → 3.3.4__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.2"
15
+ __version__ = "3.3.4"
16
16
 
17
17
  DEFAULT_CHARSET = "UTF-8"
18
18
 
fresco/options.py CHANGED
@@ -127,6 +127,12 @@ class Options(dict):
127
127
  Where filename contain multiple tags, all tags must match for the file
128
128
  to be loaded.
129
129
 
130
+ Files are processed in the order that tags are specified in the
131
+ ``tags`` parameter, and then in lexicographical order.
132
+ For example, calling ``options.load(..., tags=["dev", "local"])`` would
133
+ cause a file named "settings.dev" to be loaded before one named
134
+ "settings.local".
135
+
130
136
  Tag names may contain the names of environment variable surrounded by
131
137
  braces, for example ``{USER}``. These will be substituted for the
132
138
  environment variable's value, with any dots or path separators replaced
@@ -210,9 +216,11 @@ class Options(dict):
210
216
  ts[1]
211
217
  for ts in sorted(
212
218
  tagged_sources,
213
- key=lambda ts: -1
214
- if len(ts[0]) == 0
215
- else min(tags.index(t) for t in ts[0]),
219
+ key=(
220
+ lambda ts: ([], ts[1])
221
+ if len(ts[0]) == 0
222
+ else (sorted(tags.index(t) for t in ts[0]), ts[1])
223
+ )
216
224
  )
217
225
  ]
218
226
  else:
fresco/request.py CHANGED
@@ -294,7 +294,7 @@ class Request(object):
294
294
 
295
295
  @property
296
296
  def now( # type: ignore
297
- self, utcnow=datetime.datetime.now, utc=datetime.timezone.utc
297
+ self, now=datetime.datetime.now, utc=datetime.timezone.utc
298
298
  ):
299
299
  """
300
300
  Return a timezone-aware UTC datetime instance. The value returned is
@@ -302,7 +302,7 @@ class Request(object):
302
302
  """
303
303
  if self._now:
304
304
  return self._now
305
- self._now = utcnow().replace(tzinfo=utc)
305
+ self._now = now(utc)
306
306
  return self._now
307
307
 
308
308
  @property
fresco/response.py CHANGED
@@ -386,7 +386,7 @@ class Response(object):
386
386
  self.status = "200 OK"
387
387
  else:
388
388
  try:
389
- self.status = "%d %s" % (status, HTTP_STATUS_CODES[status])
389
+ self.status = f"{status} {HTTP_STATUS_CODES[status]}"
390
390
  except KeyError:
391
391
  self.status = str(status)
392
392
 
fresco/routing.py CHANGED
@@ -1386,7 +1386,7 @@ class RouteCollection(MutableSequence):
1386
1386
 
1387
1387
  def _get_routes(
1388
1388
  self, key: Tuple[t.Optional[str], str]
1389
- ) -> t.Sequence[t.Tuple[Route, t.Optional[PathMatch]]]:
1389
+ ) -> t.Sequence[t.Tuple[Route, PathMatch]]:
1390
1390
  method, path = key
1391
1391
  routes = ((r, r.match(path, method)) for r in self.__routes__)
1392
1392
  return [(r, t) for (r, t) in routes if t is not None]
File without changes
@@ -0,0 +1,67 @@
1
+ # encoding=UTF-8
2
+ # Copyright 2015 Oliver Cope
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ from fresco import Route
17
+ from fresco.routing import GET
18
+ from fresco.response import Response
19
+
20
+ # A unicode path that can't be represented using ASCII encoding
21
+ unquoted_unicode_path = "/ø"
22
+
23
+ # IRI quoted version of the same path. This is the string the server
24
+ # would receive as the HTTP Request-URI
25
+ quoted_unicode_path = "/%C3%B8"
26
+
27
+ # WSGI encoded version of the path. This is the string that appears in the
28
+ # environ dict.
29
+ wsgi_unicode_path = b"/\xc3\xb8".decode("latin1")
30
+
31
+ # Malformed path, as sent to the server by a non conforming client.
32
+ # The code point has been incorrectly encoded in latin-1 instead of
33
+ # UTF-8
34
+ misquoted_wsgi_unicode_path = b"/\xf8".decode("latin1")
35
+
36
+
37
+ class CBV(object):
38
+ """
39
+ A class based view
40
+ """
41
+
42
+ __routes__ = [
43
+ Route("/", GET, "index_html"),
44
+ Route("/page", GET, "view_page"),
45
+ Route("/page2", GET, "view_page", tag="page2"),
46
+ ]
47
+
48
+ def __init__(self, s):
49
+ self.s = s
50
+
51
+ def index_html(self):
52
+ return Response([self.s])
53
+
54
+ def view_page(self):
55
+ return Response([])
56
+
57
+
58
+ def module_level_function():
59
+ """
60
+ A module level function
61
+ """
62
+
63
+
64
+ def wsgi_app(environ, start_response):
65
+ start_response("200 OK", [("Content-Type", "text/plain")])
66
+
67
+ return [b"ok"]
@@ -0,0 +1,59 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+ from datetime import tzinfo, datetime, timedelta
15
+ from fresco.cookie import Cookie
16
+
17
+
18
+ class FakeTZInfo(tzinfo):
19
+ def utcoffset(self, dt):
20
+ return timedelta(seconds=3600)
21
+
22
+ def dst(self, dt):
23
+ return timedelta(seconds=0)
24
+
25
+ def tzname(self, dt):
26
+ return "ZZZ"
27
+
28
+
29
+ class TestCookie(object):
30
+ def test_basic_cookie(self):
31
+ """Simple cookie with just a field and value"""
32
+ c = Cookie("key", "value")
33
+ assert str(c) == "key=value;Path=/;SameSite=Lax"
34
+
35
+ def test_nopath_cookie(self):
36
+ """Simple cookie with just a field and value"""
37
+ c = Cookie("key", "value", path=None)
38
+ assert str(c) == "key=value;SameSite=Lax"
39
+
40
+ def test_httponly_cookie(self):
41
+ """Cookie as HttpOnly"""
42
+ c = Cookie("key", "value", httponly=True)
43
+ assert str(c) == "key=value;Path=/;HttpOnly;SameSite=Lax"
44
+
45
+ def test_secure_cookie(self):
46
+ """Cookie as secure cookie"""
47
+ c = Cookie("key", "value", secure=True)
48
+ assert str(c) == "key=value;Path=/;Secure;SameSite=Lax"
49
+
50
+ def test_secure_and_httponly(self):
51
+ """Cookie as both secure and httponly"""
52
+ c = Cookie("key", "value", secure=True, httponly=True)
53
+ assert str(c) == "key=value;Path=/;Secure;HttpOnly;SameSite=Lax"
54
+
55
+ def test_dates_are_rfc_formatted(self):
56
+ c = Cookie("a", "b", expires=datetime(2001, 1, 1, 12))
57
+ assert "Expires=Mon, 01 Jan 2001 12:00:00 GMT;" in str(c)
58
+ c = Cookie("a", "b", expires=datetime(2001, 1, 1, 12, tzinfo=FakeTZInfo()))
59
+ assert "Expires=Mon, 01 Jan 2001 11:00:00 GMT;" in str(c)