From d04b5e8dc4743890954504c265f0f840f9e97aa4 Mon Sep 17 00:00:00 2001 From: C1-BA-B1-F3 Date: Sat, 3 Oct 2026 11:31:23 +0800 Subject: [PATCH 1/3] fix(process manager): apply limit and offset in get_jobs PostgreSQL and MongoDB managers ignored the limit and offset parameters, returning all jobs regardless of the query string. Apply offset before limit in both backends, matching the existing TinyDB behaviour. Fixes #2426 --- pygeoapi/process/manager/mongodb_.py | 10 ++++++++-- pygeoapi/process/manager/postgresql.py | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pygeoapi/process/manager/mongodb_.py b/pygeoapi/process/manager/mongodb_.py index 06e6d909ad..5479bea78a 100644 --- a/pygeoapi/process/manager/mongodb_.py +++ b/pygeoapi/process/manager/mongodb_.py @@ -79,9 +79,15 @@ def get_jobs(self, status=None, limit=None, offset=None): database = self.db.job_manager_pygeoapi collection = database.jobs if status is not None: - jobs = list(collection.find({}, {"status": status})) + query = {"status": status} else: - jobs = list(collection.find({})) + query = {} + cursor = collection.find(query) + if offset: + cursor = cursor.skip(offset) + if limit: + cursor = cursor.limit(limit) + jobs = list(cursor) LOGGER.info("JOBMANAGER - MongoDB jobs queried") return { 'jobs': jobs, diff --git a/pygeoapi/process/manager/postgresql.py b/pygeoapi/process/manager/postgresql.py index cfd63eafb8..180d6ba282 100644 --- a/pygeoapi/process/manager/postgresql.py +++ b/pygeoapi/process/manager/postgresql.py @@ -133,6 +133,11 @@ def get_jobs( if status is not None: results = results.filter(self.c.status == status.value) + if offset: + results = results.offset(offset) + if limit: + results = results.limit(limit) + jobs = [r._asdict() for r in results.all()] return {'jobs': jobs, 'numberMatched': len(jobs)} From 36e9016ef59dd695c698cb41c7a3bbf0fb9af468 Mon Sep 17 00:00:00 2001 From: C1-BA-B1-F3 Date: Sat, 3 Oct 2026 12:19:58 +0800 Subject: [PATCH 2/3] fix(tiles): pass server templates to render_j2_template for TMS endpoints The tilematrixsets and tilematrixset HTML handlers passed api.tpl_config as the template configuration, but that dict carries the full server config (including 'server') and lacks the 'path' key that render_j2_template expects. The lookup therefore always fell back to the default templates, ignoring any custom theme. Pass api.config['server']['templates'] instead, matching every other render_j2_template call site. Fixes #2422 --- pygeoapi/api/tiles.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pygeoapi/api/tiles.py b/pygeoapi/api/tiles.py index afdde22b1f..cb08459f5b 100644 --- a/pygeoapi/api/tiles.py +++ b/pygeoapi/api/tiles.py @@ -389,7 +389,8 @@ def tilematrixsets(api: API, }] if request.format == F_HTML: # render - content = render_j2_template(api.tpl_config, api.tpl_config, + content = render_j2_template(api.tpl_config, + api.config['server']['templates'], 'tilematrixsets/index.html', tms, request.locale) return headers, HTTPStatus.OK, content @@ -436,7 +437,8 @@ def tilematrixset(api: API, } if request.format == F_HTML: # render - content = render_j2_template(api.tpl_config, api.tpl_config, + content = render_j2_template(api.tpl_config, + api.config['server']['templates'], 'tilematrixsets/tilematrixset.html', tms, request.locale) return headers, HTTPStatus.OK, content From a60ce90ab66130617ce919d0cb44be17c3b28cb6 Mon Sep 17 00:00:00 2001 From: C1-BA-B1-F3 Date: Sat, 3 Oct 2026 14:17:08 +0800 Subject: [PATCH 3/3] fix(provider): honour driver_name when a connection string omits the DBAPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A provider configured with a bare connection string (e.g. "postgresql://user@host/db") resolved to SQLAlchemy's default DBAPI for that backend — psycopg (v3) for PostgreSQL. Deployments that only install psycopg2 then fail with 'ModuleNotFoundError: No module named psycopg' even though the provider pins 'postgresql+psycopg2'. When the caller's URL has no '+driver' suffix and the provider's driver_name does, rewrite the URL's drivername to the pinned one. Fixes #2424 --- pygeoapi/provider/sql.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/pygeoapi/provider/sql.py b/pygeoapi/provider/sql.py index 121f48ac26..d9058d95e9 100644 --- a/pygeoapi/provider/sql.py +++ b/pygeoapi/provider/sql.py @@ -44,7 +44,7 @@ from decimal import Decimal import functools import logging -from typing import Optional, Any +from typing import Optional, Any, Union from geoalchemy2 import Geometry # noqa - this isn't used explicitly but is needed to process Geometry columns from geoalchemy2.functions import ST_MakeEnvelope, ST_Intersects @@ -60,7 +60,7 @@ desc, delete ) -from sqlalchemy.engine import URL, Engine +from sqlalchemy.engine import URL, Engine, make_url from sqlalchemy.exc import ( ConstraintColumnNotFoundError, InvalidRequestError, @@ -649,7 +649,7 @@ def get_engine( database: str, user: str, password: str, - conn_str: Optional[str] = None, + conn_str: Optional[Union[str, URL]] = None, **connect_args ) -> Engine: """ @@ -679,6 +679,18 @@ def get_engine( port=int(port), database=database ) + else: + # A caller-provided URL with a bare driver name (e.g. "postgresql://") + # resolves to SQLAlchemy's default DBAPI for that backend (psycopg v3 + # for PostgreSQL), which may not be installed. Honour the provider's + # driver_name when the URL does not already pin one. + parsed = make_url(conn_str) + if '+' not in parsed.drivername and '+' in driver_name: + backend = driver_name.split('+', 1)[0] + if parsed.drivername == backend: + conn_str = parsed.set( + drivername=driver_name + ) # Separate connection-pool tuning from DBAPI connect args. Pool keys are # applied to create_engine() directly; everything left in connect_args is