invenio-db
Advanced tools
| # -*- coding: utf-8 -*- | ||
| # | ||
| # This file is part of Invenio. | ||
| # Copyright (C) 2022 Graz University of Technology. | ||
| # | ||
| # Invenio is free software; you can redistribute it and/or modify it | ||
| # under the terms of the MIT License; see LICENSE file for more details. | ||
| """Helper proxy to the state object.""" | ||
| from flask import current_app | ||
| from werkzeug.local import LocalProxy | ||
| current_db = LocalProxy(lambda: current_app.extensions["sqlalchemy"]) |
| # -*- coding: utf-8 -*- | ||
| # | ||
| # This file is part of Invenio. | ||
| # Copyright (C) 2023 Graz University of Technology. | ||
| # | ||
| # Invenio is free software; you can redistribute it and/or modify it | ||
| # under the terms of the MIT License; see LICENSE file for more details. | ||
| """Test database integration layer.""" | ||
| from importlib_metadata import EntryPoint | ||
| from werkzeug.utils import import_string | ||
| class MockEntryPoint(EntryPoint): | ||
| """Mocking of entrypoint.""" | ||
| def load(self): | ||
| """Mock load entry point.""" | ||
| if self.name == "importfail": | ||
| raise ImportError() | ||
| else: | ||
| return import_string(self.name) | ||
| def _mock_entry_points(name): | ||
| def fn(group): | ||
| data = { | ||
| "invenio_db.models": [ | ||
| MockEntryPoint(name="demo.child", value="demo.child", group="test"), | ||
| MockEntryPoint(name="demo.parent", value="demo.parent", group="test"), | ||
| ], | ||
| "invenio_db.models_a": [ | ||
| MockEntryPoint( | ||
| name="demo.versioned_a", value="demo.versioned_a", group="test" | ||
| ), | ||
| ], | ||
| "invenio_db.models_b": [ | ||
| MockEntryPoint( | ||
| name="demo.versioned_b", value="demo.versioned_b", group="test" | ||
| ), | ||
| ], | ||
| } | ||
| if group: | ||
| return data.get(group, []) | ||
| if name: | ||
| return {name: data.get(name)} | ||
| return data | ||
| return fn |
@@ -5,3 +5,3 @@ # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2020-2024 CERN. | ||
| # Copyright (C) 2022 Graz University of Technology. | ||
| # Copyright (C) 2022-2024 Graz University of Technology. | ||
| # | ||
@@ -15,63 +15,23 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| push: | ||
| branches: master | ||
| branches: | ||
| - master | ||
| pull_request: | ||
| branches: master | ||
| branches: | ||
| - master | ||
| schedule: | ||
| # * is a special character in YAML so you have to quote this string | ||
| - cron: '0 3 * * 6' | ||
| - cron: "0 3 * * 6" | ||
| workflow_dispatch: | ||
| inputs: | ||
| reason: | ||
| description: 'Reason' | ||
| description: "Reason" | ||
| required: false | ||
| default: 'Manual trigger' | ||
| default: "Manual trigger" | ||
| jobs: | ||
| Tests: | ||
| runs-on: ubuntu-24.04 | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: [3.9, 3.12] | ||
| db-service: [postgresql11, postgresql14, mysql8, sqlite] | ||
| uses: inveniosoftware/workflows/.github/workflows/tests-python.yml@master | ||
| with: | ||
| extras: "tests,postgresql" | ||
| search-service: '[""]' | ||
| include: | ||
| - db-service: postgresql11 | ||
| EXTRAS: "tests,postgresql" | ||
| - db-service: postgresql14 | ||
| EXTRAS: "tests,postgresql" | ||
| - db-service: mysql8 | ||
| EXTRAS: "tests,mysql" | ||
| - db-service: sqlite | ||
| EXTRAS: "tests" | ||
| env: | ||
| DB: ${{ matrix.db-service }} | ||
| EXTRAS: ${{ matrix.EXTRAS }} | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Set up Python ${{ matrix.python-version }} | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| cache: pip | ||
| cache-dependency-path: setup.cfg | ||
| - name: Pre-install | ||
| uses: ./.github/actions/pre-install | ||
| if: ${{ hashFiles('.github/actions/pre-install/action.yml') != '' }} | ||
| - name: Install dependencies | ||
| run: | | ||
| pip install ".[$EXTRAS]" | ||
| pip freeze | ||
| docker version | ||
| - name: Run tests | ||
| run: ./run-tests.sh |
+18
-0
| .. | ||
| This file is part of Invenio. | ||
| Copyright (C) 2015-2024 CERN. | ||
| Copyright (C) 2024 Graz University of Technology. | ||
@@ -11,2 +12,19 @@ Invenio is free software; you can redistribute it and/or modify it | ||
| Version v2.0.0 (released 2024-11-19) | ||
| - uow: possible solution for the rollback problem | ||
| - fix: select of BinaryExpressions | ||
| - setup: increase flask-sqlalchemy | ||
| - ci: change to reusable workflows | ||
| - setup: increase min sqlalchemy dependency | ||
| - cli: password is per default hided | ||
| - refactor: move MockEntryPoint to independent file | ||
| - setup: remove upper pins | ||
| - fix: remove warning and black problems | ||
| - fix: WeakKeyDictionary | ||
| - change: add proxy file | ||
| - change: remove click 3 compatibility | ||
| - fix: tests LocalProxy | ||
| - setup: increase flask-sqlalchemy version | ||
| Version v1.3.1 (released 2024-11-14) | ||
@@ -13,0 +31,0 @@ |
| Metadata-Version: 2.1 | ||
| Name: invenio-db | ||
| Version: 1.3.1 | ||
| Version: 2.0.0 | ||
| Summary: Database management for Invenio. | ||
@@ -39,2 +39,3 @@ Home-page: https://github.com/inveniosoftware/invenio-db | ||
| Copyright (C) 2015-2024 CERN. | ||
| Copyright (C) 2024 Graz University of Technology. | ||
@@ -47,2 +48,19 @@ Invenio is free software; you can redistribute it and/or modify it | ||
| Version v2.0.0 (released 2024-11-19) | ||
| - uow: possible solution for the rollback problem | ||
| - fix: select of BinaryExpressions | ||
| - setup: increase flask-sqlalchemy | ||
| - ci: change to reusable workflows | ||
| - setup: increase min sqlalchemy dependency | ||
| - cli: password is per default hided | ||
| - refactor: move MockEntryPoint to independent file | ||
| - setup: remove upper pins | ||
| - fix: remove warning and black problems | ||
| - fix: WeakKeyDictionary | ||
| - change: add proxy file | ||
| - change: remove click 3 compatibility | ||
| - fix: tests LocalProxy | ||
| - setup: increase flask-sqlalchemy version | ||
| Version v1.3.1 (released 2024-11-14) | ||
@@ -49,0 +67,0 @@ |
@@ -1,8 +0,8 @@ | ||
| alembic<1.11.0,>=1.10.0 | ||
| Flask-Alembic>=2.0.1 | ||
| Flask-SQLAlchemy<3.0.0,>=2.1 | ||
| alembic>=1.10.0 | ||
| Flask-Alembic>=3.0.0 | ||
| Flask-SQLAlchemy>=3.0 | ||
| invenio-base>=1.2.10 | ||
| SQLAlchemy-Continuum>=1.3.12 | ||
| SQLAlchemy-Utils<0.39,>=0.33.1 | ||
| SQLAlchemy[asyncio]<1.5.0,>=1.2.18 | ||
| SQLAlchemy-Utils>=0.33.1 | ||
| SQLAlchemy[asyncio]>=2.0.0 | ||
@@ -16,3 +16,4 @@ [mysql] | ||
| [tests] | ||
| pytest-black>=0.3.0 | ||
| six>=1.0.0 | ||
| pytest-black-ng>=0.4.0 | ||
| cryptography>=2.1.4 | ||
@@ -19,0 +20,0 @@ pytest-invenio>=1.4.5 |
@@ -37,2 +37,3 @@ .dockerignore | ||
| invenio_db/ext.py | ||
| invenio_db/proxies.py | ||
| invenio_db/shared.py | ||
@@ -53,2 +54,3 @@ invenio_db/uow.py | ||
| tests/conftest.py | ||
| tests/mocks.py | ||
| tests/test_db.py | ||
@@ -55,0 +57,0 @@ tests/test_uow.py |
@@ -5,2 +5,3 @@ # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2015-2024 CERN. | ||
| # Copyright (C) 2024 Graz University of Technology. | ||
| # | ||
@@ -95,3 +96,3 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| __version__ = "1.3.1" | ||
| __version__ = "2.0.0" | ||
@@ -98,0 +99,0 @@ __all__ = ( |
@@ -26,5 +26,5 @@ # -*- coding: utf-8 -*- | ||
| "transaction", | ||
| sa.Column("issued_at", sa.DateTime(), nullable=True), | ||
| sa.Column("id", sa.BigInteger(), nullable=False), | ||
| sa.Column("remote_addr", sa.String(length=50), nullable=True), | ||
| sa.Column("issued_at", sa.DateTime(), nullable=True), | ||
| ) | ||
@@ -31,0 +31,0 @@ op.create_primary_key("pk_transaction", "transaction", ["id"]) |
+15
-27
@@ -5,2 +5,3 @@ # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2015-2018 CERN. | ||
| # Copyright (C) 2024 Graz University of Technology. | ||
| # | ||
@@ -12,20 +13,10 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| import sys | ||
| import click | ||
| from click import _termui_impl | ||
| from flask import current_app | ||
| from flask.cli import with_appcontext | ||
| from sqlalchemy_utils.functions import create_database, database_exists, drop_database | ||
| from werkzeug.local import LocalProxy | ||
| from .proxies import current_db | ||
| from .utils import create_alembic_version_table, drop_alembic_version_table | ||
| _db = LocalProxy(lambda: current_app.extensions["sqlalchemy"].db) | ||
| # Fix Python 3 compatibility issue in click | ||
| if sys.version_info > (3,): | ||
| _termui_impl.long = int # pragma: no cover | ||
| def abort_if_false(ctx, param, value): | ||
@@ -39,7 +30,3 @@ """Abort command is value is False.""" | ||
| """Render the URL for CLI output.""" | ||
| try: | ||
| return url.render_as_string(hide_password=True) | ||
| except AttributeError: | ||
| # SQLAlchemy <1.4 | ||
| return url.__to_string__(hide_password=True) | ||
| return url.render_as_string(hide_password=True) | ||
@@ -61,7 +48,7 @@ | ||
| click.secho("Creating all tables!", fg="yellow", bold=True) | ||
| with click.progressbar(_db.metadata.sorted_tables) as bar: | ||
| with click.progressbar(current_db.metadata.sorted_tables) as bar: | ||
| for table in bar: | ||
| if verbose: | ||
| click.echo(" Creating table {0}".format(table)) | ||
| table.create(bind=_db.engine, checkfirst=True) | ||
| table.create(bind=current_db.engine, checkfirst=True) | ||
| create_alembic_version_table() | ||
@@ -84,7 +71,7 @@ click.secho("Created all tables!", fg="green") | ||
| click.secho("Dropping all tables!", fg="red", bold=True) | ||
| with click.progressbar(reversed(_db.metadata.sorted_tables)) as bar: | ||
| with click.progressbar(reversed(current_db.metadata.sorted_tables)) as bar: | ||
| for table in bar: | ||
| if verbose: | ||
| click.echo(" Dropping table {0}".format(table)) | ||
| table.drop(bind=_db.engine, checkfirst=True) | ||
| table.drop(bind=current_db.engine, checkfirst=True) | ||
| drop_alembic_version_table() | ||
@@ -98,5 +85,5 @@ click.secho("Dropped all tables!", fg="green") | ||
| """Create database.""" | ||
| displayed_database = render_url(_db.engine.url) | ||
| displayed_database = render_url(current_db.engine.url) | ||
| click.secho(f"Creating database {displayed_database}", fg="green") | ||
| database_url = str(_db.engine.url) | ||
| database_url = current_db.engine.url.render_as_string(hide_password=False) | ||
| if not database_exists(database_url): | ||
@@ -117,10 +104,11 @@ create_database(database_url) | ||
| """Drop database.""" | ||
| displayed_database = render_url(_db.engine.url) | ||
| displayed_database = render_url(current_db.engine.url) | ||
| click.secho(f"Destroying database {displayed_database}", fg="red", bold=True) | ||
| if _db.engine.name == "sqlite": | ||
| plain_url = current_db.engine.url.render_as_string(hide_password=False) | ||
| if current_db.engine.name == "sqlite": | ||
| try: | ||
| drop_database(_db.engine.url) | ||
| except FileNotFoundError as e: | ||
| drop_database(plain_url) | ||
| except FileNotFoundError: | ||
| click.secho("Sqlite database has not been initialised", fg="red", bold=True) | ||
| else: | ||
| drop_database(_db.engine.url) | ||
| drop_database(plain_url) |
+9
-11
@@ -39,15 +39,13 @@ # -*- coding: utf-8 -*- | ||
| script_location = str(importlib_resources.files("invenio_db") / "alembic") | ||
| def pathify(base_entry): | ||
| return str( | ||
| importlib_resources.files(base_entry.module) | ||
| / os.path.join(base_entry.attr) | ||
| ) | ||
| entry_points = importlib_metadata.entry_points(group="invenio_db.alembic") | ||
| version_locations = [ | ||
| ( | ||
| base_entry.name, | ||
| str( | ||
| importlib_resources.files(base_entry.module) | ||
| / os.path.join(base_entry.attr) | ||
| ), | ||
| ) | ||
| for base_entry in importlib_metadata.entry_points( | ||
| group="invenio_db.alembic" | ||
| ) | ||
| (base_entry.name, pathify(base_entry)) for base_entry in entry_points | ||
| ] | ||
| script_location = str(importlib_resources.files("invenio_db") / "alembic") | ||
| app.config.setdefault( | ||
@@ -54,0 +52,0 @@ "ALEMBIC", |
| # -*- coding: utf-8 -*- | ||
| # | ||
| # Copyright (C) 2024 CERN. | ||
| # Copyright (C) 2024 Graz University of Technology. | ||
| # | ||
@@ -170,2 +171,3 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| """Entering the context.""" | ||
| self.session.begin_nested() | ||
| return self | ||
@@ -172,0 +174,0 @@ |
@@ -5,2 +5,3 @@ # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2017-2018 CERN. | ||
| # Copyright (C) 2022 Graz University of Technology. | ||
| # | ||
@@ -15,10 +16,8 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| from sqlalchemy import inspect | ||
| from werkzeug.local import LocalProxy | ||
| from .shared import db | ||
| from .proxies import current_db | ||
| from .shared import db as _db | ||
| _db = LocalProxy(lambda: current_app.extensions["sqlalchemy"].db) | ||
| def rebuild_encrypted_properties(old_key, model, properties): | ||
| def rebuild_encrypted_properties(old_key, model, properties, db=_db): | ||
| """Rebuild model's EncryptedType properties when the SECRET_KEY is changed. | ||
@@ -78,7 +77,7 @@ | ||
| """Drop alembic_version table.""" | ||
| if has_table(_db.engine, "alembic_version"): | ||
| alembic_version = _db.Table( | ||
| "alembic_version", _db.metadata, autoload_with=_db.engine | ||
| if has_table(current_db.engine, "alembic_version"): | ||
| alembic_version = current_db.Table( | ||
| "alembic_version", current_db.metadata, autoload_with=current_db.engine | ||
| ) | ||
| alembic_version.drop(bind=_db.engine) | ||
| alembic_version.drop(bind=current_db.engine) | ||
@@ -85,0 +84,0 @@ |
+19
-1
| Metadata-Version: 2.1 | ||
| Name: invenio-db | ||
| Version: 1.3.1 | ||
| Version: 2.0.0 | ||
| Summary: Database management for Invenio. | ||
@@ -39,2 +39,3 @@ Home-page: https://github.com/inveniosoftware/invenio-db | ||
| Copyright (C) 2015-2024 CERN. | ||
| Copyright (C) 2024 Graz University of Technology. | ||
@@ -47,2 +48,19 @@ Invenio is free software; you can redistribute it and/or modify it | ||
| Version v2.0.0 (released 2024-11-19) | ||
| - uow: possible solution for the rollback problem | ||
| - fix: select of BinaryExpressions | ||
| - setup: increase flask-sqlalchemy | ||
| - ci: change to reusable workflows | ||
| - setup: increase min sqlalchemy dependency | ||
| - cli: password is per default hided | ||
| - refactor: move MockEntryPoint to independent file | ||
| - setup: remove upper pins | ||
| - fix: remove warning and black problems | ||
| - fix: WeakKeyDictionary | ||
| - change: add proxy file | ||
| - change: remove click 3 compatibility | ||
| - fix: tests LocalProxy | ||
| - setup: increase flask-sqlalchemy version | ||
| Version v1.3.1 (released 2024-11-14) | ||
@@ -49,0 +67,0 @@ |
+8
-7
@@ -21,13 +21,14 @@ [metadata] | ||
| install_requires = | ||
| alembic>=1.10.0,<1.11.0 | ||
| Flask-Alembic>=2.0.1 | ||
| Flask-SQLAlchemy>=2.1,<3.0.0 | ||
| alembic>=1.10.0 | ||
| Flask-Alembic>=3.0.0 | ||
| Flask-SQLAlchemy>=3.0 | ||
| invenio-base>=1.2.10 | ||
| SQLAlchemy-Continuum>=1.3.12 | ||
| SQLAlchemy-Utils>=0.33.1,<0.39 | ||
| SQLAlchemy[asyncio]>=1.2.18,<1.5.0 | ||
| SQLAlchemy-Utils>=0.33.1 | ||
| SQLAlchemy[asyncio]>=2.0.0 | ||
| [options.extras_require] | ||
| tests = | ||
| pytest-black>=0.3.0 | ||
| six>=1.0.0 | ||
| pytest-black-ng>=0.4.0 | ||
| cryptography>=2.1.4 | ||
@@ -60,3 +61,3 @@ pytest-invenio>=1.4.5 | ||
| [pydocstyle] | ||
| add_ignore = D401 | ||
| add_ignore = D401, D202 | ||
@@ -63,0 +64,0 @@ [isort] |
@@ -20,4 +20,4 @@ # -*- coding: utf-8 -*- | ||
| @pytest.fixture() | ||
| def db(): | ||
| @pytest.fixture(name="db") | ||
| def fixture_db(): | ||
| """Database fixture with session sharing.""" | ||
@@ -24,0 +24,0 @@ import invenio_db |
+62
-63
@@ -6,2 +6,3 @@ # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2022 RERO. | ||
| # Copyright (C) 2024 Graz University of Technology. | ||
| # | ||
@@ -18,3 +19,3 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| from flask import Flask | ||
| from importlib_metadata import EntryPoint | ||
| from mocks import _mock_entry_points | ||
| from sqlalchemy import inspect | ||
@@ -24,47 +25,9 @@ from sqlalchemy.exc import IntegrityError | ||
| from sqlalchemy_utils.functions import create_database, drop_database | ||
| from werkzeug.utils import import_string | ||
| from invenio_db import InvenioDB, shared | ||
| from invenio_db import InvenioDB | ||
| from invenio_db.cli import db as db_cmd | ||
| from invenio_db.shared import NAMING_CONVENTION, MetaData, SQLAlchemy | ||
| from invenio_db.utils import drop_alembic_version_table, has_table | ||
| class MockEntryPoint(EntryPoint): | ||
| """Mocking of entrypoint.""" | ||
| def load(self): | ||
| """Mock load entry point.""" | ||
| if self.name == "importfail": | ||
| raise ImportError() | ||
| else: | ||
| return import_string(self.name) | ||
| def _mock_entry_points(name): | ||
| def fn(group): | ||
| data = { | ||
| "invenio_db.models": [ | ||
| MockEntryPoint(name="demo.child", value="demo.child", group="test"), | ||
| MockEntryPoint(name="demo.parent", value="demo.parent", group="test"), | ||
| ], | ||
| "invenio_db.models_a": [ | ||
| MockEntryPoint( | ||
| name="demo.versioned_a", value="demo.versioned_a", group="test" | ||
| ), | ||
| ], | ||
| "invenio_db.models_b": [ | ||
| MockEntryPoint( | ||
| name="demo.versioned_b", value="demo.versioned_b", group="test" | ||
| ), | ||
| ], | ||
| } | ||
| if group: | ||
| return data.get(group, []) | ||
| if name: | ||
| return {name: data.get(name)} | ||
| return data | ||
| return fn | ||
| def test_init(db, app): | ||
@@ -105,4 +68,4 @@ """Test extension initialization.""" | ||
| with app.app_context(): | ||
| Demo2.query.delete() | ||
| Demo.query.delete() | ||
| db.session.query(Demo2).delete() | ||
| db.session.query(Demo).delete() | ||
| db.session.commit() | ||
@@ -127,5 +90,4 @@ | ||
| """Test naming convention.""" | ||
| from sqlalchemy_continuum import remove_versioning | ||
| ext = InvenioDB(app, entry_point_group=False, db=db) | ||
| InvenioDB(app, entry_point_group=False, db=db) | ||
| cfg = dict( | ||
@@ -166,4 +128,4 @@ DB_VERSIONING=True, | ||
| source_db = shared.SQLAlchemy( | ||
| metadata=shared.MetaData( | ||
| source_db = SQLAlchemy( | ||
| metadata=MetaData( | ||
| naming_convention={ | ||
@@ -206,5 +168,3 @@ "ix": "source_ix_%(table_name)s_%(column_0_label)s", | ||
| target_db = shared.SQLAlchemy( | ||
| metadata=shared.MetaData(naming_convention=shared.NAMING_CONVENTION) | ||
| ) | ||
| target_db = SQLAlchemy(metadata=MetaData(naming_convention=NAMING_CONVENTION)) | ||
| target_app = Flask("target_app") | ||
@@ -230,3 +190,3 @@ target_app.config.update(**cfg) | ||
| cns.name | ||
| for model in source_models | ||
| for model in target_models | ||
| for cns in list(model.__table__.constraints) | ||
@@ -313,2 +273,5 @@ + list(model.__table__.indexes) | ||
| result = runner.invoke(db_cmd, ["init"]) | ||
| assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["destroy", "--yes-i-know"]) | ||
@@ -323,2 +286,17 @@ assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["destroy", "--yes-i-know"]) | ||
| assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["init"]) | ||
| assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["create", "-v"]) | ||
| assert result.exit_code == 1 | ||
| result = runner.invoke(db_cmd, ["create", "-v"]) | ||
| assert result.exit_code == 1 | ||
| result = runner.invoke(db_cmd, ["drop", "-v", "--yes-i-know"]) | ||
| assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["drop"]) | ||
@@ -334,6 +312,9 @@ assert result.exit_code == 1 | ||
| result = runner.invoke(db_cmd, ["drop", "--yes-i-know", "create"]) | ||
| assert result.exit_code == 1 | ||
| result = runner.invoke(db_cmd, ["destroy", "--yes-i-know"]) | ||
| assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["destroy"]) | ||
| assert result.exit_code == 1 | ||
| result = runner.invoke(db_cmd, ["init"]) | ||
| assert result.exit_code == 0 | ||
@@ -346,7 +327,20 @@ result = runner.invoke(db_cmd, ["destroy", "--yes-i-know"]) | ||
| result = runner.invoke(db_cmd, ["destroy", "--yes-i-know"]) | ||
| assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["init"]) | ||
| assert result.exit_code == 0 | ||
| result = runner.invoke(db_cmd, ["drop", "-v", "--yes-i-know"]) | ||
| assert result.exit_code == 1 | ||
| result = runner.invoke(db_cmd, ["create", "-v"]) | ||
| assert result.exit_code == 1 | ||
| result = runner.invoke(db_cmd, ["drop", "-v", "--yes-i-know"]) | ||
| assert result.exit_code == 0 | ||
| def test_local_proxy(app, db): | ||
| """Test local proxy filter.""" | ||
| from werkzeug.local import LocalProxy | ||
| InvenioDB(app, db=db) | ||
@@ -356,3 +350,3 @@ | ||
| query = db.select( | ||
| [ | ||
| *[ | ||
| db.literal("hello") != db.bindparam("a"), | ||
@@ -364,8 +358,10 @@ db.literal(0) <= db.bindparam("x"), | ||
| ) | ||
| result = db.engine.execute( | ||
| result = db.session.execute( | ||
| query, | ||
| a=LocalProxy(lambda: "world"), | ||
| x=LocalProxy(lambda: 1), | ||
| y=LocalProxy(lambda: "2"), | ||
| z=LocalProxy(lambda: None), | ||
| { | ||
| "a": "world", | ||
| "x": 1, | ||
| "y": "2", | ||
| "z": None, | ||
| }, | ||
| ).fetchone() | ||
@@ -389,2 +385,3 @@ assert result == (True, True, True, True) | ||
| raise pytest.skip("Upgrades are not supported on SQLite.") | ||
| db.drop_all() | ||
@@ -398,2 +395,3 @@ runner = app.test_cli_runner() | ||
| assert ext.alembic.migration_context._has_version_table() | ||
| # Note that compare_metadata does not detect additional sequences | ||
@@ -404,2 +402,3 @@ # and constraints. | ||
| assert not ext.alembic.compare_metadata() | ||
| ext.alembic.upgrade() | ||
@@ -424,4 +423,4 @@ assert has_table(db.engine, "transaction") | ||
| finally: | ||
| drop_database(str(db.engine.url)) | ||
| drop_database(str(db.engine.url.render_as_string(hide_password=False))) | ||
| remove_versioning(manager=ext.versioning_manager) | ||
| create_database(str(db.engine.url)) | ||
| create_database(str(db.engine.url.render_as_string(hide_password=False))) |
@@ -5,2 +5,3 @@ # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2017-2018 CERN. | ||
| # Copyright (C) 2023 Graz University of Technology. | ||
| # | ||
@@ -15,3 +16,3 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| from sqlalchemy_continuum import remove_versioning | ||
| from sqlalchemy_utils.types import EncryptedType | ||
| from sqlalchemy_utils.types import StringEncryptedType | ||
@@ -38,3 +39,4 @@ from invenio_db import InvenioDB | ||
| et = db.Column( | ||
| EncryptedType(type_in=db.Unicode, key=_secret_key), nullable=False | ||
| StringEncryptedType(length=255, type_in=db.Unicode, key=_secret_key), | ||
| nullable=False, | ||
| ) | ||
@@ -56,3 +58,3 @@ | ||
| with pytest.raises(AttributeError): | ||
| rebuild_encrypted_properties(old_secret_key, Demo, ["nonexistent"]) | ||
| rebuild_encrypted_properties(old_secret_key, Demo, ["nonexistent"], db) | ||
| assert app.secret_key == new_secret_key | ||
@@ -63,3 +65,3 @@ | ||
| db.session.query(Demo).all() | ||
| rebuild_encrypted_properties(old_secret_key, Demo, ["et"]) | ||
| rebuild_encrypted_properties(old_secret_key, Demo, ["et"], db) | ||
| d1_after = db.session.query(Demo).first() | ||
@@ -66,0 +68,0 @@ assert d1_after.et == "something" |
@@ -6,2 +6,3 @@ # -*- coding: utf-8 -*- | ||
| # Copyright (C) 2022 RERO. | ||
| # Copyright (C) 2024 Graz University of Technology. | ||
| # | ||
@@ -16,4 +17,4 @@ # Invenio is free software; you can redistribute it and/or modify it | ||
| import pytest | ||
| from mocks import _mock_entry_points | ||
| from sqlalchemy_continuum import VersioningManager, remove_versioning | ||
| from test_db import _mock_entry_points | ||
@@ -37,2 +38,4 @@ from invenio_db import InvenioDB | ||
| # this class has to be defined here, because the the db has to be the db | ||
| # from the fixture. using it "from invenio_db import db" is not working | ||
| class EarlyClass(db.Model): | ||
@@ -51,3 +54,2 @@ __versioned__ = {} | ||
| before = len(db.metadata.tables) | ||
| ec = EarlyClass() | ||
@@ -54,0 +56,0 @@ ec.pk = 1 |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
136522
2.53%63
3.28%1829
2.18%