galaxy-web-framework 26.0.1.dev0__tar.gz → 26.0.2__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 (43) hide show
  1. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/HISTORY.rst +31 -3
  2. {galaxy_web_framework-26.0.1.dev0/galaxy_web_framework.egg-info → galaxy_web_framework-26.0.2}/PKG-INFO +48 -4
  3. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/base.py +6 -0
  4. galaxy_web_framework-26.0.2/galaxy/web/framework/middleware/aiocop_integration.py +176 -0
  5. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2/galaxy_web_framework.egg-info}/PKG-INFO +48 -4
  6. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy_web_framework.egg-info/SOURCES.txt +1 -0
  7. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy_web_framework.egg-info/requires.txt +1 -0
  8. galaxy_web_framework-26.0.2/pyproject.toml +33 -0
  9. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/setup.cfg +2 -18
  10. galaxy_web_framework-26.0.1.dev0/pyproject.toml +0 -16
  11. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/LICENSE +0 -0
  12. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/MANIFEST.in +0 -0
  13. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/README.rst +0 -0
  14. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/dev-requirements.txt +0 -0
  15. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/__init__.py +0 -0
  16. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/py.typed +0 -0
  17. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/__init__.py +0 -0
  18. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/form_builder.py +0 -0
  19. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/__init__.py +0 -0
  20. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/decorators.py +0 -0
  21. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/helpers/__init__.py +0 -0
  22. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/helpers/grids.py +0 -0
  23. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/helpers/tags.py +0 -0
  24. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/__init__.py +0 -0
  25. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/error.py +0 -0
  26. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/profile.py +0 -0
  27. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/remoteuser.py +0 -0
  28. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/request_id.py +0 -0
  29. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/sqldebug.py +0 -0
  30. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/static.py +0 -0
  31. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/statsd.py +0 -0
  32. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/translogger.py +0 -0
  33. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/framework/middleware/xforwardedhost.py +0 -0
  34. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/proxy/__init__.py +0 -0
  35. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/proxy/js/Dockerfile +0 -0
  36. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/proxy/js/README.md +0 -0
  37. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/proxy/js/lib/main.js +0 -0
  38. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/proxy/js/lib/mapper.js +0 -0
  39. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/proxy/js/lib/proxy.js +0 -0
  40. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/proxy/js/package.json +0 -0
  41. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy/web/statsd_client.py +0 -0
  42. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy_web_framework.egg-info/dependency_links.txt +0 -0
  43. {galaxy_web_framework-26.0.1.dev0 → galaxy_web_framework-26.0.2}/galaxy_web_framework.egg-info/top_level.txt +0 -0
@@ -3,11 +3,39 @@ History
3
3
 
4
4
  .. to_doc
5
5
 
6
- -----------
7
- 26.0.1.dev0
8
- -----------
6
+ -------------------
7
+ 26.0.2 (2026-10-25)
8
+ -------------------
9
+
10
+
11
+ =========
12
+ Bug fixes
13
+ =========
14
+
15
+ * Return 400 for request bodies that webob cannot parse by `@rmz-oz <https://github.com/rmz-oz>`_ in `#23839 <https://github.com/galaxyproject/galaxy/pull/23839>`_
16
+
17
+ -------------------
18
+ 25.1.3 (2026-10-25)
19
+ -------------------
20
+
9
21
 
22
+ =========
23
+ Bug fixes
24
+ =========
25
+
26
+ * Fix legacy_expose_api error callable returning str instead of bytes by `@mvdbeek <https://github.com/mvdbeek>`_ in `#22106 <https://github.com/galaxyproject/galaxy/pull/22106>`_
27
+ * Return 400 for request bodies that webob cannot parse by `@rmz-oz <https://github.com/rmz-oz>`_ in `#23839 <https://github.com/galaxyproject/galaxy/pull/23839>`_
28
+
29
+ -------------------
30
+ 26.0.1 (2026-06-04)
31
+ -------------------
32
+
33
+
34
+ =========
35
+ Bug fixes
36
+ =========
10
37
 
38
+ * Add debug middleware and regression tests for blocked main event loop by `@mvdbeek <https://github.com/mvdbeek>`_ in `#22207 <https://github.com/galaxyproject/galaxy/pull/22207>`_
11
39
 
12
40
  -------------------
13
41
  26.0.0 (2026-04-08)
@@ -1,11 +1,26 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: galaxy-web-framework
3
- Version: 26.0.1.dev0
3
+ Version: 26.0.2
4
4
  Summary: Galaxy web framework
