Skip to content

Commit 3f51cf5

Browse files
committed
🚀 port changes of bdc-db 0.8.0
1 parent d6b4d0e commit 3f51cf5

12 files changed

Lines changed: 193 additions & 128 deletions

File tree

CHANGES.rst

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
..
22
This file is part of BDC-DB.
3-
Copyright (C) 2023 INPE.
3+
Copyright (C) 2025 INPE.
44
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
@@ -21,13 +21,16 @@ BDC-DB - Changes
2121
================
2222

2323

24-
Version 0.8.0 (2023-10-02)
24+
Version 0.8.0 (2026-02-12)
2525
--------------------------
2626

27-
- Upgrade libraries dependencies and support of SQLAlchemy 2x. (`#73 <https://github.com/brazil-data-cube/bdc-db/issues/73>`_).
28-
- Improve documentation for setup and extension.
29-
- Improve package Python version support: 3.8, 3.9, 3.10, 3.11+
30-
- Review unittests for bdc-db
27+
- Add support of pyproject toml (#78)
28+
- Add support of Python versions: 3.9, 3.10, 3.11, 3.12 and 3.13+
29+
- Drop support of pkg_resources (#77)
30+
- Review default values of SQLAlchemy engine options ``SQLALCHEMY_ENGINE_OPTIONS``.
31+
- Review documentation setup
32+
- Review unittests
33+
- Upgrade libraries dependencies and support of SQLAlchemy 2x. #73
3134

3235

3336
Version 0.6.3 (2022-09-22)

bdc_db/cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232

3333
def abort_if_false(ctx, param, value):
34-
"""Callback that checks the user confirmation of a command."""
34+
"""Define the callback that checks the user confirmation of a command."""
3535
if not value:
3636
ctx.abort()
3737

@@ -161,7 +161,7 @@ def show_namespaces():
161161
@db.command()
162162
@with_appcontext
163163
def create_extension_postgis():
164-
"""Enables the PostGIS extenion in the database."""
164+
"""Enable the PostGIS extenion in the database."""
165165
click.secho(f'Creating extension postgis...', bold=True, fg='yellow')
166166

167167
with _db.session.begin_nested():
@@ -207,7 +207,7 @@ def create_triggers(verbose):
207207
if verbose:
208208
click.secho(content)
209209

210-
execute(content, executor=_db.session)
210+
execute(content, executor=_db.session, commit=False)
211211

212212
click.secho(f'Triggers from "{module_name}" registered', bold=True, fg='green')
213213

bdc_db/config.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@
2727

2828
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI',
2929
'postgresql://postgres:postgres@localhost:5432/bdc')
30-
"""The database URI that should be used for the database connection.
30+
"""The database URI that should be used for the database connection.
3131
3232
Defaults to ``'postgresql://postgres:postgres@localhost:5432/bdc'``."""
3333

3434
SQLALCHEMY_TRACK_MODIFICATIONS = os.getenv('SQLALCHEMY_TRACK_MODIFICATIONS', False)
35-
"""Enable (True) or disable (False) signals before and after changes are committed to the database.
35+
"""Enable (True) or disable (False) signals before and after changes are committed to the database.
3636
3737
Defaults to ``False``."""
3838

@@ -45,7 +45,11 @@
4545
"""Define the hostname for any JSONSchemas supported by Brazil Data Cube."""
4646

4747
SQLALCHEMY_ENGINE_OPTIONS = dict(
48-
pool_pre_ping=True
48+
pool_pre_ping=True,
49+
pool_recycle=int(os.getenv("SQLALCHEMY_ENGINE_POOL_RECYCLE", 3600)),
50+
pool_size=int(os.getenv("SQLALCHEMY_ENGINE_POOL_SIZE", 2)),
51+
max_overflow=int(os.getenv("SQLALCHEMY_ENGINE_MAX_OVERFLOW", 1)),
52+
poolclass=os.getenv("SQLALCHEMY_ENGINE_POOL_CLASS"),
4953
)
5054
"""Set default engine options for SQLAlchemy instance.
5155

bdc_db/ext.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#
22
# This file is part of BDC-DB.
3-
# Copyright (C) 2022 INPE.
3+
# Copyright (C) 2025 INPE.
44
#
55
# This program is free software: you can redistribute it and/or modify
66
# it under the terms of the GNU General Public License as published by
@@ -18,8 +18,7 @@
1818

1919
"""Database management extension for Brazil Data Cube applications and services."""
2020

21-
import importlib.resources
22-
from importlib.metadata import entry_points
21+
from importlib.util import find_spec
2322
from pathlib import Path
2423
from typing import Dict, Iterable, List
2524

@@ -30,6 +29,7 @@
3029

3130
from . import config as _config
3231
from .db import db as _db
32+
from .utils import entry_points
3333

3434

3535
def alembic_include_object(object, name, type_, reflected, compare_to): # pragma: no cover
@@ -95,6 +95,9 @@ def init_app(self, app, **kwargs):
9595
entry_point_jsonschemas (str): Custom entry point group for JSONSchemas
9696
engine_options (dict): Custom SQLAlchemy Engine Options for instance object.
9797
"""
98+
if "bdc-db" in app.extensions:
99+
return # Ignore, already initialized.
100+
98101
self.init_db(app, **kwargs)
99102

100103
# Load package namespaces
@@ -108,15 +111,15 @@ def init_app(self, app, **kwargs):
108111

109112
# prepare the configuration for multiple named branches
110113
# according to each package entry point
111-
script_location = str(importlib.resources.path('bdc_db', 'alembic'))
114+
script_location = resource_path("bdc_db.alembic")
112115

113116
entrypoints = entry_points(group="bdc_db.alembic")
114117

115-
version_locations = [
116-
(base_entry.name, str(importlib.resources.path(
117-
base_entry.name, base_entry.attr
118-
))) for base_entry in entrypoints
119-
]
118+
version_locations = []
119+
for entry in entrypoints:
120+
entry_name = f"{entry.name}.{entry.attr}"
121+
122+
version_locations.append((entry.name, resource_path(entry_name)))
120123

121124
if ('bdc_db', script_location) in version_locations: # pragma: no cover
122125
version_locations.remove(('bdc_db', str(script_location)))
@@ -154,18 +157,21 @@ def init_app(self, app, **kwargs):
154157
# Add BDC-DB extension to Flask extension list
155158
app.extensions['bdc-db'] = self
156159

157-
def init_db(self, app, entry_point_group: str = 'bdc_db.models', engine_options=None, **kwargs):
160+
def init_db(self, app, entry_point_group: str = 'bdc_db.models', engine_options=None, uri: str = None, **kwargs):
158161
"""Initialize Flask-SQLAlchemy extension.
159162
160163
Args:
161164
app: Flask application
162165
entry_point_group: Entrypoint definition to load models
163166
engine_options: DB instance engine options
167+
uri: the URI to override SQLAlchemy database uri from environment. Defaults to env ``SQLALCHEMY_DATABASE_URI``.
164168
kwargs: optional Arguments to Flask-SQLAlchemy.
165169
"""
170+
uri = uri or _config.SQLALCHEMY_DATABASE_URI
171+
166172
# Setup SQLAlchemy
167173
app.config.setdefault('SQLALCHEMY_DATABASE_URI',
168-
_config.SQLALCHEMY_DATABASE_URI)
174+
uri)
169175

