microdot 2.0.6__tar.gz → 2.0.7__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 (66) hide show
  1. {microdot-2.0.6/src/microdot.egg-info → microdot-2.0.7}/PKG-INFO +3 -1
  2. {microdot-2.0.6 → microdot-2.0.7}/docs/extensions.rst +2 -2
  3. {microdot-2.0.6 → microdot-2.0.7}/docs/intro.rst +33 -6
  4. {microdot-2.0.6 → microdot-2.0.7}/pyproject.toml +7 -2
  5. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/microdot.py +9 -1
  6. {microdot-2.0.6 → microdot-2.0.7/src/microdot.egg-info}/PKG-INFO +3 -1
  7. {microdot-2.0.6 → microdot-2.0.7}/src/microdot.egg-info/SOURCES.txt +1 -0
  8. {microdot-2.0.6 → microdot-2.0.7}/src/microdot.egg-info/dependency_links.txt +0 -0
  9. {microdot-2.0.6 → microdot-2.0.7}/src/microdot.egg-info/not-zip-safe +0 -0
  10. {microdot-2.0.6 → microdot-2.0.7}/src/microdot.egg-info/requires.txt +3 -0
  11. {microdot-2.0.6 → microdot-2.0.7}/src/microdot.egg-info/top_level.txt +0 -0
  12. microdot-2.0.7/tests/files/test.txt.gz +1 -0
  13. {microdot-2.0.6 → microdot-2.0.7}/tests/test_microdot.py +20 -0
  14. {microdot-2.0.6 → microdot-2.0.7}/tests/test_response.py +13 -2
  15. {microdot-2.0.6 → microdot-2.0.7}/LICENSE +0 -0
  16. {microdot-2.0.6 → microdot-2.0.7}/MANIFEST.in +0 -0
  17. {microdot-2.0.6 → microdot-2.0.7}/README.md +0 -0
  18. {microdot-2.0.6 → microdot-2.0.7}/docs/Makefile +0 -0
  19. {microdot-2.0.6 → microdot-2.0.7}/docs/_static/css/custom.css +0 -0
  20. {microdot-2.0.6 → microdot-2.0.7}/docs/api.rst +0 -0
  21. {microdot-2.0.6 → microdot-2.0.7}/docs/conf.py +0 -0
  22. {microdot-2.0.6 → microdot-2.0.7}/docs/freezing.rst +0 -0
  23. {microdot-2.0.6 → microdot-2.0.7}/docs/index.rst +0 -0
  24. {microdot-2.0.6 → microdot-2.0.7}/docs/make.bat +0 -0
  25. {microdot-2.0.6 → microdot-2.0.7}/docs/migrating.rst +0 -0
  26. {microdot-2.0.6 → microdot-2.0.7}/setup.cfg +0 -0
  27. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/__init__.py +0 -0
  28. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/asgi.py +0 -0
  29. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/cors.py +0 -0
  30. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/helpers.py +0 -0
  31. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/jinja.py +0 -0
  32. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/session.py +0 -0
  33. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/sse.py +0 -0
  34. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/test_client.py +0 -0
  35. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/utemplate.py +0 -0
  36. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/websocket.py +0 -0
  37. {microdot-2.0.6 → microdot-2.0.7}/src/microdot/wsgi.py +0 -0
  38. {microdot-2.0.6 → microdot-2.0.7}/tests/__init__.py +0 -0
  39. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.bin +0 -0
  40. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.css +0 -0
  41. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.gif +0 -0
  42. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.gz +0 -0
  43. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.html +0 -0
  44. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.jpg +0 -0
  45. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.js +0 -0
  46. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.json +0 -0
  47. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.png +0 -0
  48. {microdot-2.0.6 → microdot-2.0.7}/tests/files/test.txt +0 -0
  49. {microdot-2.0.6 → microdot-2.0.7}/tests/mock_socket.py +0 -0
  50. {microdot-2.0.6 → microdot-2.0.7}/tests/templates/hello.jinja.txt +0 -0
  51. {microdot-2.0.6 → microdot-2.0.7}/tests/templates/hello.utemplate.txt +0 -0
  52. {microdot-2.0.6 → microdot-2.0.7}/tests/templates/hello_utemplate_txt.py +0 -0
  53. {microdot-2.0.6 → microdot-2.0.7}/tests/test_asgi.py +0 -0
  54. {microdot-2.0.6 → microdot-2.0.7}/tests/test_cors.py +0 -0
  55. {microdot-2.0.6 → microdot-2.0.7}/tests/test_end2end.py +0 -0
  56. {microdot-2.0.6 → microdot-2.0.7}/tests/test_jinja.py +0 -0
  57. {microdot-2.0.6 → microdot-2.0.7}/tests/test_multidict.py +0 -0
  58. {microdot-2.0.6 → microdot-2.0.7}/tests/test_request.py +0 -0
  59. {microdot-2.0.6 → microdot-2.0.7}/tests/test_session.py +0 -0
  60. {microdot-2.0.6 → microdot-2.0.7}/tests/test_sse.py +0 -0
  61. {microdot-2.0.6 → microdot-2.0.7}/tests/test_url_pattern.py +0 -0
  62. {microdot-2.0.6 → microdot-2.0.7}/tests/test_urlencode.py +0 -0
  63. {microdot-2.0.6 → microdot-2.0.7}/tests/test_utemplate.py +0 -0
  64. {microdot-2.0.6 → microdot-2.0.7}/tests/test_websocket.py +0 -0
  65. {microdot-2.0.6 → microdot-2.0.7}/tests/test_wsgi.py +0 -0
  66. {microdot-2.0.6 → microdot-2.0.7}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: microdot