5
5
  Home-page: https://github.com/galaxyproject/galaxy
6
6
  Author: Galaxy Project and Community
7
7
  Author-email: galaxy-committers@lists.galaxyproject.org
8
8
  License: MIT
9
+ Keywords: Galaxy
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development
22
+ Classifier: Topic :: Software Development :: Code Generators
23
+ Classifier: Topic :: Software Development :: Testing
9
24
  Requires-Python: >=3.10
10
25
  Description-Content-Type: text/x-rst
11
26
  License-File: LICENSE
@@ -18,6 +33,7 @@ Requires-Dist: pydantic>=2.7.4
18
33
  Requires-Dist: requests
19
34
  Requires-Dist: Routes
20
35
  Requires-Dist: SQLAlchemy!=2.0.41,<2.1,>=2.0.37
36
+ Requires-Dist: starlette
21
37
  Requires-Dist: WebOb
22
38
  Provides-Extra: test
23
39
  Requires-Dist: pytest; extra == "test"
@@ -42,11 +58,39 @@ History
42
58
 
43
59
  .. to_doc
44
60
 
45
- -----------
46
- 26.0.1.dev0
47
- -----------
61
+ -------------------
62
+ 26.0.2 (2026-10-25)
63
+ -------------------
64
+
65
+
66
+ =========
67
+ Bug fixes
68
+ =========
69
+
70
+ * Return 400 for request bodies that webob cannot parse by `@rmz-oz <https://github.com/rmz-oz>`_ in `#23839 <https://github.com/galaxyproject/galaxy/pull/23839>`_
71
+
72
+ -------------------
73
+ 25.1.3 (2026-10-25)
74
+ -------------------
75
+
48
76
 
77
+ =========
78
+ Bug fixes
79
+ =========
80
+
81
+ * Fix legacy_expose_api error callable returning str instead of bytes by `@mvdbeek <https://github.com/mvdbeek>`_ in `#22106 <https://github.com/galaxyproject/galaxy/pull/22106>`_
82
+ * Return 400 for request bodies that webob cannot parse by `@rmz-oz <https://github.com/rmz-oz>`_ in `#23839 <https://github.com/galaxyproject/galaxy/pull/23839>`_
83
+
84
+ -------------------
85
+ 26.0.1 (2026-06-04)
86
+ -------------------
87
+
88
+
89
+ =========
90
+ Bug fixes
91
+ =========
49
92
 
93
+ * Add debug middleware and regression tests for blocked main event loop by `@mvdbeek <https://github.com/mvdbeek>`_ in `#22207 <https://github.com/galaxyproject/galaxy/pull/22207>`_
50
94
 
51
95
  -------------------
52
96
  26.0.0 (2026-04-08)
@@ -234,6 +234,12 @@ class WebApplication:
234
234
  # https://github.com/bbangert/routes/blob/c4d5a5fb693ce8dc7cf5dbc591861acfc49d5c23/routes/__init__.py#L73
235
235
  environ["SERVER_PORT"] = str(server_port)
236
236
  rc.environ = environ
237
+ # Parse the request parameters up front so that a malformed body
238
+ # (e.g. multipart with an empty boundary) is a 400 rather than a 500.
239
+ try:
240
+ Request(environ).params.mixed()
241
+ except ValueError as e:
242
+ raise webob.exc.HTTPBadRequest(f"Malformed request body: {e}")
237
243
  # Setup the transaction
238
244
  trans = self.transaction_factory(environ)
239
245
  trans.request_id = request_id