170176
app.config.setdefault('SQLALCHEMY_TRACK_MODIFICATIONS',
171177
_config.SQLALCHEMY_TRACK_MODIFICATIONS)
@@ -271,4 +277,18 @@ def register_scripts(self, module_name: str, trigger_name: str, path: str):
271277
"""Register trigger command to BDC-DB."""
272278
self.scripts.setdefault(module_name, dict())
273279

274-
self.scripts[module_name][trigger_name] = path
280+
self.scripts[module_name][trigger_name] = path
281+
282+
283+
def resource_path(entry_name: str):
284+
"""Resolve the module path.
285+
286+
Note:
287+
This method returns None when not found or its invalid.
288+
"""
289+
spec = find_spec(entry_name)
290+
291+
if spec and spec.submodule_search_locations:
292+
path = list(spec.submodule_search_locations)[0]
293+
294+
return str(path)

bdc_db/utils.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def delete_trigger(name: str, engine: Engine, table: str, schema: str = None):
105105
execute(f'DROP TRIGGER IF EXISTS {name} ON {schema}.{table}', engine)
106106

107107

108-
def execute(statement: t.Union[str, t.Any], executor: t.Union[Engine, t.Any], *args, **kwargs):
108+
def execute(statement: t.Union[str, t.Any], executor: t.Union[Engine, t.Any], commit=True, *args, **kwargs):
109109
"""Execute a query statement in SQLAlchemy database engine.
110110
111111
Args:
@@ -116,10 +116,12 @@ def execute(statement: t.Union[str, t.Any], executor: t.Union[Engine, t.Any], *a
116116
statement = text(statement)
117117

118118
if isinstance(executor, Engine):
119-
with executor.connect() as conn:
119+
with executor.begin() as conn:
120120
result = conn.execute(statement, *args, **kwargs)
121121
else:
122122
result = executor.execute(statement, *args, **kwargs)
123+
if commit:
124+
executor.commit()
123125

124126
return result
125127

@@ -135,3 +137,31 @@ def has_schema(engine: Engine, schema: str, **kwargs) -> bool:
135137
"""
136138
inspector = inspect(engine)
137139
return inspector.has_schema(schema, **kwargs)
140+
141+
142+
def entry_points(group):
143+
"""Retrieve the package entrypoints based on group name.
144+
145+
This method resolves the retro-compatibility between python versions.
146+
On <3.10, the group property is not available due implementation.
147+
To solve that, you should use importlib_metadata instead importlib.metadata.
148+
149+
This method should be removed when we drop support on python 3.9.
150+
Its based on invenio-base:
151+
https://github.com/inveniosoftware/invenio-base/blob/9f1b8ce862f9a865291f2adfe3916459b08c73e3/invenio_base/utils.py#L19
152+
"""
153+
import importlib.metadata
154+
from sys import version_info
155+
156+
if version_info < (3, 10):
157+
eps = importlib.metadata.entry_points()
158+
if isinstance(eps, dict):
159+
eps = list(set(eps.get(group, [])))
160+
else:
161+
eps = {
162+
ep.name: ep for ep in eps
163+
}
164+
else:
165+
eps = importlib.metadata.entry_points(group=group)
166+
167+
return eps