3
- Version: 2.0.6
3
+ Version: 2.0.7
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
@@ -14,6 +14,8 @@ Classifier: Operating System :: OS Independent
14
14
  Requires-Python: >=3.8
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
+ Provides-Extra: dev
18
+ Requires-Dist: tox; extra == "dev"
17
19
  Provides-Extra: docs
18
20
  Requires-Dist: sphinx; extra == "docs"
19
21
  Requires-Dist: pyjwt; extra == "docs"
@@ -286,7 +286,7 @@ Cross-Origin Resource Sharing (CORS)
286
286
  - | None
287
287
 
288
288
  * - Examples
289
- - | `cors.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/cors/cors.py>`_
289
+ - | `app.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/cors/app.py>`_
290
290
 
291
291
  The CORS extension provides support for `Cross-Origin Resource Sharing
292
292
  (CORS) <https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS>`_. CORS is a
@@ -363,7 +363,7 @@ Using an ASGI Web Server
363
363
  - | `asgi.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot/asgi.py>`_
364
364
 
365
365
  * - Required external dependencies
366
- - | An ASGI web server, such as `Uvicorn <https://uvicorn.org/>`_.
366
+ - | An ASGI web server, such as `Uvicorn <https://www.uvicorn.org/>`_.
367
367
 
368
368
  * - Examples
369
369
  - | `hello_asgi.py <https://github.com/miguelgrinberg/microdot/blob/main/examples/hello/hello_asgi.py>`_
@@ -82,8 +82,34 @@ handler functions can be defined as ``async def`` or ``def`` functions, but
82
82
  ``async def`` functions are recommended for performance.
83
83
 
84
84
  The :func:`run() <microdot.Microdot.run>` method starts the application's web
85
- server on port 5000 by default. This method blocks while it waits for
86
- connections from clients.
85
+ server on port 5000 by default, and creates its own asynchronous loop. This
86
+ method blocks while it waits for connections from clients.
87
+
88
+ For some applications it may be necessary to run the web server alongside other
89
+ asynchronous tasks, on an already running loop. In that case, instead of
90
+ ``app.run()`` the web server can be started by invoking the
91
+ :func:`start_server() <microdot.Microdot.start_server>` coroutine as shown in
92
+ the following example::
93
+
94
+ import asyncio
95
+ from microdot import Microdot
96
+
97
+ app = Microdot()
98
+
99
+ @app.route('/')
100
+ async def index(request):
101
+ return 'Hello, world!'
102
+
103
+ async def main():
104
+ # start the server in a background task
105
+ server = asyncio.create_task(app.start_server())
106
+
107
+ # ... do other asynchronous work here ...
108
+
109
+ # cleanup before ending the application
110
+ await server
111
+
112
+ asyncio.run(main())
87
113
 