@@ -0,0 +1,176 @@
1
+ """
2
+ aiocop integration — detect blocking I/O in async handlers.
3
+
4
+ `aiocop <https://github.com/Feverup/aiocop>`_ uses ``sys.audit`` hooks to catch
5
+ specific blocking syscalls (``socket.connect``, ``open``, ``subprocess.Popen``,
6
+ etc.) from within async tasks and report the exact call site.
7
+
8
+ This module installs aiocop and adds an ASGI middleware that surfaces any
9
+ violations recorded during a request via an ``X-Aiocop-Violations`` response
10
+ header so test harnesses can fail requests that block the event loop.
11
+
12
+ Activation is opt-in via the ``GALAXY_TEST_AIOCOP`` environment variable —
13
+ aiocop is a test-only dependency and is not imported in normal production
14
+ Galaxy servers.
15
+ """
16
+
17
+ import asyncio
18
+ import logging
19
+ import os
20
+ import threading
21
+ from contextvars import ContextVar
22
+ from typing import (
23
+ Any,
24
+ Optional,
25
+ )
26
+
27
+ from starlette.types import (
28
+ ASGIApp,
29
+ Message,
30
+ Receive,
31
+ Scope,
32
+ Send,
33
+ )
34
+
35
+ log = logging.getLogger(__name__)
36
+
37
+ ENV_VAR = "GALAXY_TEST_AIOCOP"
38
+
39
+ # High-severity threshold used by aiocop itself (THRESHOLD_HIGH == 50).
40
+ # Anything at or above is considered a test-failing violation.
41
+ HIGH_SEVERITY_SCORE = 50
42
+
43
+ _request_violations: ContextVar[Optional[list[dict[str, Any]]]] = ContextVar("aiocop_request_violations", default=None)
44
+
45
+ _process_initialized = False
46
+
47
+
48
+ def aiocop_enabled() -> bool:
49
+ return os.environ.get(ENV_VAR, "").lower() in ("1", "true", "yes")
50
+
51
+
52
+ def _on_slow_task(event: Any) -> None:
53
+ if not event.blocking_events:
54
+ return
55
+ violations = _request_violations.get()
56
+ if violations is not None:
57
+ violations.extend(event.blocking_events)
58
+ log.error(
59
+ "aiocop detected blocking I/O on event loop (severity=%s, elapsed=%.1fms): %s",
60
+ event.severity_level,
61
+ event.elapsed_ms,
62
+ "; ".join(f"{e['event']} at {e['entry_point']}" for e in event.blocking_events),
63
+ )
64
+
65
+
66
+ def install_aiocop(slow_task_threshold_ms: int = 50, trace_depth: int = 20) -> None:
67
+ """Activate aiocop monitoring on the currently running event loop.
68
+
69
+ Must be called from the event-loop thread (e.g. a FastAPI ``startup``
70
+ event). aiocop normally binds its audit hook to
71
+ :func:`threading.main_thread`, but Galaxy's test harness runs uvicorn's
72
+ event loop in a child thread — so we rebind the hook to the current
73
+ thread explicitly.
74
+
75
+ The Galaxy integration test driver spins up a fresh event loop on a new
76
+ thread for every test module (see ``galaxy_test.driver.driver_util``).
77
+ aiocop has process-global state — ``sys.addaudithook`` cannot be undone
78
+ and ``patch_audit_functions`` wraps stdlib call sites in place — so we
79
+ do that setup exactly once. The per-loop pieces (loop patching, main
80
+ thread binding, slow-task callback) are re-armed on every call so the
81
+ Nth Galaxy instance is actually monitored.
82
+ """
83
+ global _process_initialized
84
+
85
+ import aiocop
86
+ from aiocop.core import (
87
+ blocking_io as _bio,
88
+ slow_tasks as _slow_tasks,
89
+ )
90
+
91
+ if not _process_initialized:
92
+ aiocop.patch_audit_functions()
93
+ aiocop.start_blocking_io_detection(trace_depth=trace_depth)
94
+ _process_initialized = True
95
+
96
+ # aiocop binds audit events to the process main thread; the Galaxy test
97
+ # server runs its event loop in a non-main thread, so pin aiocop to the
98
+ # thread that actually hosts the loop.
99
+ _bio._main_thread_id = threading.get_ident()
100
+
101
+ # Re-arm detect_slow_tasks so the on-activate hook is fresh and the
102
+ # slow-task callback isn't a stale closure from a prior Galaxy instance.
103
+ # detect_slow_tasks() short-circuits on its module-global guard, so reset
104
+ # it and clear the callback list before calling again.
105
+ _slow_tasks._detect_slow_tasks_configured = False
106
+ aiocop.clear_slow_task_callbacks()
107
+ aiocop.detect_slow_tasks(threshold_ms=slow_task_threshold_ms, on_slow_task=_on_slow_task)
108
+ aiocop.activate()
109
+ log.info("aiocop blocking-I/O detection activated (threshold=%dms)", slow_task_threshold_ms)
110
+
111
+
112
+ class AiocopMiddleware:
113
+ """Attach per-request aiocop violations to an ``X-Aiocop-Violations`` header.
114
+
115
+ The header is only emitted when at least one blocking event was captured.
116
+ Format:
117
+
118
+ ``count=<n>;severity=<max>;first=<event>@<entry_point>``
119
+
120
+ ``severity`` is the maximum severity weight among the captured events
121
+ (see ``aiocop.core.blocking_io.BLOCKING_EVENTS_DICT``). A value of
122
+ 50 or higher indicates a high-severity block that should fail tests.
123
+
124
+ aiocop itself is installed on the first ``lifespan`` startup event so
125
+ it binds to the event loop actually serving traffic (Galaxy's test
126
+ harness runs uvicorn in a child thread — see
127
+ :func:`galaxy_test.driver.driver_util.launch_server`).
128
+ """
129
+
130
+ def __init__(self, app: ASGIApp):
131
+ self.app = app
132
+ self._installed = False
133
+
134
+ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
135
+ if scope["type"] == "lifespan":
136
+ # Wrap lifespan startup to install aiocop as soon as the loop
137
+ # is running, before any request is served.
138
+ async def send_wrapper(message: Message) -> None:
139
+ if message.get("type") == "lifespan.startup.complete" and not self._installed:
140
+ install_aiocop()
141
+ self._installed = True
142
+ await send(message)
143
+
144
+ return await self.app(scope, receive, send_wrapper)
145
+
146
+ if scope["type"] != "http":
147
+ return await self.app(scope, receive, send)
148
+
149
+ violations: list[dict[str, Any]] = []
150
+ token = _request_violations.set(violations)
151
+ response_started = False
152
+
153
+ async def send_with_header(message: Message) -> None:
154
+ nonlocal response_started
155
+ if message["type"] == "http.response.start" and not response_started:
156
+ response_started = True
157
+ # aiocop's slow-task callback fires when the task step that
158
+ # did the blocking I/O ends; yield once to let any pending
159
+ # callback populate `violations` before we emit headers.
160
+ await asyncio.sleep(0)
161
+ if violations:
162
+ max_severity = max(int(v.get("severity") or 0) for v in violations)
163
+ first = violations[0]
164
+ summary = (
165
+ f"count={len(violations)};severity={max_severity};"
166
+ f"first={first['event']}@{first['entry_point']}"
167
+ )
168
+ headers = list(message.get("headers", []))
169
+ headers.append((b"x-aiocop-violations", summary.encode("latin-1")))
170
+ message = {**message, "headers": headers}
171
+ await send(message)
172
+
173
+ try:
174
+ await self.app(scope, receive, send_with_header)
175
+ finally:
176
+ _request_violations.reset(token)
@@ -1,11 +1,26 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: galaxy-web-framework
3
- Version: 26.0.1.dev0
3
+ Version: 26.0.2
4
4
  Summary: Galaxy web framework
