microdot 2.3.3__tar.gz → 2.3.4__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.
Files changed (72) hide show
  1. {microdot-2.3.3/src/microdot.egg-info → microdot-2.3.4}/PKG-INFO +1 -1
  2. {microdot-2.3.3 → microdot-2.3.4}/pyproject.toml +1 -1
  3. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/asgi.py +5 -7
  4. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/cors.py +2 -1
  5. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/microdot.py +2 -2
  6. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/multipart.py +8 -1
  7. {microdot-2.3.3 → microdot-2.3.4/src/microdot.egg-info}/PKG-INFO +1 -1
  8. {microdot-2.3.3 → microdot-2.3.4}/tests/test_multipart.py +31 -0
  9. {microdot-2.3.3 → microdot-2.3.4}/tests/test_request.py +4 -3
  10. {microdot-2.3.3 → microdot-2.3.4}/tox.ini +3 -2
  11. {microdot-2.3.3 → microdot-2.3.4}/LICENSE +0 -0
  12. {microdot-2.3.3 → microdot-2.3.4}/MANIFEST.in +0 -0
  13. {microdot-2.3.3 → microdot-2.3.4}/README.md +0 -0
  14. {microdot-2.3.3 → microdot-2.3.4}/docs/Makefile +0 -0
  15. {microdot-2.3.3 → microdot-2.3.4}/docs/_static/css/custom.css +0 -0
  16. {microdot-2.3.3 → microdot-2.3.4}/docs/api.rst +0 -0
  17. {microdot-2.3.3 → microdot-2.3.4}/docs/conf.py +0 -0
  18. {microdot-2.3.3 → microdot-2.3.4}/docs/extensions.rst +0 -0
  19. {microdot-2.3.3 → microdot-2.3.4}/docs/freezing.rst +0 -0
  20. {microdot-2.3.3 → microdot-2.3.4}/docs/index.rst +0 -0
  21. {microdot-2.3.3 → microdot-2.3.4}/docs/intro.rst +0 -0
  22. {microdot-2.3.3 → microdot-2.3.4}/docs/make.bat +0 -0
  23. {microdot-2.3.3 → microdot-2.3.4}/docs/migrating.rst +0 -0
  24. {microdot-2.3.3 → microdot-2.3.4}/setup.cfg +0 -0
  25. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/__init__.py +0 -0
  26. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/auth.py +0 -0
  27. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/helpers.py +0 -0
  28. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/jinja.py +0 -0
  29. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/login.py +0 -0
  30. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/session.py +0 -0
  31. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/sse.py +0 -0
  32. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/test_client.py +0 -0
  33. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/utemplate.py +0 -0
  34. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/websocket.py +0 -0
  35. {microdot-2.3.3 → microdot-2.3.4}/src/microdot/wsgi.py +0 -0
  36. {microdot-2.3.3 → microdot-2.3.4}/src/microdot.egg-info/SOURCES.txt +0 -0
  37. {microdot-2.3.3 → microdot-2.3.4}/src/microdot.egg-info/dependency_links.txt +0 -0
  38. {microdot-2.3.3 → microdot-2.3.4}/src/microdot.egg-info/not-zip-safe +0 -0
  39. {microdot-2.3.3 → microdot-2.3.4}/src/microdot.egg-info/requires.txt +0 -0
  40. {microdot-2.3.3 → microdot-2.3.4}/src/microdot.egg-info/top_level.txt +0 -0
  41. {microdot-2.3.3 → microdot-2.3.4}/tests/__init__.py +0 -0
  42. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.bin +0 -0
  43. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.css +0 -0
  44. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.gif +0 -0
  45. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.gz +0 -0
  46. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.html +0 -0
  47. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.jpg +0 -0
  48. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.js +0 -0
  49. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.json +0 -0
  50. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.png +0 -0
  51. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.txt +0 -0
  52. {microdot-2.3.3 → microdot-2.3.4}/tests/files/test.txt.gz +0 -0
  53. {microdot-2.3.3 → microdot-2.3.4}/tests/mock_socket.py +0 -0
  54. {microdot-2.3.3 → microdot-2.3.4}/tests/templates/hello.jinja.txt +0 -0
  55. {microdot-2.3.3 → microdot-2.3.4}/tests/templates/hello.utemplate.txt +0 -0
  56. {microdot-2.3.3 → microdot-2.3.4}/tests/templates/hello_utemplate_txt.py +0 -0
  57. {microdot-2.3.3 → microdot-2.3.4}/tests/test_asgi.py +0 -0
  58. {microdot-2.3.3 → microdot-2.3.4}/tests/test_auth.py +0 -0
  59. {microdot-2.3.3 → microdot-2.3.4}/tests/test_cors.py +0 -0
  60. {microdot-2.3.3 → microdot-2.3.4}/tests/test_end2end.py +0 -0
  61. {microdot-2.3.3 → microdot-2.3.4}/tests/test_jinja.py +0 -0
  62. {microdot-2.3.3 → microdot-2.3.4}/tests/test_login.py +0 -0
  63. {microdot-2.3.3 → microdot-2.3.4}/tests/test_microdot.py +0 -0
  64. {microdot-2.3.3 → microdot-2.3.4}/tests/test_multidict.py +0 -0
  65. {microdot-2.3.3 → microdot-2.3.4}/tests/test_response.py +0 -0
  66. {microdot-2.3.3 → microdot-2.3.4}/tests/test_session.py +0 -0
  67. {microdot-2.3.3 → microdot-2.3.4}/tests/test_sse.py +0 -0
  68. {microdot-2.3.3 → microdot-2.3.4}/tests/test_url_pattern.py +0 -0
  69. {microdot-2.3.3 → microdot-2.3.4}/tests/test_urlencode.py +0 -0
  70. {microdot-2.3.3 → microdot-2.3.4}/tests/test_utemplate.py +0 -0
  71. {microdot-2.3.3 → microdot-2.3.4}/tests/test_websocket.py +0 -0
  72. {microdot-2.3.3 → microdot-2.3.4}/tests/test_wsgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microdot