88
114
  Running with CPython
89
115
  ^^^^^^^^^^^^^^^^^^^^
@@ -92,7 +118,7 @@ Running with CPython
92
118
  :align: left
93
119
 
94
120
  * - Required Microdot source files
95
- - | `microdot.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot.py>`_
121
+ - | `microdot.py <https://github.com/miguelgrinberg/microdot/blob/main/src/microdot/microdot.py>`_
96
122
 
97
123
  * - Required external dependencies
98
124
  - | None
@@ -118,7 +144,7 @@ Running with MicroPython
118
144
  :align: left
119
145
 
120
146
  * - Required Microdot source files
121
- - | `microdot.py <https://github.com/miguelgrinberg/microdot/tree/main/src/microdot.py>`_
147
+ - | `microdot.py <https://github.com/miguelgrinberg/microdot/blob/main/src/microdot/microdot.py>`_
122
148
 
123
149
  * - Required external dependencies
124
150
  - | None
@@ -145,8 +171,9 @@ changed by passing the ``port`` argument to the ``run()`` method.
145
171
  Web Server Configuration
146
172
  ^^^^^^^^^^^^^^^^^^^^^^^^
147
173
 
148
- The :func:`run() <microdot.Microdot.run>` method supports a few arguments to
149
- configure the web server.
174
+ The :func:`run() <microdot.Microdot.run>` and
175
+ :func:`start_server() <microdot.Microdot.start_server>` methods support a few
176
+ arguments to configure the web server.
150
177
 
151
178
  - ``port``: The port number to listen on. Pass the desired port number in this