5
5
  Home-page: https://github.com/galaxyproject/galaxy
6
6
  Author: Galaxy Project and Community
7
7
  Author-email: galaxy-committers@lists.galaxyproject.org
8
8
  License: MIT
9
+ Keywords: Galaxy
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development
22
+ Classifier: Topic :: Software Development :: Code Generators
23
+ Classifier: Topic :: Software Development :: Testing
9
24
  Requires-Python: >=3.10
10
25
  Description-Content-Type: text/x-rst
11
26
  License-File: LICENSE
@@ -18,6 +33,7 @@ Requires-Dist: pydantic>=2.7.4
18
33
  Requires-Dist: requests
19
34
  Requires-Dist: Routes
20
35
  Requires-Dist: SQLAlchemy!=2.0.41,<2.1,>=2.0.37
36
+ Requires-Dist: starlette
21
37
  Requires-Dist: WebOb
22
38
  Provides-Extra: test
23
39
  Requires-Dist: pytest; extra == "test"
@@ -42,11 +58,39 @@ History
42
58
 
43
59
  .. to_doc
44
60
 
45
- -----------
46
- 26.0.1.dev0
47
- -----------
61
+ -------------------
62
+ 26.0.2 (2026-10-25)
63
+ -------------------
64
+
65
+
66
+ =========
67
+ Bug fixes
68
+ =========
69
+
70
+ * Return 400 for request bodies that webob cannot parse by `@rmz-oz <https://github.com/rmz-oz>`_ in `#23839 <https://github.com/galaxyproject/galaxy/pull/23839>`_
71
+
72
+ -------------------
73
+ 25.1.3 (2026-10-25)
74
+ -------------------
75
+
48
76
 