bdc_db/version.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@
1818

1919
"""Version information for BDC-DB."""
2020

21-
__version__ = '0.8.0'
21+
from importlib.metadata import version
22+
23+
__version__ = version(__package__)

docs/sphinx/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@
7171
html_theme = 'sphinx_rtd_theme'
7272

7373
html_theme_options = {
74-
'analytics_id': 'XXXXXXXXXX',
74+
# 'analytics_id': 'XXXXXXXXXX',
7575
'logo_only': False,
76-
'display_version': True,
76+
# 'display_version': True,
7777
'prev_next_buttons_location': 'both',
7878
'style_external_links': True,
7979
#'vcs_pageview_mode': 'edit',

pyproject.toml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
[project]
2+
name = "bdc-db"
3+
description = "A database management extension for Brazil Data Cube Applications and Services."
4+
readme = "README.rst"
5+
requires-python = ">=3.8"
6+
license = "GPL-3.0-only"
7+
authors = [
8+
{name = "Brazil Data Cube Team", email = "[email protected]"},
9+
]
10+
keywords = [
11+
"database",
12+
"postgres",
13+
"bdc",
14+
"big",
15+
"orm",
16+
]
17+
classifiers = [
18+
"Intended Audience :: Information Technology",
19+
"Intended Audience :: Science/Research",
20+
"Programming Language :: Python :: 3.8",
21+
"Programming Language :: Python :: 3.9",
22+
"Programming Language :: Python :: 3.10",
23+
"Programming Language :: Python :: 3.11",
24+
"Programming Language :: Python :: 3.12",
25+
"Programming Language :: Python :: 3.13",
26+
"Topic :: Software Development :: Libraries :: Python Modules",
27+
]
28+
version="0.8.0"
29+
dependencies = [
30+
"Flask>=2",
31+
"Flask-SQLAlchemy>=3.0",
32+
"Flask-Alembic>=2.0.0,<3.2.0",
33+
"invenio-jsonschemas>=1.1.4",
34+
"jsonschema>=3",
35+
"psycopg2-binary>=2.8",
36+
"SQLAlchemy>=1.3",
37+
"SQLAlchemy-Utils>=0.40.0",
38+
"alembic>=1.12",
39+
]
40+
41+
# Extras Dependencies
42+
[project.optional-dependencies]
43+
dev = ["pre-commit"]
44+
docs = [
45+
"Sphinx>=7.0",
46+
"sphinx_rtd_theme",
47+
"sphinx-copybutton",
48+
"sphinx-tabs",
49+
]
50+
tests = [
51+
"coverage>=6.4",
52+
"coveralls>=3.3",
53+
"pytest>=7.4",
54+
"pytest-cov>=4.1",
55+
"pydocstyle>=4.0",
56+
"isort>4.3",
57+
"check-manifest>=0.40",
58+
]
59+
all = ["bdc-db[docs,tests]"]
60+
## End extras dependencies
61+
62+
[build-system]
63+
requires = ["setuptools>=67.0", "wheel"]
64+
build-backend = "setuptools.build_meta"
65+
66+
[tool.setuptools.packages.find]
67+
include = ["bdc_db*"]
68+
exclude = ["tests*"]
69+
namespaces = false
70+
71+
[tool.setuptools.package-data]
72+
"bdc_db" = ["py.typed", "alembic/**"]
73+
74+
[project.urls]
75+
Homepage = "https://github.com/brazil-data-cube/bdc-db"
76+
Documentation = "https://github.com/brazil-data-cube/bdc-db"
77+
Issues = "https://github.com/brazil-data-cube/bdc-db/-/issues"
78+
Source = "https://github.com/brazil-data-cube/bdc-db"
79+
# Changelog = ""
80+
81+
[project.scripts]
82+
bdc-db = "bdc_db.cli:cli"

run-tests.sh

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@
1919

2020
pydocstyle bdc_db tests setup.py && \
2121
isort bdc_db tests setup.py --check-only --diff && \
22-
check-manifest --ignore ".travis-*" --ignore ".readthedocs.*" && \
22+
check-manifest --ignore ".travis-*" && \
2323
sphinx-build -qnW --color -b doctest docs/sphinx/ docs/sphinx/_build/doctest && \
24-
pytest
24+
25+
# When mode is package, just set context to wheel package name. Otherwise, it the local bdc_db fill fallback as default and no coverage will be found.
26+
if [ "${MODE}" == "package" ]; then
27+
mkdir -p tmp && cd tmp
28+
pytest ../tests --pyargs bdc_db --cov=bdc_db
29+
cd .. && rm -r tmp
30+
else
31+
pytest
32+
fi

0 commit comments

Comments
 (0)