This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/main by this push:
new c17e42d Add a blueprint for general GET routes
c17e42d is described below
commit c17e42db0b55ac70c8de961f44f72e15384fe40a
Author: Sean B. Palmer <[email protected]>
AuthorDate: Sun Oct 26 18:43:50 2025 +0000
Add a blueprint for general GET routes
---
atr/blueprints/__init__.py | 2 +
atr/blueprints/get.py | 78 ++++++++++++++++++++++
atr/docs/code-conventions.html | 2 +-
atr/docs/code-conventions.md | 2 +-
atr/{blueprints => get}/__init__.py | 24 +------
.../__init__.py => get/example_test.py} | 30 +++------
atr/route.py | 1 -
7 files changed, 94 insertions(+), 45 deletions(-)
diff --git a/atr/blueprints/__init__.py b/atr/blueprints/__init__.py
index e9ae23f..b72501b 100644
--- a/atr/blueprints/__init__.py
+++ b/atr/blueprints/__init__.py
@@ -21,6 +21,7 @@ from typing import Protocol, runtime_checkable
import asfquart.base as base
import atr.blueprints.api as api
+import atr.blueprints.get as get
@runtime_checkable
@@ -38,3 +39,4 @@ def check_module(module: ModuleType) -> None:
def register(app: base.QuartApp) -> None:
check_module(api.register(app))
+ check_module(get.register(app))
diff --git a/atr/blueprints/get.py b/atr/blueprints/get.py
new file mode 100644
index 0000000..54df06a
--- /dev/null
+++ b/atr/blueprints/get.py
@@ -0,0 +1,78 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from collections.abc import Awaitable, Callable
+from types import ModuleType
+from typing import Any
+
+import asfquart.auth as auth
+import asfquart.base as base
+import asfquart.session as session
+import quart
+
+import atr.route as route
+
+_BLUEPRINT = quart.Blueprint("get_blueprint", __name__)
+
+
+def register(app: base.QuartApp) -> ModuleType:
+ import atr.get as get
+
+ app.register_blueprint(_BLUEPRINT)
+ return get
+
+
+def committer(path: str) -> Callable[[route.CommitterRouteHandler[Any]],
route.RouteHandler[Any]]:
+ def decorator(func: route.CommitterRouteHandler[Any]) ->
route.RouteHandler[Any]:
+ async def wrapper(*args: Any, **kwargs: Any) -> Any:
+ web_session = await session.read()
+ if web_session is None:
+ raise base.ASFQuartException("Not authenticated",
errorcode=401)
+
+ enhanced_session = route.CommitterSession(web_session)
+ return await func(enhanced_session, *args, **kwargs)
+
+ wrapper.__name__ = func.__name__
+ wrapper.__doc__ = func.__doc__
+
+ endpoint = func.__module__.replace(".", "_") + "_" + func.__name__
+
+ decorated = auth.require(auth.Requirements.committer)(wrapper)
+ _BLUEPRINT.add_url_rule(path, endpoint=endpoint, view_func=decorated,
methods=["GET"])
+
+ return decorated
+
+ return decorator
+
+
+def public(path: str) -> Callable[[Callable[..., Awaitable[Any]]],
route.RouteHandler[Any]]:
+ def decorator(func: Callable[..., Awaitable[Any]]) ->
route.RouteHandler[Any]:
+ async def wrapper(*args: Any, **kwargs: Any) -> Any:
+ web_session = await session.read()
+ enhanced_session = route.CommitterSession(web_session) if
web_session else None
+ return await func(enhanced_session, *args, **kwargs)
+
+ wrapper.__name__ = func.__name__
+ wrapper.__doc__ = func.__doc__
+
+ endpoint = func.__module__.replace(".", "_") + "_" + func.__name__
+
+ _BLUEPRINT.add_url_rule(path, endpoint=endpoint, view_func=wrapper,
methods=["GET"])
+
+ return wrapper
+
+ return decorator
diff --git a/atr/docs/code-conventions.html b/atr/docs/code-conventions.html
index 95ede86..4487cbe 100644
--- a/atr/docs/code-conventions.html
+++ b/atr/docs/code-conventions.html
@@ -41,7 +41,7 @@ def process_data(data):
<h3 id="avoid-excessive-indentation">Avoid excessive indentation</h3>
<p>When you find yourself nesting code more than two or three levels deep,
extract the nested logic into separate functions. This improves readability,
testability, and maintainability. Each function should handle a single, well
defined piece of logic.</p>
<h3 id="do-not-use-lint-or-type-checker-ignore-statements">Do not use lint or
type checker ignore statements</h3>
-<p>You must not use <code># noqa</code>, <code># type: ignore</code>, or
equivalents, even to ignore specific errors. The single exception to this is
when there is a bug in the linter or type checker.</p>
+<p>You must not use <code># noqa</code>, <code># type: ignore</code>, or
equivalents such as <code>cast</code>, even to ignore specific errors. The
single exception to this is when there is a bug in the linter or type
checker.</p>
<p>File level lint ignores can be added to the project's
<code>pyproject.toml</code>, but they must be used sparingly.</p>
<h3 id="use-double-quotes-for-all-strings">Use double quotes for all
strings</h3>
<p>This includes triple quoted strings.</p>
diff --git a/atr/docs/code-conventions.md b/atr/docs/code-conventions.md
index 19bdaf6..6742be2 100644
--- a/atr/docs/code-conventions.md
+++ b/atr/docs/code-conventions.md
@@ -56,7 +56,7 @@ When you find yourself nesting code more than two or three
levels deep, extract
### Do not use lint or type checker ignore statements
-You must not use `# noqa`, `# type: ignore`, or equivalents, even to ignore
specific errors. The single exception to this is when there is a bug in the
linter or type checker.
+You must not use `# noqa`, `# type: ignore`, or equivalents such as `cast`,
even to ignore specific errors. The single exception to this is when there is a
bug in the linter or type checker.
File level lint ignores can be added to the project's `pyproject.toml`, but
they must be used sparingly.
diff --git a/atr/blueprints/__init__.py b/atr/get/__init__.py
similarity index 53%
copy from atr/blueprints/__init__.py
copy to atr/get/__init__.py
index e9ae23f..63c60e2 100644
--- a/atr/blueprints/__init__.py
+++ b/atr/get/__init__.py
@@ -15,26 +15,8 @@
# specific language governing permissions and limitations
# under the License.
-from types import ModuleType
-from typing import Protocol, runtime_checkable
+from .example_test import respond as example_test
-import asfquart.base as base
+ROUTES_MODULE = True
-import atr.blueprints.api as api
-
-
-@runtime_checkable
-class RoutesModule(Protocol):
- ROUTES_MODULE: bool = True
-
-
-def check_module(module: ModuleType) -> None:
- # We need to know that the routes were actually imported
- # Otherwise ASFQuart will not know about them, even if the blueprint is
registered
- # In other words, registering a blueprint does not automatically import
its routes
- if not isinstance(module, RoutesModule):
- raise ValueError(f"Module {module} is not a RoutesModule")
-
-
-def register(app: base.QuartApp) -> None:
- check_module(api.register(app))
+__all__ = ["example_test"]
diff --git a/atr/blueprints/__init__.py b/atr/get/example_test.py
similarity index 53%
copy from atr/blueprints/__init__.py
copy to atr/get/example_test.py
index e9ae23f..7850f03 100644
--- a/atr/blueprints/__init__.py
+++ b/atr/get/example_test.py
@@ -15,26 +15,14 @@
# specific language governing permissions and limitations
# under the License.
-from types import ModuleType
-from typing import Protocol, runtime_checkable
+import atr.blueprints.get as get
+import atr.route as route
-import asfquart.base as base
-import atr.blueprints.api as api
-
-
-@runtime_checkable
-class RoutesModule(Protocol):
- ROUTES_MODULE: bool = True
-
-
-def check_module(module: ModuleType) -> None:
- # We need to know that the routes were actually imported
- # Otherwise ASFQuart will not know about them, even if the blueprint is
registered
- # In other words, registering a blueprint does not automatically import
its routes
- if not isinstance(module, RoutesModule):
- raise ValueError(f"Module {module} is not a RoutesModule")
-
-
-def register(app: base.QuartApp) -> None:
- check_module(api.register(app))
[email protected]("/example/test")
+async def respond(session: route.CommitterSession) -> str:
+ return f"""\
+<h1>Test route</h1>
+<p>Hello, {session.asf_uid}!</p>
+<p>This is a test GET route for committers only.</p>
+"""
diff --git a/atr/route.py b/atr/route.py
index 9b8ff19..faca13f 100644
--- a/atr/route.py
+++ b/atr/route.py
@@ -24,7 +24,6 @@ import time
from typing import TYPE_CHECKING, Any, Concatenate, Final, NoReturn,
ParamSpec, Protocol, TypeVar
import aiofiles
-import aiofiles.os
import asfquart
import asfquart.auth as auth
import asfquart.base as base
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]