diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index edd6e172..63ab6d53 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -47,7 +47,7 @@ jobs: POSTGRESQL_VERSION: ${{matrix.POSTGRESQL_VERSION}} MYSQL_VERSION: ${{matrix.MYSQL_VERSION}} DB: ${{ matrix.DB }} - EXTRAS: tests,${{ matrix.DB }} + EXTRAS: tests,admin,${{ matrix.DB }} steps: - name: Checkout diff --git a/invenio_records/dumpers/indexedat.py b/invenio_records/dumpers/indexedat.py index c9614a1e..2af506f9 100644 --- a/invenio_records/dumpers/indexedat.py +++ b/invenio_records/dumpers/indexedat.py @@ -2,6 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2022 CERN. +# Copyright (C) 2024 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. @@ -11,7 +12,7 @@ Dumper used to dump/load the indexed time of a record to/from a search engine body. """ -import arrow +from datetime import datetime, timezone from .search import SearchDumperExt @@ -25,7 +26,7 @@ def __init__(self, key="indexed_at"): def dump(self, record, data): """Dump relations.""" - data[self.key] = arrow.utcnow().isoformat() + data[self.key] = datetime.now(timezone.utc).isoformat() def load(self, data, record_cls): """Load (remove) indexed data.""" diff --git a/invenio_records/dumpers/search.py b/invenio_records/dumpers/search.py index ec730019..6508f9bd 100644 --- a/invenio_records/dumpers/search.py +++ b/invenio_records/dumpers/search.py @@ -2,6 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2020 CERN. +# Copyright (C) 2024 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. @@ -17,7 +18,7 @@ import arrow import pytz from invenio_db import db -from sqlalchemy.sql.sqltypes import JSON, Boolean, DateTime, Integer, String, Text +from sqlalchemy.sql.sqltypes import JSON, Boolean, DateTime, Integer, String from sqlalchemy.sql.type_api import Variant from sqlalchemy_utils.types.uuid import UUIDType @@ -96,7 +97,7 @@ def _serialize(value, dump_type): if value is None: return value if dump_type in (datetime,): - return pytz.utc.localize(value).isoformat() + return value.isoformat() elif dump_type in (UUID,): return str(value) elif dump_type is not None: diff --git a/invenio_records/models.py b/invenio_records/models.py index b9beeaef..7b0a517f 100644 --- a/invenio_records/models.py +++ b/invenio_records/models.py @@ -2,6 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2015-2020 CERN. +# Copyright (C) 2024 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. @@ -10,7 +11,7 @@ import uuid from copy import deepcopy -from datetime import datetime +from datetime import datetime, timezone from invenio_db import db from sqlalchemy.dialects import mysql, postgresql @@ -19,7 +20,7 @@ from sqlalchemy_utils.types import JSONType, UUIDType -class Timestamp(object): +class Timestamp: """Timestamp model mix-in with fractional seconds support. SQLAlchemy-Utils timestamp model does not have support for fractional @@ -28,12 +29,12 @@ class Timestamp(object): created = db.Column( db.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), - default=datetime.utcnow, + default=lambda: datetime.now(timezone.utc), nullable=False, ) updated = db.Column( db.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), - default=datetime.utcnow, + default=lambda: datetime.now(timezone.utc), nullable=False, ) @@ -41,7 +42,7 @@ class Timestamp(object): @db.event.listens_for(Timestamp, "before_update", propagate=True) def timestamp_before_update(mapper, connection, target): """Update `updated` property with current time on `before_update` event.""" - target.updated = datetime.utcnow() + target.updated = datetime.now(timezone.utc) class RecordMetadataBase(Timestamp): diff --git a/invenio_records/validators.py b/invenio_records/validators.py index 5cbc4e42..392d6a02 100644 --- a/invenio_records/validators.py +++ b/invenio_records/validators.py @@ -3,6 +3,7 @@ # This file is part of Invenio. # Copyright (C) 2015-2018 CERN. # Copyright (C) 2021 TU Wien. +# Copyright (C) 2024 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. @@ -11,7 +12,7 @@ from jsonschema.validators import Draft4Validator, extend, validator_for -PartialDraft4Validator = extend(Draft4Validator, {"required": None}) +PartialDraft4Validator = extend(Draft4Validator, {"required": lambda *_: None}) """Partial JSON Schema (draft 4) validator. Special validator that contains the same validation rules of Draft4Validator, diff --git a/requirements-devel.txt b/requirements-devel.txt deleted file mode 100644 index 8ceaed28..00000000 --- a/requirements-devel.txt +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of Invenio. -# Copyright (C) 2015-2018 CERN. -# -# 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. - --e git+git://github.com/inveniosoftware/invenio-db.git#egg=invenio-db diff --git a/requirements-docs.txt b/requirements-docs.txt deleted file mode 100644 index d3b317b9..00000000 --- a/requirements-docs.txt +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of Invenio. -# Copyright (C) 2015-2018 CERN. -# -# 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. -# -# !WARNING! !WARNING! !WARNING! !WARNING! !WARNING! !WARNING! !WARNING! -# Do NOT delete this file, even when it seems to be useless! -# It used by read Read the Docs to build our documentation! -# !WARNING! !WARNING! !WARNING! !WARNING! !WARNING! !WARNING! !WARNING! - --e .[docs] diff --git a/setup.cfg b/setup.cfg index 440f3491..eb5fd6da 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,8 +38,7 @@ install_requires = [options.extras_require] tests = - pytest-black>=0.3.0 - invenio-admin>=1.4.0,<2.0.0 + pytest-black-ng>=0.3.0 pytest-invenio>=2.1.0,<3.0.0 pytest-mock>=1.6.0 sphinx>=4.5.0 diff --git a/tests/test_api.py b/tests/test_api.py index 5af37c1b..14d0d4fd 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -2,6 +2,7 @@ # # This file is part of Invenio. # Copyright (C) 2015-2018 CERN. +# Copyright (C) 2024 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. @@ -11,7 +12,7 @@ import copy import uuid -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import pytest from jsonresolver import JSONResolver @@ -22,13 +23,12 @@ from invenio_records import Record from invenio_records.errors import MissingModelError -from invenio_records.models import RecordMetadata from invenio_records.validators import PartialDraft4Validator def strip_ms(dt): """Strip microseconds.""" - return dt - timedelta(microseconds=dt.microsecond) + return (dt - timedelta(microseconds=dt.microsecond)).replace(tzinfo=None) def test_get_records(testapp, db): @@ -61,17 +61,20 @@ def test_revision_id_created_updated_properties(testapp, db): assert record.revision_id == 0 dt_c = record.created assert dt_c + assert strip_ms(record.created) == strip_ms(dt_c) dt_u = record.updated assert dt_u record["title"] = "test 2" record.commit() db.session.commit() + assert record.revision_id == 1 assert strip_ms(record.created) == strip_ms(dt_c) assert strip_ms(record.updated) >= strip_ms(dt_u) - assert dt_u.tzinfo is None - utcnow = datetime.utcnow() + # Why was that necessary to test? + # assert dt_u.tzinfo is None + utcnow = datetime.now(timezone.utc) assert dt_u > utcnow - timedelta(seconds=10) assert dt_u < utcnow + timedelta(seconds=10) diff --git a/tests/test_systemfields.py b/tests/test_systemfields.py index e4708114..32c4af05 100644 --- a/tests/test_systemfields.py +++ b/tests/test_systemfields.py @@ -3,6 +3,7 @@ # This file is part of Invenio. # Copyright (C) 2020 CERN. # Copyright (C) 2021 RERO. +# Copyright (C) 2024 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. @@ -247,14 +248,16 @@ def test_extension_post_create(testapp, db, ExtensionRecord): def test_extension_pre_dump(testapp, db, ExtensionRecord): """Test pre dump hook.""" - rec = ExtensionRecord({}).dumps() + with pytest.deprecated_call(): + rec = ExtensionRecord({}).dumps() assert ExtensionRecord.ext.called == ["pre_init", "post_init", "pre_dump"] def test_extension_post_load(testapp, db, ExtensionRecord): """Test post load hook.""" - dump = ExtensionRecord({}).dumps() - rec = ExtensionRecord.loads(dump) + with pytest.deprecated_call(): + dump = ExtensionRecord({}).dumps() + rec = ExtensionRecord.loads(dump) assert ExtensionRecord.ext.called == [ "pre_init", "post_init",