152
179
  argument to use a port different than the default of 5000. For example::
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "microdot"
3
- version = "2.0.6"
3
+ version = "2.0.7"
4
4
  authors = [
5
5
  { name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com" },
6
6
  ]
@@ -14,6 +14,8 @@ classifiers = [
14
14
  "Operating System :: OS Independent",
15
15
  ]
16
16
  requires-python = ">=3.8"
17
+ dependencies = [
18
+ ]
17
19
 
18
20
  [project.readme]
19
21
  file = "README.md"
@@ -24,9 +26,12 @@ Homepage = "https://github.com/miguelgrinberg/microdot"
24
26
  "Bug Tracker" = "https://github.com/miguelgrinberg/microdot/issues"
25
27
 
26
28
  [project.optional-dependencies]
29
+ dev = [
30
+ "tox",
31
+ ]
27
32
  docs = [
28
33
  "sphinx",
29
- "pyjwt"
34
+ "pyjwt",
30
35
  ]
31
36
 
32
37
  [tool.setuptools]
@@ -774,7 +774,10 @@ class Response:
774
774
  first.
775
775
  """
776
776
  if content_type is None:
777
- ext = filename.split('.')[-1]
777
+ if compressed and filename.endswith('.gz'):
778
+ ext = filename[:-3].split('.')[-1]
779
+ else:
780
+ ext = filename.split('.')[-1]
778
781
  if ext in Response.types_map:
779
782
  content_type = Response.types_map[ext]
780
783
  else:
@@ -1366,7 +1369,12 @@ class Microdot:
1366
1369
  if res is None:
1367
1370
  res = await invoke_handler(
1368
1371
  f, req, **req.url_args)
1372
+ if isinstance(res, int):
1373
+ res = '', res
1369
1374
  if isinstance(res, tuple):
1375
+ if isinstance(res[0], int):
1376
+ res = ('', res[0],
1377
+ res[1] if len(res) > 1 else {})
1370
1378
  body = res[0]
1371
1379
  if isinstance(res[1], int):
1372
1380
  status_code = res[1]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: microdot
3
- Version: 2.0.6
3
+ Version: 2.0.7
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
@@ -14,6 +14,8 @@ Classifier: Operating System :: OS Independent
14
14
  Requires-Python: >=3.8
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
+ Provides-Extra: dev
18
+ Requires-Dist: tox; extra == "dev"
17
19
  Provides-Extra: docs
18
20
  Requires-Dist: sphinx; extra == "docs"
19
21
  Requires-Dist: pyjwt; extra == "docs"
@@ -58,6 +58,7 @@ tests/files/test.js
58
58
  tests/files/test.json
59
59
  tests/files/test.png
60
60
  tests/files/test.txt
61
+ tests/files/test.txt.gz
61
62
  tests/templates/hello.jinja.txt
62
63
  tests/templates/hello.utemplate.txt
63
64
  tests/templates/hello_utemplate_txt.py
@@ -1,4 +1,7 @@
1
1
 
2
+ [dev]
3
+ tox
4
+
2
5
  [docs]
3
6
  sphinx
4
7
  pyjwt
@@ -0,0 +1 @@
1
+ foo
@@ -274,6 +274,14 @@ class TestMicrodot(unittest.TestCase):
274
274
  return '<p>four</p>', 202, \
275
275
  {'Content-Type': 'text/html; charset=UTF-8'}
276
276
 
277
+ @app.route('/status')
278
+ def five(req):
279
+ return 202
280
+
281
+ @app.route('/status-headers')
282
+ def six(req):
283
+ return 202, {'Content-Type': 'text/html; charset=UTF-8'}
284
+
277
285
  client = TestClient(app)
278
286
 
279
287
  res = self._run(client.get('/body'))
@@ -299,6 +307,18 @@ class TestMicrodot(unittest.TestCase):
299
307
  'text/html; charset=UTF-8')
300
308
  self.assertEqual(res.text, '<p>four</p>')
301
309
 
310
+ res = self._run(client.get('/status'))
311
+ self.assertEqual(res.text, '')
312
+ self.assertEqual(res.status_code, 202)
313
+ self.assertEqual(res.headers['Content-Type'],
314
+ 'text/plain; charset=UTF-8')
315
+
316
+ res = self._run(client.get('/status-headers'))
317
+ self.assertEqual(res.text, '')
318
+ self.assertEqual(res.status_code, 202)
319
+ self.assertEqual(res.headers['Content-Type'],
320
+ 'text/html; charset=UTF-8')
321
+
302
322
  def test_before_after_request(self):
303
323
  app = Microdot()
304
324
 
@@ -136,10 +136,10 @@ class TestResponse(unittest.TestCase):
136
136
  self.assertTrue(fd.response.endswith(b'\r\n\r\nfoobar'))
137
137
 
138
138
  def test_create_from_other(self):
139
- res = Response(123)
139
+ res = Response(23.7)
140
140
  self.assertEqual(res.status_code, 200)
141
141
  self.assertEqual(res.headers, {})
142
- self.assertEqual(res.body, 123)
142
+ self.assertEqual(res.body, 23.7)
143
143
 
144
144
  def test_create_with_status_code(self):
145
145
  res = Response('not found', 404)
@@ -280,6 +280,17 @@ class TestResponse(unittest.TestCase):
280
280
  'application/octet-stream')
281
281
  self.assertEqual(res.headers['Content-Encoding'], 'gzip')
282
282
 
283
+ def test_send_file_gzip_handling(self):
284
+ res = Response.send_file('tests/files/test.txt.gz')
285
+ self.assertEqual(res.status_code, 200)
286
+ self.assertEqual(res.headers['Content-Type'],
287
+ 'application/octet-stream')
288
+
289
+ res = Response.send_file('tests/files/test.txt.gz', compressed=True)
290
+ self.assertEqual(res.status_code, 200)
291
+ self.assertEqual(res.headers['Content-Type'], 'text/plain')
292
+ self.assertEqual(res.headers['Content-Encoding'], 'gzip')
293
+
283
294
  def test_default_content_type(self):
284
295
  original_content_type = Response.default_content_type
285
296
  res = Response('foo')
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