77
+ =========
78
+ Bug fixes
79
+ =========
80
+
81
+ * Fix legacy_expose_api error callable returning str instead of bytes by `@mvdbeek <https://github.com/mvdbeek>`_ in `#22106 <https://github.com/galaxyproject/galaxy/pull/22106>`_
82
+ * Return 400 for request bodies that webob cannot parse by `@rmz-oz <https://github.com/rmz-oz>`_ in `#23839 <https://github.com/galaxyproject/galaxy/pull/23839>`_
83
+
84
+ -------------------
85
+ 26.0.1 (2026-06-04)
86
+ -------------------
87
+
88
+
89
+ =========
90
+ Bug fixes
91
+ =========
49
92
 
93
+ * Add debug middleware and regression tests for blocked main event loop by `@mvdbeek <https://github.com/mvdbeek>`_ in `#22207 <https://github.com/galaxyproject/galaxy/pull/22207>`_
50
94
 
51
95
  -------------------
52
96
  26.0.0 (2026-04-08)
@@ -17,6 +17,7 @@ galaxy/web/framework/helpers/__init__.py
17
17
  galaxy/web/framework/helpers/grids.py
18
18
  galaxy/web/framework/helpers/tags.py
19
19
  galaxy/web/framework/middleware/__init__.py
20
+ galaxy/web/framework/middleware/aiocop_integration.py
20
21
  galaxy/web/framework/middleware/error.py
21
22
  galaxy/web/framework/middleware/profile.py
22
23
  galaxy/web/framework/middleware/remoteuser.py
@@ -7,6 +7,7 @@ pydantic>=2.7.4
7
7
  requests
8
8
  Routes
9
9
  SQLAlchemy!=2.0.41,<2.1,>=2.0.37
10
+ starlette
10
11
  WebOb
11
12
 
12
13
  [test]
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ build-backend = "setuptools.build_meta"
3
+ requires = ["setuptools"]
4
+
5
+ [project]
6
+ dynamic = [
7
+ "authors",
8
+ "dependencies",
9
+ "description",
10
+ "license",
11
+ "optional-dependencies",
12
+ "readme",
13
+ "requires-python",
14
+ "version",
15
+ ]
16
+ name = "galaxy-web-framework"
17
+ classifiers = [
18
+ "Development Status :: 5 - Production/Stable",
19
+ "Environment :: Console",
20
+ "Intended Audience :: Developers",
21
+ "Natural Language :: English",
22
+ "Operating System :: POSIX",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
29
+ "Topic :: Software Development",
30
+ "Topic :: Software Development :: Code Generators",
31
+ "Topic :: Software Development :: Testing",
32
+ ]
33
+ keywords = ["Galaxy"]
@@ -1,24 +1,7 @@
1
1
  [metadata]
2
2
  author = Galaxy Project and Community
3
3
  author_email = galaxy-committers@lists.galaxyproject.org
4
- classifiers =
5
- Development Status :: 5 - Production/Stable
6
- Environment :: Console
7
- Intended Audience :: Developers
8
- Natural Language :: English
9
- Operating System :: POSIX
10
- Programming Language :: Python :: 3
11
- Programming Language :: Python :: 3.10
12
- Programming Language :: Python :: 3.11
13
- Programming Language :: Python :: 3.12
14
- Programming Language :: Python :: 3.13
15
- Programming Language :: Python :: 3.14
16
- Topic :: Software Development
17
- Topic :: Software Development :: Code Generators
18
- Topic :: Software Development :: Testing
19
4
  description = Galaxy web framework
20
- keywords =
21
- Galaxy
22
5
  license = MIT
23
6
  license_files =
24
7
  LICENSE
@@ -26,7 +9,7 @@ long_description = file: README.rst, HISTORY.rst
26
9
  long_description_content_type = text/x-rst
27
10
  name = galaxy-web-framework
28
11
  url = https://github.com/galaxyproject/galaxy
29
- version = 26.0.1.dev0
12
+ version = 26.0.2
30
13
 
31
14
  [options]
32
15
  include_package_data = True
@@ -40,6 +23,7 @@ install_requires =
40
23
  requests
41
24
  Routes
42
25
  SQLAlchemy>=2.0.37,<2.1,!=2.0.41
26
+ starlette
43
27
  WebOb
44
28
  packages = find:
45
29
  python_requires = >=3.10
@@ -1,16 +0,0 @@
1
- [build-system]
2
- build-backend = "setuptools.build_meta"
3
- requires = ["setuptools"]
4
-
5
- [project]
6
- dynamic = [
7
- "authors",
8
- "dependencies",
9
- "description",
10
- "license",
11
- "optional-dependencies",
12
- "readme",
13
- "requires-python",
14
- "version",
15
- ]
16
- name = "galaxy-web-framework"