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]

Reply via email to