4 Commits

Author SHA1 Message Date
Miguel Grinberg
c2e18004f7 Release 2.0.1 2023-12-23 12:49:52 +00:00
Miguel Grinberg
bd18ceb442 Addressed some inadvertent mistakes in the template extensions 2023-12-23 12:48:27 +00:00
Miguel Grinberg
f38d6d760a Updated readme and change log #nolog 2023-12-23 00:04:22 +00:00
Miguel Grinberg
dee4914bdd Version 2.0.1.dev0 2023-12-22 20:42:53 +00:00
20 changed files with 103 additions and 87 deletions

View File

@@ -1,8 +1,19 @@
# Microdot change log
**Release 2.0.1** - 2023-12-23
- Addressed some inadvertent mistakes in the template extensions ([commit](https://github.com/miguelgrinberg/microdot/commit/bd18ceb4424e9dfb52b1e6d498edd260aa24fc53))
**Release 2.0.0** - 2023-12-22
- Major redesign switching to asyncio as the base implementation (See the [Migration Guide](https://microdot.readthedocs.io/en/stable/migrating.html) in the docs for details) [#186](https://github.com/miguelgrinberg/microdot/issues/186) ([commit](https://github.com/miguelgrinberg/microdot/commit/20ea305fe793eb206b52af9eb5c5f3c1e9f57dbb))
- Major redesign [#186](https://github.com/miguelgrinberg/microdot/issues/186) ([commit](https://github.com/miguelgrinberg/microdot/commit/20ea305fe793eb206b52af9eb5c5f3c1e9f57dbb))
- Code reorganization as a `microdot` package
- Asyncio is now the core implementation
- New support for Server-Sent Events (SSE)
- Several extensions redesigned
- Support for "partitioned" cookies
- [Cross-compiling and freezing](https://microdot.readthedocs.io/en/stable/freezing.html) guidance
- A [Migration Guide](https://microdot.readthedocs.io/en/stable/migrating.html) to help transition to version 2 from older releases
**Release 1.3.4** - 2023-11-08

View File

@@ -32,5 +32,10 @@ describes the backwards incompatible changes that were made.
## Resources
- Documentation: [Latest](https://microdot.readthedocs.io/en/latest/) [Stable](https://microdot.readthedocs.io/en/stable/) [Legacy v1.x](https://microdot.readthedocs.io/en/v1/)
- Documentation
- [Stable](https://microdot.readthedocs.io/en/stable/)
- [Latest](https://microdot.readthedocs.io/en/latest/)
- Still using version 1?
- [Code](https://github.com/miguelgrinberg/microdot/tree/v1)
- [Documentation](https://microdot.readthedocs.io/en/v1/)
- [Change Log](https://github.com/miguelgrinberg/microdot/blob/main/CHANGES.md)

View File

@@ -129,11 +129,10 @@ are the asynchronous versions of these two methods.
The default location from where templates are loaded is the *templates*
subdirectory. This location can be changed with the
:func:`init_templates <microdot.utemplate.init_templates>` function::
:func:`Template.initialize <microdot.utemplate.Template.initialize>` class
method::
from microdot.utemplate import init_templates
init_templates('my_templates')
Template.initialize('my_templates')
Using the Jinja Engine
^^^^^^^^^^^^^^^^^^^^^^
@@ -174,17 +173,15 @@ method, which returns a generator instead of a string.
The default location from where templates are loaded is the *templates*
subdirectory. This location can be changed with the
:func:`init_templates <microdot.utemplate.init_templates>` function::
:func:`Template.initialize <microdot.jinja.Template.initialize>` class method::
from microdot.jinja import init_templates
Template.initialize('my_templates')
init_templates('my_templates')
The ``init_templates()`` function also accepts ``enable_async`` argument, which
The ``initialize()`` method also accepts ``enable_async`` argument, which
can be set to ``True`` if asynchronous rendering of templates is desired. If
this option is enabled, then the
:func:`render_async() <microdot.utemplate.Template.render_async>` and
:func:`generate_async() <microdot.utemplate.Template.generate_async>` methods
:func:`render_async() <microdot.jinja.Template.render_async>` and
:func:`generate_async() <microdot.jinja.Template.generate_async>` methods
must be used.
.. note::

View File

@@ -1,7 +1,7 @@
from microdot import Microdot, Response
from microdot.jinja import template, init_templates
from microdot.jinja import Template
init_templates('templates', enable_async=True)
Template.initialize('templates', enable_async=True)
app = Microdot()
Response.default_content_type = 'text/html'
@@ -11,7 +11,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return await template('index.html').render_async(name=name)
return await Template('index.html').render_async(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot import Microdot, Response
from microdot.jinja import template
from microdot.jinja import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -7,12 +7,12 @@ Response.default_content_type = 'text/html'
@app.route('/')
async def index(req):
return template('page1.html').render(page='Page 1')
return Template('page1.html').render(page='Page 1')
@app.route('/page2')
async def page2(req):
return template('page2.html').render(page='Page 2')
return Template('page2.html').render(page='Page 2')
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot import Microdot, Response
from microdot.jinja import template
from microdot.jinja import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').render(name=name)
return Template('index.html').render(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot.asgi import Microdot, Response
from microdot.jinja import template
from microdot.jinja import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').render(name=name)
return Template('index.html').render(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot.wsgi import Microdot, Response
from microdot.jinja import template
from microdot.jinja import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').render(name=name)
return Template('index.html').render(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot import Microdot, Response
from microdot.jinja import template
from microdot.jinja import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').generate(name=name)
return Template('index.html').generate(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot import Microdot, Response
from microdot.utemplate import template
from microdot.utemplate import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return await template('index.html').render_async(name=name)
return await Template('index.html').render_async(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot import Microdot, Response
from microdot.utemplate import template
from microdot.utemplate import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -7,12 +7,12 @@ Response.default_content_type = 'text/html'
@app.route('/')
async def index(req):
return template('page1.html').render(page='Page 1')
return Template('page1.html').render(page='Page 1')
@app.route('/page2')
async def page2(req):
return template('page2.html').render(page='Page 2')
return Template('page2.html').render(page='Page 2')
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot import Microdot, Response
from microdot.utemplate import template
from microdot.utemplate import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').render(name=name)
return Template('index.html').render(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot.asgi import Microdot, Response
from microdot.utemplate import template
from microdot.utemplate import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').render(name=name)
return Template('index.html').render(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot.wsgi import Microdot, Response
from microdot.utemplate import template
from microdot.utemplate import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').render(name=name)
return Template('index.html').render(name=name)
if __name__ == '__main__':

View File

@@ -1,5 +1,5 @@
from microdot import Microdot, Response
from microdot.utemplate import template
from microdot.utemplate import Template
app = Microdot()
Response.default_content_type = 'text/html'
@@ -10,7 +10,7 @@ async def index(req):
name = None
if req.method == 'POST':
name = req.form.get('name')
return template('index.html').generate(name=name)
return Template('index.html').generate(name=name)
if __name__ == '__main__':

View File

@@ -1,6 +1,6 @@
[project]
name = "microdot"
version = "2.0.0"
version = "2.0.1"
authors = [
{ name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com" },
]

View File

@@ -3,14 +3,22 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape
_jinja_env = None
def init_templates(template_dir='templates', enable_async=False, **kwargs):
class Template:
"""A template object.
:param template: The filename of the template to render, relative to the
configured template directory.
"""
@classmethod
def initialize(cls, template_dir='templates', enable_async=False,
**kwargs):
"""Initialize the templating subsystem.
:param template_dir: the directory where templates are stored. This
argument is optional. The default is to load templates
from a *templates* subdirectory.
:param enable_async: set to ``True`` to enable the async rendering engine
in Jinja, and the ``render_async()`` and
argument is optional. The default is to load
templates from a *templates* subdirectory.
:param enable_async: set to ``True`` to enable the async rendering
engine in Jinja, and the ``render_async()`` and
``generate_async()`` methods.
:param kwargs: any additional options to be passed to Jinja's
``Environment`` class.
@@ -23,16 +31,9 @@ def init_templates(template_dir='templates', enable_async=False, **kwargs):
**kwargs
)
class Template:
"""A template object.
:param template: The filename of the template to render, relative to the
configured template directory.
"""
def __init__(self, template):
if _jinja_env is None: # pragma: no cover
init_templates()
self.initialize()
#: The name of the template
self.name = template
self.template = _jinja_env.get_template(template)

View File

@@ -3,30 +3,32 @@ from utemplate import recompile
_loader = None
def init_templates(template_dir='templates', loader_class=recompile.Loader):
"""Initialize the templating subsystem.
:param template_dir: the directory where templates are stored. This
argument is optional. The default is to load templates
from a *templates* subdirectory.
:param loader_class: the ``utemplate.Loader`` class to use when loading
templates. This argument is optional. The default is
the ``recompile.Loader`` class, which automatically
recompiles templates when they change.
"""
global _loader
_loader = loader_class(None, template_dir)
class Template:
"""A template object.
:param template: The filename of the template to render, relative to the
configured template directory.
"""
@classmethod
def initialize(cls, template_dir='templates',
loader_class=recompile.Loader):
"""Initialize the templating subsystem.
:param template_dir: the directory where templates are stored. This
argument is optional. The default is to load
templates from a *templates* subdirectory.
:param loader_class: the ``utemplate.Loader`` class to use when loading
templates. This argument is optional. The default
is the ``recompile.Loader`` class, which
automatically recompiles templates when they
change.
"""
global _loader
_loader = loader_class(None, template_dir)
def __init__(self, template):
if _loader is None: # pragma: no cover
init_templates()
self.initialize()
#: The name of the template
self.name = template
self.template = _loader.load(template)

View File

@@ -2,10 +2,10 @@ import asyncio
import sys
import unittest
from microdot import Microdot
from microdot.jinja import Template, init_templates
from microdot.jinja import Template
from microdot.test_client import TestClient
init_templates('tests/templates')
Template.initialize('tests/templates')
@unittest.skipIf(sys.implementation.name == 'micropython',
@@ -49,7 +49,7 @@ class TestJinja(unittest.TestCase):
self.assertEqual(res.body, b'Hello, foo!')
def test_render_async_template_in_app(self):
init_templates('tests/templates', enable_async=True)
Template.initialize('tests/templates', enable_async=True)
app = Microdot()
@@ -62,10 +62,10 @@ class TestJinja(unittest.TestCase):
self.assertEqual(res.status_code, 200)
self.assertEqual(res.body, b'Hello, foo!')
init_templates('tests/templates')
Template.initialize('tests/templates')
def test_generate_async_template_in_app(self):
init_templates('tests/templates', enable_async=True)
Template.initialize('tests/templates', enable_async=True)
app = Microdot()
@@ -78,4 +78,4 @@ class TestJinja(unittest.TestCase):
self.assertEqual(res.status_code, 200)
self.assertEqual(res.body, b'Hello, foo!')
init_templates('tests/templates')
Template.initialize('tests/templates')

View File

@@ -2,9 +2,9 @@ import asyncio
import unittest
from microdot import Microdot
from microdot.test_client import TestClient
from microdot.utemplate import Template, init_templates
from microdot.utemplate import Template
init_templates('tests/templates')
Template.initialize('tests/templates')
class TestUTemplate(unittest.TestCase):