3
- Version: 2.3.3
3
+ Version: 2.3.4
4
4
  Summary: The impossibly small web framework for MicroPython
5
5
  Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/miguelgrinberg/microdot
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "microdot"
3
- version = "2.3.3"
3
+ version = "2.3.4"
4
4
  authors = [
5
5
  { name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com" },
6
6
  ]
@@ -127,19 +127,17 @@ class Microdot(BaseMicrodot):
127
127
  monitor_task = asyncio.ensure_future(cancel_monitor())
128
128
 
129
129
  body_iter = res.body_iter().__aiter__()
130
- res_body = b''
131
130
  try:
132
- res_body = await body_iter.__anext__()
133
131
  while not cancelled: # pragma: no branch
134
- next_body = await body_iter.__anext__()
132
+ res_body = await body_iter.__anext__()
135
133
  await send({'type': 'http.response.body',
136
134
  'body': res_body,
137
135
  'more_body': True})
138
- res_body = next_body
139
136
  except StopAsyncIteration:
140
- await send({'type': 'http.response.body',
141
- 'body': res_body,
142
- 'more_body': False})
137
+ pass
138
+ await send({'type': 'http.response.body',
139
+ 'body': b'',
140
+ 'more_body': False})
143
141
  if hasattr(body_iter, 'aclose'): # pragma: no branch
144
142
  await body_iter.aclose()
145
143
  cancelled = True
@@ -104,7 +104,8 @@ class CORS:
104
104
 
105
105
  def after_request(self, request, response):
106
106
  saved_vary = response.headers.get('Vary')
107
- response.headers.update(self.get_cors_headers(request))
107
+ if request: # pragma: no branch
108
+ response.headers.update(self.get_cors_headers(request))
108
109
  if saved_vary and saved_vary != response.headers.get('Vary'):
109
110
  response.headers['Vary'] = (
110
111
  saved_vary + ', ' + response.headers['Vary'])
@@ -366,8 +366,8 @@ class Request:
366
366
  self.content_type = self.headers['Content-Type']
367
367
  if 'Cookie' in self.headers:
368
368
  for cookie in self.headers['Cookie'].split(';'):
369
- name, value = cookie.strip().split('=', 1)
370
- self.cookies[name] = value
369
+ c = cookie.strip().split('=', 1)
370
+ self.cookies[c[0]] = c[1] if len(c) > 1 else ''
371
371
 
372
372
  self._body = body
373
373
  self.body_used = False
@@ -31,7 +31,10 @@ class FormDataIter:
31
31
  the next iteration, as the internal stream stored in ``FileUpload``
32
32
  instances is invalidated at the end of the iteration.
33
33
  """
34
- #: The size of the buffer used to read chunks of the request body.
34
+ #: The size of the buffer used to read chunks of the request body. This
35
+ #: size must be large enough to hold at least one complete header or
36
+ #: boundary line, so it is not recommended to lower it, but it can be made
37
+ #: higher to improve performance at the expense of RAM.
35
38
  buffer_size = 256
36
39
 
37
40
  def __init__(self, request):
@@ -59,6 +62,7 @@ class FormDataIter:
59
62
  pass
60
63
 
61
64
  # make sure we are at a boundary
65
+ await self._fill_buffer()
62
66
  s = self.buffer.split(self.boundary, 1)
63
67
  if len(s) != 2 or s[0] != b'':
64
68
  abort(400) # pragma: no cover
@@ -111,6 +115,9 @@ class FormDataIter:
111
115
  return name, FileUpload(filename, content_type, self._read_buffer)
112
116
 
113
117
  async def _fill_buffer(self):
118
+ if self.buffer[-len(self.boundary) - 4:] == self.boundary + b'--\r\n':
119
+ # we have reached the end of the body
120
+ return
114
121
  self.buffer += await self.request.stream.read(
115
122
  self.buffer_size + self.extra_size - len(self.buffer))
116
123
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microdot
3
- Version: 2.3.3
3
+ Version: 2.3.4
4
4
  Summary: The impossibly small web framework for MicroPython
5
5
  Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/miguelgrinberg/microdot
@@ -99,6 +99,37 @@ class TestMultipart(unittest.TestCase):
99
99
  'g': 'g|text/html|<p>hello</p>'})
100
100
  FileUpload.max_memory_size = saved_max_memory_size
101
101
 
102
+ def test_large_file_upload(self):
103
+ saved_buffer_size = FormDataIter.buffer_size
104
+ FormDataIter.buffer_size = 100
105
+ saved_max_memory_size = FileUpload.max_memory_size
106
+ FileUpload.max_memory_size = 200
107
+
108
+ app = Microdot()
109
+
110
+ @app.post('/')
111
+ @with_form_data
112
+ async def index(req):
113
+ return {"len": len(await req.files['f'].read())}
114
+
115
+ client = TestClient(app)
116
+
117
+ res = self._run(client.post(
118
+ '/', headers={
119
+ 'Content-Type': 'multipart/form-data; boundary=boundary',
120
+ },
121
+ body=(
122
+ b'--boundary\r\n'
123
+ b'Content-Disposition: form-data; name="f"; filename="f"\r\n'
124
+ b'Content-Type: text/plain\r\n\r\n' + b'*' * 398 + b'\r\n'
125
+ b'--boundary--\r\n')
126
+ ))
127
+ self.assertEqual(res.status_code, 200)
128
+ self.assertEqual(res.json, {'len': 398})
129
+
130
+ FormDataIter.buffer_size = saved_buffer_size
131
+ FileUpload.max_memory_size = saved_max_memory_size
132
+
102
133
  def test_file_save(self):
103
134
  app = Microdot()
104
135
 
@@ -35,16 +35,17 @@ class TestRequest(unittest.TestCase):
35
35
  def test_headers(self):
36
36
  fd = get_async_request_fd('GET', '/foo', headers={
37
37
  'Content-Type': 'application/json',
38
- 'Cookie': 'foo=bar;abc=def',
38
+ 'Cookie': 'foo=bar;nothing;abc=def;',
39
39
  'Content-Length': '3'}, body='aaa')
40
40
  req = self._run(Request.create('app', fd, 'writer', 'addr'))
41
41
  self.assertEqual(req.headers, {
42
42
  'Host': 'example.com:1234',
43
43
  'Content-Type': 'application/json',
44
- 'Cookie': 'foo=bar;abc=def',
44
+ 'Cookie': 'foo=bar;nothing;abc=def;',
45
45
  'Content-Length': '3'})
46
46
  self.assertEqual(req.content_type, 'application/json')
47
- self.assertEqual(req.cookies, {'foo': 'bar', 'abc': 'def'})
47
+ self.assertEqual(req.cookies, {'foo': 'bar', 'nothing': '',
48
+ 'abc': 'def', '': ''})
48
49
  self.assertEqual(req.content_length, 3)
49
50
  self.assertEqual(req.body, b'aaa')
50
51
 
@@ -1,16 +1,17 @@
1
1
  [tox]
2
- envlist=flake8,py38,py39,py310,py311,py312,upy,cpy,benchmark,docs
2
+ envlist=flake8,py38,py39,py310,py311,py312,py313,py314upy,cpy,benchmark,docs
3
3
  skipsdist=True
4
4
  skip_missing_interpreters=True
5
5
 
6
6
  [gh-actions]
7
7
  python =
8
- 3.7: py37
9
8
  3.8: py38
10
9
  3.9: py39
11
10
  3.10: py310
12
11
  3.11: py311
13
12
  3.12: py312
13
+ 3.13: py313
14
+ 3.14: py314
14
15
  pypy3: pypy3
15
16
 
16
17
  [testenv]
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes