async def test_nested(client, app): @app.middleware async def mid(app, req, receive, send): response = await app(req, receive, send) response.headers['x-app'] = 'OK' return response from muffin import Application subapp = Application() @subapp.route('/route') def subroute(request): return 'OK from subroute' @subapp.middleware async def mid(app, req, receive, send): response = await app(req, receive, send) response.headers['x-subapp'] = 'OK' return response app.route('/sub')(subapp) res = await client.get('/sub/route') assert res.status_code == 200 assert await res.text() == 'OK from subroute' assert res.headers['x-app'] == 'OK' assert res.headers['x-subapp'] == 'OK'
async def test_plugin_config(app, client): from muffin import Application from muffin.plugins import BasePlugin class Plugin(BasePlugin): name = 'plugin' defaults = { 'debug': True, 'option': 11, } after_setup = True def setup(self, app, **options): super(Plugin, self).setup(app, **options) self.after_setup = self.cfg.option plugin = Plugin(debug=False) assert plugin.cfg assert plugin.cfg.debug is False app = Application('tests.appcfg') plugin = Plugin(app) assert plugin.cfg.option == 42 # from application config plugin = Plugin(app, option=22) assert plugin.cfg.option == 22 assert plugin.after_setup == 22
def setup(self, app: Application, **options): # noqa """Setup the plugin's commands.""" super(Plugin, self).setup(app, **options) self.__locale_selector: t.Optional[t.Callable[ [Request], t.Awaitable[t.Optional[str]]]] = select_locale_by_request # noqa # Install a middleware for autodetection if self.cfg.auto_detect_locale: app.middleware(self.__middleware__, insert_first=True) @app.manage(lifespan=False) def babel_extract_messages(*dirnames: str, project: str = app.cfg.name, domain: str = self.cfg.domain, locations: bool = True, charset: str = 'utf-8', locale: str = self.cfg.default_locale): """Extract messages from source code. :param charset: charset to use in the output :param domain: set domain name for locales :param project: set project name in output :param version: set project version in output :param locations: add message locations """ dirs = [d for d in dirnames if os.path.isdir(d)] catalog = Catalog(locale=locale, project=project, charset=charset) for dname in dirs: for filename, lineno, message, comments, context in extract_from_dir( dname, method_map=self.cfg.sources_map, options_map=self.cfg.options_map): lines = [] if locations: filepath = os.path.normpath( os.path.join(dname, filename)) lines = [(filepath, lineno)] catalog.add(message, None, lines, auto_comments=comments, context=context) locales_dir = self.cfg.locale_folders[0] output = os.path.join(locales_dir, locale, 'LC_MESSAGES', '%s.po' % domain) if os.path.exists(output): with open(output, 'rb') as f: template = read_po(f, locale=locale, charset=charset) template.update(catalog) catalog = template if not os.path.exists(os.path.dirname(output)): os.makedirs(os.path.dirname(output)) logger.info('writing PO template file to %s', output) outfile = open(output, 'wb') try: write_po(outfile, catalog, include_previous=True, sort_output=not locations, sort_by_file=locations) finally: outfile.close() @app.manage(lifespan=False) def babel_compile_messages(use_fuzzy=False, statistics=False, domain=self.cfg.domain): # noqa """Compile messages for locales. :param domain: set domain name for locales """ for locales_dir in self.cfg.locale_folders: for locale in os.listdir(locales_dir): po_file = os.path.join(locales_dir, locale, 'LC_MESSAGES', domain + '.po') if not os.path.exists(po_file): continue with open(po_file, 'r') as po: catalog = read_po(po, locale) mo_file = os.path.join(locales_dir, locale, 'LC_MESSAGES', domain + '.mo') with open(mo_file, 'wb') as mo: logger.info('writing MO template file to %s', mo_file) write_mo(mo, catalog, use_fuzzy=use_fuzzy)
def setup(self, app: Application, **options): """Initialize the application.""" super().setup(app, **options) self.cfg.update(prefix=self.cfg.prefix.rstrip('/')) self.api.setup(app, prefix=f"{self.cfg.prefix}/api", openapi=False) self.auth['storage'] = self.cfg.auth_storage self.auth['storage_name'] = self.cfg.auth_storage_name self.auth['loginURL'] = self.cfg.login_url self.auth['logoutURL'] = self.cfg.logout_url custom_js = self.cfg.custom_js_url custom_css = self.cfg.custom_css_url title = self.cfg.title prefix = self.cfg.prefix def authorize(view): """Authorization.""" async def decorator(request): """Authorize an user.""" if self.api.authorize: auth = await self.api.authorize(request) if not auth: if self.cfg.login_url: return ResponseRedirect(self.cfg.login_url) return await view(request) return decorator @authorize async def render_admin(_): """Render admin page.""" return TEMPLATE.format( prefix=prefix, title=title, main_js_url=self.cfg.main_js_url.format(prefix=prefix), custom_js=f"<script src={custom_js}></script>" if custom_js else '', custom_css=f"<link rel='stylesheet' href={custom_css} />" if custom_css else '', ) app.route(f"/{prefix.lstrip('/')}")(render_admin) @authorize async def ra(request): data = self.to_ra() if self.__dashboard__: data['dashboard'] = await self.__dashboard__(request) return data app.route(f"{prefix}/ra.json")(ra) async def render_admin_static(_): return ResponseFile(PACKAGE_DIR / 'main.js') app.route(f"{prefix}/main.js")(render_admin_static) async def login(request): return await self.__login__(request) app.route(f"{prefix}/login")(login) async def ident(request): return await self.__ident__(request) app.route(f"{prefix}/ident")(ident)
"""Simple basic app for testing.""" from muffin import Application app = Application(debug=True, name='muffin') @app.route('/') async def index(request): return 'OK' @app.on_startup async def start(): app.state = 'started'
"""Setup the application and plugins.""" from muffin import Application from .. import views # Create Muffin Application named 'example' app = Application(name='example', debug=True) app.route('/')(views.index) app.route('/admin.css')(views.admin_css) # Import the app's components app.import_submodules()
def app(): from muffin import Application return Application()
async def test_plugin(app, client): from muffin import Application, TestClient from muffin.plugins import BasePlugin with pytest.raises(TypeError): BasePlugin() start = mock.MagicMock() finish = mock.MagicMock() assert BasePlugin.middleware is None assert BasePlugin.startup is None assert BasePlugin.shutdown is None class Plugin(BasePlugin): name = 'plugin' defaults = { 'debug': True, 'option': 42, } async def middleware(self, handler, request, receive, send): response = await handler(request, receive, send) response.headers['x-plugin'] = '42' return response async def startup(self): return start() def shutdown(self): return finish() plugin = Plugin(DEBUG=False) assert plugin.cfg assert plugin.cfg.debug is False app = Application('muffin', DEBUG=True, PLUGIN_DEBUG=True) plugin.setup(app, option=43) assert plugin.app is app assert app.plugins['plugin'] is plugin assert plugin.cfg.debug is True assert plugin.cfg.option == 43 @app.route('/') async def index(request): return 'OK' assert not start.called assert not finish.called client = TestClient(app) async with client.lifespan(): assert start.called assert not finish.called res = await client.get('/') assert res.status_code == 200 assert res.headers['x-plugin'] == '42' assert await res.text() == 'OK' assert finish.called
import time from pathlib import Path from uuid import uuid4 from muffin import Application, ResponseHTML, ResponseText, ResponseError upload_dir = Path(__file__).parent.parent app = Application(debug=True) # first add ten more routes to load routing system # ------------------------------------------------ async def req_ok(request): return 'ok' for n in range(5): app.route(f"/route-{n}", f"/route-dyn-{n}/{{part}}")(req_ok) # then prepare endpoints for the benchmark # ---------------------------------------- @app.route('/html') async def html(request): """Return HTML content and a custom header.""" content = "<b>HTML OK</b>" headers = {'x-time': f"{time.time()}"} return ResponseHTML(content, headers=headers) @app.route('/upload', methods=['POST'])
@coroutine def middleware(request): if hasattr(request, 'user'): response = None else: response = token_auth_handler(request, get_authorization_header(request), not_auth_token, set_user, Token) if not response: response = yield from handler(request) return response return middleware app = application = Application('noteit', **options) app._middlewares.extend( [token_middleware_factory, baseauth_middleware_factory]) for model in [Note, Report, User, Token, NoteBook]: app.ps.peewee.register(model) class SuperHandler(Handler): @abcoroutine def make_response(self, request, response): while iscoroutine(response): response = yield from response status = 200
def app(): return Application(debug=True)
import time import datetime #import trio from muffin import Application, Request, ResponseJSON app = Application() origin_clock_start = datetime.datetime.now().timestamp() - time.perf_counter() def pretty_time(seconds: float) -> str: present = time.localtime(origin_clock_start + seconds) return str( datetime.datetime(present.tm_year, present.tm_mon, present.tm_mday, present.tm_hour, present.tm_min, present.tm_sec)) @app.route("/") async def timed_api(request: Request): # Callable? received = time.perf_counter() # trio.current_time() scheduled = received + 5 print( f"Request received @ {pretty_time(received)} scheduled to reply @ {pretty_time(scheduled_response)}." ) #trio.sleep_until(scheduled_response) time.sleep(5) handled = time.perf_counter() # trio.current_time() response = { 'received': received,
"""The example uses muffin-grpc plugin to setup a GRPC server/client.""" from pathlib import Path from muffin import Application from muffin_grpc import Plugin as GRPC from muffin_jinja2 import Plugin as Jinja2 app = Application('grpc-example', debug=True, root=Path(__file__).parent) jinja2 = Jinja2(app, template_folders=[app.cfg.root / 'templates'], auto_reload=True) grpc = GRPC(app, server="[::]:50051", build_dir=app.cfg.root / 'proto') grpc.add_proto(grpc.cfg.build_dir / 'src/helloworld.proto') from .rpc import * # noqa from .views import * # noqa